Wed, 31 Dec 2014 06:09:35 +0100
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 |