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.

     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/. */
     6 #include "primpl.h"
     7 #include <process.h>  /* for _beginthread() */
     8 #include <signal.h>
     9 #include <float.h>
    11 /* --- globals ------------------------------------------------ */
    12 _NSPR_TLS*        pThreadLocalStorage = 0;
    13 _PRInterruptTable             _pr_interruptTable[] = { { 0 } };
    14 APIRET (* APIENTRY QueryThreadContext)(TID, ULONG, PCONTEXTRECORD);
    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 }
    30 void
    31 _PR_MD_EARLY_INIT()
    32 {
    33    HMODULE hmod;
    35    if (DosLoadModule(NULL, 0, "DOSCALL1", &hmod) == 0)
    36        DosQueryProcAddr(hmod, 877, "DOSQUERYTHREADCONTEXT",
    37                         (PFN *)&QueryThreadContext);
    38 }
    40 static void
    41 _pr_SetThreadMDHandle(PRThread *thread)
    42 {
    43    PTIB ptib;
    44    PPIB ppib;
    45    PRUword rc;
    47    rc = DosGetInfoBlocks(&ptib, &ppib);
    49    thread->md.handle = ptib->tib_ptib2->tib2_ultid;
    50 }
    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
    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 }
   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 }
   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 }
   134 PRStatus
   135 _PR_MD_INIT_THREAD(PRThread *thread)
   136 {
   137    APIRET rv;
   139    if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) {
   140       _pr_SetThreadMDHandle(thread);
   141    }
   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 }
   148 typedef struct param_store
   149 {
   150     void (*start)(void *);
   151     PRThread* thread;
   152 } PARAMSTORE;
   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;
   162     PR_OS2_SetFloatExcpHandler(&excpreg);
   164     params = *pParams;
   165     PR_Free(pParams);
   166     params.start(params.thread);
   168     PR_OS2_UnsetFloatExcpHandler(&excpreg);
   169 }
   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     }
   190     /*
   191      * On OS/2, a thread is created with a thread priority of
   192      * THREAD_PRIORITY_NORMAL
   193      */
   195     if (priority != PR_PRIORITY_NORMAL) {
   196         _PR_MD_SET_PRIORITY(&(thread->md), priority);
   197     }
   199     return PR_SUCCESS;
   200 }
   202 void
   203 _PR_MD_YIELD(void)
   204 {
   205     /* Isn't there some problem with DosSleep(0) on OS/2? */
   206     DosSleep(0);
   207 }
   209 void
   210 _PR_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri)
   211 {
   212     int nativePri = PRTYC_NOCHANGE;
   213     BOOL rv;
   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 }
   240 void
   241 _PR_MD_CLEAN_THREAD(PRThread *thread)
   242 {
   243     APIRET rv;
   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     }
   251     if (thread->md.handle) {
   252         thread->md.handle = 0;
   253     }
   254 }
   256 void
   257 _PR_MD_EXIT_THREAD(PRThread *thread)
   258 {
   259     _PR_MD_CLEAN_THREAD(thread);
   260     _PR_MD_SET_CURRENT_THREAD(NULL);
   261 }
   264 void
   265 _PR_MD_EXIT(PRIntn status)
   266 {
   267     _exit(status);
   268 }
   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;
   278  /* This is what windows does:
   279     int rv;
   281     rv = SetThreadAffinityMask(thread->md.handle, mask);
   283     return rv?0:-1;
   284   */
   285 }
   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;
   294  /* This is what windows does:
   295     PRInt32 rv, system_mask;
   297     rv = GetProcessAffinityMask(GetCurrentProcess(), mask, &system_mask);
   299     return rv?0:-1;
   300   */
   301 }
   302 #endif /* HAVE_THREAD_AFFINITY */
   304 void
   305 _PR_MD_SUSPEND_CPU(_PRCPU *cpu) 
   306 {
   307     _PR_MD_SUSPEND_THREAD(cpu->thread);
   308 }
   310 void
   311 _PR_MD_RESUME_CPU(_PRCPU *cpu)
   312 {
   313     _PR_MD_RESUME_THREAD(cpu->thread);
   314 }
   316 void
   317 _PR_MD_SUSPEND_THREAD(PRThread *thread)
   318 {
   319     if (_PR_IS_NATIVE_THREAD(thread)) {
   320        APIRET rc;
   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 }
   330 void
   331 _PR_MD_RESUME_THREAD(PRThread *thread)
   332 {
   333     if (_PR_IS_NATIVE_THREAD(thread)) {
   334         DosResumeThread(thread->md.handle);
   335     }
   336 }
   339 PRThread*
   340 _MD_CURRENT_THREAD(void)
   341 {
   342     PRThread *thread;
   344     thread = _MD_GET_ATTACHED_THREAD();
   346     if (NULL == thread) {
   347         thread = _PRI_AttachThread(PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0);
   348     }
   350     PR_ASSERT(thread != NULL);
   351     return thread;
   352 }

mercurial