1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is the Netscape Portable Runtime (NSPR).
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
40 #if !defined (USE_SVR4_THREADS)
43 * using only NSPR threads here
48 void _MD_EarlyInit(void)
52 PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
55 (void) setjmp(CONTEXT(t));
57 *np = sizeof(CONTEXT(t)) / sizeof(PRWord);
58 return (PRWord *) CONTEXT(t);
61 #ifdef ALARMS_BREAK_TCP /* I don't think they do */
63 PRInt32 _MD_connect(PRInt32 osfd, const PRNetAddr *addr, PRInt32 addrlen,
64 PRIntervalTime timeout)
68 _MD_BLOCK_CLOCK_INTERRUPTS();
69 rv = _connect(osfd,addr,addrlen);
70 _MD_UNBLOCK_CLOCK_INTERRUPTS();
73 PRInt32 _MD_accept(PRInt32 osfd, PRNetAddr *addr, PRInt32 addrlen,
74 PRIntervalTime timeout)
78 _MD_BLOCK_CLOCK_INTERRUPTS();
79 rv = _accept(osfd,addr,addrlen);
80 _MD_UNBLOCK_CLOCK_INTERRUPTS();
86 * These are also implemented in pratom.c using NSPR locks. Any reason
87 * this might be better or worse? If you like this better, define
88 * _PR_HAVE_ATOMIC_OPS in include/md/unixware.h
90 #ifdef _PR_HAVE_ATOMIC_OPS
91 /* Atomic operations */
93 static FILE *_uw_semf;
98 /* Sigh. Sure wish SYSV semaphores weren't such a pain to use */
99 if ((_uw_semf = tmpfile()) == NULL)
106 _MD_ATOMIC_INCREMENT(PRInt32 *val)
110 unflockfile(_uw_semf);
114 _MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val)
118 unflockfile(_uw_semf);
122 _MD_ATOMIC_DECREMENT(PRInt32 *val)
126 unflockfile(_uw_semf);
130 _MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
134 unflockfile(_uw_semf);
139 _MD_SET_PRIORITY(_MDThread *thread, PRUintn newPri)
145 _MD_InitializeThread(PRThread *thread)
151 _MD_WAIT(PRThread *thread, PRIntervalTime ticks)
153 PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE));
154 _PR_MD_SWITCH_CONTEXT(thread);
159 _MD_WAKEUP_WAITER(PRThread *thread)
162 PR_ASSERT(!(thread->flags & _PR_GLOBAL_SCOPE));
167 /* These functions should not be called for Unixware */
171 PR_NOT_REACHED("_MD_YIELD should not be called for Unixware.");
177 void (*start) (void *),
178 PRThreadPriority priority,
183 PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for Unixware.");
186 #else /* USE_SVR4_THREADS */
189 * SPARC v9 (Ultras) do have an atomic test-and-set operation. But
190 * SPARC v8 doesn't. We should detect in the init if we are running on
191 * v8 or v9, and then use assembly where we can.
197 static mutex_t _unixware_atomic = DEFAULTMUTEX;
199 #define TEST_THEN_ADD(where, inc) \
200 if (mutex_lock(&_unixware_atomic) != 0)\
203 if (mutex_unlock(&_unixware_atomic) != 0)\
206 #define TEST_THEN_SET(where, val) \
207 if (mutex_lock(&_unixware_atomic) != 0)\
210 if (mutex_unlock(&_unixware_atomic) != 0)\
214 _MD_INIT_ATOMIC(void)
219 _MD_ATOMIC_INCREMENT(PRInt32 *val)
221 TEST_THEN_ADD(val, 1);
225 _MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val)
227 TEST_THEN_ADD(ptr, val);
231 _MD_ATOMIC_DECREMENT(PRInt32 *val)
233 TEST_THEN_ADD(val, 0xffffffff);
237 _MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
239 TEST_THEN_SET(val, newval);
247 #include <sys/procfs.h>
248 #include <sys/syscall.h>
251 THREAD_KEY_T threadid_key;
252 THREAD_KEY_T cpuid_key;
253 THREAD_KEY_T last_thread_key;
254 static sigset_t set, oldset;
256 void _MD_EarlyInit(void)
258 THR_KEYCREATE(&threadid_key, NULL);
259 THR_KEYCREATE(&cpuid_key, NULL);
260 THR_KEYCREATE(&last_thread_key, NULL);
262 sigaddset(&set, SIGALRM);
265 PRStatus _MD_CREATE_THREAD(PRThread *thread,
266 void (*start)(void *),
267 PRThreadPriority priority,
274 /* mask out SIGALRM for native thread creation */
275 thr_sigsetmask(SIG_BLOCK, &set, &oldset);
277 flags = (state == PR_JOINABLE_THREAD ? THR_SUSPENDED/*|THR_NEW_LWP*/
278 : THR_SUSPENDED|THR_DETACHED/*|THR_NEW_LWP*/);
279 if (_PR_IS_GCABLE_THREAD(thread) ||
280 (scope == PR_GLOBAL_BOUND_THREAD))
283 if (thr_create(NULL, thread->stack->stackSize,
284 (void *(*)(void *)) start, (void *) thread,
286 &thread->md.handle)) {
287 thr_sigsetmask(SIG_SETMASK, &oldset, NULL);
292 /* When the thread starts running, then the lwpid is set to the right
293 * value. Until then we want to mark this as 'uninit' so that
294 * its register state is initialized properly for GC */
296 thread->md.lwpid = -1;
297 thr_sigsetmask(SIG_SETMASK, &oldset, NULL);
298 _MD_NEW_SEM(&thread->md.waiter_sem, 0);
300 if ((scope == PR_GLOBAL_THREAD) || (scope == PR_GLOBAL_BOUND_THREAD)) {
301 thread->flags |= _PR_GLOBAL_SCOPE;
305 ** Set the thread priority. This will also place the thread on
308 ** Force PR_SetThreadPriority to set the priority by
309 ** setting thread->priority to 100.
313 pri = thread->priority;
314 thread->priority = 100;
315 PR_SetThreadPriority( thread, pri );
317 PR_LOG(_pr_thread_lm, PR_LOG_MIN,
318 ("(0X%x)[Start]: on to runq at priority %d",
319 thread, thread->priority));
322 /* Activate the thread */
323 if (thr_continue( thread->md.handle ) ) {
329 void _MD_cleanup_thread(PRThread *thread)
334 hdl = thread->md.handle;
337 ** First, suspend the thread (unless it's the active one)
338 ** Because we suspend it first, we don't have to use LOCK_SCHEDULER to
339 ** prevent both of us modifying the thread structure at the same time.
341 if ( thread != _PR_MD_CURRENT_THREAD() ) {
344 PR_LOG(_pr_thread_lm, PR_LOG_MIN,
345 ("(0X%x)[DestroyThread]\n", thread));
347 _MD_DESTROY_SEM(&thread->md.waiter_sem);
350 void _MD_SET_PRIORITY(_MDThread *md_thread, PRUintn newPri)
352 if(thr_setprio((thread_t)md_thread->handle, newPri)) {
353 PR_LOG(_pr_thread_lm, PR_LOG_MIN,
354 ("_PR_SetThreadPriority: can't set thread priority\n"));
359 struct _MDCVar *md_cv, struct _MDLock *md_lock, PRIntervalTime timeout)
364 PRThread *me = _PR_MD_CURRENT_THREAD();
366 msec = PR_IntervalToMilliseconds(timeout);
370 tt.tv_sec += msec / PR_MSEC_PER_SEC;
371 tt.tv_nsec += (msec % PR_MSEC_PER_SEC) * PR_NSEC_PER_MSEC;
372 /* Check for nsec overflow - otherwise we'll get an EINVAL */
373 if (tt.tv_nsec >= PR_NSEC_PER_SEC) {
375 tt.tv_nsec -= PR_NSEC_PER_SEC;
377 me->md.sp = unixware_getsp();
380 /* XXX Solaris 2.5.x gives back EINTR occasionally for no reason
381 * hence ignore EINTR for now */
383 COND_TIMEDWAIT(&md_cv->cv, &md_lock->lock, &tt);
386 void _MD_lock(struct _MDLock *md_lock)
388 mutex_lock(&md_lock->lock);
391 void _MD_unlock(struct _MDLock *md_lock)
393 mutex_unlock(&((md_lock)->lock));
397 PRThread *_pr_current_thread_tls()
401 thr_getspecific(threadid_key, (void **)&ret);
406 _MD_WAIT(PRThread *thread, PRIntervalTime ticks)
408 _MD_WAIT_SEM(&thread->md.waiter_sem);
413 _MD_WAKEUP_WAITER(PRThread *thread)
415 if (thread == NULL) {
418 _MD_POST_SEM(&thread->md.waiter_sem);
422 _PRCPU *_pr_current_cpu_tls()
426 thr_getspecific(cpuid_key, (void **)&ret);
430 PRThread *_pr_last_thread_tls()
434 thr_getspecific(last_thread_key, (void **)&ret);
438 _MDLock _pr_ioq_lock;
440 void _MD_INIT_IO (void)
442 _MD_NEW_LOCK(&_pr_ioq_lock);
445 PRStatus _MD_InitializeThread(PRThread *thread)
447 if (!_PR_IS_NATIVE_THREAD(thread))
449 /* prime the sp; substract 4 so we don't hit the assert that
450 * curr sp > base_stack
452 thread->md.sp = (uint_t) thread->stack->allocBase - sizeof(long);
453 thread->md.lwpid = _lwp_self();
454 thread->md.handle = THR_SELF();
456 /* all threads on Solaris are global threads from NSPR's perspective
457 * since all of them are mapped to Solaris threads.
459 thread->flags |= _PR_GLOBAL_SCOPE;
461 /* For primordial/attached thread, we don't create an underlying native thread.
462 * So, _MD_CREATE_THREAD() does not get called. We need to do initialization
463 * like allocating thread's synchronization variables and set the underlying
464 * native thread's priority.
466 if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) {
467 _MD_NEW_SEM(&thread->md.waiter_sem, 0);
468 _MD_SET_PRIORITY(&(thread->md), thread->priority);
473 static sigset_t old_mask; /* store away original gc thread sigmask */
474 static int gcprio; /* store away original gc thread priority */
475 static lwpid_t *all_lwps=NULL; /* list of lwps that we suspended */
476 static int num_lwps ;
477 static int suspendAllOn = 0;
479 #define VALID_SP(sp, bottom, top) \
480 (((uint_t)(sp)) > ((uint_t)(bottom)) && ((uint_t)(sp)) < ((uint_t)(top)))
482 void unixware_preempt_off()
485 (void)sigfillset(&set);
486 sigprocmask (SIG_SETMASK, &set, &old_mask);
489 void unixware_preempt_on()
491 sigprocmask (SIG_SETMASK, &old_mask, NULL);
494 void _MD_Begin_SuspendAll()
496 unixware_preempt_off();
498 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin_SuspendAll\n"));
499 /* run at highest prio so I cannot be preempted */
500 thr_getprio(thr_self(), &gcprio);
501 thr_setprio(thr_self(), 0x7fffffff);
505 void _MD_End_SuspendAll()
509 void _MD_End_ResumeAll()
511 PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End_ResumeAll\n"));
512 thr_setprio(thr_self(), gcprio);
513 unixware_preempt_on();
517 void _MD_Suspend(PRThread *thr)
520 int lwp_main_proc_fd = 0;
522 thr_suspend(thr->md.handle);
523 if (!_PR_IS_GCABLE_THREAD(thr))
525 /* XXX Primordial thread can't be bound to an lwp, hence there is no
526 * way we can assume that we can get the lwp status for primordial
527 * thread reliably. Hence we skip this for primordial thread, hoping
528 * that the SP is saved during lock and cond. wait.
529 * XXX - Again this is concern only for java interpreter, not for the
530 * server, 'cause primordial thread in the server does not do java work
532 if (thr->flags & _PR_PRIMORDIAL)
535 /* if the thread is not started yet then don't do anything */
536 if (!suspendAllOn || thr->md.lwpid == -1)
540 void _MD_Resume(PRThread *thr)
542 if (!_PR_IS_GCABLE_THREAD(thr) || !suspendAllOn){
543 /*XXX When the suspendAllOn is set, we will be trying to do lwp_suspend
544 * during that time we can't call any thread lib or libc calls. Hence
545 * make sure that no resume is requested for Non gcable thread
546 * during suspendAllOn */
547 PR_ASSERT(!suspendAllOn);
548 thr_continue(thr->md.handle);
551 if (thr->md.lwpid == -1)
554 if ( _lwp_continue(thr->md.lwpid) < 0) {
555 PR_ASSERT(0); /* ARGH, we are hosed! */
560 PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
563 (void) getcontext(CONTEXT(t)); /* XXX tune me: set md_IRIX.c */
566 if (t->md.lwpid == -1)
567 memset(&t->md.context.uc_mcontext.gregs[0], 0, NGREG * sizeof(PRWord));
568 return (PRWord*) &t->md.context.uc_mcontext.gregs[0];
572 _pr_unixware_clock_gettime (struct timespec *tp)
576 gettimeofday(&tv, NULL);
577 tp->tv_sec = tv.tv_sec;
578 tp->tv_nsec = tv.tv_usec * 1000;
583 #endif /* USE_SVR4_THREADS */