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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial