nsprpub/pr/src/md/unix/unixware.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial