Back to index

lightning-sunbird  0.9+nobinonly
os2thred.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "primpl.h"
00039 #include <process.h>  /* for _beginthread() */
00040 
00041 #ifdef XP_OS2_VACPP
00042 #include <time.h>     /* for _tzset() */
00043 #endif
00044 
00045 #ifdef XP_OS2_EMX
00046 #include <signal.h>
00047 #endif
00048 
00049 #include <float.h>
00050 
00051 /* --- globals ------------------------------------------------ */
00052 _NSPR_TLS*        pThreadLocalStorage = 0;
00053 _PRInterruptTable             _pr_interruptTable[] = { { 0 } };
00054 APIRET (* APIENTRY QueryThreadContext)(TID, ULONG, PCONTEXTRECORD);
00055 
00056 void
00057 _PR_MD_ENSURE_TLS(void)
00058 {
00059    if(!pThreadLocalStorage)
00060    {
00061       /* Allocate thread local storage (TLS).  Note, that only 32 bytes can
00062        * be allocated at a time. 
00063        */
00064       int rc = DosAllocThreadLocalMemory(sizeof(_NSPR_TLS) / 4, (PULONG*)&pThreadLocalStorage);
00065       PR_ASSERT(rc == NO_ERROR);
00066       memset(pThreadLocalStorage, 0, sizeof(_NSPR_TLS));
00067    }
00068 }
00069 
00070 void
00071 _PR_MD_EARLY_INIT()
00072 {
00073    HMODULE hmod;
00074 
00075    if (DosLoadModule(NULL, 0, "DOSCALL1", &hmod) == 0)
00076        DosQueryProcAddr(hmod, 877, "DOSQUERYTHREADCONTEXT",
00077                         (PFN *)&QueryThreadContext);
00078 
00079 #ifdef XP_OS2_VACPP
00080    _tzset();
00081 #endif
00082 }
00083 
00084 static void
00085 _pr_SetThreadMDHandle(PRThread *thread)
00086 {
00087    PTIB ptib;
00088    PPIB ppib;
00089    PRUword rc;
00090 
00091    rc = DosGetInfoBlocks(&ptib, &ppib);
00092 
00093    thread->md.handle = ptib->tib_ptib2->tib2_ultid;
00094 }
00095 
00096 /* On OS/2, some system function calls seem to change the FPU control word,
00097  * such that we crash with a floating underflow exception.  The FIX_FPU() call
00098  * in jsnum.c does not always work, as sometimes FIX_FPU() is called BEFORE the
00099  * OS/2 system call that horks the FPU control word.  So, we set an exception
00100  * handler that covers any floating point exceptions and resets the FPU CW to
00101  * the required value.
00102  */
00103 static ULONG
00104 _System OS2_FloatExcpHandler(PEXCEPTIONREPORTRECORD p1,
00105                              PEXCEPTIONREGISTRATIONRECORD p2,
00106                              PCONTEXTRECORD p3,
00107                              PVOID pv)
00108 {
00109 #ifdef DEBUG_pedemonte
00110     printf("Entering exception handler; ExceptionNum = %x\n", p1->ExceptionNum);
00111     switch(p1->ExceptionNum) {
00112         case XCPT_FLOAT_DENORMAL_OPERAND:
00113             printf("got XCPT_FLOAT_DENORMAL_OPERAND\n");
00114             break;
00115         case XCPT_FLOAT_DIVIDE_BY_ZERO:
00116             printf("got XCPT_FLOAT_DIVIDE_BY_ZERO\n");
00117             break;
00118         case XCPT_FLOAT_INEXACT_RESULT:
00119             printf("got XCPT_FLOAT_INEXACT_RESULT\n");
00120             break;
00121         case XCPT_FLOAT_INVALID_OPERATION:
00122             printf("got XCPT_FLOAT_INVALID_OPERATION\n");
00123             break;
00124         case XCPT_FLOAT_OVERFLOW:
00125             printf("got XCPT_FLOAT_OVERFLOW\n");
00126             break;
00127         case XCPT_FLOAT_STACK_CHECK:
00128             printf("got XCPT_FLOAT_STACK_CHECK\n");
00129             break;
00130         case XCPT_FLOAT_UNDERFLOW:
00131             printf("got XCPT_FLOAT_UNDERFLOW\n");
00132             break;
00133     }
00134 #endif
00135 
00136     switch(p1->ExceptionNum) {
00137         case XCPT_FLOAT_DENORMAL_OPERAND:
00138         case XCPT_FLOAT_DIVIDE_BY_ZERO:
00139         case XCPT_FLOAT_INEXACT_RESULT:
00140         case XCPT_FLOAT_INVALID_OPERATION:
00141         case XCPT_FLOAT_OVERFLOW:
00142         case XCPT_FLOAT_STACK_CHECK:
00143         case XCPT_FLOAT_UNDERFLOW:
00144         {
00145             unsigned cw = p3->ctx_env[0];
00146             if ((cw & MCW_EM) != MCW_EM) {
00147                 /* Mask out all floating point exceptions */
00148                 p3->ctx_env[0] |= MCW_EM;
00149                 /* Following two lines set precision to 53 bit mantissa.  See jsnum.c */
00150                 p3->ctx_env[0] &= ~MCW_PC;
00151                 p3->ctx_env[0] |= PC_53;
00152                 return XCPT_CONTINUE_EXECUTION;
00153             }
00154         }
00155     }
00156     return XCPT_CONTINUE_SEARCH;
00157 }
00158 
00159 PR_IMPLEMENT(void)
00160 PR_OS2_SetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* excpreg)
00161 {
00162     /* setup the exception handler for the thread */
00163     APIRET rv;
00164     excpreg->ExceptionHandler = OS2_FloatExcpHandler;
00165     excpreg->prev_structure = NULL;
00166     rv = DosSetExceptionHandler(excpreg);
00167     PR_ASSERT(rv == NO_ERROR);
00168 }
00169 
00170 PR_IMPLEMENT(void)
00171 PR_OS2_UnsetFloatExcpHandler(EXCEPTIONREGISTRATIONRECORD* excpreg)
00172 {
00173     /* unset exception handler */
00174     APIRET rv = DosUnsetExceptionHandler(excpreg);
00175     PR_ASSERT(rv == NO_ERROR);
00176 }
00177 
00178 PRStatus
00179 _PR_MD_INIT_THREAD(PRThread *thread)
00180 {
00181    APIRET rv;
00182 
00183    if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) {
00184       _pr_SetThreadMDHandle(thread);
00185    }
00186 
00187    /* Create the blocking IO semaphore */
00188    rv = DosCreateEventSem(NULL, &(thread->md.blocked_sema), 0, 0);
00189    return (rv == NO_ERROR) ? PR_SUCCESS : PR_FAILURE;
00190 }
00191 
00192 typedef struct param_store
00193 {
00194     void (*start)(void *);
00195     PRThread* thread;
00196 } PARAMSTORE;
00197 
00198 /* This is a small intermediate function that sets/unsets the exception
00199    handler before calling the initial thread function */
00200 static void
00201 ExcpStartFunc(void* arg)
00202 {
00203     EXCEPTIONREGISTRATIONRECORD excpreg;
00204     PARAMSTORE params, *pParams = arg;
00205 
00206     PR_OS2_SetFloatExcpHandler(&excpreg);
00207 
00208     params = *pParams;
00209     PR_Free(pParams);
00210     params.start(params.thread);
00211 
00212     PR_OS2_UnsetFloatExcpHandler(&excpreg);
00213 }
00214 
00215 PRStatus
00216 _PR_MD_CREATE_THREAD(PRThread *thread, 
00217                   void (*start)(void *), 
00218                   PRThreadPriority priority, 
00219                   PRThreadScope scope, 
00220                   PRThreadState state, 
00221                   PRUint32 stackSize)
00222 {
00223     PARAMSTORE* params = PR_Malloc(sizeof(PARAMSTORE));
00224     params->start = start;
00225     params->thread = thread;
00226 #ifdef XP_OS2_VACPP /* No exception handler for VACPP */
00227     thread->md.handle = thread->id = (TID) _beginthread(
00228                     (void(* _Optlink)(void*))start,
00229                     NULL, 
00230                     thread->stack->stackSize,
00231                     thread);
00232 #else
00233     thread->md.handle = thread->id = (TID) _beginthread(ExcpStartFunc,
00234                                                         NULL, 
00235                                                         thread->stack->stackSize,
00236                                                         params);
00237 #endif
00238     if(thread->md.handle == -1) {
00239         return PR_FAILURE;
00240     }
00241 
00242     /*
00243      * On OS/2, a thread is created with a thread priority of
00244      * THREAD_PRIORITY_NORMAL
00245      */
00246 
00247     if (priority != PR_PRIORITY_NORMAL) {
00248         _PR_MD_SET_PRIORITY(&(thread->md), priority);
00249     }
00250 
00251     return PR_SUCCESS;
00252 }
00253 
00254 void
00255 _PR_MD_YIELD(void)
00256 {
00257     /* Isn't there some problem with DosSleep(0) on OS/2? */
00258     DosSleep(0);
00259 }
00260 
00261 void
00262 _PR_MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri)
00263 {
00264     int nativePri = PRTYC_NOCHANGE;
00265     BOOL rv;
00266 
00267     if (newPri < PR_PRIORITY_FIRST) {
00268         newPri = PR_PRIORITY_FIRST;
00269     } else if (newPri > PR_PRIORITY_LAST) {
00270         newPri = PR_PRIORITY_LAST;
00271     }
00272     switch (newPri) {
00273         case PR_PRIORITY_LOW:
00274         case PR_PRIORITY_NORMAL:
00275             nativePri = PRTYC_REGULAR;
00276             break;
00277         case PR_PRIORITY_HIGH:
00278             nativePri = PRTYC_FOREGROUNDSERVER;
00279             break;
00280         case PR_PRIORITY_URGENT:
00281             nativePri = PRTYC_TIMECRITICAL;
00282     }
00283     rv = DosSetPriority(PRTYS_THREAD, nativePri, 0, thread->handle);
00284     PR_ASSERT(rv == NO_ERROR);
00285     if (rv != NO_ERROR) {
00286         PR_LOG(_pr_thread_lm, PR_LOG_MIN,
00287                 ("PR_SetThreadPriority: can't set thread priority\n"));
00288     }
00289     return;
00290 }
00291 
00292 void
00293 _PR_MD_CLEAN_THREAD(PRThread *thread)
00294 {
00295     APIRET rv;
00296 
00297     if (thread->md.blocked_sema) {
00298         rv = DosCloseEventSem(thread->md.blocked_sema);
00299         PR_ASSERT(rv == NO_ERROR);
00300         thread->md.blocked_sema = 0;
00301     }
00302 
00303     if (thread->md.handle) {
00304         thread->md.handle = 0;
00305     }
00306 }
00307 
00308 void
00309 _PR_MD_EXIT_THREAD(PRThread *thread)
00310 {
00311     _PR_MD_CLEAN_THREAD(thread);
00312     _PR_MD_SET_CURRENT_THREAD(NULL);
00313 }
00314 
00315 
00316 void
00317 _PR_MD_EXIT(PRIntn status)
00318 {
00319     _exit(status);
00320 }
00321 
00322 #ifdef HAVE_THREAD_AFFINITY
00323 PR_EXTERN(PRInt32) 
00324 _PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask )
00325 {
00326    /* Can we do this on OS/2?  Only on SMP versions? */
00327    PR_ASSERT(!"Not implemented");
00328    return 0;
00329 
00330  /* This is what windows does:
00331     int rv;
00332 
00333     rv = SetThreadAffinityMask(thread->md.handle, mask);
00334 
00335     return rv?0:-1;
00336   */
00337 }
00338 
00339 PR_EXTERN(PRInt32)
00340 _PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask)
00341 {
00342    /* Can we do this on OS/2?  Only on SMP versions? */
00343    PR_ASSERT(!"Not implemented");
00344    return 0;
00345 
00346  /* This is what windows does:
00347     PRInt32 rv, system_mask;
00348 
00349     rv = GetProcessAffinityMask(GetCurrentProcess(), mask, &system_mask);
00350     
00351     return rv?0:-1;
00352   */
00353 }
00354 #endif /* HAVE_THREAD_AFFINITY */
00355 
00356 void
00357 _PR_MD_SUSPEND_CPU(_PRCPU *cpu) 
00358 {
00359     _PR_MD_SUSPEND_THREAD(cpu->thread);
00360 }
00361 
00362 void
00363 _PR_MD_RESUME_CPU(_PRCPU *cpu)
00364 {
00365     _PR_MD_RESUME_THREAD(cpu->thread);
00366 }
00367 
00368 void
00369 _PR_MD_SUSPEND_THREAD(PRThread *thread)
00370 {
00371     if (_PR_IS_NATIVE_THREAD(thread)) {
00372        APIRET rc;
00373 
00374         /* XXXMB - DosSuspendThread() is not a blocking call; how do we
00375          * know when the thread is *REALLY* suspended?
00376          */
00377        rc = DosSuspendThread(thread->md.handle);
00378        PR_ASSERT(rc == NO_ERROR);
00379     }
00380 }
00381 
00382 void
00383 _PR_MD_RESUME_THREAD(PRThread *thread)
00384 {
00385     if (_PR_IS_NATIVE_THREAD(thread)) {
00386         DosResumeThread(thread->md.handle);
00387     }
00388 }
00389 
00390 
00391 PRThread*
00392 _MD_CURRENT_THREAD(void)
00393 {
00394     PRThread *thread;
00395 
00396     thread = _MD_GET_ATTACHED_THREAD();
00397 
00398     if (NULL == thread) {
00399         thread = _PRI_AttachThread(PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0);
00400     }
00401 
00402     PR_ASSERT(thread != NULL);
00403     return thread;
00404 }
00405