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

changeset 0
6474c204b198
     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 +

mercurial