1 /* This code implemented by cvale (at) netcom.com */ 2 3 #define INCL_DOSPROCESS 4 #define INCL_DOSSEMAPHORES 5 #include "os2.h" 6 #include "limits.h" 7 8 #include "process.h" 9 10 #if defined(PYCC_GCC) 11 #include <sys/builtin.h> 12 #include <sys/fmutex.h> 13 #else 14 long PyThread_get_thread_ident(void); 15 #endif 16 17 /* default thread stack size of 64kB */ 18 #if !defined(THREAD_STACK_SIZE) 19 #define THREAD_STACK_SIZE 0x10000 20 #endif 21 22 #define OS2_STACKSIZE(x) (x ? x : THREAD_STACK_SIZE) 23 24 /* 25 * Initialization of the C package, should not be needed. 26 */ 27 static void 28 PyThread__init_thread(void) 29 { 30 } 31 32 /* 33 * Thread support. 34 */ 35 long 36 PyThread_start_new_thread(void (*func)(void *), void *arg) 37 { 38 int thread_id; 39 40 thread_id = _beginthread(func, 41 NULL, 42 OS2_STACKSIZE(_pythread_stacksize), 43 arg); 44 45 if (thread_id == -1) { 46 dprintf(("_beginthread failed. return %ld\n", errno)); 47 } 48 49 return thread_id; 50 } 51 52 long 53 PyThread_get_thread_ident(void) 54 { 55 #if !defined(PYCC_GCC) 56 PPIB pib; 57 PTIB tib; 58 #endif 59 60 if (!initialized) 61 PyThread_init_thread(); 62 63 #if defined(PYCC_GCC) 64 return _gettid(); 65 #else 66 DosGetInfoBlocks(&tib, &pib); 67 return tib->tib_ptib2->tib2_ultid; 68 #endif 69 } 70 71 void 72 PyThread_exit_thread(void) 73 { 74 dprintf(("%ld: PyThread_exit_thread called\n", 75 PyThread_get_thread_ident())); 76 if (!initialized) 77 exit(0); 78 _endthread(); 79 } 80 81 /* 82 * Lock support. This is implemented with an event semaphore and critical 83 * sections to make it behave more like a posix mutex than its OS/2 84 * counterparts. 85 */ 86 87 typedef struct os2_lock_t { 88 int is_set; 89 HEV changed; 90 } *type_os2_lock; 91 92 PyThread_type_lock 93 PyThread_allocate_lock(void) 94 { 95 #if defined(PYCC_GCC) 96 _fmutex *sem = malloc(sizeof(_fmutex)); 97 if (!initialized) 98 PyThread_init_thread(); 99 dprintf(("%ld: PyThread_allocate_lock() -> %lx\n", 100 PyThread_get_thread_ident(), 101 (long)sem)); 102 if (_fmutex_create(sem, 0)) { 103 free(sem); 104 sem = NULL; 105 } 106 return (PyThread_type_lock)sem; 107 #else 108 APIRET rc; 109 type_os2_lock lock = (type_os2_lock)malloc(sizeof(struct os2_lock_t)); 110 111 dprintf(("PyThread_allocate_lock called\n")); 112 if (!initialized) 113 PyThread_init_thread(); 114 115 lock->is_set = 0; 116 117 DosCreateEventSem(NULL, &lock->changed, 0, 0); 118 119 dprintf(("%ld: PyThread_allocate_lock() -> %p\n", 120 PyThread_get_thread_ident(), 121 lock->changed)); 122 123 return (PyThread_type_lock)lock; 124 #endif 125 } 126 127 void 128 PyThread_free_lock(PyThread_type_lock aLock) 129 { 130 #if !defined(PYCC_GCC) 131 type_os2_lock lock = (type_os2_lock)aLock; 132 #endif 133 134 dprintf(("%ld: PyThread_free_lock(%p) called\n", 135 PyThread_get_thread_ident(),aLock)); 136 137 #if defined(PYCC_GCC) 138 if (aLock) { 139 _fmutex_close((_fmutex *)aLock); 140 free((_fmutex *)aLock); 141 } 142 #else 143 DosCloseEventSem(lock->changed); 144 free(aLock); 145 #endif 146 } 147 148 /* 149 * Return 1 on success if the lock was acquired 150 * 151 * and 0 if the lock was not acquired. 152 */ 153 int 154 PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag) 155 { 156 #if !defined(PYCC_GCC) 157 int done = 0; 158 ULONG count; 159 PID pid = 0; 160 TID tid = 0; 161 type_os2_lock lock = (type_os2_lock)aLock; 162 #endif 163 164 dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", 165 PyThread_get_thread_ident(), 166 aLock, 167 waitflag)); 168 169 #if defined(PYCC_GCC) 170 /* always successful if the lock doesn't exist */ 171 if (aLock && 172 _fmutex_request((_fmutex *)aLock, waitflag ? 0 : _FMR_NOWAIT)) 173 return 0; 174 #else 175 while (!done) { 176 /* if the lock is currently set, we have to wait for 177 * the state to change 178 */ 179 if (lock->is_set) { 180 if (!waitflag) 181 return 0; 182 DosWaitEventSem(lock->changed, SEM_INDEFINITE_WAIT); 183 } 184 185 /* enter a critical section and try to get the semaphore. If 186 * it is still locked, we will try again. 187 */ 188 if (DosEnterCritSec()) 189 return 0; 190 191 if (!lock->is_set) { 192 lock->is_set = 1; 193 DosResetEventSem(lock->changed, &count); 194 done = 1; 195 } 196 197 DosExitCritSec(); 198 } 199 #endif 200 201 return 1; 202 } 203 204 void 205 PyThread_release_lock(PyThread_type_lock aLock) 206 { 207 #if !defined(PYCC_GCC) 208 type_os2_lock lock = (type_os2_lock)aLock; 209 #endif 210 211 dprintf(("%ld: PyThread_release_lock(%p) called\n", 212 PyThread_get_thread_ident(), 213 aLock)); 214 215 #if defined(PYCC_GCC) 216 if (aLock) 217 _fmutex_release((_fmutex *)aLock); 218 #else 219 if (!lock->is_set) { 220 dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", 221 PyThread_get_thread_ident(), 222 aLock, 223 GetLastError())); 224 return; 225 } 226 227 if (DosEnterCritSec()) { 228 dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", 229 PyThread_get_thread_ident(), 230 aLock, 231 GetLastError())); 232 return; 233 } 234 235 lock->is_set = 0; 236 DosPostEventSem(lock->changed); 237 238 DosExitCritSec(); 239 #endif 240 } 241 242 /* minimum/maximum thread stack sizes supported */ 243 #define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */ 244 #define THREAD_MAX_STACKSIZE 0x2000000 /* 32MB */ 245 246 /* set the thread stack size. 247 * Return 0 if size is valid, -1 otherwise. 248 */ 249 static int 250 _pythread_os2_set_stacksize(size_t size) 251 { 252 /* set to default */ 253 if (size == 0) { 254 _pythread_stacksize = 0; 255 return 0; 256 } 257 258 /* valid range? */ 259 if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) { 260 _pythread_stacksize = size; 261 return 0; 262 } 263 264 return -1; 265 } 266 267 #define THREAD_SET_STACKSIZE(x) _pythread_os2_set_stacksize(x) 268