1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/md/os2/os2thred.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,353 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "primpl.h" 1.10 +#include <process.h> /* for _beginthread() */ 1.11 +#include <signal.h> 1.12 +#include <float.h> 1.13 + 1.14 +/* --- globals ------------------------------------------------ */ 1.15 +_NSPR_TLS* pThreadLocalStorage = 0; 1.16 +_PRInterruptTable _pr_interruptTable[] = { { 0 } }; 1.17 +APIRET (* APIENTRY QueryThreadContext)(TID, ULONG, PCONTEXTRECORD); 1.18 + 1.19 +void 1.20 +_PR_MD_ENSURE_TLS(void) 1.21 +{ 1.22 + if(!pThreadLocalStorage) 1.23 + { 1.24 + /* Allocate thread local storage (TLS). Note, that only 32 bytes can 1.25 + * be allocated at a time. 1.26 + */ 1.27 + int rc = DosAllocThreadLocalMemory(sizeof(_NSPR_TLS) / 4, (PULONG*)&pThreadLocalStorage); 1.28 + PR_ASSERT(rc == NO_ERROR); 1.29 + memset(pThreadLocalStorage, 0, sizeof(_NSPR_TLS)); 1.30 + } 1.31 +} 1.32 + 1.33 +void 1.34 +_PR_MD_EARLY_INIT() 1.35 +{ 1.36 + HMODULE hmod; 1.37 + 1.38 + if (DosLoadModule(NULL, 0, "DOSCALL1", &hmod) == 0) 1.39 + DosQueryProcAddr(hmod, 877, "DOSQUERYTHREADCONTEXT", 1.40 + (PFN *)&QueryThreadContext); 1.41 +} 1.42 + 1.43 +static void 1.44 +_pr_SetThreadMDHandle(PRThread *thread) 1.45 +{ 1.46 + PTIB ptib; 1.47 + PPIB ppib; 1.48 + PRUword rc; 1.49 + 1.50 + rc = DosGetInfoBlocks(&ptib, &ppib); 1.51 + 1.52 + thread->md.handle = ptib->tib_ptib2->tib2_ultid; 1.53 +} 1.54 + 1.55 +/* On OS/2, some system function calls seem to change the FPU control word, 1.56 + * such that we crash with a floating underflow exception. The FIX_FPU() call 1.57 + * in jsnum.c does not always work, as sometimes FIX_FPU() is called BEFORE the 1.58 + * OS/2 system call that horks the FPU control word. So, we set an exception 1.59 + * handler that covers any floating point exceptions and resets the FPU CW to 1.60 + * the required value. 1.61 + */ 1.62 +static ULONG 1.63 +_System OS2_FloatExcpHandler(PEXCEPTIONREPORTRECORD p1, 1.64 + PEXCEPTIONREGISTRATIONRECORD p2, 1.65 + PCONTEXTRECORD p3, 1.66 + PVOID pv) 1.67 +{ 1.68 +#ifdef DEBUG_pedemonte 1.69 + printf("Entering exception handler; ExceptionNum = %x\n", p1->ExceptionNum); 1.70 + switch(p1->ExceptionNum) { 1.71 + case XCPT_FLOAT_DENORMAL_OPERAND: 1.72 + printf("got XCPT_FLOAT_DENORMAL_OPERAND\n"); 1.73 + break; 1.74 + case XCPT_FLOAT_DIVIDE_BY_ZERO: 1.75 + printf("got XCPT_FLOAT_DIVIDE_BY_ZERO\n"); 1.76 + break; 1.77 + case XCPT_FLOAT_INEXACT_RESULT: 1.78 + printf("got XCPT_FLOAT_INEXACT_RESULT\n"); 1.79 + break; 1.80 + case XCPT_FLOAT_INVALID_OPERATION: 1.81 + printf("got XCPT_FLOAT_INVALID_OPERATION\n"); 1.82 + break; 1.83 + case XCPT_FLOAT_OVERFLOW: 1.84 + printf("got XCPT_FLOAT_OVERFLOW\n"); 1.85 + break; 1.86 + case XCPT_FLOAT_STACK_CHECK: 1.87 + printf("got XCPT_FLOAT_STACK_CHECK\n"); 1.88 + break; 1.89 + case XCPT_FLOAT_UNDERFLOW: 1.90 + printf("got XCPT_FLOAT_UNDERFLOW\n"); 1.91 + break; 1.92 + } 1.93 +#endif 1.94 + 1.95 + switch(p1->ExceptionNum) { 1.96 + case XCPT_FLOAT_DENORMAL_OPERAND: 1.97 + case XCPT_FLOAT_DIVIDE_BY_ZERO: 1.98 + case XCPT_FLOAT_INEXACT_RESULT: 1.99 + case XCPT_FLOAT_INVALID_OPERATION: 1.100 + case XCPT_FLOAT_OVERFLOW: 1.101 + case XCPT_FLOAT_STACK_CHECK: 1.102 + case XCPT_FLOAT_UNDERFLOW: 1.103 + { 1.104 + unsigned cw = p3->ctx_env[0]; 1.105 + if ((cw & MCW_EM) != MCW_EM) { 1.106 + /* Mask out all floating point exceptions */ 1.107 + p3->ctx_env[0] |= MCW_EM; 1.108 + /* Following two lines set precision to 53 bit mantissa. See jsnum.c */ 1.109 + p3->ctx_env[0] &= ~MCW_PC; 1.110 + p3->ctx_env[0] |= PC_53; 1.111 + return XCPT_CONTINUE_EXECUTION; 1.112 + } 1.113 + } 1.114 + } 1.115 + return XCPT_CONTINUE_SEARCH; 1.116 +} 1.117 + 1.118 +PR_IMPLEMENT(void) 1.119 +PR_OS2_SetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* excpreg) 1.120 +{ 1.121 + /* setup the exception handler for the thread */ 1.122 + APIRET rv; 1.123 + excpreg->ExceptionHandler = OS2_FloatExcpHandler; 1.124 + excpreg->prev_structure = NULL; 1.125 + rv = DosSetExceptionHandler(excpreg); 1.126 + PR_ASSERT(rv == NO_ERROR); 1.127 +} 1.128 + 1.129 +PR_IMPLEMENT(void) 1.130 +PR_OS2_UnsetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* excpreg) 1.131 +{ 1.132 + /* unset exception handler */ 1.133 + APIRET rv = DosUnsetExceptionHandler(excpreg); 1.134 + PR_ASSERT(rv == NO_ERROR); 1.135 +} 1.136 + 1.137 +PRStatus 1.138 +_PR_MD_INIT_THREAD(PRThread *thread) 1.139 +{ 1.140 + APIRET rv; 1.141 + 1.142 + if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) { 1.143 + _pr_SetThreadMDHandle(thread); 1.144 + } 1.145 + 1.146 + /* Create the blocking IO semaphore */ 1.147 + rv = DosCreateEventSem(NULL, &(thread->md.blocked_sema), 0, 0); 1.148 + return (rv == NO_ERROR) ? PR_SUCCESS : PR_FAILURE; 1.149 +} 1.150 + 1.151 +typedef struct param_store 1.152 +{ 1.153 + void (*start)(void *); 1.154 + PRThread* thread; 1.155 +} PARAMSTORE; 1.156 + 1.157 +/* This is a small intermediate function that sets/unsets the exception 1.158 + handler before calling the initial thread function */ 1.159 +static void 1.160 +ExcpStartFunc(void* arg) 1.161 +{ 1.162 + EXCEPTIONREGISTRATIONRECORD excpreg; 1.163 + PARAMSTORE params, *pParams = arg; 1.164 + 1.165 + PR_OS2_SetFloatExcpHandler(&excpreg); 1.166 + 1.167 + params = *pParams; 1.168 + PR_Free(pParams); 1.169 + params.start(params.thread); 1.170 + 1.171 + PR_OS2_UnsetFloatExcpHandler(&excpreg); 1.172 +} 1.173 + 1.174 +PRStatus 1.175 +_PR_MD_CREATE_THREAD(PRThread *thread, 1.176 + void (*start)(void *), 1.177 + PRThreadPriority priority, 1.178 + PRThreadScope scope, 1.179 + PRThreadState state, 1.180 + PRUint32 stackSize) 1.181 +{ 1.182 + PARAMSTORE* params = PR_Malloc(sizeof(PARAMSTORE)); 1.183 + params->start = start; 1.184 + params->thread = thread; 1.185 + thread->md.handle = thread->id = (TID) _beginthread(ExcpStartFunc, 1.186 + NULL, 1.187 + thread->stack->stackSize, 1.188 + params); 1.189 + if(thread->md.handle == -1) { 1.190 + return PR_FAILURE; 1.191 + } 1.192 + 1.193 + /* 1.194 + * On OS/2, a thread is created with a thread priority of 1.195 + * THREAD_PRIORITY_NORMAL 1.196 + */ 1.197 + 1.198 + if (priority != PR_PRIORITY_NORMAL) { 1.199 + _PR_MD_SET_PRIORITY(&(thread->md), priority); 1.200 + } 1.201 + 1.202 + return PR_SUCCESS; 1.203 +} 1.204 + 1.205 +void 1.206 +_PR_MD_YIELD(void) 1.207 +{ 1.208 + /* Isn't there some problem with DosSleep(0) on OS/2? */ 1.209 + DosSleep(0); 1.210 +} 1.211 + 1.212 +void 1.213 +_PR_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri) 1.214 +{ 1.215 + int nativePri = PRTYC_NOCHANGE; 1.216 + BOOL rv; 1.217 + 1.218 + if (newPri < PR_PRIORITY_FIRST) { 1.219 + newPri = PR_PRIORITY_FIRST; 1.220 + } else if (newPri > PR_PRIORITY_LAST) { 1.221 + newPri = PR_PRIORITY_LAST; 1.222 + } 1.223 + switch (newPri) { 1.224 + case PR_PRIORITY_LOW: 1.225 + case PR_PRIORITY_NORMAL: 1.226 + nativePri = PRTYC_REGULAR; 1.227 + break; 1.228 + case PR_PRIORITY_HIGH: 1.229 + nativePri = PRTYC_FOREGROUNDSERVER; 1.230 + break; 1.231 + case PR_PRIORITY_URGENT: 1.232 + nativePri = PRTYC_TIMECRITICAL; 1.233 + } 1.234 + rv = DosSetPriority(PRTYS_THREAD, nativePri, 0, thread->handle); 1.235 + PR_ASSERT(rv == NO_ERROR); 1.236 + if (rv != NO_ERROR) { 1.237 + PR_LOG(_pr_thread_lm, PR_LOG_MIN, 1.238 + ("PR_SetThreadPriority: can't set thread priority\n")); 1.239 + } 1.240 + return; 1.241 +} 1.242 + 1.243 +void 1.244 +_PR_MD_CLEAN_THREAD(PRThread *thread) 1.245 +{ 1.246 + APIRET rv; 1.247 + 1.248 + if (thread->md.blocked_sema) { 1.249 + rv = DosCloseEventSem(thread->md.blocked_sema); 1.250 + PR_ASSERT(rv == NO_ERROR); 1.251 + thread->md.blocked_sema = 0; 1.252 + } 1.253 + 1.254 + if (thread->md.handle) { 1.255 + thread->md.handle = 0; 1.256 + } 1.257 +} 1.258 + 1.259 +void 1.260 +_PR_MD_EXIT_THREAD(PRThread *thread) 1.261 +{ 1.262 + _PR_MD_CLEAN_THREAD(thread); 1.263 + _PR_MD_SET_CURRENT_THREAD(NULL); 1.264 +} 1.265 + 1.266 + 1.267 +void 1.268 +_PR_MD_EXIT(PRIntn status) 1.269 +{ 1.270 + _exit(status); 1.271 +} 1.272 + 1.273 +#ifdef HAVE_THREAD_AFFINITY 1.274 +PR_EXTERN(PRInt32) 1.275 +_PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask ) 1.276 +{ 1.277 + /* Can we do this on OS/2? Only on SMP versions? */ 1.278 + PR_ASSERT(!"Not implemented"); 1.279 + return 0; 1.280 + 1.281 + /* This is what windows does: 1.282 + int rv; 1.283 + 1.284 + rv = SetThreadAffinityMask(thread->md.handle, mask); 1.285 + 1.286 + return rv?0:-1; 1.287 + */ 1.288 +} 1.289 + 1.290 +PR_EXTERN(PRInt32) 1.291 +_PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask) 1.292 +{ 1.293 + /* Can we do this on OS/2? Only on SMP versions? */ 1.294 + PR_ASSERT(!"Not implemented"); 1.295 + return 0; 1.296 + 1.297 + /* This is what windows does: 1.298 + PRInt32 rv, system_mask; 1.299 + 1.300 + rv = GetProcessAffinityMask(GetCurrentProcess(), mask, &system_mask); 1.301 + 1.302 + return rv?0:-1; 1.303 + */ 1.304 +} 1.305 +#endif /* HAVE_THREAD_AFFINITY */ 1.306 + 1.307 +void 1.308 +_PR_MD_SUSPEND_CPU(_PRCPU *cpu) 1.309 +{ 1.310 + _PR_MD_SUSPEND_THREAD(cpu->thread); 1.311 +} 1.312 + 1.313 +void 1.314 +_PR_MD_RESUME_CPU(_PRCPU *cpu) 1.315 +{ 1.316 + _PR_MD_RESUME_THREAD(cpu->thread); 1.317 +} 1.318 + 1.319 +void 1.320 +_PR_MD_SUSPEND_THREAD(PRThread *thread) 1.321 +{ 1.322 + if (_PR_IS_NATIVE_THREAD(thread)) { 1.323 + APIRET rc; 1.324 + 1.325 + /* XXXMB - DosSuspendThread() is not a blocking call; how do we 1.326 + * know when the thread is *REALLY* suspended? 1.327 + */ 1.328 + rc = DosSuspendThread(thread->md.handle); 1.329 + PR_ASSERT(rc == NO_ERROR); 1.330 + } 1.331 +} 1.332 + 1.333 +void 1.334 +_PR_MD_RESUME_THREAD(PRThread *thread) 1.335 +{ 1.336 + if (_PR_IS_NATIVE_THREAD(thread)) { 1.337 + DosResumeThread(thread->md.handle); 1.338 + } 1.339 +} 1.340 + 1.341 + 1.342 +PRThread* 1.343 +_MD_CURRENT_THREAD(void) 1.344 +{ 1.345 + PRThread *thread; 1.346 + 1.347 + thread = _MD_GET_ATTACHED_THREAD(); 1.348 + 1.349 + if (NULL == thread) { 1.350 + thread = _PRI_AttachThread(PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0); 1.351 + } 1.352 + 1.353 + PR_ASSERT(thread != NULL); 1.354 + return thread; 1.355 +} 1.356 +