Back to index

lightning-sunbird  0.9+nobinonly
unixware.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 #if !defined (USE_SVR4_THREADS)
00041 
00042 /*
00043          * using only NSPR threads here
00044  */
00045 
00046 #include <setjmp.h>
00047 
00048 void _MD_EarlyInit(void)
00049 {
00050 }
00051 
00052 PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
00053 {
00054     if (isCurrent) {
00055        (void) setjmp(CONTEXT(t));
00056     }
00057     *np = sizeof(CONTEXT(t)) / sizeof(PRWord);
00058     return (PRWord *) CONTEXT(t);
00059 }
00060 
00061 #ifdef ALARMS_BREAK_TCP /* I don't think they do */
00062 
00063 PRInt32 _MD_connect(PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen,
00064                         PRIntervalTime timeout)
00065 {
00066     PRInt32 rv;
00067 
00068     _MD_BLOCK_CLOCK_INTERRUPTS();
00069     rv = _connect(osfd,addr,addrlen);
00070     _MD_UNBLOCK_CLOCK_INTERRUPTS();
00071 }
00072 
00073 PRInt32 _MD_accept(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen,
00074                         PRIntervalTime timeout)
00075 {
00076     PRInt32 rv;
00077 
00078     _MD_BLOCK_CLOCK_INTERRUPTS();
00079     rv = _accept(osfd,addr,addrlen);
00080     _MD_UNBLOCK_CLOCK_INTERRUPTS();
00081     return(rv);
00082 }
00083 #endif
00084 
00085 /*
00086  * These are also implemented in pratom.c using NSPR locks.  Any reason
00087  * this might be better or worse?  If you like this better, define
00088  * _PR_HAVE_ATOMIC_OPS in include/md/unixware.h
00089  */
00090 #ifdef _PR_HAVE_ATOMIC_OPS
00091 /* Atomic operations */
00092 #include  <stdio.h>
00093 static FILE *_uw_semf;
00094 
00095 void
00096 _MD_INIT_ATOMIC(void)
00097 {
00098     /* Sigh.  Sure wish SYSV semaphores weren't such a pain to use */
00099     if ((_uw_semf = tmpfile()) == NULL)
00100         PR_ASSERT(0);
00101 
00102     return;
00103 }
00104 
00105 void
00106 _MD_ATOMIC_INCREMENT(PRInt32 *val)
00107 {
00108     flockfile(_uw_semf);
00109     (*val)++;
00110     unflockfile(_uw_semf);
00111 }
00112 
00113 void
00114 _MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val)
00115 {
00116     flockfile(_uw_semf);
00117     (*ptr) += val;
00118     unflockfile(_uw_semf);
00119 }
00120 
00121 void
00122 _MD_ATOMIC_DECREMENT(PRInt32 *val)
00123 {
00124     flockfile(_uw_semf);
00125     (*val)--;
00126     unflockfile(_uw_semf);
00127 }
00128 
00129 void
00130 _MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
00131 {
00132     flockfile(_uw_semf);
00133     *val = newval;
00134     unflockfile(_uw_semf);
00135 }
00136 #endif
00137 
00138 void
00139 _MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri)
00140 {
00141     return;
00142 }
00143 
00144 PRStatus
00145 _MD_InitializeThread(PRThread *thread)
00146 {
00147        return PR_SUCCESS;
00148 }
00149 
00150 PRStatus
00151 _MD_WAIT(PRThread *thread, PRIntervalTime ticks)
00152 {
00153     PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE));
00154     _PR_MD_SWITCH_CONTEXT(thread);
00155     return PR_SUCCESS;
00156 }
00157 
00158 PRStatus
00159 _MD_WAKEUP_WAITER(PRThread *thread)
00160 {
00161     if (thread) {
00162        PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE));
00163     }
00164     return PR_SUCCESS;
00165 }
00166 
00167 /* These functions should not be called for Unixware */
00168 void
00169 _MD_YIELD(void)
00170 {
00171     PR_NOT_REACHED("_MD_YIELD should not be called for Unixware.");
00172 }
00173 
00174 PRStatus
00175 _MD_CREATE_THREAD(
00176     PRThread *thread,
00177     void (*start) (void *),
00178     PRThreadPriority priority,
00179     PRThreadScope scope,
00180     PRThreadState state,
00181     PRUint32 stackSize)
00182 {
00183     PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Unixware.");
00184 }
00185 
00186 #else  /* USE_SVR4_THREADS */
00187 
00188 /* NOTE:
00189  * SPARC v9 (Ultras) do have an atomic test-and-set operation.  But
00190  * SPARC v8 doesn't.  We should detect in the init if we are running on
00191  * v8 or v9, and then use assembly where we can.
00192  */
00193 
00194 #include <thread.h>
00195 #include <synch.h>
00196 
00197 static mutex_t _unixware_atomic = DEFAULTMUTEX;
00198 
00199 #define TEST_THEN_ADD(where, inc) \
00200     if (mutex_lock(&_unixware_atomic) != 0)\
00201         PR_ASSERT(0);\
00202     *where += inc;\
00203     if (mutex_unlock(&_unixware_atomic) != 0)\
00204         PR_ASSERT(0);
00205 
00206 #define TEST_THEN_SET(where, val) \
00207     if (mutex_lock(&_unixware_atomic) != 0)\
00208         PR_ASSERT(0);\
00209     *where = val;\
00210     if (mutex_unlock(&_unixware_atomic) != 0)\
00211         PR_ASSERT(0);
00212 
00213 void
00214 _MD_INIT_ATOMIC(void)
00215 {
00216 }
00217 
00218 void
00219 _MD_ATOMIC_INCREMENT(PRInt32 *val)
00220 {
00221     TEST_THEN_ADD(val, 1);
00222 }
00223 
00224 void
00225 _MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val)
00226 {
00227     TEST_THEN_ADD(ptr, val);
00228 }
00229 
00230 void
00231 _MD_ATOMIC_DECREMENT(PRInt32 *val)
00232 {
00233     TEST_THEN_ADD(val, 0xffffffff);
00234 }
00235 
00236 void
00237 _MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
00238 {
00239     TEST_THEN_SET(val, newval);
00240 }
00241 
00242 #include <signal.h>
00243 #include <errno.h>
00244 #include <fcntl.h>
00245 
00246 #include <sys/lwp.h>
00247 #include <sys/procfs.h>
00248 #include <sys/syscall.h>
00249 
00250 
00251 THREAD_KEY_T threadid_key;
00252 THREAD_KEY_T cpuid_key;
00253 THREAD_KEY_T last_thread_key;
00254 static sigset_t set, oldset;
00255 
00256 void _MD_EarlyInit(void)
00257 {
00258     THR_KEYCREATE(&threadid_key, NULL);
00259     THR_KEYCREATE(&cpuid_key, NULL);
00260     THR_KEYCREATE(&last_thread_key, NULL);
00261     sigemptyset(&set);
00262     sigaddset(&set, SIGALRM);
00263 }
00264 
00265 PRStatus _MD_CREATE_THREAD(PRThread *thread, 
00266                                    void (*start)(void *), 
00267                                    PRThreadPriority priority,
00268                                    PRThreadScope scope, 
00269                                    PRThreadState state, 
00270                                    PRUint32 stackSize) 
00271 {
00272        long flags;
00273        
00274     /* mask out SIGALRM for native thread creation */
00275     thr_sigsetmask(SIG_BLOCK, &set, &oldset); 
00276 
00277     flags = (state == PR_JOINABLE_THREAD ? THR_SUSPENDED/*|THR_NEW_LWP*/ 
00278                         : THR_SUSPENDED|THR_DETACHED/*|THR_NEW_LWP*/);
00279        if (_PR_IS_GCABLE_THREAD(thread) ||
00280                                                  (scope == PR_GLOBAL_BOUND_THREAD))
00281               flags |= THR_BOUND;
00282 
00283     if (thr_create(NULL, thread->stack->stackSize,
00284                   (void *(*)(void *)) start, (void *) thread, 
00285                               flags,
00286                   &thread->md.handle)) {
00287         thr_sigsetmask(SIG_SETMASK, &oldset, NULL); 
00288        return PR_FAILURE;
00289     }
00290 
00291 
00292     /* When the thread starts running, then the lwpid is set to the right
00293      * value. Until then we want to mark this as 'uninit' so that
00294      * its register state is initialized properly for GC */
00295 
00296     thread->md.lwpid = -1;
00297     thr_sigsetmask(SIG_SETMASK, &oldset, NULL); 
00298     _MD_NEW_SEM(&thread->md.waiter_sem, 0);
00299 
00300        if ((scope == PR_GLOBAL_THREAD) || (scope == PR_GLOBAL_BOUND_THREAD)) {
00301               thread->flags |= _PR_GLOBAL_SCOPE;
00302     }
00303 
00304     /* 
00305     ** Set the thread priority.  This will also place the thread on 
00306     ** the runQ.
00307     **
00308     ** Force PR_SetThreadPriority to set the priority by
00309     ** setting thread->priority to 100.
00310     */
00311     {
00312     int pri;
00313     pri = thread->priority;
00314     thread->priority = 100;
00315     PR_SetThreadPriority( thread, pri );
00316 
00317     PR_LOG(_pr_thread_lm, PR_LOG_MIN, 
00318             ("(0X%x)[Start]: on to runq at priority %d",
00319             thread, thread->priority));
00320     }
00321 
00322     /* Activate the thread */
00323     if (thr_continue( thread->md.handle ) ) {
00324        return PR_FAILURE;
00325     }
00326     return PR_SUCCESS;
00327 }
00328 
00329 void _MD_cleanup_thread(PRThread *thread)
00330 {
00331     thread_t hdl;
00332     PRMonitor *mon;
00333 
00334     hdl = thread->md.handle;
00335 
00336     /* 
00337     ** First, suspend the thread (unless it's the active one)
00338     ** Because we suspend it first, we don't have to use LOCK_SCHEDULER to
00339     ** prevent both of us modifying the thread structure at the same time.
00340     */
00341     if ( thread != _PR_MD_CURRENT_THREAD() ) {
00342         thr_suspend(hdl);
00343     }
00344     PR_LOG(_pr_thread_lm, PR_LOG_MIN,
00345             ("(0X%x)[DestroyThread]\n", thread));
00346 
00347     _MD_DESTROY_SEM(&thread->md.waiter_sem);
00348 }
00349 
00350 void _MD_SET_PRIORITY(_MDThread *md_thread, PRUintn newPri)
00351 {
00352        if(thr_setprio((thread_t)md_thread->handle, newPri)) {
00353               PR_LOG(_pr_thread_lm, PR_LOG_MIN,
00354                  ("_PR_SetThreadPriority: can't set thread priority\n"));
00355        }
00356 }
00357 
00358 void _MD_WAIT_CV(
00359     struct _MDCVar *md_cv, struct _MDLock *md_lock, PRIntervalTime timeout)
00360 {
00361     struct timespec tt;
00362     PRUint32 msec;
00363     int rv;
00364     PRThread *me = _PR_MD_CURRENT_THREAD();
00365 
00366     msec = PR_IntervalToMilliseconds(timeout);
00367 
00368     GETTIME (&tt);
00369 
00370     tt.tv_sec += msec / PR_MSEC_PER_SEC;
00371     tt.tv_nsec += (msec % PR_MSEC_PER_SEC) * PR_NSEC_PER_MSEC;
00372     /* Check for nsec overflow - otherwise we'll get an EINVAL */
00373     if (tt.tv_nsec >= PR_NSEC_PER_SEC) {
00374         tt.tv_sec++;
00375         tt.tv_nsec -= PR_NSEC_PER_SEC;
00376     }
00377     me->md.sp = unixware_getsp();
00378 
00379 
00380     /* XXX Solaris 2.5.x gives back EINTR occasionally for no reason
00381      * hence ignore EINTR for now */
00382 
00383     COND_TIMEDWAIT(&md_cv->cv, &md_lock->lock, &tt);
00384 }
00385 
00386 void _MD_lock(struct _MDLock *md_lock)
00387 {
00388     mutex_lock(&md_lock->lock);
00389 }
00390 
00391 void _MD_unlock(struct _MDLock *md_lock)
00392 {
00393     mutex_unlock(&((md_lock)->lock));
00394 }
00395 
00396 
00397 PRThread *_pr_current_thread_tls()
00398 {
00399     PRThread *ret;
00400 
00401     thr_getspecific(threadid_key, (void **)&ret);
00402     return ret;
00403 }
00404 
00405 PRStatus
00406 _MD_WAIT(PRThread *thread, PRIntervalTime ticks)
00407 {
00408         _MD_WAIT_SEM(&thread->md.waiter_sem);
00409         return PR_SUCCESS;
00410 }
00411 
00412 PRStatus
00413 _MD_WAKEUP_WAITER(PRThread *thread)
00414 {
00415        if (thread == NULL) {
00416               return PR_SUCCESS;
00417        }
00418        _MD_POST_SEM(&thread->md.waiter_sem);
00419        return PR_SUCCESS;
00420 }
00421 
00422 _PRCPU *_pr_current_cpu_tls()
00423 {
00424     _PRCPU *ret;
00425 
00426     thr_getspecific(cpuid_key, (void **)&ret);
00427     return ret;
00428 }
00429 
00430 PRThread *_pr_last_thread_tls()
00431 {
00432     PRThread *ret;
00433 
00434     thr_getspecific(last_thread_key, (void **)&ret);
00435     return ret;
00436 }
00437 
00438 _MDLock _pr_ioq_lock;
00439 
00440 void _MD_INIT_IO (void)
00441 {
00442     _MD_NEW_LOCK(&_pr_ioq_lock);
00443 }
00444 
00445 PRStatus _MD_InitializeThread(PRThread *thread)
00446 {
00447     if (!_PR_IS_NATIVE_THREAD(thread))
00448         return;
00449               /* prime the sp; substract 4 so we don't hit the assert that
00450                * curr sp > base_stack
00451                */
00452     thread->md.sp = (uint_t) thread->stack->allocBase - sizeof(long);
00453     thread->md.lwpid = _lwp_self();
00454     thread->md.handle = THR_SELF();
00455 
00456        /* all threads on Solaris are global threads from NSPR's perspective
00457         * since all of them are mapped to Solaris threads.
00458         */
00459     thread->flags |= _PR_GLOBAL_SCOPE;
00460 
00461        /* For primordial/attached thread, we don't create an underlying native thread.
00462         * So, _MD_CREATE_THREAD() does not get called.  We need to do initialization
00463         * like allocating thread's synchronization variables and set the underlying
00464         * native thread's priority.
00465         */
00466        if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) {
00467            _MD_NEW_SEM(&thread->md.waiter_sem, 0);
00468            _MD_SET_PRIORITY(&(thread->md), thread->priority);
00469        }
00470        return PR_SUCCESS;
00471 }
00472 
00473 static sigset_t old_mask;   /* store away original gc thread sigmask */
00474 static int gcprio;          /* store away original gc thread priority */
00475 static lwpid_t *all_lwps=NULL;     /* list of lwps that we suspended */
00476 static int num_lwps ;
00477 static int suspendAllOn = 0;
00478 
00479 #define VALID_SP(sp, bottom, top)  \
00480        (((uint_t)(sp)) > ((uint_t)(bottom)) && ((uint_t)(sp)) < ((uint_t)(top)))
00481 
00482 void unixware_preempt_off()
00483 {
00484     sigset_t set;
00485     (void)sigfillset(&set);
00486     sigprocmask (SIG_SETMASK, &set, &old_mask);
00487 }
00488 
00489 void unixware_preempt_on()
00490 {
00491     sigprocmask (SIG_SETMASK, &old_mask, NULL);      
00492 }
00493 
00494 void _MD_Begin_SuspendAll()
00495 {
00496     unixware_preempt_off();
00497 
00498     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin_SuspendAll\n"));
00499     /* run at highest prio so I cannot be preempted */
00500     thr_getprio(thr_self(), &gcprio);
00501     thr_setprio(thr_self(), 0x7fffffff); 
00502     suspendAllOn = 1;
00503 }
00504 
00505 void _MD_End_SuspendAll()
00506 {
00507 }
00508 
00509 void _MD_End_ResumeAll()
00510 {
00511     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End_ResumeAll\n"));
00512     thr_setprio(thr_self(), gcprio);
00513     unixware_preempt_on();
00514     suspendAllOn = 0;
00515 }
00516 
00517 void _MD_Suspend(PRThread *thr)
00518 {
00519    int lwp_fd, result;
00520    int lwp_main_proc_fd = 0;
00521 
00522     thr_suspend(thr->md.handle);
00523     if (!_PR_IS_GCABLE_THREAD(thr))
00524       return;
00525     /* XXX Primordial thread can't be bound to an lwp, hence there is no
00526      * way we can assume that we can get the lwp status for primordial
00527      * thread reliably. Hence we skip this for primordial thread, hoping
00528      * that the SP is saved during lock and cond. wait. 
00529      * XXX - Again this is concern only for java interpreter, not for the
00530      * server, 'cause primordial thread in the server does not do java work
00531      */
00532     if (thr->flags & _PR_PRIMORDIAL)
00533       return;
00534 
00535     /* if the thread is not started yet then don't do anything */
00536     if (!suspendAllOn || thr->md.lwpid == -1)
00537       return;
00538 
00539 }
00540 void _MD_Resume(PRThread *thr)
00541 {
00542    if (!_PR_IS_GCABLE_THREAD(thr) || !suspendAllOn){
00543      /*XXX When the suspendAllOn is set, we will be trying to do lwp_suspend
00544       * during that time we can't call any thread lib or libc calls. Hence
00545       * make sure that no resume is requested for Non gcable thread
00546       * during suspendAllOn */
00547       PR_ASSERT(!suspendAllOn);
00548       thr_continue(thr->md.handle);
00549       return;
00550    }
00551    if (thr->md.lwpid == -1)
00552      return;
00553  
00554    if ( _lwp_continue(thr->md.lwpid) < 0) {
00555       PR_ASSERT(0);  /* ARGH, we are hosed! */
00556    }
00557 }
00558 
00559 
00560 PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
00561 {
00562     if (isCurrent) {
00563        (void) getcontext(CONTEXT(t));     /* XXX tune me: set md_IRIX.c */
00564     }
00565     *np = NGREG;
00566     if (t->md.lwpid == -1)
00567       memset(&t->md.context.uc_mcontext.gregs[0], 0, NGREG * sizeof(PRWord));
00568     return (PRWord*) &t->md.context.uc_mcontext.gregs[0];
00569 }
00570 
00571 int
00572 _pr_unixware_clock_gettime (struct timespec *tp)
00573 {
00574     struct timeval tv;
00575  
00576     gettimeofday(&tv, NULL);
00577     tp->tv_sec = tv.tv_sec;
00578     tp->tv_nsec = tv.tv_usec * 1000;
00579     return 0;
00580 }
00581 
00582 
00583 #endif /* USE_SVR4_THREADS */