thread_sgi.h 8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <ulocks.h>
#include <errno.h>

11 12
#define HDR_SIZE        2680    /* sizeof(ushdr_t) */
#define MAXPROC         100     /* max # of threads that can be started */
13 14

static usptr_t *shared_arena;
15 16 17 18
static ulock_t count_lock;      /* protection for some variables */
static ulock_t wait_lock;       /* lock used to wait for other threads */
static int waiting_for_threads; /* protected by count_lock */
static int nthreads;            /* protected by count_lock */
19
static int exit_status;
20 21
static int exiting;             /* we're already exiting (for maybe_exit) */
static pid_t my_pid;            /* PID of main thread */
22
static struct pidlist {
23 24 25 26
    pid_t parent;
    pid_t child;
} pidlist[MAXPROC];     /* PIDs of other threads; protected by count_lock */
static int maxpidindex;         /* # of PIDs in pidlist */
27 28 29
/*
 * Initialization.
 */
30
static void PyThread__init_thread(void)
31 32
{
#ifdef USE_DL
33
    long addr, size;
34 35 36 37
#endif /* USE_DL */


#ifdef USE_DL
38 39 40 41 42 43 44 45 46
    if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
        perror("usconfig - CONF_INITSIZE (check)");
    if (usconfig(CONF_INITSIZE, size) < 0)
        perror("usconfig - CONF_INITSIZE (reset)");
    addr = (long) dl_getrange(size + HDR_SIZE);
    dprintf(("trying to use addr %p-%p for shared arena\n", addr, addr+size));
    errno = 0;
    if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
        perror("usconfig - CONF_ATTACHADDR (set)");
47
#endif /* USE_DL */
48 49 50 51 52 53
    if (usconfig(CONF_INITUSERS, 16) < 0)
        perror("usconfig - CONF_INITUSERS");
    my_pid = getpid();          /* so that we know which is the main thread */
    if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0)
        perror("usconfig - CONF_ARENATYPE");
    usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */
54
#ifdef Py_DEBUG
55 56 57 58
    if (thread_debug & 4)
        usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);
    else if (thread_debug & 2)
        usconfig(CONF_LOCKTYPE, US_DEBUG);
59
#endif /* Py_DEBUG */
60 61
    if ((shared_arena = usinit(tmpnam(0))) == 0)
        perror("usinit");
62
#ifdef USE_DL
63 64
    if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
        perror("usconfig - CONF_ATTACHADDR (reset)");
65
#endif /* USE_DL */
66 67 68 69 70 71
    if ((count_lock = usnewlock(shared_arena)) == NULL)
        perror("usnewlock (count_lock)");
    (void) usinitlock(count_lock);
    if ((wait_lock = usnewlock(shared_arena)) == NULL)
        perror("usnewlock (wait_lock)");
    dprintf(("arena start: %p, arena size: %ld\n",  shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena)));
72 73 74 75 76 77
}

/*
 * Thread support.
 */

78
static void clean_threads(void)
79
{
80 81
    int i, j;
    pid_t mypid, pid;
82

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
    /* clean up any exited threads */
    mypid = getpid();
    i = 0;
    while (i < maxpidindex) {
        if (pidlist[i].parent == mypid && (pid = pidlist[i].child) > 0) {
            pid = waitpid(pid, 0, WNOHANG);
            if (pid > 0) {
                /* a thread has exited */
                pidlist[i] = pidlist[--maxpidindex];
                /* remove references to children of dead proc */
                for (j = 0; j < maxpidindex; j++)
                    if (pidlist[j].parent == pid)
                        pidlist[j].child = -1;
                continue; /* don't increment i */
            }
        }
        i++;
    }
    /* clean up the list */
    i = 0;
    while (i < maxpidindex) {
        if (pidlist[i].child == -1) {
            pidlist[i] = pidlist[--maxpidindex];
            continue; /* don't increment i */
        }
        i++;
    }
110 111
}

