1 2 #include <stdlib.h> 3 #include <stdio.h> 4 #include <signal.h> 5 #include <sys/types.h> 6 #include <sys/wait.h> 7 #include <sys/prctl.h> 8 #include <ulocks.h> 9 #include <errno.h> 10 11 #define HDR_SIZE 2680 /* sizeof(ushdr_t) */ 12 #define MAXPROC 100 /* max # of threads that can be started */ 13 14 static usptr_t *shared_arena; 15 static ulock_t count_lock; /* protection for some variables */ 16 static ulock_t wait_lock; /* lock used to wait for other threads */ 17 static int waiting_for_threads; /* protected by count_lock */ 18 static int nthreads; /* protected by count_lock */ 19 static int exit_status; 20 static int exiting; /* we're already exiting (for maybe_exit) */ 21 static pid_t my_pid; /* PID of main thread */ 22 static struct pidlist { 23 pid_t parent; 24 pid_t child; 25 } pidlist[MAXPROC]; /* PIDs of other threads; protected by count_lock */ 26 static int maxpidindex; /* # of PIDs in pidlist */ 27 /* 28 * Initialization. 29 */ 30 static void PyThread__init_thread(void) 31 { 32 #ifdef USE_DL 33 long addr, size; 34 #endif /* USE_DL */ 35 36 37 #ifdef USE_DL 38 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0) 39 perror("usconfig - CONF_INITSIZE (check)"); 40 if (usconfig(CONF_INITSIZE, size) < 0) 41 perror("usconfig - CONF_INITSIZE (reset)"); 42 addr = (long) dl_getrange(size + HDR_SIZE); 43 dprintf(("trying to use addr %p-%p for shared arena\n", addr, addr+size)); 44 errno = 0; 45 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0) 46 perror("usconfig - CONF_ATTACHADDR (set)"); 47 #endif /* USE_DL */ 48 if (usconfig(CONF_INITUSERS, 16) < 0) 49 perror("usconfig - CONF_INITUSERS"); 50 my_pid = getpid(); /* so that we know which is the main thread */ 51 if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0) 52 perror("usconfig - CONF_ARENATYPE"); 53 usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */ 54 #ifdef Py_DEBUG 55 if (thread_debug & 4) 56 usconfig(CONF_LOCKTYPE, US_DEBUGPLUS); 57 else if (thread_debug & 2) 58 usconfig(CONF_LOCKTYPE, US_DEBUG); 59 #endif /* Py_DEBUG */ 60 if ((shared_arena = usinit(tmpnam(0))) == 0) 61 perror("usinit"); 62 #ifdef USE_DL 63 if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */ 64 perror("usconfig - CONF_ATTACHADDR (reset)"); 65 #endif /* USE_DL */ 66 if ((count_lock = usnewlock(shared_arena)) == NULL) 67 perror("usnewlock (count_lock)"); 68 (void) usinitlock(count_lock); 69 if ((wait_lock = usnewlock(shared_arena)) == NULL) 70 perror("usnewlock (wait_lock)"); 71 dprintf(("arena start: %p, arena size: %ld\n", shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena))); 72 } 73 74 /* 75 * Thread support. 76 */ 77 78 static void clean_threads(void) 79 { 80 int i, j; 81 pid_t mypid, pid; 82 83 /* clean up any exited threads */ 84 mypid = getpid(); 85 i = 0; 86 while (i < maxpidindex) { 87 if (pidlist[i].parent == mypid && (pid = pidlist[i].child) > 0) { 88 pid = waitpid(pid, 0, WNOHANG); 89 if (pid > 0) { 90 /* a thread has exited */ 91 pidlist[i] = pidlist[--maxpidindex]; 92 /* remove references to children of dead proc */ 93 for (j = 0; j < maxpidindex; j++) 94 if (pidlist[j].parent == pid) 95 pidlist[j].child = -1; 96 continue; /* don't increment i */ 97 } 98 } 99 i++; 100 } 101 /* clean up the list */ 102 i = 0; 103 while (i < maxpidindex) { 104 if (pidlist[i].child == -1) { 105 pidlist[i] = pidlist[--maxpidindex]; 106 continue; /* don't increment i */ 107 } 108 i++; 109 } 110 } 111 112 long PyThread_start_new_thread(void (*func)(void *), void *arg) 113 { 114 #ifdef USE_DL 115 long addr, size; 116 static int local_initialized = 0; 117 #endif /* USE_DL */ 118 int success = 0; /* init not needed when SOLARIS_THREADS and */ 119 /* C_THREADS implemented properly */ 120 121 dprintf(("PyThread_start_new_thread called\n")); 122 if (!initialized) 123 PyThread_init_thread(); 124 switch (ussetlock(count_lock)) { 125 case 0: return 0; 126 case -1: perror("ussetlock (count_lock)"); 127 } 128 if (maxpidindex >= MAXPROC) 129 success = -1; 130 else { 131 #ifdef USE_DL 132 if (!local_initialized) { 133 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0) 134 perror("usconfig - CONF_INITSIZE (check)"); 135 if (usconfig(CONF_INITSIZE, size) < 0) 136 perror("usconfig - CONF_INITSIZE (reset)"); 137 addr = (long) dl_getrange(size + HDR_SIZE); 138 dprintf(("trying to use addr %p-%p for sproc\n", 139 addr, addr+size)); 140 errno = 0; 141 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && 142 errno != 0) 143 perror("usconfig - CONF_ATTACHADDR (set)"); 144 } 145 #endif /* USE_DL */ 146 clean_threads(); 147 if ((success = sproc(func, PR_SALL, arg)) < 0) 148 perror("sproc"); 149 #ifdef USE_DL 150 if (!local_initialized) { 151 if (usconfig(CONF_ATTACHADDR, addr) < 0) 152 /* reset address */ 153 perror("usconfig - CONF_ATTACHADDR (reset)"); 154 local_initialized = 1; 155 } 156 #endif /* USE_DL */ 157 if (success >= 0) { 158 nthreads++; 159 pidlist[maxpidindex].parent = getpid(); 160 pidlist[maxpidindex++].child = success; 161 dprintf(("pidlist[%d] = %d\n", 162 maxpidindex-1, success)); 163 } 164 } 165 if (usunsetlock(count_lock) < 0) 166 perror("usunsetlock (count_lock)"); 167 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 dprintf(("PyThread_exit_thread called\n")); 178 if (!initialized) 179 exit(0); 180 if (ussetlock(count_lock) < 0) 181 perror("ussetlock (count_lock)"); 182 nthreads--; 183 if (getpid() == my_pid) { 184 /* main thread; wait for other threads to exit */ 185 exiting = 1; 186 waiting_for_threads = 1; 187 if (ussetlock(wait_lock) < 0) 188 perror("ussetlock (wait_lock)"); 189 for (;;) { 190 if (nthreads < 0) { 191 dprintf(("really exit (%d)\n", exit_status)); 192 exit(exit_status); 193 } 194 if (usunsetlock(count_lock) < 0) 195 perror("usunsetlock (count_lock)"); 196 dprintf(("waiting for other threads (%d)\n", nthreads)); 197 if (ussetlock(wait_lock) < 0) 198 perror("ussetlock (wait_lock)"); 199 if (ussetlock(count_lock) < 0) 200 perror("ussetlock (count_lock)"); 201 } 202 } 203 /* not the main thread */ 204 if (waiting_for_threads) { 205 dprintf(("main thread is waiting\n")); 206 if (usunsetlock(wait_lock) < 0) 207 perror("usunsetlock (wait_lock)"); 208 } 209 if (usunsetlock(count_lock) < 0) 210 perror("usunsetlock (count_lock)"); 211 _exit(0); 212 } 213 214 /* 215 * Lock support. 216 */ 217 PyThread_type_lock PyThread_allocate_lock(void) 218 { 219 ulock_t lock; 220 221 dprintf(("PyThread_allocate_lock called\n")); 222 if (!initialized) 223 PyThread_init_thread(); 224 225 if ((lock = usnewlock(shared_arena)) == NULL) 226 perror("usnewlock"); 227 (void) usinitlock(lock); 228 dprintf(("PyThread_allocate_lock() -> %p\n", lock)); 229 return (PyThread_type_lock) lock; 230 } 231 232 void PyThread_free_lock(PyThread_type_lock lock) 233 { 234 dprintf(("PyThread_free_lock(%p) called\n", lock)); 235 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 dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); 243 errno = 0; /* clear it just in case */ 244 if (waitflag) 245 success = ussetlock((ulock_t) lock); 246 else 247 success = uscsetlock((ulock_t) lock, 1); /* Try it once */ 248 if (success < 0) 249 perror(waitflag ? "ussetlock" : "uscsetlock"); 250 dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); 251 return success; 252 } 253 254 void PyThread_release_lock(PyThread_type_lock lock) 255 { 256 dprintf(("PyThread_release_lock(%p) called\n", lock)); 257 if (usunsetlock((ulock_t) lock) < 0) 258 perror("usunsetlock"); 259 } 260