Back to index

lightning-sunbird  0.9+nobinonly
solaris.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 
00040 
00041 extern PRBool suspendAllOn;
00042 extern PRThread *suspendAllThread;
00043 
00044 extern void _MD_SET_PRIORITY(_MDThread *md, PRThreadPriority newPri);
00045 
00046 PRIntervalTime _MD_Solaris_TicksPerSecond(void)
00047 {
00048     /*
00049      * Ticks have a 10-microsecond resolution.  So there are
00050      * 100000 ticks per second.
00051      */
00052     return 100000UL;
00053 }
00054 
00055 /* Interval timers, implemented using gethrtime() */
00056 
00057 PRIntervalTime _MD_Solaris_GetInterval(void)
00058 {
00059     union {
00060        hrtime_t hrt;  /* hrtime_t is a 64-bit (long long) integer */
00061        PRInt64 pr64;
00062     } time;
00063     PRInt64 resolution;
00064     PRIntervalTime ticks;
00065 
00066     time.hrt = gethrtime();  /* in nanoseconds */
00067     /*
00068      * Convert from nanoseconds to ticks.  A tick's resolution is
00069      * 10 microseconds, or 10000 nanoseconds.
00070      */
00071     LL_I2L(resolution, 10000);
00072     LL_DIV(time.pr64, time.pr64, resolution);
00073     LL_L2UI(ticks, time.pr64);
00074     return ticks;
00075 }
00076 
00077 #ifdef _PR_PTHREADS
00078 void _MD_EarlyInit(void)
00079 {
00080 }
00081 
00082 PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np)
00083 {
00084        *np = 0;
00085        return NULL;
00086 }
00087 #endif /* _PR_PTHREADS */
00088 
00089 #if !defined(i386) && !defined(IS_64)
00090 #if defined(_PR_HAVE_ATOMIC_OPS)
00091 /* NOTE:
00092  * SPARC v9 (Ultras) do have an atomic test-and-set operation.  But
00093  * SPARC v8 doesn't.  We should detect in the init if we are running on
00094  * v8 or v9, and then use assembly where we can.
00095  *
00096  * This code uses the Solaris threads API.  It can be used in both the
00097  * pthreads and Solaris threads versions of nspr20 because "POSIX threads
00098  * and Solaris threads are fully compatible even within the same process",
00099  * to quote from pthread_create(3T).
00100  */
00101 
00102 #include <thread.h>
00103 #include <synch.h>
00104 
00105 static mutex_t _solaris_atomic = DEFAULTMUTEX;
00106 
00107 PRInt32
00108 _MD_AtomicIncrement(PRInt32 *val)
00109 {
00110     PRInt32 rv;
00111     if (mutex_lock(&_solaris_atomic) != 0)
00112         PR_ASSERT(0);
00113 
00114     rv = ++(*val);
00115 
00116     if (mutex_unlock(&_solaris_atomic) != 0)\
00117         PR_ASSERT(0);
00118 
00119        return rv;
00120 }
00121 
00122 PRInt32
00123 _MD_AtomicAdd(PRInt32 *ptr, PRInt32 val)
00124 {
00125     PRInt32 rv;
00126     if (mutex_lock(&_solaris_atomic) != 0)
00127         PR_ASSERT(0);
00128 
00129     rv = ((*ptr) += val);
00130 
00131     if (mutex_unlock(&_solaris_atomic) != 0)\
00132         PR_ASSERT(0);
00133 
00134        return rv;
00135 }
00136 
00137 PRInt32
00138 _MD_AtomicDecrement(PRInt32 *val)
00139 {
00140     PRInt32 rv;
00141     if (mutex_lock(&_solaris_atomic) != 0)
00142         PR_ASSERT(0);
00143 
00144     rv = --(*val);
00145 
00146     if (mutex_unlock(&_solaris_atomic) != 0)\
00147         PR_ASSERT(0);
00148 
00149        return rv;
00150 }
00151 
00152 PRInt32
00153 _MD_AtomicSet(PRInt32 *val, PRInt32 newval)
00154 {
00155     PRInt32 rv;
00156     if (mutex_lock(&_solaris_atomic) != 0)
00157         PR_ASSERT(0);
00158 
00159     rv = *val;
00160     *val = newval;
00161 
00162     if (mutex_unlock(&_solaris_atomic) != 0)\
00163         PR_ASSERT(0);
00164 
00165        return rv;
00166 }
00167 #endif  /* _PR_HAVE_ATOMIC_OPS */
00168 #endif  /* !defined(i386) */
00169 
00170 #if defined(_PR_GLOBAL_THREADS_ONLY)
00171 #include <signal.h>
00172 #include <errno.h>
00173 #include <fcntl.h>
00174 #include <thread.h>
00175 
00176 #include <sys/lwp.h>
00177 #include <sys/procfs.h>
00178 #include <sys/syscall.h>
00179 extern int syscall();  /* not declared in sys/syscall.h */
00180 
00181 static sigset_t old_mask;   /* store away original gc thread sigmask */
00182 static PRIntn gcprio;              /* store away original gc thread priority */
00183 
00184 THREAD_KEY_T threadid_key;
00185 THREAD_KEY_T cpuid_key;
00186 THREAD_KEY_T last_thread_key;
00187 static sigset_t set, oldset;
00188 
00189 static void
00190 threadid_key_destructor(void *value)
00191 {
00192     PRThread *me = (PRThread *)value;
00193     PR_ASSERT(me != NULL);
00194     /* the thread could be PRIMORDIAL (thus not ATTACHED) */
00195     if (me->flags & _PR_ATTACHED) {
00196         /*
00197          * The Solaris thread library sets the thread specific
00198          * data (the current thread) to NULL before invoking
00199          * the destructor.  We need to restore it to prevent the
00200          * _PR_MD_CURRENT_THREAD() call in _PRI_DetachThread()
00201          * from attaching the thread again.
00202          */
00203         _PR_MD_SET_CURRENT_THREAD(me);
00204         _PRI_DetachThread();
00205     }
00206 }
00207 
00208 void _MD_EarlyInit(void)
00209 {
00210     THR_KEYCREATE(&threadid_key, threadid_key_destructor);
00211     THR_KEYCREATE(&cpuid_key, NULL);
00212     THR_KEYCREATE(&last_thread_key, NULL);
00213     sigemptyset(&set);
00214     sigaddset(&set, SIGALRM);
00215 }
00216 
00217 PRStatus _MD_CreateThread(PRThread *thread, 
00218                                    void (*start)(void *), 
00219                                    PRThreadPriority priority,
00220                                    PRThreadScope scope, 
00221                                    PRThreadState state, 
00222                                    PRUint32 stackSize) 
00223 {
00224        PRInt32 flags;
00225        
00226     /* mask out SIGALRM for native thread creation */
00227     thr_sigsetmask(SIG_BLOCK, &set, &oldset); 
00228 
00229     /*
00230      * Note that we create joinable threads with the THR_DETACHED
00231      * flag.  The reasons why we don't use thr_join to implement
00232      * PR_JoinThread are:
00233      * - We use a termination condition variable in the PRThread
00234      *   structure to implement PR_JoinThread across all classic
00235      *   nspr implementation strategies.
00236      * - The native threads may be recycled by NSPR to run other
00237      *   new NSPR threads, so the native threads may not terminate
00238      *   when the corresponding NSPR threads terminate.  
00239      */
00240     flags = THR_SUSPENDED|THR_DETACHED;
00241     if (_PR_IS_GCABLE_THREAD(thread) || (thread->flags & _PR_BOUND_THREAD) ||
00242                                                  (scope == PR_GLOBAL_BOUND_THREAD))
00243               flags |= THR_BOUND;
00244 
00245     if (thr_create(NULL, thread->stack->stackSize,
00246                   (void *(*)(void *)) start, (void *) thread, 
00247                               flags,
00248                   &thread->md.handle)) {
00249         thr_sigsetmask(SIG_SETMASK, &oldset, NULL); 
00250         return PR_FAILURE;
00251     }
00252 
00253     /* When the thread starts running, then the lwpid is set to the right
00254      * value. Until then we want to mark this as 'uninit' so that
00255      * its register state is initialized properly for GC */
00256 
00257     thread->md.lwpid = -1;
00258     thr_sigsetmask(SIG_SETMASK, &oldset, NULL); 
00259     _MD_NEW_SEM(&thread->md.waiter_sem, 0);
00260 
00261     if ((scope == PR_GLOBAL_THREAD) || (scope == PR_GLOBAL_BOUND_THREAD)) {
00262               thread->flags |= _PR_GLOBAL_SCOPE;
00263     }
00264 
00265     _MD_SET_PRIORITY(&(thread->md), priority);
00266 
00267     /* Activate the thread */
00268     if (thr_continue( thread->md.handle ) ) {
00269        return PR_FAILURE;
00270     }
00271     return PR_SUCCESS;
00272 }
00273 
00274 void _MD_cleanup_thread(PRThread *thread)
00275 {
00276     thread_t hdl;
00277 
00278     hdl = thread->md.handle;
00279 
00280     /* 
00281     ** First, suspend the thread (unless it's the active one)
00282     ** Because we suspend it first, we don't have to use LOCK_SCHEDULER to
00283     ** prevent both of us modifying the thread structure at the same time.
00284     */
00285     if ( thread != _PR_MD_CURRENT_THREAD() ) {
00286         thr_suspend(hdl);
00287     }
00288     PR_LOG(_pr_thread_lm, PR_LOG_MIN,
00289             ("(0X%x)[DestroyThread]\n", thread));
00290 
00291     _MD_DESTROY_SEM(&thread->md.waiter_sem);
00292 }
00293 
00294 void _MD_exit_thread(PRThread *thread)
00295 {
00296     _MD_CLEAN_THREAD(thread);
00297     _MD_SET_CURRENT_THREAD(NULL);
00298 }
00299 
00300 void _MD_SET_PRIORITY(_MDThread *md_thread,
00301         PRThreadPriority newPri)
00302 {
00303        PRIntn nativePri;
00304 
00305        if (newPri < PR_PRIORITY_FIRST) {
00306               newPri = PR_PRIORITY_FIRST;
00307        } else if (newPri > PR_PRIORITY_LAST) {
00308               newPri = PR_PRIORITY_LAST;
00309        }
00310        /* Solaris priorities are from 0 to 127 */
00311        nativePri = newPri * 127 / PR_PRIORITY_LAST;
00312        if(thr_setprio((thread_t)md_thread->handle, nativePri)) {
00313               PR_LOG(_pr_thread_lm, PR_LOG_MIN,
00314                  ("_PR_SetThreadPriority: can't set thread priority\n"));
00315        }
00316 }
00317 
00318 void _MD_WAIT_CV(
00319     struct _MDCVar *md_cv, struct _MDLock *md_lock, PRIntervalTime timeout)
00320 {
00321     struct timespec tt;
00322     PRUint32 msec;
00323     PRThread *me = _PR_MD_CURRENT_THREAD();
00324 
00325        PR_ASSERT((!suspendAllOn) || (suspendAllThread != me));
00326 
00327     if (PR_INTERVAL_NO_TIMEOUT == timeout) {
00328         COND_WAIT(&md_cv->cv, &md_lock->lock);
00329     } else {
00330         msec = PR_IntervalToMilliseconds(timeout);
00331 
00332         GETTIME(&tt);
00333         tt.tv_sec += msec / PR_MSEC_PER_SEC;
00334         tt.tv_nsec += (msec % PR_MSEC_PER_SEC) * PR_NSEC_PER_MSEC;
00335         /* Check for nsec overflow - otherwise we'll get an EINVAL */
00336         if (tt.tv_nsec >= PR_NSEC_PER_SEC) {
00337             tt.tv_sec++;
00338             tt.tv_nsec -= PR_NSEC_PER_SEC;
00339         }
00340         COND_TIMEDWAIT(&md_cv->cv, &md_lock->lock, &tt);
00341     }
00342 }
00343 
00344 void _MD_lock(struct _MDLock *md_lock)
00345 {
00346 #ifdef DEBUG
00347     /* This code was used for GC testing to make sure that we didn't attempt
00348      * to grab any locks while threads are suspended.
00349      */
00350     PRLock *lock;
00351     
00352     if ((suspendAllOn) && (suspendAllThread == _PR_MD_CURRENT_THREAD())) {
00353         lock = ((PRLock *) ((char*) (md_lock) - offsetof(PRLock,ilock)));
00354        PR_ASSERT(lock->owner == NULL);
00355         return;
00356     }
00357 #endif /* DEBUG */
00358 
00359     mutex_lock(&md_lock->lock);
00360 }
00361 
00362 PRThread *_pr_attached_thread_tls()
00363 {
00364     PRThread *ret;
00365 
00366     thr_getspecific(threadid_key, (void **)&ret);
00367     return ret;
00368 }
00369 
00370 PRThread *_pr_current_thread_tls()
00371 {
00372     PRThread *thread;
00373 
00374     thread = _MD_GET_ATTACHED_THREAD();
00375 
00376     if (NULL == thread) {
00377         thread = _PRI_AttachThread(
00378             PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0);
00379     }
00380     PR_ASSERT(thread != NULL);
00381 
00382     return thread;
00383 }
00384 
00385 PRStatus
00386 _MD_wait(PRThread *thread, PRIntervalTime ticks)
00387 {
00388         _MD_WAIT_SEM(&thread->md.waiter_sem);
00389         return PR_SUCCESS;
00390 }
00391 
00392 PRStatus
00393 _MD_WakeupWaiter(PRThread *thread)
00394 {
00395        if (thread == NULL) {
00396               return PR_SUCCESS;
00397        }
00398        _MD_POST_SEM(&thread->md.waiter_sem);
00399        return PR_SUCCESS;
00400 }
00401 
00402 _PRCPU *_pr_current_cpu_tls()
00403 {
00404     _PRCPU *ret;
00405 
00406     thr_getspecific(cpuid_key, (void **)&ret);
00407     return ret;
00408 }
00409 
00410 PRThread *_pr_last_thread_tls()
00411 {
00412     PRThread *ret;
00413 
00414     thr_getspecific(last_thread_key, (void **)&ret);
00415     return ret;
00416 }
00417 
00418 _MDLock _pr_ioq_lock;
00419 
00420 void
00421 _MD_InitIO(void)
00422 {
00423     _MD_NEW_LOCK(&_pr_ioq_lock);
00424 }
00425 
00426 PRStatus _MD_InitializeThread(PRThread *thread)
00427 {
00428     if (!_PR_IS_NATIVE_THREAD(thread))
00429         return PR_SUCCESS;
00430     /* sol_curthread is an asm routine which grabs GR7; GR7 stores an internal
00431      * thread structure ptr used by solaris.  We'll use this ptr later
00432      * with suspend/resume to find which threads are running on LWPs.
00433      */
00434     thread->md.threadID = sol_curthread();
00435               /* prime the sp; substract 4 so we don't hit the assert that
00436                * curr sp > base_stack
00437                */
00438     thread->md.sp = (uint_t) thread->stack->allocBase - sizeof(long);
00439     thread->md.lwpid = _lwp_self();
00440     thread->md.handle = THR_SELF();
00441 
00442        /* all threads on Solaris are global threads from NSPR's perspective
00443         * since all of them are mapped to Solaris threads.
00444         */
00445     thread->flags |= _PR_GLOBAL_SCOPE;
00446  
00447        /* For primordial/attached thread, we don't create an underlying native thread.
00448         * So, _MD_CREATE_THREAD() does not get called.  We need to do initialization
00449         * like allocating thread's synchronization variables and set the underlying
00450         * native thread's priority.
00451         */
00452        if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) {
00453            _MD_NEW_SEM(&thread->md.waiter_sem, 0);
00454            _MD_SET_PRIORITY(&(thread->md), thread->priority);
00455        }
00456        return PR_SUCCESS;
00457 }
00458 
00459 /* Sleep for n milliseconds, n < 1000   */
00460 void solaris_msec_sleep(int n)
00461 {
00462     struct timespec ts;
00463 
00464     ts.tv_sec = 0;
00465     ts.tv_nsec = 1000000*n;
00466     if (syscall(SYS_nanosleep, &ts, 0, 0) < 0) {
00467         PR_ASSERT(0);
00468     }
00469 }      
00470 
00471 #define VALID_SP(sp, bottom, top)   \
00472        (((uint_t)(sp)) > ((uint_t)(bottom)) && ((uint_t)(sp)) < ((uint_t)(top)))
00473 
00474 void solaris_record_regs(PRThread *t, prstatus_t *lwpstatus)
00475 {
00476 #ifdef sparc
00477        long *regs = (long *)&t->md.context.uc_mcontext.gregs[0];
00478 
00479        PR_ASSERT(_PR_IS_GCABLE_THREAD(t));
00480        PR_ASSERT(t->md.threadID == lwpstatus->pr_reg[REG_G7]);
00481 
00482        t->md.sp = lwpstatus->pr_reg[REG_SP];
00483        PR_ASSERT(VALID_SP(t->md.sp, t->stack->stackBottom, t->stack->stackTop));
00484 
00485        regs[0] = lwpstatus->pr_reg[R_G1];
00486        regs[1] = lwpstatus->pr_reg[R_G2];
00487        regs[2] = lwpstatus->pr_reg[R_G3];
00488        regs[3] = lwpstatus->pr_reg[R_G4];
00489        regs[4] = lwpstatus->pr_reg[R_O0];
00490        regs[5] = lwpstatus->pr_reg[R_O1];
00491        regs[6] = lwpstatus->pr_reg[R_O2];
00492        regs[7] = lwpstatus->pr_reg[R_O3];
00493        regs[8] = lwpstatus->pr_reg[R_O4];
00494        regs[9] = lwpstatus->pr_reg[R_O5];
00495        regs[10] = lwpstatus->pr_reg[R_O6];
00496        regs[11] = lwpstatus->pr_reg[R_O7];
00497 #elif defined(i386)
00498        /*
00499         * To be implemented and tested
00500         */
00501        PR_ASSERT(0);
00502        PR_ASSERT(t->md.threadID == lwpstatus->pr_reg[GS]);
00503        t->md.sp = lwpstatus->pr_reg[UESP];
00504 #endif
00505 }   
00506 
00507 void solaris_preempt_off()
00508 {
00509     sigset_t set;
00510  
00511     (void)sigfillset(&set);
00512     syscall(SYS_sigprocmask, SIG_SETMASK, &set, &old_mask);
00513 }
00514 
00515 void solaris_preempt_on()
00516 {
00517     syscall(SYS_sigprocmask, SIG_SETMASK, &old_mask, NULL);      
00518 }
00519 
00520 int solaris_open_main_proc_fd()
00521 {
00522     char buf[30];
00523     int fd;
00524 
00525     /* Not locked, so must be created while threads coming up */
00526     PR_snprintf(buf, sizeof(buf), "/proc/%ld", getpid());
00527     if ( (fd = syscall(SYS_open, buf, O_RDONLY)) < 0) {
00528         return -1;
00529     }
00530     return fd;
00531 }
00532 
00533 /* Return a file descriptor for the /proc entry corresponding to the
00534  * given lwp. 
00535  */
00536 int solaris_open_lwp(lwpid_t id, int lwp_main_proc_fd)
00537 {
00538     int result;
00539 
00540     if ( (result = syscall(SYS_ioctl, lwp_main_proc_fd, PIOCOPENLWP, &id)) <0)
00541         return -1; /* exited??? */
00542 
00543     return result;
00544 }
00545 void _MD_Begin_SuspendAll()
00546 {
00547     solaris_preempt_off();
00548 
00549     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin_SuspendAll\n"));
00550     /* run at highest prio so I cannot be preempted */
00551     thr_getprio(thr_self(), &gcprio);
00552     thr_setprio(thr_self(), 0x7fffffff); 
00553     suspendAllOn = PR_TRUE;
00554     suspendAllThread = _PR_MD_CURRENT_THREAD();
00555 }
00556 
00557 void _MD_End_SuspendAll()
00558 {
00559 }
00560 
00561 void _MD_End_ResumeAll()
00562 {
00563     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End_ResumeAll\n"));
00564     thr_setprio(thr_self(), gcprio);
00565     solaris_preempt_on();
00566     suspendAllThread = NULL;
00567     suspendAllOn = PR_FALSE;
00568 }
00569 
00570 void _MD_Suspend(PRThread *thr)
00571 {
00572    int lwp_fd, result;
00573    prstatus_t lwpstatus;
00574    int lwp_main_proc_fd = 0;
00575   
00576    if (!_PR_IS_GCABLE_THREAD(thr) || !suspendAllOn){
00577      /*XXX When the suspendAllOn is set, we will be trying to do lwp_suspend
00578       * during that time we can't call any thread lib or libc calls. Hence
00579       * make sure that no suspension is requested for Non gcable thread
00580       * during suspendAllOn */
00581       PR_ASSERT(!suspendAllOn);
00582       thr_suspend(thr->md.handle);
00583       return;
00584    }
00585 
00586     /* XXX Primordial thread can't be bound to an lwp, hence there is no
00587      * way we can assume that we can get the lwp status for primordial
00588      * thread reliably. Hence we skip this for primordial thread, hoping
00589      * that the SP is saved during lock and cond. wait. 
00590      * XXX - Again this is concern only for java interpreter, not for the
00591      * server, 'cause primordial thread in the server does not do java work
00592      */
00593     if (thr->flags & _PR_PRIMORDIAL)
00594       return;
00595     
00596     /* XXX Important Note: If the start function of a thread is not called,
00597      * lwpid is -1. Then, skip this thread. This thread will get caught
00598      * in PR_NativeRunThread before calling the start function, because
00599      * we hold the pr_activeLock during suspend/resume */
00600 
00601     /* if the thread is not started yet then don't do anything */
00602     if (!suspendAllOn || thr->md.lwpid == -1)
00603       return;
00604 
00605     if (_lwp_suspend(thr->md.lwpid) < 0) { 
00606        PR_ASSERT(0);
00607        return;
00608     }
00609 
00610     if ( (lwp_main_proc_fd = solaris_open_main_proc_fd()) < 0) {
00611         PR_ASSERT(0);
00612         return;   /* XXXMB ARGH, we're hosed! */
00613     }
00614 
00615    if ( (lwp_fd = solaris_open_lwp(thr->md.lwpid, lwp_main_proc_fd)) < 0) {
00616            PR_ASSERT(0);
00617            close(lwp_main_proc_fd);
00618           return;
00619    }
00620    if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) {
00621             /* Hopefully the thread just died... */
00622            close(lwp_fd);
00623            close(lwp_main_proc_fd);
00624           return;
00625    }
00626             while ( !(lwpstatus.pr_flags & PR_STOPPED) ) {
00627                 if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) {
00628                     PR_ASSERT(0);  /* ARGH SOMETHING WRONG! */
00629                     break;
00630                 }
00631                 solaris_msec_sleep(1);
00632             }
00633             solaris_record_regs(thr, &lwpstatus);
00634             close(lwp_fd);
00635    close(lwp_main_proc_fd);
00636 }
00637 
00638 #ifdef OLD_CODE
00639 
00640 void _MD_SuspendAll()
00641 {
00642     /* On solaris there are threads, and there are LWPs. 
00643      * Calling _PR_DoSingleThread would freeze all of the threads bound to LWPs
00644      * but not necessarily stop all LWPs (for example if someone did
00645      * an attachthread of a thread which was not bound to an LWP).
00646      * So now go through all the LWPs for this process and freeze them.
00647      *
00648      * Note that if any thread which is capable of having the GC run on it must
00649      * had better be a LWP with a single bound thread on it.  Otherwise, this 
00650      * might not stop that thread from being run.
00651      */
00652     PRThread *current = _PR_MD_CURRENT_THREAD();
00653     prstatus_t status, lwpstatus;
00654     int result, index, lwp_fd;
00655     lwpid_t me = _lwp_self();
00656     int err;
00657     int lwp_main_proc_fd;
00658 
00659     solaris_preempt_off();
00660 
00661     /* run at highest prio so I cannot be preempted */
00662     thr_getprio(thr_self(), &gcprio);
00663     thr_setprio(thr_self(), 0x7fffffff); 
00664 
00665     current->md.sp = (uint_t)&me;  /* set my own stack pointer */
00666 
00667     if ( (lwp_main_proc_fd = solaris_open_main_proc_fd()) < 0) {
00668         PR_ASSERT(0);
00669         solaris_preempt_on();
00670         return;   /* XXXMB ARGH, we're hosed! */
00671     }
00672 
00673     if ( (result = syscall(SYS_ioctl, lwp_main_proc_fd, PIOCSTATUS, &status)) < 0) {
00674         err = errno;
00675         PR_ASSERT(0);
00676         goto failure;   /* XXXMB ARGH, we're hosed! */
00677     }
00678 
00679     num_lwps = status.pr_nlwp;
00680 
00681     if ( (all_lwps = (lwpid_t *)PR_MALLOC((num_lwps+1) * sizeof(lwpid_t)))==NULL) {
00682         PR_ASSERT(0);
00683         goto failure;   /* XXXMB ARGH, we're hosed! */
00684     }
00685            
00686     if ( (result = syscall(SYS_ioctl, lwp_main_proc_fd, PIOCLWPIDS, all_lwps)) < 0) {
00687         PR_ASSERT(0);
00688         PR_DELETE(all_lwps);
00689         goto failure;   /* XXXMB ARGH, we're hosed! */
00690     }
00691 
00692     for (index=0; index< num_lwps; index++) {
00693         if (all_lwps[index] != me)  {
00694             if (_lwp_suspend(all_lwps[index]) < 0) { 
00695                 /* could happen if lwp exited */
00696                 all_lwps[index] = me;     /* dummy it up */
00697             }
00698         }
00699     }
00700 
00701     /* Turns out that lwp_suspend is not a blocking call.
00702      * Go through the list and make sure they are all stopped.
00703      */
00704     for (index=0; index< num_lwps; index++) {
00705         if (all_lwps[index] != me)  {
00706             if ( (lwp_fd = solaris_open_lwp(all_lwps[index], lwp_main_proc_fd)) < 0) {
00707                 PR_ASSERT(0);
00708                 PR_DELETE(all_lwps);
00709                 all_lwps = NULL;
00710                 goto failure;   /* XXXMB ARGH, we're hosed! */
00711             }
00712 
00713             if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) {
00714                 /* Hopefully the thread just died... */
00715                 close(lwp_fd);
00716                 continue;
00717             }
00718             while ( !(lwpstatus.pr_flags & PR_STOPPED) ) {
00719                 if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) {
00720                     PR_ASSERT(0);  /* ARGH SOMETHING WRONG! */
00721                     break;
00722                 }
00723                 solaris_msec_sleep(1);
00724             }
00725             solaris_record_regs(&lwpstatus);
00726             close(lwp_fd);
00727         }
00728     }
00729 
00730     close(lwp_main_proc_fd);
00731 
00732     return;
00733 failure:
00734     solaris_preempt_on();
00735     thr_setprio(thr_self(), gcprio);
00736     close(lwp_main_proc_fd);
00737     return;
00738 }
00739 
00740 void _MD_ResumeAll()
00741 {
00742     int i;
00743     lwpid_t me = _lwp_self();
00744  
00745     for (i=0; i < num_lwps; i++) {
00746         if (all_lwps[i] == me)
00747             continue;
00748         if ( _lwp_continue(all_lwps[i]) < 0) {
00749             PR_ASSERT(0);  /* ARGH, we are hosed! */
00750         }
00751     }
00752 
00753     /* restore priority and sigmask */
00754     thr_setprio(thr_self(), gcprio);
00755     solaris_preempt_on();
00756     PR_DELETE(all_lwps);
00757     all_lwps = NULL;
00758 }
00759 #endif /* OLD_CODE */
00760 
00761 #ifdef USE_SETJMP
00762 PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
00763 {
00764     if (isCurrent) {
00765               (void) setjmp(CONTEXT(t));
00766     }
00767     *np = sizeof(CONTEXT(t)) / sizeof(PRWord);
00768     return (PRWord *) CONTEXT(t);
00769 }
00770 #else
00771 PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np)
00772 {
00773     if (isCurrent) {
00774               (void) getcontext(CONTEXT(t));
00775     }
00776     *np = NGREG;
00777     return (PRWord*) &t->md.context.uc_mcontext.gregs[0];
00778 }
00779 #endif  /* USE_SETJMP */
00780 
00781 #else /* _PR_GLOBAL_THREADS_ONLY */
00782 
00783 #if defined(_PR_LOCAL_THREADS_ONLY)
00784 
00785 void _MD_EarlyInit(void)
00786 {
00787 }
00788 
00789 void _MD_SolarisInit()
00790 {
00791     _PR_UnixInit();
00792 }
00793 
00794 void
00795 _MD_SET_PRIORITY(_MDThread *thread, PRThreadPriority newPri)
00796 {
00797     return;
00798 }
00799 
00800 PRStatus
00801 _MD_InitializeThread(PRThread *thread)
00802 {
00803        return PR_SUCCESS;
00804 }
00805 
00806 PRStatus
00807 _MD_WAIT(PRThread *thread, PRIntervalTime ticks)
00808 {
00809     PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE));
00810     _PR_MD_SWITCH_CONTEXT(thread);
00811     return PR_SUCCESS;
00812 }
00813 
00814 PRStatus
00815 _MD_WAKEUP_WAITER(PRThread *thread)
00816 {
00817        PR_ASSERT((thread == NULL) || (!(thread->flags & _PR_GLOBAL_SCOPE)));
00818     return PR_SUCCESS;
00819 }
00820 
00821 /* These functions should not be called for Solaris */
00822 void
00823 _MD_YIELD(void)
00824 {
00825     PR_NOT_REACHED("_MD_YIELD should not be called for Solaris");
00826 }
00827 
00828 PRStatus
00829 _MD_CREATE_THREAD(
00830     PRThread *thread,
00831     void (*start) (void *),
00832     PRThreadPriority priority,
00833     PRThreadScope scope,
00834     PRThreadState state,
00835     PRUint32 stackSize)
00836 {
00837     PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Solaris");
00838        return(PR_FAILURE);
00839 }
00840 
00841 #ifdef USE_SETJMP
00842 PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
00843 {
00844     if (isCurrent) {
00845               (void) setjmp(CONTEXT(t));
00846     }
00847     *np = sizeof(CONTEXT(t)) / sizeof(PRWord);
00848     return (PRWord *) CONTEXT(t);
00849 }
00850 #else
00851 PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np)
00852 {
00853     if (isCurrent) {
00854               (void) getcontext(CONTEXT(t));
00855     }
00856     *np = NGREG;
00857     return (PRWord*) &t->md.context.uc_mcontext.gregs[0];
00858 }
00859 #endif  /* USE_SETJMP */
00860 
00861 #endif  /* _PR_LOCAL_THREADS_ONLY */
00862 
00863 #endif /* _PR_GLOBAL_THREADS_ONLY */
00864 
00865 #ifndef _PR_PTHREADS
00866 #if defined(i386) && defined(SOLARIS2_4)
00867 /* 
00868  * Because clock_gettime() on Solaris/x86 2.4 always generates a
00869  * segmentation fault, we use an emulated version _pr_solx86_clock_gettime(),
00870  * which is implemented using gettimeofday().
00871  */
00872 
00873 int
00874 _pr_solx86_clock_gettime(clockid_t clock_id, struct timespec *tp)
00875 {
00876     struct timeval tv;
00877 
00878     if (clock_id != CLOCK_REALTIME) {
00879        errno = EINVAL;
00880        return -1;
00881     }
00882 
00883     gettimeofday(&tv, NULL);
00884     tp->tv_sec = tv.tv_sec;
00885     tp->tv_nsec = tv.tv_usec * 1000;
00886     return 0;
00887 }
00888 #endif  /* i386 && SOLARIS2_4 */
00889 #endif  /* _PR_PTHREADS */