112
long PyThread_start_new_thread(void (*func)(void *), void *arg)
113 114
{
#ifdef USE_DL
115 116
    long addr, size;
    static int local_initialized = 0;
117
#endif /* USE_DL */
118 119
    int success = 0;            /* init not needed when SOLARIS_THREADS and */
                /* C_THREADS implemented properly */
120

121 122 123 124 125 126 127 128 129 130
    dprintf(("PyThread_start_new_thread called\n"));
    if (!initialized)
        PyThread_init_thread();
    switch (ussetlock(count_lock)) {
    case 0: return 0;
    case -1: perror("ussetlock (count_lock)");
    }
    if (maxpidindex >= MAXPROC)
        success = -1;
    else {
131
#ifdef USE_DL
132 133 134 135 136 137 138 139 140 141 142 143 144
        if (!local_initialized) {
            if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
                perror("usconfig - CONF_INITSIZE (check)");
            if (usconfig(CONF_INITSIZE, size) < 0)
                perror("usconfig - CONF_INITSIZE (reset)");
            addr = (long) dl_getrange(size + HDR_SIZE);
            dprintf(("trying to use addr %p-%p for sproc\n",
                     addr, addr+size));
            errno = 0;
            if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 &&
                errno != 0)
                perror("usconfig - CONF_ATTACHADDR (set)");
        }
145
#endif /* USE_DL */
146 147 148
        clean_threads();
        if ((success = sproc(func, PR_SALL, arg)) < 0)
            perror("sproc");
149
#ifdef USE_DL
150 151 152 153 154 155
        if (!local_initialized) {
            if (usconfig(CONF_ATTACHADDR, addr) < 0)
                /* reset address */
                perror("usconfig - CONF_ATTACHADDR (reset)");
            local_initialized = 1;
        }
156
#endif /* USE_DL */
157 158 159 160 161 162 163 164 165 166 167
        if (success >= 0) {
            nthreads++;
            pidlist[maxpidindex].parent = getpid();
            pidlist[maxpidindex++].child = success;
            dprintf(("pidlist[%d] = %d\n",
                     maxpidindex-1, success));
        }
    }
    if (usunsetlock(count_lock) < 0)
        perror("usunsetlock (count_lock)");
    return success;
168 169
}

170
long PyThread_get_thread_ident(void)
171
{
172
    return getpid();
173 174
}

175
void PyThread_exit_thread(void)
176
{
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
    dprintf(("PyThread_exit_thread called\n"));
    if (!initialized)
        exit(0);
    if (ussetlock(count_lock) < 0)
        perror("ussetlock (count_lock)");
    nthreads--;
    if (getpid() == my_pid) {
        /* main thread; wait for other threads to exit */
        exiting = 1;
        waiting_for_threads = 1;
        if (ussetlock(wait_lock) < 0)
            perror("ussetlock (wait_lock)");
        for (;;) {
            if (nthreads < 0) {
                dprintf(("really exit (%d)\n", exit_status));
                exit(exit_status);
            }
            if (usunsetlock(count_lock) < 0)
                perror("usunsetlock (count_lock)");
            dprintf(("waiting for other threads (%d)\n", nthreads));
            if (ussetlock(wait_lock) < 0)
                perror("ussetlock (wait_lock)");
            if (ussetlock(count_lock) < 0)
                perror("ussetlock (count_lock)");
        }
    }
    /* not the main thread */
    if (waiting_for_threads) {
        dprintf(("main thread is waiting\n"));
        if (usunsetlock(wait_lock) < 0)
            perror("usunsetlock (wait_lock)");
    }
    if (usunsetlock(count_lock) < 0)
        perror("usunsetlock (count_lock)");
    _exit(0);
212 213 214 215 216
}

/*
 * Lock support.
 */
217
PyThread_type_lock PyThread_allocate_lock(void)
218
{
219
    ulock_t lock;
220

221 222 223
    dprintf(("PyThread_allocate_lock called\n"));
    if (!initialized)
        PyThread_init_thread();
224

225 226 227 228 229
    if ((lock = usnewlock(shared_arena)) == NULL)
        perror("usnewlock");
    (void) usinitlock(lock);
    dprintf(("PyThread_allocate_lock() -> %p\n", lock));
    return (PyThread_type_lock) lock;
230 231
}

232
void PyThread_free_lock(PyThread_type_lock lock)
233
{
234 235
    dprintf(("PyThread_free_lock(%p) called\n", lock));
    usfreelock((ulock_t) lock, shared_arena);
236 237
}

238
int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
239
{
240
    int success;
241

242 243 244 245 246 247 248 249 250 251
    dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
    errno = 0;                  /* clear it just in case */
    if (waitflag)
        success = ussetlock((ulock_t) lock);
    else
        success = uscsetlock((ulock_t) lock, 1); /* Try it once */
    if (success < 0)
        perror(waitflag ? "ussetlock" : "uscsetlock");
    dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
    return success;
252 253
}

254
void PyThread_release_lock(PyThread_type_lock lock)
255
{
256 257 258
    dprintf(("PyThread_release_lock(%p) called\n", lock));
    if (usunsetlock((ulock_t) lock) < 0)
        perror("usunsetlock");
259
}