1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/md/unix/unixware.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,551 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "primpl.h" 1.10 + 1.11 +#if !defined (USE_SVR4_THREADS) 1.12 + 1.13 +/* 1.14 + * using only NSPR threads here 1.15 + */ 1.16 + 1.17 +#include <setjmp.h> 1.18 + 1.19 +void _MD_EarlyInit(void) 1.20 +{ 1.21 +} 1.22 + 1.23 +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) 1.24 +{ 1.25 + if (isCurrent) { 1.26 + (void) setjmp(CONTEXT(t)); 1.27 + } 1.28 + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); 1.29 + return (PRWord *) CONTEXT(t); 1.30 +} 1.31 + 1.32 +#ifdef ALARMS_BREAK_TCP /* I don't think they do */ 1.33 + 1.34 +PRInt32 _MD_connect(PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen, 1.35 + PRIntervalTime timeout) 1.36 +{ 1.37 + PRInt32 rv; 1.38 + 1.39 + _MD_BLOCK_CLOCK_INTERRUPTS(); 1.40 + rv = _connect(osfd,addr,addrlen); 1.41 + _MD_UNBLOCK_CLOCK_INTERRUPTS(); 1.42 +} 1.43 + 1.44 +PRInt32 _MD_accept(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen, 1.45 + PRIntervalTime timeout) 1.46 +{ 1.47 + PRInt32 rv; 1.48 + 1.49 + _MD_BLOCK_CLOCK_INTERRUPTS(); 1.50 + rv = _accept(osfd,addr,addrlen); 1.51 + _MD_UNBLOCK_CLOCK_INTERRUPTS(); 1.52 + return(rv); 1.53 +} 1.54 +#endif 1.55 + 1.56 +/* 1.57 + * These are also implemented in pratom.c using NSPR locks. Any reason 1.58 + * this might be better or worse? If you like this better, define 1.59 + * _PR_HAVE_ATOMIC_OPS in include/md/unixware.h 1.60 + */ 1.61 +#ifdef _PR_HAVE_ATOMIC_OPS 1.62 +/* Atomic operations */ 1.63 +#include <stdio.h> 1.64 +static FILE *_uw_semf; 1.65 + 1.66 +void 1.67 +_MD_INIT_ATOMIC(void) 1.68 +{ 1.69 + /* Sigh. Sure wish SYSV semaphores weren't such a pain to use */ 1.70 + if ((_uw_semf = tmpfile()) == NULL) 1.71 + PR_ASSERT(0); 1.72 + 1.73 + return; 1.74 +} 1.75 + 1.76 +void 1.77 +_MD_ATOMIC_INCREMENT(PRInt32 *val) 1.78 +{ 1.79 + flockfile(_uw_semf); 1.80 + (*val)++; 1.81 + unflockfile(_uw_semf); 1.82 +} 1.83 + 1.84 +void 1.85 +_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) 1.86 +{ 1.87 + flockfile(_uw_semf); 1.88 + (*ptr) += val; 1.89 + unflockfile(_uw_semf); 1.90 +} 1.91 + 1.92 +void 1.93 +_MD_ATOMIC_DECREMENT(PRInt32 *val) 1.94 +{ 1.95 + flockfile(_uw_semf); 1.96 + (*val)--; 1.97 + unflockfile(_uw_semf); 1.98 +} 1.99 + 1.100 +void 1.101 +_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) 1.102 +{ 1.103 + flockfile(_uw_semf); 1.104 + *val = newval; 1.105 + unflockfile(_uw_semf); 1.106 +} 1.107 +#endif 1.108 + 1.109 +void 1.110 +_MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri) 1.111 +{ 1.112 + return; 1.113 +} 1.114 + 1.115 +PRStatus 1.116 +_MD_InitializeThread(PRThread *thread) 1.117 +{ 1.118 + return PR_SUCCESS; 1.119 +} 1.120 + 1.121 +PRStatus 1.122 +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) 1.123 +{ 1.124 + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); 1.125 + _PR_MD_SWITCH_CONTEXT(thread); 1.126 + return PR_SUCCESS; 1.127 +} 1.128 + 1.129 +PRStatus 1.130 +_MD_WAKEUP_WAITER(PRThread *thread) 1.131 +{ 1.132 + if (thread) { 1.133 + PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE)); 1.134 + } 1.135 + return PR_SUCCESS; 1.136 +} 1.137 + 1.138 +/* These functions should not be called for Unixware */ 1.139 +void 1.140 +_MD_YIELD(void) 1.141 +{ 1.142 + PR_NOT_REACHED("_MD_YIELD should not be called for Unixware."); 1.143 +} 1.144 + 1.145 +PRStatus 1.146 +_MD_CREATE_THREAD( 1.147 + PRThread *thread, 1.148 + void (*start) (void *), 1.149 + PRThreadPriority priority, 1.150 + PRThreadScope scope, 1.151 + PRThreadState state, 1.152 + PRUint32 stackSize) 1.153 +{ 1.154 + PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Unixware."); 1.155 +} 1.156 + 1.157 +#else /* USE_SVR4_THREADS */ 1.158 + 1.159 +/* NOTE: 1.160 + * SPARC v9 (Ultras) do have an atomic test-and-set operation. But 1.161 + * SPARC v8 doesn't. We should detect in the init if we are running on 1.162 + * v8 or v9, and then use assembly where we can. 1.163 + */ 1.164 + 1.165 +#include <thread.h> 1.166 +#include <synch.h> 1.167 + 1.168 +static mutex_t _unixware_atomic = DEFAULTMUTEX; 1.169 + 1.170 +#define TEST_THEN_ADD(where, inc) \ 1.171 + if (mutex_lock(&_unixware_atomic) != 0)\ 1.172 + PR_ASSERT(0);\ 1.173 + *where += inc;\ 1.174 + if (mutex_unlock(&_unixware_atomic) != 0)\ 1.175 + PR_ASSERT(0); 1.176 + 1.177 +#define TEST_THEN_SET(where, val) \ 1.178 + if (mutex_lock(&_unixware_atomic) != 0)\ 1.179 + PR_ASSERT(0);\ 1.180 + *where = val;\ 1.181 + if (mutex_unlock(&_unixware_atomic) != 0)\ 1.182 + PR_ASSERT(0); 1.183 + 1.184 +void 1.185 +_MD_INIT_ATOMIC(void) 1.186 +{ 1.187 +} 1.188 + 1.189 +void 1.190 +_MD_ATOMIC_INCREMENT(PRInt32 *val) 1.191 +{ 1.192 + TEST_THEN_ADD(val, 1); 1.193 +} 1.194 + 1.195 +void 1.196 +_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) 1.197 +{ 1.198 + TEST_THEN_ADD(ptr, val); 1.199 +} 1.200 + 1.201 +void 1.202 +_MD_ATOMIC_DECREMENT(PRInt32 *val) 1.203 +{ 1.204 + TEST_THEN_ADD(val, 0xffffffff); 1.205 +} 1.206 + 1.207 +void 1.208 +_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) 1.209 +{ 1.210 + TEST_THEN_SET(val, newval); 1.211 +} 1.212 + 1.213 +#include <signal.h> 1.214 +#include <errno.h> 1.215 +#include <fcntl.h> 1.216 + 1.217 +#include <sys/lwp.h> 1.218 +#include <sys/procfs.h> 1.219 +#include <sys/syscall.h> 1.220 + 1.221 + 1.222 +THREAD_KEY_T threadid_key; 1.223 +THREAD_KEY_T cpuid_key; 1.224 +THREAD_KEY_T last_thread_key; 1.225 +static sigset_t set, oldset; 1.226 + 1.227 +void _MD_EarlyInit(void) 1.228 +{ 1.229 + THR_KEYCREATE(&threadid_key, NULL); 1.230 + THR_KEYCREATE(&cpuid_key, NULL); 1.231 + THR_KEYCREATE(&last_thread_key, NULL); 1.232 + sigemptyset(&set); 1.233 + sigaddset(&set, SIGALRM); 1.234 +} 1.235 + 1.236 +PRStatus _MD_CREATE_THREAD(PRThread *thread, 1.237 + void (*start)(void *), 1.238 + PRThreadPriority priority, 1.239 + PRThreadScope scope, 1.240 + PRThreadState state, 1.241 + PRUint32 stackSize) 1.242 +{ 1.243 + long flags; 1.244 + 1.245 + /* mask out SIGALRM for native thread creation */ 1.246 + thr_sigsetmask(SIG_BLOCK, &set, &oldset); 1.247 + 1.248 + flags = (state == PR_JOINABLE_THREAD ? THR_SUSPENDED/*|THR_NEW_LWP*/ 1.249 + : THR_SUSPENDED|THR_DETACHED/*|THR_NEW_LWP*/); 1.250 + if (_PR_IS_GCABLE_THREAD(thread) || 1.251 + (scope == PR_GLOBAL_BOUND_THREAD)) 1.252 + flags |= THR_BOUND; 1.253 + 1.254 + if (thr_create(NULL, thread->stack->stackSize, 1.255 + (void *(*)(void *)) start, (void *) thread, 1.256 + flags, 1.257 + &thread->md.handle)) { 1.258 + thr_sigsetmask(SIG_SETMASK, &oldset, NULL); 1.259 + return PR_FAILURE; 1.260 + } 1.261 + 1.262 + 1.263 + /* When the thread starts running, then the lwpid is set to the right 1.264 + * value. Until then we want to mark this as 'uninit' so that 1.265 + * its register state is initialized properly for GC */ 1.266 + 1.267 + thread->md.lwpid = -1; 1.268 + thr_sigsetmask(SIG_SETMASK, &oldset, NULL); 1.269 + _MD_NEW_SEM(&thread->md.waiter_sem, 0); 1.270 + 1.271 + if ((scope == PR_GLOBAL_THREAD) || (scope == PR_GLOBAL_BOUND_THREAD)) { 1.272 + thread->flags |= _PR_GLOBAL_SCOPE; 1.273 + } 1.274 + 1.275 + /* 1.276 + ** Set the thread priority. This will also place the thread on 1.277 + ** the runQ. 1.278 + ** 1.279 + ** Force PR_SetThreadPriority to set the priority by 1.280 + ** setting thread->priority to 100. 1.281 + */ 1.282 + { 1.283 + int pri; 1.284 + pri = thread->priority; 1.285 + thread->priority = 100; 1.286 + PR_SetThreadPriority( thread, pri ); 1.287 + 1.288 + PR_LOG(_pr_thread_lm, PR_LOG_MIN, 1.289 + ("(0X%x)[Start]: on to runq at priority %d", 1.290 + thread, thread->priority)); 1.291 + } 1.292 + 1.293 + /* Activate the thread */ 1.294 + if (thr_continue( thread->md.handle ) ) { 1.295 + return PR_FAILURE; 1.296 + } 1.297 + return PR_SUCCESS; 1.298 +} 1.299 + 1.300 +void _MD_cleanup_thread(PRThread *thread) 1.301 +{ 1.302 + thread_t hdl; 1.303 + PRMonitor *mon; 1.304 + 1.305 + hdl = thread->md.handle; 1.306 + 1.307 + /* 1.308 + ** First, suspend the thread (unless it's the active one) 1.309 + ** Because we suspend it first, we don't have to use LOCK_SCHEDULER to 1.310 + ** prevent both of us modifying the thread structure at the same time. 1.311 + */ 1.312 + if ( thread != _PR_MD_CURRENT_THREAD() ) { 1.313 + thr_suspend(hdl); 1.314 + } 1.315 + PR_LOG(_pr_thread_lm, PR_LOG_MIN, 1.316 + ("(0X%x)[DestroyThread]\n", thread)); 1.317 + 1.318 + _MD_DESTROY_SEM(&thread->md.waiter_sem); 1.319 +} 1.320 + 1.321 +void _MD_SET_PRIORITY(_MDThread *md_thread, PRUintn newPri) 1.322 +{ 1.323 + if(thr_setprio((thread_t)md_thread->handle, newPri)) { 1.324 + PR_LOG(_pr_thread_lm, PR_LOG_MIN, 1.325 + ("_PR_SetThreadPriority: can't set thread priority\n")); 1.326 + } 1.327 +} 1.328 + 1.329 +void _MD_WAIT_CV( 1.330 + struct _MDCVar *md_cv, struct _MDLock *md_lock, PRIntervalTime timeout) 1.331 +{ 1.332 + struct timespec tt; 1.333 + PRUint32 msec; 1.334 + int rv; 1.335 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.336 + 1.337 + msec = PR_IntervalToMilliseconds(timeout); 1.338 + 1.339 + GETTIME (&tt); 1.340 + 1.341 + tt.tv_sec += msec / PR_MSEC_PER_SEC; 1.342 + tt.tv_nsec += (msec % PR_MSEC_PER_SEC) * PR_NSEC_PER_MSEC; 1.343 + /* Check for nsec overflow - otherwise we'll get an EINVAL */ 1.344 + if (tt.tv_nsec >= PR_NSEC_PER_SEC) { 1.345 + tt.tv_sec++; 1.346 + tt.tv_nsec -= PR_NSEC_PER_SEC; 1.347 + } 1.348 + me->md.sp = unixware_getsp(); 1.349 + 1.350 + 1.351 + /* XXX Solaris 2.5.x gives back EINTR occasionally for no reason 1.352 + * hence ignore EINTR for now */ 1.353 + 1.354 + COND_TIMEDWAIT(&md_cv->cv, &md_lock->lock, &tt); 1.355 +} 1.356 + 1.357 +void _MD_lock(struct _MDLock *md_lock) 1.358 +{ 1.359 + mutex_lock(&md_lock->lock); 1.360 +} 1.361 + 1.362 +void _MD_unlock(struct _MDLock *md_lock) 1.363 +{ 1.364 + mutex_unlock(&((md_lock)->lock)); 1.365 +} 1.366 + 1.367 + 1.368 +PRThread *_pr_current_thread_tls() 1.369 +{ 1.370 + PRThread *ret; 1.371 + 1.372 + thr_getspecific(threadid_key, (void **)&ret); 1.373 + return ret; 1.374 +} 1.375 + 1.376 +PRStatus 1.377 +_MD_WAIT(PRThread *thread, PRIntervalTime ticks) 1.378 +{ 1.379 + _MD_WAIT_SEM(&thread->md.waiter_sem); 1.380 + return PR_SUCCESS; 1.381 +} 1.382 + 1.383 +PRStatus 1.384 +_MD_WAKEUP_WAITER(PRThread *thread) 1.385 +{ 1.386 + if (thread == NULL) { 1.387 + return PR_SUCCESS; 1.388 + } 1.389 + _MD_POST_SEM(&thread->md.waiter_sem); 1.390 + return PR_SUCCESS; 1.391 +} 1.392 + 1.393 +_PRCPU *_pr_current_cpu_tls() 1.394 +{ 1.395 + _PRCPU *ret; 1.396 + 1.397 + thr_getspecific(cpuid_key, (void **)&ret); 1.398 + return ret; 1.399 +} 1.400 + 1.401 +PRThread *_pr_last_thread_tls() 1.402 +{ 1.403 + PRThread *ret; 1.404 + 1.405 + thr_getspecific(last_thread_key, (void **)&ret); 1.406 + return ret; 1.407 +} 1.408 + 1.409 +_MDLock _pr_ioq_lock; 1.410 + 1.411 +void _MD_INIT_IO (void) 1.412 +{ 1.413 + _MD_NEW_LOCK(&_pr_ioq_lock); 1.414 +} 1.415 + 1.416 +PRStatus _MD_InitializeThread(PRThread *thread) 1.417 +{ 1.418 + if (!_PR_IS_NATIVE_THREAD(thread)) 1.419 + return; 1.420 + /* prime the sp; substract 4 so we don't hit the assert that 1.421 + * curr sp > base_stack 1.422 + */ 1.423 + thread->md.sp = (uint_t) thread->stack->allocBase - sizeof(long); 1.424 + thread->md.lwpid = _lwp_self(); 1.425 + thread->md.handle = THR_SELF(); 1.426 + 1.427 + /* all threads on Solaris are global threads from NSPR's perspective 1.428 + * since all of them are mapped to Solaris threads. 1.429 + */ 1.430 + thread->flags |= _PR_GLOBAL_SCOPE; 1.431 + 1.432 + /* For primordial/attached thread, we don't create an underlying native thread. 1.433 + * So, _MD_CREATE_THREAD() does not get called. We need to do initialization 1.434 + * like allocating thread's synchronization variables and set the underlying 1.435 + * native thread's priority. 1.436 + */ 1.437 + if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) { 1.438 + _MD_NEW_SEM(&thread->md.waiter_sem, 0); 1.439 + _MD_SET_PRIORITY(&(thread->md), thread->priority); 1.440 + } 1.441 + return PR_SUCCESS; 1.442 +} 1.443 + 1.444 +static sigset_t old_mask; /* store away original gc thread sigmask */ 1.445 +static int gcprio; /* store away original gc thread priority */ 1.446 +static lwpid_t *all_lwps=NULL; /* list of lwps that we suspended */ 1.447 +static int num_lwps ; 1.448 +static int suspendAllOn = 0; 1.449 + 1.450 +#define VALID_SP(sp, bottom, top) \ 1.451 + (((uint_t)(sp)) > ((uint_t)(bottom)) && ((uint_t)(sp)) < ((uint_t)(top))) 1.452 + 1.453 +void unixware_preempt_off() 1.454 +{ 1.455 + sigset_t set; 1.456 + (void)sigfillset(&set); 1.457 + sigprocmask (SIG_SETMASK, &set, &old_mask); 1.458 +} 1.459 + 1.460 +void unixware_preempt_on() 1.461 +{ 1.462 + sigprocmask (SIG_SETMASK, &old_mask, NULL); 1.463 +} 1.464 + 1.465 +void _MD_Begin_SuspendAll() 1.466 +{ 1.467 + unixware_preempt_off(); 1.468 + 1.469 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin_SuspendAll\n")); 1.470 + /* run at highest prio so I cannot be preempted */ 1.471 + thr_getprio(thr_self(), &gcprio); 1.472 + thr_setprio(thr_self(), 0x7fffffff); 1.473 + suspendAllOn = 1; 1.474 +} 1.475 + 1.476 +void _MD_End_SuspendAll() 1.477 +{ 1.478 +} 1.479 + 1.480 +void _MD_End_ResumeAll() 1.481 +{ 1.482 + PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End_ResumeAll\n")); 1.483 + thr_setprio(thr_self(), gcprio); 1.484 + unixware_preempt_on(); 1.485 + suspendAllOn = 0; 1.486 +} 1.487 + 1.488 +void _MD_Suspend(PRThread *thr) 1.489 +{ 1.490 + int lwp_fd, result; 1.491 + int lwp_main_proc_fd = 0; 1.492 + 1.493 + thr_suspend(thr->md.handle); 1.494 + if (!_PR_IS_GCABLE_THREAD(thr)) 1.495 + return; 1.496 + /* XXX Primordial thread can't be bound to an lwp, hence there is no 1.497 + * way we can assume that we can get the lwp status for primordial 1.498 + * thread reliably. Hence we skip this for primordial thread, hoping 1.499 + * that the SP is saved during lock and cond. wait. 1.500 + * XXX - Again this is concern only for java interpreter, not for the 1.501 + * server, 'cause primordial thread in the server does not do java work 1.502 + */ 1.503 + if (thr->flags & _PR_PRIMORDIAL) 1.504 + return; 1.505 + 1.506 + /* if the thread is not started yet then don't do anything */ 1.507 + if (!suspendAllOn || thr->md.lwpid == -1) 1.508 + return; 1.509 + 1.510 +} 1.511 +void _MD_Resume(PRThread *thr) 1.512 +{ 1.513 + if (!_PR_IS_GCABLE_THREAD(thr) || !suspendAllOn){ 1.514 + /*XXX When the suspendAllOn is set, we will be trying to do lwp_suspend 1.515 + * during that time we can't call any thread lib or libc calls. Hence 1.516 + * make sure that no resume is requested for Non gcable thread 1.517 + * during suspendAllOn */ 1.518 + PR_ASSERT(!suspendAllOn); 1.519 + thr_continue(thr->md.handle); 1.520 + return; 1.521 + } 1.522 + if (thr->md.lwpid == -1) 1.523 + return; 1.524 + 1.525 + if ( _lwp_continue(thr->md.lwpid) < 0) { 1.526 + PR_ASSERT(0); /* ARGH, we are hosed! */ 1.527 + } 1.528 +} 1.529 + 1.530 + 1.531 +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) 1.532 +{ 1.533 + if (isCurrent) { 1.534 + (void) getcontext(CONTEXT(t)); /* XXX tune me: set md_IRIX.c */ 1.535 + } 1.536 + *np = NGREG; 1.537 + if (t->md.lwpid == -1) 1.538 + memset(&t->md.context.uc_mcontext.gregs[0], 0, NGREG * sizeof(PRWord)); 1.539 + return (PRWord*) &t->md.context.uc_mcontext.gregs[0]; 1.540 +} 1.541 + 1.542 +int 1.543 +_pr_unixware_clock_gettime (struct timespec *tp) 1.544 +{ 1.545 + struct timeval tv; 1.546 + 1.547 + gettimeofday(&tv, NULL); 1.548 + tp->tv_sec = tv.tv_sec; 1.549 + tp->tv_nsec = tv.tv_usec * 1000; 1.550 + return 0; 1.551 +} 1.552 + 1.553 + 1.554 +#endif /* USE_SVR4_THREADS */