home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / md / unix / solaris.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  21.4 KB  |  809 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.  
  19. #include "primpl.h"
  20.  
  21.  
  22. extern PRBool suspendAllOn;
  23. extern PRThread *suspendAllThread;
  24.  
  25. extern void _MD_SET_PRIORITY(_MDThread *md, PRThreadPriority newPri);
  26.  
  27. PRIntervalTime _MD_Solaris_TicksPerSecond(void)
  28. {
  29.     /*
  30.      * Ticks have a 10-microsecond resolution.  So there are
  31.      * 100000 ticks per second.
  32.      */
  33.     return 100000UL;
  34. }
  35.  
  36. /* Interval timers, implemented using gethrtime() */
  37.  
  38. PRIntervalTime _MD_Solaris_GetInterval(void)
  39. {
  40.     union {
  41.     hrtime_t hrt;  /* hrtime_t is a 64-bit (long long) integer */
  42.     PRInt64 pr64;
  43.     } time;
  44.     PRInt64 resolution;
  45.     PRIntervalTime ticks;
  46.  
  47.     time.hrt = gethrtime();  /* in nanoseconds */
  48.     /*
  49.      * Convert from nanoseconds to ticks.  A tick's resolution is
  50.      * 10 microseconds, or 10000 nanoseconds.
  51.      */
  52.     LL_I2L(resolution, 10000);
  53.     LL_DIV(time.pr64, time.pr64, resolution);
  54.     LL_L2UI(ticks, time.pr64);
  55.     return ticks;
  56. }
  57.  
  58. #ifdef _PR_PTHREADS
  59. void _MD_EarlyInit(void)
  60. {
  61. }
  62.  
  63. PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np)
  64. {
  65.     *np = 0;
  66.     return NULL;
  67. }
  68. #endif /* _PR_PTHREADS */
  69.  
  70. #if defined(_PR_HAVE_ATOMIC_OPS)
  71. /* NOTE:
  72.  * SPARC v9 (Ultras) do have an atomic test-and-set operation.  But
  73.  * SPARC v8 doesn't.  We should detect in the init if we are running on
  74.  * v8 or v9, and then use assembly where we can.
  75.  *
  76.  * This code uses the Solaris threads API.  It can be used in both the
  77.  * pthreads and Solaris threads versions of nspr20 because "POSIX threads
  78.  * and Solaris threads are fully compatible even within the same process",
  79.  * to quote from pthread_create(3T).
  80.  */
  81.  
  82. #include <thread.h>
  83. #include <synch.h>
  84.  
  85. static mutex_t _solaris_atomic = DEFAULTMUTEX;
  86.  
  87. PRInt32
  88. _MD_AtomicIncrement(PRInt32 *val)
  89. {
  90.     PRInt32 rv;
  91.     if (mutex_lock(&_solaris_atomic) != 0)
  92.         PR_ASSERT(0);
  93.  
  94.     rv = ++(*val);
  95.  
  96.     if (mutex_unlock(&_solaris_atomic) != 0)\
  97.         PR_ASSERT(0);
  98.  
  99.     return rv;
  100. }
  101.  
  102. PRInt32
  103. _MD_AtomicDecrement(PRInt32 *val)
  104. {
  105.     PRInt32 rv;
  106.     if (mutex_lock(&_solaris_atomic) != 0)
  107.         PR_ASSERT(0);
  108.  
  109.     rv = --(*val);
  110.  
  111.     if (mutex_unlock(&_solaris_atomic) != 0)\
  112.         PR_ASSERT(0);
  113.  
  114.     return rv;
  115. }
  116.  
  117. PRInt32
  118. _MD_AtomicSet(PRInt32 *val, PRInt32 newval)
  119. {
  120.     PRInt32 rv;
  121.     if (mutex_lock(&_solaris_atomic) != 0)
  122.         PR_ASSERT(0);
  123.  
  124.     rv = *val;
  125.     *val = newval;
  126.  
  127.     if (mutex_unlock(&_solaris_atomic) != 0)\
  128.         PR_ASSERT(0);
  129.  
  130.     return rv;
  131. }
  132. #endif  /* _PR_HAVE_ATOMIC_OPS */
  133.  
  134. #if defined(_PR_GLOBAL_THREADS_ONLY)
  135. #include <signal.h>
  136. #include <errno.h>
  137. #include <fcntl.h>
  138. #include <thread.h>
  139.  
  140. #include <sys/lwp.h>
  141. #include <sys/procfs.h>
  142. #include <sys/syscall.h>
  143. extern int syscall();  /* not declared in sys/syscall.h */
  144.  
  145. static sigset_t old_mask;    /* store away original gc thread sigmask */
  146. static PRIntn gcprio;        /* store away original gc thread priority */
  147.  
  148. THREAD_KEY_T threadid_key;
  149. THREAD_KEY_T cpuid_key;
  150. THREAD_KEY_T last_thread_key;
  151. static sigset_t set, oldset;
  152.  
  153. void _MD_EarlyInit(void)
  154. {
  155.     THR_KEYCREATE(&threadid_key, NULL);
  156.     THR_KEYCREATE(&cpuid_key, NULL);
  157.     THR_KEYCREATE(&last_thread_key, NULL);
  158.     sigemptyset(&set);
  159.     sigaddset(&set, SIGALRM);
  160. }
  161.  
  162. PRStatus _MD_CreateThread(PRThread *thread, 
  163.                     void (*start)(void *), 
  164.                     PRThreadPriority priority,
  165.                     PRThreadScope scope, 
  166.                     PRThreadState state, 
  167.                     PRUint32 stackSize) 
  168. {
  169.     PRInt32 flags;
  170.     
  171.     /* mask out SIGALRM for native thread creation */
  172.     thr_sigsetmask(SIG_BLOCK, &set, &oldset); 
  173.  
  174.     flags = (state == PR_JOINABLE_THREAD) ?
  175.         THR_SUSPENDED : THR_SUSPENDED|THR_DETACHED;
  176.     if (thread->flags & (_PR_GCABLE_THREAD|_PR_BOUND_THREAD))
  177.         flags |= THR_BOUND;
  178.  
  179.     if (thr_create(NULL, thread->stack->stackSize,
  180.                   (void *(*)(void *)) start, (void *) thread, 
  181.                   flags,
  182.                   &thread->md.handle)) {
  183.         thr_sigsetmask(SIG_SETMASK, &oldset, NULL); 
  184.         return PR_FAILURE;
  185.     }
  186.  
  187.     /* When the thread starts running, then the lwpid is set to the right
  188.      * value. Until then we want to mark this as 'uninit' so that
  189.      * its register state is initialized properly for GC */
  190.  
  191.     thread->md.lwpid = -1;
  192.     thr_sigsetmask(SIG_SETMASK, &oldset, NULL); 
  193.     _MD_NEW_SEM(&thread->md.waiter_sem, 0);
  194.  
  195.     if (scope == PR_GLOBAL_THREAD) {
  196.     thread->flags |= _PR_GLOBAL_SCOPE;
  197.     }
  198.  
  199.     _MD_SET_PRIORITY(&(thread->md), priority);
  200.  
  201.     /* Activate the thread */
  202.     if (thr_continue( thread->md.handle ) ) {
  203.     return PR_FAILURE;
  204.     }
  205.     return PR_SUCCESS;
  206. }
  207.  
  208. void _MD_cleanup_thread(PRThread *thread)
  209. {
  210.     thread_t hdl;
  211.  
  212.     hdl = thread->md.handle;
  213.  
  214.     /* 
  215.     ** First, suspend the thread (unless it's the active one)
  216.     ** Because we suspend it first, we don't have to use LOCK_SCHEDULER to
  217.     ** prevent both of us modifying the thread structure at the same time.
  218.     */
  219.     if ( thread != _PR_MD_CURRENT_THREAD() ) {
  220.         thr_suspend(hdl);
  221.     }
  222.     PR_LOG(_pr_thread_lm, PR_LOG_MIN,
  223.             ("(0X%x)[DestroyThread]\n", thread));
  224.  
  225.     _MD_DESTROY_SEM(&thread->md.waiter_sem);
  226. }
  227.  
  228. void _MD_exit_thread(PRThread *thread)
  229. {
  230.     _MD_CLEAN_THREAD(thread);
  231.     _MD_SET_CURRENT_THREAD(NULL);
  232. }
  233.  
  234. void _MD_SET_PRIORITY(_MDThread *md_thread,
  235.         PRThreadPriority newPri)
  236. {
  237.     PRIntn nativePri;
  238.  
  239.     if (newPri < PR_PRIORITY_FIRST) {
  240.         newPri = PR_PRIORITY_FIRST;
  241.     } else if (newPri > PR_PRIORITY_LAST) {
  242.         newPri = PR_PRIORITY_LAST;
  243.     }
  244.     /* Solaris priorities are from 0 to 127 */
  245.     nativePri = newPri * 127 / PR_PRIORITY_LAST;
  246.     if(thr_setprio((thread_t)md_thread->handle, nativePri)) {
  247.         PR_LOG(_pr_thread_lm, PR_LOG_MIN,
  248.            ("_PR_SetThreadPriority: can't set thread priority\n"));
  249.     }
  250. }
  251.  
  252. void _MD_WAIT_CV(
  253.     struct _MDCVar *md_cv, struct _MDLock *md_lock, PRIntervalTime timeout)
  254. {
  255.     struct timespec tt;
  256.     PRUint32 msec;
  257.     PRThread *me = _PR_MD_CURRENT_THREAD();
  258.  
  259.     PR_ASSERT((!suspendAllOn) || (suspendAllThread != me));
  260.  
  261.     if (PR_INTERVAL_NO_TIMEOUT == timeout) {
  262.         COND_WAIT(&md_cv->cv, &md_lock->lock);
  263.     } else {
  264.         msec = PR_IntervalToMilliseconds(timeout);
  265.  
  266.         GETTIME(&tt);
  267.         tt.tv_sec += msec / PR_MSEC_PER_SEC;
  268.         tt.tv_nsec += (msec % PR_MSEC_PER_SEC) * PR_NSEC_PER_MSEC;
  269.         /* Check for nsec overflow - otherwise we'll get an EINVAL */
  270.         if (tt.tv_nsec >= PR_NSEC_PER_SEC) {
  271.             tt.tv_sec++;
  272.             tt.tv_nsec -= PR_NSEC_PER_SEC;
  273.         }
  274.         COND_TIMEDWAIT(&md_cv->cv, &md_lock->lock, &tt);
  275.     }
  276. }
  277.  
  278. void _MD_lock(struct _MDLock *md_lock)
  279. {
  280. #ifdef DEBUG
  281.     /* This code was used for GC testing to make sure that we didn't attempt
  282.      * to grab any locks while threads are suspended.
  283.      */
  284.     PRLock *lock;
  285.     
  286.     if ((suspendAllOn) && (suspendAllThread == _PR_MD_CURRENT_THREAD())) {
  287.         lock = ((PRLock *) ((char*) (md_lock) - offsetof(PRLock,ilock)));
  288.     PR_ASSERT(lock->owner == NULL);
  289.         return;
  290.     }
  291. #endif /* DEBUG */
  292.  
  293.     mutex_lock(&md_lock->lock);
  294. }
  295.  
  296. PRThread *_pr_current_thread_tls()
  297. {
  298.     PRThread *ret;
  299.  
  300.     thr_getspecific(threadid_key, (void **)&ret);
  301.     return ret;
  302. }
  303.  
  304. PRStatus
  305. _MD_wait(PRThread *thread, PRIntervalTime ticks)
  306. {
  307.         _MD_WAIT_SEM(&thread->md.waiter_sem);
  308.         return PR_SUCCESS;
  309. }
  310.  
  311. PRStatus
  312. _MD_WakeupWaiter(PRThread *thread)
  313. {
  314.     if (thread == NULL) {
  315.         return PR_SUCCESS;
  316.     }
  317.     _MD_POST_SEM(&thread->md.waiter_sem);
  318.     return PR_SUCCESS;
  319. }
  320.  
  321. _PRCPU *_pr_current_cpu_tls()
  322. {
  323.     _PRCPU *ret;
  324.  
  325.     thr_getspecific(cpuid_key, (void **)&ret);
  326.     return ret;
  327. }
  328.  
  329. PRThread *_pr_last_thread_tls()
  330. {
  331.     PRThread *ret;
  332.  
  333.     thr_getspecific(last_thread_key, (void **)&ret);
  334.     return ret;
  335. }
  336.  
  337. _MDLock _pr_ioq_lock;
  338.  
  339. void
  340. _MD_InitIO(void)
  341. {
  342.     _MD_NEW_LOCK(&_pr_ioq_lock);
  343. }
  344.  
  345. PRStatus _MD_InitializeThread(PRThread *thread)
  346. {
  347.     if (!_PR_IS_NATIVE_THREAD(thread))
  348.         return PR_SUCCESS;
  349.     /* sol_curthread is an asm routine which grabs GR7; GR7 stores an internal
  350.      * thread structure ptr used by solaris.  We'll use this ptr later
  351.      * with suspend/resume to find which threads are running on LWPs.
  352.      */
  353.     thread->md.threadID = sol_curthread();
  354.         /* prime the sp; substract 4 so we don't hit the assert that
  355.          * curr sp > base_stack
  356.          */
  357.     thread->md.sp = (uint_t) thread->stack->allocBase - sizeof(long);
  358.     thread->md.lwpid = _lwp_self();
  359.     thread->md.handle = THR_SELF();
  360.  
  361.     /* all threads on Solaris are global threads from NSPR's perspective
  362.      * since all of them are mapped to Solaris threads.
  363.      */
  364.     thread->flags |= _PR_GLOBAL_SCOPE;
  365.  
  366.      /* For primordial/attached thread, we don't create an underlying native thread.
  367.       * So, _MD_CREATE_THREAD() does not get called.  We need to do initialization
  368.       * like allocating thread's synchronization variables and set the underlying
  369.       * native thread's priority.
  370.       */
  371.     if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) {
  372.         _MD_NEW_SEM(&thread->md.waiter_sem, 0);
  373.         _MD_SET_PRIORITY(&(thread->md), thread->priority);
  374.     }
  375.     return PR_SUCCESS;
  376. }
  377.  
  378. /* Sleep for n milliseconds, n < 1000   */
  379. void solaris_msec_sleep(int n)
  380. {
  381.     struct timespec ts;
  382.  
  383.     ts.tv_sec = 0;
  384.     ts.tv_nsec = 1000000*n;
  385.     if (syscall(SYS_nanosleep, &ts, 0, 0) < 0) {
  386.         PR_ASSERT(0);
  387.     }
  388. }      
  389.  
  390. #define VALID_SP(sp, bottom, top)   \
  391.     (((uint_t)(sp)) > ((uint_t)(bottom)) && ((uint_t)(sp)) < ((uint_t)(top)))
  392.  
  393. void solaris_record_regs(PRThread *t, prstatus_t *lwpstatus)
  394. {
  395. #ifdef sparc
  396.     long *regs = (long *)&t->md.context.uc_mcontext.gregs[0];
  397.  
  398.     PR_ASSERT(t->flags & _PR_GCABLE_THREAD);
  399.     PR_ASSERT(t->md.threadID == lwpstatus->pr_reg[REG_G7]);
  400.  
  401.     t->md.sp = lwpstatus->pr_reg[REG_SP];
  402.     PR_ASSERT(VALID_SP(t->md.sp, t->stack->stackBottom, t->stack->stackTop));
  403.  
  404.     regs[0] = lwpstatus->pr_reg[R_G1];
  405.     regs[1] = lwpstatus->pr_reg[R_G2];
  406.     regs[2] = lwpstatus->pr_reg[R_G3];
  407.     regs[3] = lwpstatus->pr_reg[R_G4];
  408.     regs[4] = lwpstatus->pr_reg[R_O0];
  409.     regs[5] = lwpstatus->pr_reg[R_O1];
  410.     regs[6] = lwpstatus->pr_reg[R_O2];
  411.     regs[7] = lwpstatus->pr_reg[R_O3];
  412.     regs[8] = lwpstatus->pr_reg[R_O4];
  413.     regs[9] = lwpstatus->pr_reg[R_O5];
  414.     regs[10] = lwpstatus->pr_reg[R_O6];
  415.     regs[11] = lwpstatus->pr_reg[R_O7];
  416. #elif defined(i386)
  417.     /*
  418.      * To be implemented and tested
  419.      */
  420.     PR_ASSERT(0);
  421.     PR_ASSERT(t->md.threadID == lwpstatus->pr_reg[GS]);
  422.     t->md.sp = lwpstatus->pr_reg[UESP];
  423. #endif
  424. }   
  425.  
  426. void solaris_preempt_off()
  427. {
  428.     sigset_t set;
  429.  
  430.     (void)sigfillset(&set);
  431.     syscall(SYS_sigprocmask, SIG_SETMASK, &set, &old_mask);
  432. }
  433.  
  434. void solaris_preempt_on()
  435. {
  436.     syscall(SYS_sigprocmask, SIG_SETMASK, &old_mask, NULL);      
  437. }
  438.  
  439. int solaris_open_main_proc_fd()
  440. {
  441.     char buf[30];
  442.     int fd;
  443.  
  444.     /* Not locked, so must be created while threads coming up */
  445.     PR_snprintf(buf, sizeof(buf), "/proc/%ld", getpid());
  446.     if ( (fd = syscall(SYS_open, buf, O_RDONLY)) < 0) {
  447.         return -1;
  448.     }
  449.     return fd;
  450. }
  451.  
  452. /* Return a file descriptor for the /proc entry corresponding to the
  453.  * given lwp. 
  454.  */
  455. int solaris_open_lwp(lwpid_t id, int lwp_main_proc_fd)
  456. {
  457.     int result;
  458.  
  459.     if ( (result = syscall(SYS_ioctl, lwp_main_proc_fd, PIOCOPENLWP, &id)) <0)
  460.         return -1; /* exited??? */
  461.  
  462.     return result;
  463. }
  464. void _MD_Begin_SuspendAll()
  465. {
  466.     solaris_preempt_off();
  467.  
  468.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin_SuspendAll\n"));
  469.     /* run at highest prio so I cannot be preempted */
  470.     thr_getprio(thr_self(), &gcprio);
  471.     thr_setprio(thr_self(), 0x7fffffff); 
  472.     suspendAllOn = PR_TRUE;
  473.     suspendAllThread = _PR_MD_CURRENT_THREAD();
  474. }
  475.  
  476. void _MD_End_SuspendAll()
  477. {
  478. }
  479.  
  480. void _MD_End_ResumeAll()
  481. {
  482.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End_ResumeAll\n"));
  483.     thr_setprio(thr_self(), gcprio);
  484.     solaris_preempt_on();
  485.     suspendAllThread = NULL;
  486.     suspendAllOn = PR_FALSE;
  487. }
  488.  
  489. void _MD_Suspend(PRThread *thr)
  490. {
  491.    int lwp_fd, result;
  492.    prstatus_t lwpstatus;
  493.    int lwp_main_proc_fd = 0;
  494.   
  495.    if (!(thr->flags & _PR_GCABLE_THREAD) || !suspendAllOn){
  496.      /*XXX When the suspendAllOn is set, we will be trying to do lwp_suspend
  497.       * during that time we can't call any thread lib or libc calls. Hence
  498.       * make sure that no suspension is requested for Non gcable thread
  499.       * during suspendAllOn */
  500.       PR_ASSERT(!suspendAllOn);
  501.       thr_suspend(thr->md.handle);
  502.       return;
  503.    }
  504.  
  505.     /* XXX Primordial thread can't be bound to an lwp, hence there is no
  506.      * way we can assume that we can get the lwp status for primordial
  507.      * thread reliably. Hence we skip this for primordial thread, hoping
  508.      * that the SP is saved during lock and cond. wait. 
  509.      * XXX - Again this is concern only for java interpreter, not for the
  510.      * server, 'cause primordial thread in the server does not do java work
  511.      */
  512.     if (thr->flags & _PR_PRIMORDIAL)
  513.       return;
  514.     
  515.     /* XXX Important Note: If the start function of a thread is not called,
  516.      * lwpid is -1. Then, skip this thread. This thread will get caught
  517.      * in PR_NativeRunThread before calling the start function, because
  518.      * we hold the pr_activeLock during suspend/resume */
  519.  
  520.     /* if the thread is not started yet then don't do anything */
  521.     if (!suspendAllOn || thr->md.lwpid == -1)
  522.       return;
  523.  
  524.     if (_lwp_suspend(thr->md.lwpid) < 0) { 
  525.        PR_ASSERT(0);
  526.        return;
  527.     }
  528.  
  529.     if ( (lwp_main_proc_fd = solaris_open_main_proc_fd()) < 0) {
  530.         PR_ASSERT(0);
  531.         return;   /* XXXMB ARGH, we're hosed! */
  532.     }
  533.  
  534.    if ( (lwp_fd = solaris_open_lwp(thr->md.lwpid, lwp_main_proc_fd)) < 0) {
  535.            PR_ASSERT(0);
  536.            close(lwp_main_proc_fd);
  537.        return;
  538.    }
  539.    if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) {
  540.             /* Hopefully the thread just died... */
  541.            close(lwp_fd);
  542.            close(lwp_main_proc_fd);
  543.        return;
  544.    }
  545.             while ( !(lwpstatus.pr_flags & PR_STOPPED) ) {
  546.                 if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) {
  547.                     PR_ASSERT(0);  /* ARGH SOMETHING WRONG! */
  548.                     break;
  549.                 }
  550.                 solaris_msec_sleep(1);
  551.             }
  552.             solaris_record_regs(thr, &lwpstatus);
  553.             close(lwp_fd);
  554.    close(lwp_main_proc_fd);
  555. }
  556.  
  557. #ifdef OLD_CODE
  558.  
  559. void _MD_SuspendAll()
  560. {
  561.     /* On solaris there are threads, and there are LWPs. 
  562.      * Calling _PR_DoSingleThread would freeze all of the threads bound to LWPs
  563.      * but not necessarily stop all LWPs (for example if someone did
  564.      * an attachthread of a thread which was not bound to an LWP).
  565.      * So now go through all the LWPs for this process and freeze them.
  566.      *
  567.      * Note that if any thread which is capable of having the GC run on it must
  568.      * had better be a LWP with a single bound thread on it.  Otherwise, this 
  569.      * might not stop that thread from being run.
  570.      */
  571.     PRThread *current = _PR_MD_CURRENT_THREAD();
  572.     prstatus_t status, lwpstatus;
  573.     int result, index, lwp_fd;
  574.     lwpid_t me = _lwp_self();
  575.     int err;
  576.     int lwp_main_proc_fd;
  577.  
  578.     solaris_preempt_off();
  579.  
  580.     /* run at highest prio so I cannot be preempted */
  581.     thr_getprio(thr_self(), &gcprio);
  582.     thr_setprio(thr_self(), 0x7fffffff); 
  583.  
  584.     current->md.sp = (uint_t)&me;    /* set my own stack pointer */
  585.  
  586.     if ( (lwp_main_proc_fd = solaris_open_main_proc_fd()) < 0) {
  587.         PR_ASSERT(0);
  588.         solaris_preempt_on();
  589.         return;   /* XXXMB ARGH, we're hosed! */
  590.     }
  591.  
  592.     if ( (result = syscall(SYS_ioctl, lwp_main_proc_fd, PIOCSTATUS, &status)) < 0) {
  593.         err = errno;
  594.         PR_ASSERT(0);
  595.         goto failure;   /* XXXMB ARGH, we're hosed! */
  596.     }
  597.  
  598.     num_lwps = status.pr_nlwp;
  599.  
  600.     if ( (all_lwps = (lwpid_t *)PR_MALLOC((num_lwps+1) * sizeof(lwpid_t)))==NULL) {
  601.         PR_ASSERT(0);
  602.         goto failure;   /* XXXMB ARGH, we're hosed! */
  603.     }
  604.            
  605.     if ( (result = syscall(SYS_ioctl, lwp_main_proc_fd, PIOCLWPIDS, all_lwps)) < 0) {
  606.         PR_ASSERT(0);
  607.         PR_DELETE(all_lwps);
  608.         goto failure;   /* XXXMB ARGH, we're hosed! */
  609.     }
  610.  
  611.     for (index=0; index< num_lwps; index++) {
  612.         if (all_lwps[index] != me)  {
  613.             if (_lwp_suspend(all_lwps[index]) < 0) { 
  614.                 /* could happen if lwp exited */
  615.                 all_lwps[index] = me;    /* dummy it up */
  616.             }
  617.         }
  618.     }
  619.  
  620.     /* Turns out that lwp_suspend is not a blocking call.
  621.      * Go through the list and make sure they are all stopped.
  622.      */
  623.     for (index=0; index< num_lwps; index++) {
  624.         if (all_lwps[index] != me)  {
  625.             if ( (lwp_fd = solaris_open_lwp(all_lwps[index], lwp_main_proc_fd)) < 0) {
  626.                 PR_ASSERT(0);
  627.                 PR_DELETE(all_lwps);
  628.                 all_lwps = NULL;
  629.                 goto failure;   /* XXXMB ARGH, we're hosed! */
  630.             }
  631.  
  632.             if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) {
  633.                 /* Hopefully the thread just died... */
  634.                 close(lwp_fd);
  635.                 continue;
  636.             }
  637.             while ( !(lwpstatus.pr_flags & PR_STOPPED) ) {
  638.                 if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) {
  639.                     PR_ASSERT(0);  /* ARGH SOMETHING WRONG! */
  640.                     break;
  641.                 }
  642.                 solaris_msec_sleep(1);
  643.             }
  644.             solaris_record_regs(&lwpstatus);
  645.             close(lwp_fd);
  646.         }
  647.     }
  648.  
  649.     close(lwp_main_proc_fd);
  650.  
  651.     return;
  652. failure:
  653.     solaris_preempt_on();
  654.     thr_setprio(thr_self(), gcprio);
  655.     close(lwp_main_proc_fd);
  656.     return;
  657. }
  658.  
  659. void _MD_ResumeAll()
  660. {
  661.     int i;
  662.     lwpid_t me = _lwp_self();
  663.  
  664.     for (i=0; i < num_lwps; i++) {
  665.         if (all_lwps[i] == me)
  666.             continue;
  667.         if ( _lwp_continue(all_lwps[i]) < 0) {
  668.             PR_ASSERT(0);  /* ARGH, we are hosed! */
  669.         }
  670.     }
  671.  
  672.     /* restore priority and sigmask */
  673.     thr_setprio(thr_self(), gcprio);
  674.     solaris_preempt_on();
  675.     PR_DELETE(all_lwps);
  676.     all_lwps = NULL;
  677. }
  678. #endif /* OLD_CODE */
  679.  
  680. #ifdef USE_SETJMP
  681. PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
  682. {
  683.     if (isCurrent) {
  684.         (void) setjmp(CONTEXT(t));
  685.     }
  686.     *np = sizeof(CONTEXT(t)) / sizeof(PRWord);
  687.     return (PRWord *) CONTEXT(t);
  688. }
  689. #else
  690. PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np)
  691. {
  692.     if (isCurrent) {
  693.         (void) getcontext(CONTEXT(t));
  694.     }
  695.     *np = NGREG;
  696.     return (PRWord*) &t->md.context.uc_mcontext.gregs[0];
  697. }
  698. #endif  /* USE_SETJMP */
  699.  
  700. #else /* _PR_GLOBAL_THREADS_ONLY */
  701.  
  702. #if defined(_PR_LOCAL_THREADS_ONLY)
  703.  
  704. void _MD_EarlyInit(void)
  705. {
  706. }
  707.  
  708. void _MD_SolarisInit()
  709. {
  710.     _PR_UnixInit();
  711. }
  712.  
  713. void
  714. _MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri)
  715. {
  716.     return;
  717. }
  718.  
  719. PRStatus
  720. _MD_InitializeThread(PRThread *thread)
  721. {
  722.     return PR_SUCCESS;
  723. }
  724.  
  725. PRStatus
  726. _MD_WAIT(PRThread *thread, PRIntervalTime ticks)
  727. {
  728.     PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE));
  729.     _PR_MD_SWITCH_CONTEXT(thread);
  730.     return PR_SUCCESS;
  731. }
  732.  
  733. PRStatus
  734. _MD_WAKEUP_WAITER(PRThread *thread)
  735. {
  736.     PR_ASSERT((thread == NULL) || (!(thread->flags & _PR_GLOBAL_SCOPE)));
  737.     return PR_SUCCESS;
  738. }
  739.  
  740. /* These functions should not be called for Solaris */
  741. void
  742. _MD_YIELD(void)
  743. {
  744.     PR_NOT_REACHED("_MD_YIELD should not be called for Solaris");
  745. }
  746.  
  747. PRStatus
  748. _MD_CREATE_THREAD(
  749.     PRThread *thread,
  750.     void (*start) (void *),
  751.     PRThreadPriority priority,
  752.     PRThreadScope scope,
  753.     PRThreadState state,
  754.     PRUint32 stackSize)
  755. {
  756.     PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Solaris");
  757.     return(PR_FAILURE);
  758. }
  759.  
  760. #ifdef USE_SETJMP
  761. PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
  762. {
  763.     if (isCurrent) {
  764.         (void) setjmp(CONTEXT(t));
  765.     }
  766.     *np = sizeof(CONTEXT(t)) / sizeof(PRWord);
  767.     return (PRWord *) CONTEXT(t);
  768. }
  769. #else
  770. PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np)
  771. {
  772.     if (isCurrent) {
  773.         (void) getcontext(CONTEXT(t));
  774.     }
  775.     *np = NGREG;
  776.     return (PRWord*) &t->md.context.uc_mcontext.gregs[0];
  777. }
  778. #endif  /* USE_SETJMP */
  779.  
  780. #endif  /* _PR_LOCAL_THREADS_ONLY */
  781.  
  782. #endif /* _PR_GLOBAL_THREADS_ONLY */
  783.  
  784. #ifndef _PR_PTHREADS
  785. #if defined(i386) && defined(SOLARIS2_4)
  786. /* 
  787.  * Because clock_gettime() on Solaris/x86 2.4 always generates a
  788.  * segmentation fault, we use an emulated version _pr_solx86_clock_gettime(),
  789.  * which is implemented using gettimeofday().
  790.  */
  791.  
  792. int
  793. _pr_solx86_clock_gettime(clockid_t clock_id, struct timespec *tp)
  794. {
  795.     struct timeval tv;
  796.  
  797.     if (clock_id != CLOCK_REALTIME) {
  798.     errno = EINVAL;
  799.     return -1;
  800.     }
  801.  
  802.     gettimeofday(&tv);
  803.     tp->tv_sec = tv.tv_sec;
  804.     tp->tv_nsec = tv.tv_usec * 1000;
  805.     return 0;
  806. }
  807. #endif  /* i386 && SOLARIS2_4 */
  808. #endif  /* _PR_PTHREADS */
  809.