home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / md / unix / unixware.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  13.2 KB  |  549 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. #include "primpl.h"
  19.  
  20. #if !defined (USE_SVR4_THREADS)
  21.  
  22. /*
  23.          * using only NSPR threads here
  24.  */
  25.  
  26. #include <setjmp.h>
  27.  
  28. void _MD_EarlyInit(void)
  29. {
  30. }
  31.  
  32. PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
  33. {
  34.     if (isCurrent) {
  35.     (void) setjmp(CONTEXT(t));
  36.     }
  37.     *np = sizeof(CONTEXT(t)) / sizeof(PRWord);
  38.     return (PRWord *) CONTEXT(t);
  39. }
  40.  
  41. #ifdef ALARMS_BREAK_TCP /* I don't think they do */
  42.  
  43. PRInt32 _MD_connect(PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen,
  44.                         PRIntervalTime timeout)
  45. {
  46.     PRInt32 rv;
  47.  
  48.     _MD_BLOCK_CLOCK_INTERRUPTS();
  49.     rv = _connect(osfd,addr,addrlen);
  50.     _MD_UNBLOCK_CLOCK_INTERRUPTS();
  51. }
  52.  
  53. PRInt32 _MD_accept(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen,
  54.                         PRIntervalTime timeout)
  55. {
  56.     PRInt32 rv;
  57.  
  58.     _MD_BLOCK_CLOCK_INTERRUPTS();
  59.     rv = _accept(osfd,addr,addrlen);
  60.     _MD_UNBLOCK_CLOCK_INTERRUPTS();
  61.     return(rv);
  62. }
  63. #endif
  64.  
  65. /*
  66.  * These are also implemented in pratom.c using NSPR locks.  Any reason
  67.  * this might be better or worse?  If you like this better, define
  68.  * _PR_HAVE_ATOMIC_OPS in include/md/unixware.h
  69.  */
  70. #ifdef _PR_HAVE_ATOMIC_OPS
  71. /* Atomic operations */
  72. #include  <stdio.h>
  73. static FILE *_uw_semf;
  74.  
  75. void
  76. _MD_INIT_ATOMIC(void)
  77. {
  78.     /* Sigh.  Sure wish SYSV semaphores weren't such a pain to use */
  79.     if ((_uw_semf = tmpfile()) == NULL)
  80.         PR_ASSERT(0);
  81.  
  82.     return;
  83. }
  84.  
  85. void
  86. _MD_ATOMIC_INCREMENT(PRInt32 *val)
  87. {
  88.     flockfile(_uw_semf);
  89.     (*val)++;
  90.     unflockfile(_uw_semf);
  91. }
  92.  
  93. void
  94. _MD_ATOMIC_DECREMENT(PRInt32 *val)
  95. {
  96.     flockfile(_uw_semf);
  97.     (*val)--;
  98.     unflockfile(_uw_semf);
  99. }
  100.  
  101. void
  102. _MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
  103. {
  104.     flockfile(_uw_semf);
  105.     *val = newval;
  106.     unflockfile(_uw_semf);
  107. }
  108. #endif
  109.  
  110. void
  111. _MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri)
  112. {
  113.     return;
  114. }
  115.  
  116. PRStatus
  117. _MD_InitializeThread(PRThread *thread)
  118. {
  119.     return PR_SUCCESS;
  120. }
  121.  
  122. PRStatus
  123. _MD_WAIT(PRThread *thread, PRIntervalTime ticks)
  124. {
  125.     PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE));
  126.     _PR_MD_SWITCH_CONTEXT(thread);
  127.     return PR_SUCCESS;
  128. }
  129.  
  130. PRStatus
  131. _MD_WAKEUP_WAITER(PRThread *thread)
  132. {
  133.     if (thread) {
  134.     PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE));
  135.     }
  136.     return PR_SUCCESS;
  137. }
  138.  
  139. /* These functions should not be called for Unixware */
  140. void
  141. _MD_YIELD(void)
  142. {
  143.     PR_NOT_REACHED("_MD_YIELD should not be called for Unixware.");
  144. }
  145.  
  146. PRStatus
  147. _MD_CREATE_THREAD(
  148.     PRThread *thread,
  149.     void (*start) (void *),
  150.     PRThreadPriority priority,
  151.     PRThreadScope scope,
  152.     PRThreadState state,
  153.     PRUint32 stackSize)
  154. {
  155.     PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Unixware.");
  156. }
  157.  
  158. #else  /* USE_SVR4_THREADS */
  159.  
  160. /* NOTE:
  161.  * SPARC v9 (Ultras) do have an atomic test-and-set operation.  But
  162.  * SPARC v8 doesn't.  We should detect in the init if we are running on
  163.  * v8 or v9, and then use assembly where we can.
  164.  */
  165.  
  166. #include <thread.h>
  167. #include <synch.h>
  168.  
  169. static mutex_t _unixware_atomic = DEFAULTMUTEX;
  170.  
  171. #define TEST_THEN_ADD(where, inc) \
  172.     if (mutex_lock(&_unixware_atomic) != 0)\
  173.         PR_ASSERT(0);\
  174.     *where += inc;\
  175.     if (mutex_unlock(&_unixware_atomic) != 0)\
  176.         PR_ASSERT(0);
  177.  
  178. #define TEST_THEN_SET(where, val) \
  179.     if (mutex_lock(&_unixware_atomic) != 0)\
  180.         PR_ASSERT(0);\
  181.     *where = val;\
  182.     if (mutex_unlock(&_unixware_atomic) != 0)\
  183.         PR_ASSERT(0);
  184.  
  185. void
  186. _MD_INIT_ATOMIC(void)
  187. {
  188. }
  189.  
  190. void
  191. _MD_ATOMIC_INCREMENT(PRInt32 *val)
  192. {
  193.     TEST_THEN_ADD(val, 1);
  194. }
  195.  
  196. void
  197. _MD_ATOMIC_DECREMENT(PRInt32 *val)
  198. {
  199.     TEST_THEN_ADD(val, 0xffffffff);
  200. }
  201.  
  202. void
  203. _MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
  204. {
  205.     TEST_THEN_SET(val, newval);
  206. }
  207.  
  208. #include <signal.h>
  209. #include <errno.h>
  210. #include <fcntl.h>
  211.  
  212. #include <sys/lwp.h>
  213. #include <sys/procfs.h>
  214. #include <sys/syscall.h>
  215.  
  216.  
  217. THREAD_KEY_T threadid_key;
  218. THREAD_KEY_T cpuid_key;
  219. THREAD_KEY_T last_thread_key;
  220. static sigset_t set, oldset;
  221.  
  222. void _MD_EarlyInit(void)
  223. {
  224.     THR_KEYCREATE(&threadid_key, NULL);
  225.     THR_KEYCREATE(&cpuid_key, NULL);
  226.     THR_KEYCREATE(&last_thread_key, NULL);
  227.     sigemptyset(&set);
  228.     sigaddset(&set, SIGALRM);
  229. }
  230.  
  231. PRStatus _MD_CREATE_THREAD(PRThread *thread, 
  232.                     void (*start)(void *), 
  233.                     PRThreadPriority priority,
  234.                     PRThreadScope scope, 
  235.                     PRThreadState state, 
  236.                     PRUint32 stackSize) 
  237. {
  238.     long flags;
  239.     
  240.     /* mask out SIGALRM for native thread creation */
  241.     thr_sigsetmask(SIG_BLOCK, &set, &oldset); 
  242.  
  243.     flags = (state == PR_JOINABLE_THREAD ? THR_SUSPENDED/*|THR_NEW_LWP*/ 
  244.                : THR_SUSPENDED|THR_DETACHED/*|THR_NEW_LWP*/);
  245.     if (thread->flags & _PR_GCABLE_THREAD)
  246.         flags |= THR_BOUND;
  247.  
  248.     if (thr_create(NULL, thread->stack->stackSize,
  249.                   (void *(*)(void *)) start, (void *) thread, 
  250.                   flags,
  251.                   &thread->md.handle)) {
  252.         thr_sigsetmask(SIG_SETMASK, &oldset, NULL); 
  253.     return PR_FAILURE;
  254.     }
  255.  
  256.  
  257.     /* When the thread starts running, then the lwpid is set to the right
  258.      * value. Until then we want to mark this as 'uninit' so that
  259.      * its register state is initialized properly for GC */
  260.  
  261.     thread->md.lwpid = -1;
  262.     thr_sigsetmask(SIG_SETMASK, &oldset, NULL); 
  263.     _MD_NEW_SEM(&thread->md.waiter_sem, 0);
  264.  
  265.     if (scope == PR_GLOBAL_THREAD) {
  266.     thread->flags |= _PR_GLOBAL_SCOPE;
  267.     }
  268.  
  269.     /* 
  270.     ** Set the thread priority.  This will also place the thread on 
  271.     ** the runQ.
  272.     **
  273.     ** Force PR_SetThreadPriority to set the priority by
  274.     ** setting thread->priority to 100.
  275.     */
  276.     {
  277.     int pri;
  278.     pri = thread->priority;
  279.     thread->priority = 100;
  280.     PR_SetThreadPriority( thread, pri );
  281.  
  282.     PR_LOG(_pr_thread_lm, PR_LOG_MIN, 
  283.             ("(0X%x)[Start]: on to runq at priority %d",
  284.             thread, thread->priority));
  285.     }
  286.  
  287.     /* Activate the thread */
  288.     if (thr_continue( thread->md.handle ) ) {
  289.     return PR_FAILURE;
  290.     }
  291.     return PR_SUCCESS;
  292. }
  293.  
  294. void _MD_cleanup_thread(PRThread *thread)
  295. {
  296.     thread_t hdl;
  297.     PRMonitor *mon;
  298.  
  299.     hdl = thread->md.handle;
  300.  
  301.     /* 
  302.     ** First, suspend the thread (unless it's the active one)
  303.     ** Because we suspend it first, we don't have to use LOCK_SCHEDULER to
  304.     ** prevent both of us modifying the thread structure at the same time.
  305.     */
  306.     if ( thread != _PR_MD_CURRENT_THREAD() ) {
  307.         thr_suspend(hdl);
  308.     }
  309.     PR_LOG(_pr_thread_lm, PR_LOG_MIN,
  310.             ("(0X%x)[DestroyThread]\n", thread));
  311.  
  312.     _MD_DESTROY_SEM(&thread->md.waiter_sem);
  313. }
  314.  
  315. void _MD_SET_PRIORITY(_MDThread *md_thread, PRUintn newPri)
  316. {
  317.     if(thr_setprio((thread_t)md_thread->handle, newPri)) {
  318.         PR_LOG(_pr_thread_lm, PR_LOG_MIN,
  319.            ("_PR_SetThreadPriority: can't set thread priority\n"));
  320.     }
  321. }
  322.  
  323. void _MD_WAIT_CV(
  324.     struct _MDCVar *md_cv, struct _MDLock *md_lock, PRIntervalTime timeout)
  325. {
  326.     struct timespec tt;
  327.     PRUint32 msec;
  328.     int rv;
  329.     PRThread *me = _PR_MD_CURRENT_THREAD();
  330.  
  331.     msec = PR_IntervalToMilliseconds(timeout);
  332.  
  333.     GETTIME (&tt);
  334.  
  335.     tt.tv_sec += msec / PR_MSEC_PER_SEC;
  336.     tt.tv_nsec += (msec % PR_MSEC_PER_SEC) * PR_NSEC_PER_MSEC;
  337.     /* Check for nsec overflow - otherwise we'll get an EINVAL */
  338.     if (tt.tv_nsec >= PR_NSEC_PER_SEC) {
  339.         tt.tv_sec++;
  340.         tt.tv_nsec -= PR_NSEC_PER_SEC;
  341.     }
  342.     me->md.sp = unixware_getsp();
  343.  
  344.  
  345.     /* XXX Solaris 2.5.x gives back EINTR occasionally for no reason
  346.      * hence ignore EINTR for now */
  347.  
  348.     COND_TIMEDWAIT(&md_cv->cv, &md_lock->lock, &tt);
  349. }
  350.  
  351. void _MD_lock(struct _MDLock *md_lock)
  352. {
  353.     mutex_lock(&md_lock->lock);
  354. }
  355.  
  356. void _MD_unlock(struct _MDLock *md_lock)
  357. {
  358.     mutex_unlock(&((md_lock)->lock));
  359. }
  360.  
  361.  
  362. PRThread *_pr_current_thread_tls()
  363. {
  364.     PRThread *ret;
  365.  
  366.     thr_getspecific(threadid_key, (void **)&ret);
  367.     return ret;
  368. }
  369.  
  370. PRStatus
  371. _MD_WAIT(PRThread *thread, PRIntervalTime ticks)
  372. {
  373.         _MD_WAIT_SEM(&thread->md.waiter_sem);
  374.         return PR_SUCCESS;
  375. }
  376.  
  377. PRStatus
  378. _MD_WAKEUP_WAITER(PRThread *thread)
  379. {
  380.     if (thread == NULL) {
  381.         return PR_SUCCESS;
  382.     }
  383.     _MD_POST_SEM(&thread->md.waiter_sem);
  384.     return PR_SUCCESS;
  385. }
  386.  
  387. _PRCPU *_pr_current_cpu_tls()
  388. {
  389.     _PRCPU *ret;
  390.  
  391.     thr_getspecific(cpuid_key, (void **)&ret);
  392.     return ret;
  393. }
  394.  
  395. PRThread *_pr_last_thread_tls()
  396. {
  397.     PRThread *ret;
  398.  
  399.     thr_getspecific(last_thread_key, (void **)&ret);
  400.     return ret;
  401. }
  402.  
  403. _MDLock _pr_ioq_lock;
  404.  
  405. void _MD_INIT_IO (void)
  406. {
  407.     _MD_NEW_LOCK(&_pr_ioq_lock);
  408. }
  409.  
  410. PRStatus _MD_InitializeThread(PRThread *thread)
  411. {
  412.     if (!_PR_IS_NATIVE_THREAD(thread))
  413.         return;
  414.         /* prime the sp; substract 4 so we don't hit the assert that
  415.          * curr sp > base_stack
  416.          */
  417.     thread->md.sp = (uint_t) thread->stack->allocBase - sizeof(long);
  418.     thread->md.lwpid = _lwp_self();
  419.     thread->md.handle = THR_SELF();
  420.  
  421.     /* all threads on Solaris are global threads from NSPR's perspective
  422.      * since all of them are mapped to Solaris threads.
  423.      */
  424.     thread->flags |= _PR_GLOBAL_SCOPE;
  425.  
  426.      /* For primordial/attached thread, we don't create an underlying native thread.
  427.       * So, _MD_CREATE_THREAD() does not get called.  We need to do initialization
  428.       * like allocating thread's synchronization variables and set the underlying
  429.       * native thread's priority.
  430.       */
  431.     if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) {
  432.         _MD_NEW_SEM(&thread->md.waiter_sem, 0);
  433.         _MD_SET_PRIORITY(&(thread->md), thread->priority);
  434.     }
  435.     return PR_SUCCESS;
  436. }
  437.  
  438. static sigset_t old_mask;    /* store away original gc thread sigmask */
  439. static int gcprio;        /* store away original gc thread priority */
  440. static lwpid_t *all_lwps=NULL;    /* list of lwps that we suspended */
  441. static int num_lwps ;
  442. static int suspendAllOn = 0;
  443.  
  444. #define VALID_SP(sp, bottom, top)    \
  445.        (((uint_t)(sp)) > ((uint_t)(bottom)) && ((uint_t)(sp)) < ((uint_t)(top)))
  446.  
  447. void unixware_preempt_off()
  448. {
  449.     sigset_t set;
  450.     (void)sigfillset(&set);
  451.     sigprocmask (SIG_SETMASK, &set, &old_mask);
  452. }
  453.  
  454. void unixware_preempt_on()
  455. {
  456.     sigprocmask (SIG_SETMASK, &old_mask, NULL);      
  457. }
  458.  
  459. void _MD_Begin_SuspendAll()
  460. {
  461.     unixware_preempt_off();
  462.  
  463.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin_SuspendAll\n"));
  464.     /* run at highest prio so I cannot be preempted */
  465.     thr_getprio(thr_self(), &gcprio);
  466.     thr_setprio(thr_self(), 0x7fffffff); 
  467.     suspendAllOn = 1;
  468. }
  469.  
  470. void _MD_End_SuspendAll()
  471. {
  472. }
  473.  
  474. void _MD_End_ResumeAll()
  475. {
  476.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End_ResumeAll\n"));
  477.     thr_setprio(thr_self(), gcprio);
  478.     unixware_preempt_on();
  479.     suspendAllOn = 0;
  480. }
  481.  
  482. void _MD_Suspend(PRThread *thr)
  483. {
  484.    int lwp_fd, result;
  485.    int lwp_main_proc_fd = 0;
  486.  
  487.     thr_suspend(thr->md.handle);
  488.     if (!(thr->flags & _PR_GCABLE_THREAD))
  489.       return;
  490.     /* XXX Primordial thread can't be bound to an lwp, hence there is no
  491.      * way we can assume that we can get the lwp status for primordial
  492.      * thread reliably. Hence we skip this for primordial thread, hoping
  493.      * that the SP is saved during lock and cond. wait. 
  494.      * XXX - Again this is concern only for java interpreter, not for the
  495.      * server, 'cause primordial thread in the server does not do java work
  496.      */
  497.     if (thr->flags & _PR_PRIMORDIAL)
  498.       return;
  499.  
  500.     /* if the thread is not started yet then don't do anything */
  501.     if (!suspendAllOn || thr->md.lwpid == -1)
  502.       return;
  503.  
  504. }
  505. void _MD_Resume(PRThread *thr)
  506. {
  507.    if (!(thr->flags & _PR_GCABLE_THREAD) || !suspendAllOn){
  508.      /*XXX When the suspendAllOn is set, we will be trying to do lwp_suspend
  509.       * during that time we can't call any thread lib or libc calls. Hence
  510.       * make sure that no resume is requested for Non gcable thread
  511.       * during suspendAllOn */
  512.       PR_ASSERT(!suspendAllOn);
  513.       thr_continue(thr->md.handle);
  514.       return;
  515.    }
  516.    if (thr->md.lwpid == -1)
  517.      return;
  518.  
  519.    if ( _lwp_continue(thr->md.lwpid) < 0) {
  520.       PR_ASSERT(0);  /* ARGH, we are hosed! */
  521.    }
  522. }
  523.  
  524.  
  525. PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
  526. {
  527.     if (isCurrent) {
  528.     (void) getcontext(CONTEXT(t));    /* XXX tune me: set md_IRIX.c */
  529.     }
  530.     *np = NGREG;
  531.     if (t->md.lwpid == -1)
  532.       memset(&t->md.context.uc_mcontext.gregs[0], 0, NGREG * sizeof(PRWord));
  533.     return (PRWord*) &t->md.context.uc_mcontext.gregs[0];
  534. }
  535.  
  536. int
  537. _pr_unixware_clock_gettime (struct timespec *tp)
  538. {
  539.     struct timeval tv;
  540.  
  541.     gettimeofday(&tv, NULL);
  542.     tp->tv_sec = tv.tv_sec;
  543.     tp->tv_nsec = tv.tv_usec * 1000;
  544.     return 0;
  545. }
  546.  
  547.  
  548. #endif /* USE_SVR4_THREADS */
  549.