|
1 /* This code implemented by cvale@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 static void |
|
72 do_PyThread_exit_thread(int no_cleanup) |
|
73 { |
|
74 dprintf(("%ld: PyThread_exit_thread called\n", |
|
75 PyThread_get_thread_ident())); |
|
76 if (!initialized) |
|
77 if (no_cleanup) |
|
78 _exit(0); |
|
79 else |
|
80 exit(0); |
|
81 _endthread(); |
|
82 } |
|
83 |
|
84 void |
|
85 PyThread_exit_thread(void) |
|
86 { |
|
87 do_PyThread_exit_thread(0); |
|
88 } |
|
89 |
|
90 void |
|
91 PyThread__exit_thread(void) |
|
92 { |
|
93 do_PyThread_exit_thread(1); |
|
94 } |
|
95 |
|
96 #ifndef NO_EXIT_PROG |
|
97 static void |
|
98 do_PyThread_exit_prog(int status, int no_cleanup) |
|
99 { |
|
100 dprintf(("PyThread_exit_prog(%d) called\n", status)); |
|
101 if (!initialized) |
|
102 if (no_cleanup) |
|
103 _exit(status); |
|
104 else |
|
105 exit(status); |
|
106 } |
|
107 |
|
108 void |
|
109 PyThread_exit_prog(int status) |
|
110 { |
|
111 do_PyThread_exit_prog(status, 0); |
|
112 } |
|
113 |
|
114 void |
|
115 PyThread__exit_prog(int status) |
|
116 { |
|
117 do_PyThread_exit_prog(status, 1); |
|
118 } |
|
119 #endif /* NO_EXIT_PROG */ |
|
120 |
|
121 /* |
|
122 * Lock support. This is implemented with an event semaphore and critical |
|
123 * sections to make it behave more like a posix mutex than its OS/2 |
|
124 * counterparts. |
|
125 */ |
|
126 |
|
127 typedef struct os2_lock_t { |
|
128 int is_set; |
|
129 HEV changed; |
|
130 } *type_os2_lock; |
|
131 |
|
132 PyThread_type_lock |
|
133 PyThread_allocate_lock(void) |
|
134 { |
|
135 #if defined(PYCC_GCC) |
|
136 _fmutex *sem = malloc(sizeof(_fmutex)); |
|
137 if (!initialized) |
|
138 PyThread_init_thread(); |
|
139 dprintf(("%ld: PyThread_allocate_lock() -> %lx\n", |
|
140 PyThread_get_thread_ident(), |
|
141 (long)sem)); |
|
142 if (_fmutex_create(sem, 0)) { |
|
143 free(sem); |
|
144 sem = NULL; |
|
145 } |
|
146 return (PyThread_type_lock)sem; |
|
147 #else |
|
148 APIRET rc; |
|
149 type_os2_lock lock = (type_os2_lock)malloc(sizeof(struct os2_lock_t)); |
|
150 |
|
151 dprintf(("PyThread_allocate_lock called\n")); |
|
152 if (!initialized) |
|
153 PyThread_init_thread(); |
|
154 |
|
155 lock->is_set = 0; |
|
156 |
|
157 DosCreateEventSem(NULL, &lock->changed, 0, 0); |
|
158 |
|
159 dprintf(("%ld: PyThread_allocate_lock() -> %p\n", |
|
160 PyThread_get_thread_ident(), |
|
161 lock->changed)); |
|
162 |
|
163 return (PyThread_type_lock)lock; |
|
164 #endif |
|
165 } |
|
166 |
|
167 void |
|
168 PyThread_free_lock(PyThread_type_lock aLock) |
|
169 { |
|
170 #if !defined(PYCC_GCC) |
|
171 type_os2_lock lock = (type_os2_lock)aLock; |
|
172 #endif |
|
173 |
|
174 dprintf(("%ld: PyThread_free_lock(%p) called\n", |
|
175 PyThread_get_thread_ident(),aLock)); |
|
176 |
|
177 #if defined(PYCC_GCC) |
|
178 if (aLock) { |
|
179 _fmutex_close((_fmutex *)aLock); |
|
180 free((_fmutex *)aLock); |
|
181 } |
|
182 #else |
|
183 DosCloseEventSem(lock->changed); |
|
184 free(aLock); |
|
185 #endif |
|
186 } |
|
187 |
|
188 /* |
|
189 * Return 1 on success if the lock was acquired |
|
190 * |
|
191 * and 0 if the lock was not acquired. |
|
192 */ |
|
193 int |
|
194 PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag) |
|
195 { |
|
196 #if !defined(PYCC_GCC) |
|
197 int done = 0; |
|
198 ULONG count; |
|
199 PID pid = 0; |
|
200 TID tid = 0; |
|
201 type_os2_lock lock = (type_os2_lock)aLock; |
|
202 #endif |
|
203 |
|
204 dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", |
|
205 PyThread_get_thread_ident(), |
|
206 aLock, |
|
207 waitflag)); |
|
208 |
|
209 #if defined(PYCC_GCC) |
|
210 /* always successful if the lock doesn't exist */ |
|
211 if (aLock && |
|
212 _fmutex_request((_fmutex *)aLock, waitflag ? 0 : _FMR_NOWAIT)) |
|
213 return 0; |
|
214 #else |
|
215 while (!done) { |
|
216 /* if the lock is currently set, we have to wait for |
|
217 * the state to change |
|
218 */ |
|
219 if (lock->is_set) { |
|
220 if (!waitflag) |
|
221 return 0; |
|
222 DosWaitEventSem(lock->changed, SEM_INDEFINITE_WAIT); |
|
223 } |
|
224 |
|
225 /* enter a critical section and try to get the semaphore. If |
|
226 * it is still locked, we will try again. |
|
227 */ |
|
228 if (DosEnterCritSec()) |
|
229 return 0; |
|
230 |
|
231 if (!lock->is_set) { |
|
232 lock->is_set = 1; |
|
233 DosResetEventSem(lock->changed, &count); |
|
234 done = 1; |
|
235 } |
|
236 |
|
237 DosExitCritSec(); |
|
238 } |
|
239 #endif |
|
240 |
|
241 return 1; |
|
242 } |
|
243 |
|
244 void |
|
245 PyThread_release_lock(PyThread_type_lock aLock) |
|
246 { |
|
247 #if !defined(PYCC_GCC) |
|
248 type_os2_lock lock = (type_os2_lock)aLock; |
|
249 #endif |
|
250 |
|
251 dprintf(("%ld: PyThread_release_lock(%p) called\n", |
|
252 PyThread_get_thread_ident(), |
|
253 aLock)); |
|
254 |
|
255 #if defined(PYCC_GCC) |
|
256 if (aLock) |
|
257 _fmutex_release((_fmutex *)aLock); |
|
258 #else |
|
259 if (!lock->is_set) { |
|
260 dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", |
|
261 PyThread_get_thread_ident(), |
|
262 aLock, |
|
263 GetLastError())); |
|
264 return; |
|
265 } |
|
266 |
|
267 if (DosEnterCritSec()) { |
|
268 dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", |
|
269 PyThread_get_thread_ident(), |
|
270 aLock, |
|
271 GetLastError())); |
|
272 return; |
|
273 } |
|
274 |
|
275 lock->is_set = 0; |
|
276 DosPostEventSem(lock->changed); |
|
277 |
|
278 DosExitCritSec(); |
|
279 #endif |
|
280 } |
|
281 |
|
282 /* minimum/maximum thread stack sizes supported */ |
|
283 #define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */ |
|
284 #define THREAD_MAX_STACKSIZE 0x2000000 /* 32MB */ |
|
285 |
|
286 /* set the thread stack size. |
|
287 * Return 0 if size is valid, -1 otherwise. |
|
288 */ |
|
289 static int |
|
290 _pythread_os2_set_stacksize(size_t size) |
|
291 { |
|
292 /* set to default */ |
|
293 if (size == 0) { |
|
294 _pythread_stacksize = 0; |
|
295 return 0; |
|
296 } |
|
297 |
|
298 /* valid range? */ |
|
299 if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) { |
|
300 _pythread_stacksize = size; |
|
301 return 0; |
|
302 } |
|
303 |
|
304 return -1; |
|
305 } |
|
306 |
|
307 #define THREAD_SET_STACKSIZE(x) _pythread_os2_set_stacksize(x) |