nsprpub/pr/src/md/os2/os2thred.c

branch
TOR_BUG_3246
changeset 5
4ab42b5ab56c
equal deleted inserted replaced
-1:000000000000 0:58b7325d02e9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "primpl.h"
7 #include <process.h> /* for _beginthread() */
8 #include <signal.h>
9 #include <float.h>
10
11 /* --- globals ------------------------------------------------ */
12 _NSPR_TLS* pThreadLocalStorage = 0;
13 _PRInterruptTable _pr_interruptTable[] = { { 0 } };
14 APIRET (* APIENTRY QueryThreadContext)(TID, ULONG, PCONTEXTRECORD);
15
16 void
17 _PR_MD_ENSURE_TLS(void)
18 {
19 if(!pThreadLocalStorage)
20 {
21 /* Allocate thread local storage (TLS). Note, that only 32 bytes can
22 * be allocated at a time.
23 */
24 int rc = DosAllocThreadLocalMemory(sizeof(_NSPR_TLS) / 4, (PULONG*)&pThreadLocalStorage);
25 PR_ASSERT(rc == NO_ERROR);
26 memset(pThreadLocalStorage, 0, sizeof(_NSPR_TLS));
27 }
28 }
29
30 void
31 _PR_MD_EARLY_INIT()
32 {
33 HMODULE hmod;
34
35 if (DosLoadModule(NULL, 0, "DOSCALL1", &hmod) == 0)
36 DosQueryProcAddr(hmod, 877, "DOSQUERYTHREADCONTEXT",
37 (PFN *)&QueryThreadContext);
38 }
39
40 static void
41 _pr_SetThreadMDHandle(PRThread *thread)
42 {
43 PTIB ptib;
44 PPIB ppib;
45 PRUword rc;
46
47 rc = DosGetInfoBlocks(&ptib, &ppib);
48
49 thread->md.handle = ptib->tib_ptib2->tib2_ultid;
50 }
51
52 /* On OS/2, some system function calls seem to change the FPU control word,
53 * such that we crash with a floating underflow exception. The FIX_FPU() call
54 * in jsnum.c does not always work, as sometimes FIX_FPU() is called BEFORE the
55 * OS/2 system call that horks the FPU control word. So, we set an exception
56 * handler that covers any floating point exceptions and resets the FPU CW to
57 * the required value.
58 */
59 static ULONG
60 _System OS2_FloatExcpHandler(PEXCEPTIONREPORTRECORD p1,
61 PEXCEPTIONREGISTRATIONRECORD p2,
62 PCONTEXTRECORD p3,
63 PVOID pv)
64 {
65 #ifdef DEBUG_pedemonte
66 printf("Entering exception handler; ExceptionNum = %x\n", p1->ExceptionNum);
67 switch(p1->ExceptionNum) {
68 case XCPT_FLOAT_DENORMAL_OPERAND:
69 printf("got XCPT_FLOAT_DENORMAL_OPERAND\n");
70 break;
71 case XCPT_FLOAT_DIVIDE_BY_ZERO:
72 printf("got XCPT_FLOAT_DIVIDE_BY_ZERO\n");
73 break;
74 case XCPT_FLOAT_INEXACT_RESULT:
75 printf("got XCPT_FLOAT_INEXACT_RESULT\n");
76 break;
77 case XCPT_FLOAT_INVALID_OPERATION:
78 printf("got XCPT_FLOAT_INVALID_OPERATION\n");
79 break;
80 case XCPT_FLOAT_OVERFLOW:
81 printf("got XCPT_FLOAT_OVERFLOW\n");
82 break;
83 case XCPT_FLOAT_STACK_CHECK:
84 printf("got XCPT_FLOAT_STACK_CHECK\n");
85 break;
86 case XCPT_FLOAT_UNDERFLOW:
87 printf("got XCPT_FLOAT_UNDERFLOW\n");
88 break;
89 }
90 #endif
91
92 switch(p1->ExceptionNum) {
93 case XCPT_FLOAT_DENORMAL_OPERAND:
94 case XCPT_FLOAT_DIVIDE_BY_ZERO:
95 case XCPT_FLOAT_INEXACT_RESULT:
96 case XCPT_FLOAT_INVALID_OPERATION:
97 case XCPT_FLOAT_OVERFLOW:
98 case XCPT_FLOAT_STACK_CHECK:
99 case XCPT_FLOAT_UNDERFLOW:
100 {
101 unsigned cw = p3->ctx_env[0];
102 if ((cw & MCW_EM) != MCW_EM) {
103 /* Mask out all floating point exceptions */
104 p3->ctx_env[0] |= MCW_EM;
105 /* Following two lines set precision to 53 bit mantissa. See jsnum.c */
106 p3->ctx_env[0] &= ~MCW_PC;
107 p3->ctx_env[0] |= PC_53;
108 return XCPT_CONTINUE_EXECUTION;
109 }
110 }
111 }
112 return XCPT_CONTINUE_SEARCH;
113 }
114
115 PR_IMPLEMENT(void)
116 PR_OS2_SetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* excpreg)
117 {
118 /* setup the exception handler for the thread */
119 APIRET rv;
120 excpreg->ExceptionHandler = OS2_FloatExcpHandler;
121 excpreg->prev_structure = NULL;
122 rv = DosSetExceptionHandler(excpreg);
123 PR_ASSERT(rv == NO_ERROR);
124 }
125
126 PR_IMPLEMENT(void)
127 PR_OS2_UnsetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* excpreg)
128 {
129 /* unset exception handler */
130 APIRET rv = DosUnsetExceptionHandler(excpreg);
131 PR_ASSERT(rv == NO_ERROR);
132 }
133
134 PRStatus
135 _PR_MD_INIT_THREAD(PRThread *thread)
136 {
137 APIRET rv;
138
139 if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) {
140 _pr_SetThreadMDHandle(thread);
141 }
142
143 /* Create the blocking IO semaphore */
144 rv = DosCreateEventSem(NULL, &(thread->md.blocked_sema), 0, 0);
145 return (rv == NO_ERROR) ? PR_SUCCESS : PR_FAILURE;
146 }
147
148 typedef struct param_store
149 {
150 void (*start)(void *);
151 PRThread* thread;
152 } PARAMSTORE;
153
154 /* This is a small intermediate function that sets/unsets the exception
155 handler before calling the initial thread function */
156 static void
157 ExcpStartFunc(void* arg)
158 {
159 EXCEPTIONREGISTRATIONRECORD excpreg;
160 PARAMSTORE params, *pParams = arg;
161
162 PR_OS2_SetFloatExcpHandler(&excpreg);
163
164 params = *pParams;
165 PR_Free(pParams);
166 params.start(params.thread);
167
168 PR_OS2_UnsetFloatExcpHandler(&excpreg);
169 }
170
171 PRStatus
172 _PR_MD_CREATE_THREAD(PRThread *thread,
173 void (*start)(void *),
174 PRThreadPriority priority,
175 PRThreadScope scope,
176 PRThreadState state,
177 PRUint32 stackSize)
178 {
179 PARAMSTORE* params = PR_Malloc(sizeof(PARAMSTORE));
180 params->start = start;
181 params->thread = thread;
182 thread->md.handle = thread->id = (TID) _beginthread(ExcpStartFunc,
183 NULL,
184 thread->stack->stackSize,
185 params);
186 if(thread->md.handle == -1) {
187 return PR_FAILURE;
188 }
189
190 /*
191 * On OS/2, a thread is created with a thread priority of
192 * THREAD_PRIORITY_NORMAL
193 */
194
195 if (priority != PR_PRIORITY_NORMAL) {
196 _PR_MD_SET_PRIORITY(&(thread->md), priority);
197 }
198
199 return PR_SUCCESS;
200 }
201
202 void
203 _PR_MD_YIELD(void)
204 {
205 /* Isn't there some problem with DosSleep(0) on OS/2? */
206 DosSleep(0);
207 }
208
209 void
210 _PR_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri)
211 {
212 int nativePri = PRTYC_NOCHANGE;
213 BOOL rv;
214
215 if (newPri < PR_PRIORITY_FIRST) {
216 newPri = PR_PRIORITY_FIRST;
217 } else if (newPri > PR_PRIORITY_LAST) {
218 newPri = PR_PRIORITY_LAST;
219 }
220 switch (newPri) {
221 case PR_PRIORITY_LOW:
222 case PR_PRIORITY_NORMAL:
223 nativePri = PRTYC_REGULAR;
224 break;
225 case PR_PRIORITY_HIGH:
226 nativePri = PRTYC_FOREGROUNDSERVER;
227 break;
228 case PR_PRIORITY_URGENT:
229 nativePri = PRTYC_TIMECRITICAL;
230 }
231 rv = DosSetPriority(PRTYS_THREAD, nativePri, 0, thread->handle);
232 PR_ASSERT(rv == NO_ERROR);
233 if (rv != NO_ERROR) {
234 PR_LOG(_pr_thread_lm, PR_LOG_MIN,
235 ("PR_SetThreadPriority: can't set thread priority\n"));
236 }
237 return;
238 }
239
240 void
241 _PR_MD_CLEAN_THREAD(PRThread *thread)
242 {
243 APIRET rv;
244
245 if (thread->md.blocked_sema) {
246 rv = DosCloseEventSem(thread->md.blocked_sema);
247 PR_ASSERT(rv == NO_ERROR);
248 thread->md.blocked_sema = 0;
249 }
250
251 if (thread->md.handle) {
252 thread->md.handle = 0;
253 }
254 }
255
256 void
257 _PR_MD_EXIT_THREAD(PRThread *thread)
258 {
259 _PR_MD_CLEAN_THREAD(thread);
260 _PR_MD_SET_CURRENT_THREAD(NULL);
261 }
262
263
264 void
265 _PR_MD_EXIT(PRIntn status)
266 {
267 _exit(status);
268 }
269
270 #ifdef HAVE_THREAD_AFFINITY
271 PR_EXTERN(PRInt32)
272 _PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask )
273 {
274 /* Can we do this on OS/2? Only on SMP versions? */
275 PR_ASSERT(!"Not implemented");
276 return 0;
277
278 /* This is what windows does:
279 int rv;
280
281 rv = SetThreadAffinityMask(thread->md.handle, mask);
282
283 return rv?0:-1;
284 */
285 }
286
287 PR_EXTERN(PRInt32)
288 _PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask)
289 {
290 /* Can we do this on OS/2? Only on SMP versions? */
291 PR_ASSERT(!"Not implemented");
292 return 0;
293
294 /* This is what windows does:
295 PRInt32 rv, system_mask;
296
297 rv = GetProcessAffinityMask(GetCurrentProcess(), mask, &system_mask);
298
299 return rv?0:-1;
300 */
301 }
302 #endif /* HAVE_THREAD_AFFINITY */
303
304 void
305 _PR_MD_SUSPEND_CPU(_PRCPU *cpu)
306 {
307 _PR_MD_SUSPEND_THREAD(cpu->thread);
308 }
309
310 void
311 _PR_MD_RESUME_CPU(_PRCPU *cpu)
312 {
313 _PR_MD_RESUME_THREAD(cpu->thread);
314 }
315
316 void
317 _PR_MD_SUSPEND_THREAD(PRThread *thread)
318 {
319 if (_PR_IS_NATIVE_THREAD(thread)) {
320 APIRET rc;
321
322 /* XXXMB - DosSuspendThread() is not a blocking call; how do we
323 * know when the thread is *REALLY* suspended?
324 */
325 rc = DosSuspendThread(thread->md.handle);
326 PR_ASSERT(rc == NO_ERROR);
327 }
328 }
329
330 void
331 _PR_MD_RESUME_THREAD(PRThread *thread)
332 {
333 if (_PR_IS_NATIVE_THREAD(thread)) {
334 DosResumeThread(thread->md.handle);
335 }
336 }
337
338
339 PRThread*
340 _MD_CURRENT_THREAD(void)
341 {
342 PRThread *thread;
343
344 thread = _MD_GET_ATTACHED_THREAD();
345
346 if (NULL == thread) {
347 thread = _PRI_AttachThread(PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0);
348 }
349
350 PR_ASSERT(thread != NULL);
351 return thread;
352 }
353

mercurial