87
87
#endif /* _PR_PTHREADS */
89
#if !defined(i386) && !defined(IS_64)
90
#if defined(_PR_HAVE_ATOMIC_OPS)
92
* SPARC v9 (Ultras) do have an atomic test-and-set operation. But
93
* SPARC v8 doesn't. We should detect in the init if we are running on
94
* v8 or v9, and then use assembly where we can.
96
* This code uses the Solaris threads API. It can be used in both the
97
* pthreads and Solaris threads versions of nspr20 because "POSIX threads
98
* and Solaris threads are fully compatible even within the same process",
99
* to quote from pthread_create(3T).
105
static mutex_t _solaris_atomic = DEFAULTMUTEX;
108
_MD_AtomicIncrement(PRInt32 *val)
111
if (mutex_lock(&_solaris_atomic) != 0)
116
if (mutex_unlock(&_solaris_atomic) != 0)\
123
_MD_AtomicAdd(PRInt32 *ptr, PRInt32 val)
126
if (mutex_lock(&_solaris_atomic) != 0)
129
rv = ((*ptr) += val);
131
if (mutex_unlock(&_solaris_atomic) != 0)\
138
_MD_AtomicDecrement(PRInt32 *val)
141
if (mutex_lock(&_solaris_atomic) != 0)
146
if (mutex_unlock(&_solaris_atomic) != 0)\
153
_MD_AtomicSet(PRInt32 *val, PRInt32 newval)
156
if (mutex_lock(&_solaris_atomic) != 0)
162
if (mutex_unlock(&_solaris_atomic) != 0)\
167
#endif /* _PR_HAVE_ATOMIC_OPS */
168
#endif /* !defined(i386) */
170
#if defined(_PR_GLOBAL_THREADS_ONLY)
177
#include <sys/procfs.h>
178
#include <sys/syscall.h>
179
extern int syscall(); /* not declared in sys/syscall.h */
181
static sigset_t old_mask; /* store away original gc thread sigmask */
182
static PRIntn gcprio; /* store away original gc thread priority */
184
THREAD_KEY_T threadid_key;
185
THREAD_KEY_T cpuid_key;
186
THREAD_KEY_T last_thread_key;
187
static sigset_t set, oldset;
190
threadid_key_destructor(void *value)
192
PRThread *me = (PRThread *)value;
193
PR_ASSERT(me != NULL);
194
/* the thread could be PRIMORDIAL (thus not ATTACHED) */
195
if (me->flags & _PR_ATTACHED) {
197
* The Solaris thread library sets the thread specific
198
* data (the current thread) to NULL before invoking
199
* the destructor. We need to restore it to prevent the
200
* _PR_MD_CURRENT_THREAD() call in _PRI_DetachThread()
201
* from attaching the thread again.
203
_PR_MD_SET_CURRENT_THREAD(me);
208
void _MD_EarlyInit(void)
210
THR_KEYCREATE(&threadid_key, threadid_key_destructor);
211
THR_KEYCREATE(&cpuid_key, NULL);
212
THR_KEYCREATE(&last_thread_key, NULL);
214
sigaddset(&set, SIGALRM);
217
PRStatus _MD_CreateThread(PRThread *thread,
218
void (*start)(void *),
219
PRThreadPriority priority,
226
/* mask out SIGALRM for native thread creation */
227
thr_sigsetmask(SIG_BLOCK, &set, &oldset);
230
* Note that we create joinable threads with the THR_DETACHED
231
* flag. The reasons why we don't use thr_join to implement
233
* - We use a termination condition variable in the PRThread
234
* structure to implement PR_JoinThread across all classic
235
* nspr implementation strategies.
236
* - The native threads may be recycled by NSPR to run other
237
* new NSPR threads, so the native threads may not terminate
238
* when the corresponding NSPR threads terminate.
240
flags = THR_SUSPENDED|THR_DETACHED;
241
if (_PR_IS_GCABLE_THREAD(thread) || (thread->flags & _PR_BOUND_THREAD) ||
242
(scope == PR_GLOBAL_BOUND_THREAD))
245
if (thr_create(NULL, thread->stack->stackSize,
246
(void *(*)(void *)) start, (void *) thread,
248
&thread->md.handle)) {
249
thr_sigsetmask(SIG_SETMASK, &oldset, NULL);
253
/* When the thread starts running, then the lwpid is set to the right
254
* value. Until then we want to mark this as 'uninit' so that
255
* its register state is initialized properly for GC */
257
thread->md.lwpid = -1;
258
thr_sigsetmask(SIG_SETMASK, &oldset, NULL);
259
_MD_NEW_SEM(&thread->md.waiter_sem, 0);
261
if ((scope == PR_GLOBAL_THREAD) || (scope == PR_GLOBAL_BOUND_THREAD)) {
262
thread->flags |= _PR_GLOBAL_SCOPE;
265
_MD_SET_PRIORITY(&(thread->md), priority);
267
/* Activate the thread */
268
if (thr_continue( thread->md.handle ) ) {
274
void _MD_cleanup_thread(PRThread *thread)
278
hdl = thread->md.handle;
281
** First, suspend the thread (unless it's the active one)
282
** Because we suspend it first, we don't have to use LOCK_SCHEDULER to
283
** prevent both of us modifying the thread structure at the same time.
285
if ( thread != _PR_MD_CURRENT_THREAD() ) {
288
PR_LOG(_pr_thread_lm, PR_LOG_MIN,
289
("(0X%x)[DestroyThread]\n", thread));
291
_MD_DESTROY_SEM(&thread->md.waiter_sem);
294
void _MD_exit_thread(PRThread *thread)
296
_MD_CLEAN_THREAD(thread);
297
_MD_SET_CURRENT_THREAD(NULL);
300
void _MD_SET_PRIORITY(_MDThread *md_thread,
301
PRThreadPriority newPri)
305
if (newPri < PR_PRIORITY_FIRST) {
306
newPri = PR_PRIORITY_FIRST;
307
} else if (newPri > PR_PRIORITY_LAST) {
308
newPri = PR_PRIORITY_LAST;
310
/* Solaris priorities are from 0 to 127 */
311
nativePri = newPri * 127 / PR_PRIORITY_LAST;
312
if(thr_setprio((thread_t)md_thread->handle, nativePri)) {
313
PR_LOG(_pr_thread_lm, PR_LOG_MIN,
314
("_PR_SetThreadPriority: can't set thread priority\n"));
319
struct _MDCVar *md_cv, struct _MDLock *md_lock, PRIntervalTime timeout)
323
PRThread *me = _PR_MD_CURRENT_THREAD();
325
PR_ASSERT((!suspendAllOn) || (suspendAllThread != me));
327
if (PR_INTERVAL_NO_TIMEOUT == timeout) {
328
COND_WAIT(&md_cv->cv, &md_lock->lock);
330
msec = PR_IntervalToMilliseconds(timeout);
333
tt.tv_sec += msec / PR_MSEC_PER_SEC;
334
tt.tv_nsec += (msec % PR_MSEC_PER_SEC) * PR_NSEC_PER_MSEC;
335
/* Check for nsec overflow - otherwise we'll get an EINVAL */
336
if (tt.tv_nsec >= PR_NSEC_PER_SEC) {
338
tt.tv_nsec -= PR_NSEC_PER_SEC;
340
COND_TIMEDWAIT(&md_cv->cv, &md_lock->lock, &tt);
344
void _MD_lock(struct _MDLock *md_lock)
347
/* This code was used for GC testing to make sure that we didn't attempt
348
* to grab any locks while threads are suspended.
352
if ((suspendAllOn) && (suspendAllThread == _PR_MD_CURRENT_THREAD())) {
353
lock = ((PRLock *) ((char*) (md_lock) - offsetof(PRLock,ilock)));
354
PR_ASSERT(lock->owner == NULL);
359
mutex_lock(&md_lock->lock);
362
PRThread *_pr_attached_thread_tls()
366
thr_getspecific(threadid_key, (void **)&ret);
370
PRThread *_pr_current_thread_tls()
374
thread = _MD_GET_ATTACHED_THREAD();
376
if (NULL == thread) {
377
thread = _PRI_AttachThread(
378
PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL, 0);
380
PR_ASSERT(thread != NULL);
386
_MD_wait(PRThread *thread, PRIntervalTime ticks)
388
_MD_WAIT_SEM(&thread->md.waiter_sem);
393
_MD_WakeupWaiter(PRThread *thread)
395
if (thread == NULL) {
398
_MD_POST_SEM(&thread->md.waiter_sem);
402
_PRCPU *_pr_current_cpu_tls()
406
thr_getspecific(cpuid_key, (void **)&ret);
410
PRThread *_pr_last_thread_tls()
414
thr_getspecific(last_thread_key, (void **)&ret);
418
_MDLock _pr_ioq_lock;
423
_MD_NEW_LOCK(&_pr_ioq_lock);
426
PRStatus _MD_InitializeThread(PRThread *thread)
428
if (!_PR_IS_NATIVE_THREAD(thread))
430
/* sol_curthread is an asm routine which grabs GR7; GR7 stores an internal
431
* thread structure ptr used by solaris. We'll use this ptr later
432
* with suspend/resume to find which threads are running on LWPs.
434
thread->md.threadID = sol_curthread();
435
/* prime the sp; substract 4 so we don't hit the assert that
436
* curr sp > base_stack
438
thread->md.sp = (uint_t) thread->stack->allocBase - sizeof(long);
439
thread->md.lwpid = _lwp_self();
440
thread->md.handle = THR_SELF();
442
/* all threads on Solaris are global threads from NSPR's perspective
443
* since all of them are mapped to Solaris threads.
445
thread->flags |= _PR_GLOBAL_SCOPE;
447
/* For primordial/attached thread, we don't create an underlying native thread.
448
* So, _MD_CREATE_THREAD() does not get called. We need to do initialization
449
* like allocating thread's synchronization variables and set the underlying
450
* native thread's priority.
452
if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) {
453
_MD_NEW_SEM(&thread->md.waiter_sem, 0);
454
_MD_SET_PRIORITY(&(thread->md), thread->priority);
459
/* Sleep for n milliseconds, n < 1000 */
460
void solaris_msec_sleep(int n)
465
ts.tv_nsec = 1000000*n;
466
if (syscall(SYS_nanosleep, &ts, 0, 0) < 0) {
471
#define VALID_SP(sp, bottom, top) \
472
(((uint_t)(sp)) > ((uint_t)(bottom)) && ((uint_t)(sp)) < ((uint_t)(top)))
474
void solaris_record_regs(PRThread *t, prstatus_t *lwpstatus)
477
long *regs = (long *)&t->md.context.uc_mcontext.gregs[0];
479
PR_ASSERT(_PR_IS_GCABLE_THREAD(t));
480
PR_ASSERT(t->md.threadID == lwpstatus->pr_reg[REG_G7]);
482
t->md.sp = lwpstatus->pr_reg[REG_SP];
483
PR_ASSERT(VALID_SP(t->md.sp, t->stack->stackBottom, t->stack->stackTop));
485
regs[0] = lwpstatus->pr_reg[R_G1];
486
regs[1] = lwpstatus->pr_reg[R_G2];
487
regs[2] = lwpstatus->pr_reg[R_G3];
488
regs[3] = lwpstatus->pr_reg[R_G4];
489
regs[4] = lwpstatus->pr_reg[R_O0];
490
regs[5] = lwpstatus->pr_reg[R_O1];
491
regs[6] = lwpstatus->pr_reg[R_O2];
492
regs[7] = lwpstatus->pr_reg[R_O3];
493
regs[8] = lwpstatus->pr_reg[R_O4];
494
regs[9] = lwpstatus->pr_reg[R_O5];
495
regs[10] = lwpstatus->pr_reg[R_O6];
496
regs[11] = lwpstatus->pr_reg[R_O7];
499
* To be implemented and tested
502
PR_ASSERT(t->md.threadID == lwpstatus->pr_reg[GS]);
503
t->md.sp = lwpstatus->pr_reg[UESP];
507
void solaris_preempt_off()
511
(void)sigfillset(&set);
512
syscall(SYS_sigprocmask, SIG_SETMASK, &set, &old_mask);
515
void solaris_preempt_on()
517
syscall(SYS_sigprocmask, SIG_SETMASK, &old_mask, NULL);
520
int solaris_open_main_proc_fd()
525
/* Not locked, so must be created while threads coming up */
526
PR_snprintf(buf, sizeof(buf), "/proc/%ld", getpid());
527
if ( (fd = syscall(SYS_open, buf, O_RDONLY)) < 0) {
533
/* Return a file descriptor for the /proc entry corresponding to the
536
int solaris_open_lwp(lwpid_t id, int lwp_main_proc_fd)
540
if ( (result = syscall(SYS_ioctl, lwp_main_proc_fd, PIOCOPENLWP, &id)) <0)
541
return -1; /* exited??? */
545
void _MD_Begin_SuspendAll()
547
solaris_preempt_off();
549
PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin_SuspendAll\n"));
550
/* run at highest prio so I cannot be preempted */
551
thr_getprio(thr_self(), &gcprio);
552
thr_setprio(thr_self(), 0x7fffffff);
553
suspendAllOn = PR_TRUE;
554
suspendAllThread = _PR_MD_CURRENT_THREAD();
557
void _MD_End_SuspendAll()
561
void _MD_End_ResumeAll()
563
PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End_ResumeAll\n"));
564
thr_setprio(thr_self(), gcprio);
565
solaris_preempt_on();
566
suspendAllThread = NULL;
567
suspendAllOn = PR_FALSE;
570
void _MD_Suspend(PRThread *thr)
573
prstatus_t lwpstatus;
574
int lwp_main_proc_fd = 0;
576
if (!_PR_IS_GCABLE_THREAD(thr) || !suspendAllOn){
577
/*XXX When the suspendAllOn is set, we will be trying to do lwp_suspend
578
* during that time we can't call any thread lib or libc calls. Hence
579
* make sure that no suspension is requested for Non gcable thread
580
* during suspendAllOn */
581
PR_ASSERT(!suspendAllOn);
582
thr_suspend(thr->md.handle);
586
/* XXX Primordial thread can't be bound to an lwp, hence there is no
587
* way we can assume that we can get the lwp status for primordial
588
* thread reliably. Hence we skip this for primordial thread, hoping
589
* that the SP is saved during lock and cond. wait.
590
* XXX - Again this is concern only for java interpreter, not for the
591
* server, 'cause primordial thread in the server does not do java work
593
if (thr->flags & _PR_PRIMORDIAL)
596
/* XXX Important Note: If the start function of a thread is not called,
597
* lwpid is -1. Then, skip this thread. This thread will get caught
598
* in PR_NativeRunThread before calling the start function, because
599
* we hold the pr_activeLock during suspend/resume */
601
/* if the thread is not started yet then don't do anything */
602
if (!suspendAllOn || thr->md.lwpid == -1)
605
if (_lwp_suspend(thr->md.lwpid) < 0) {
610
if ( (lwp_main_proc_fd = solaris_open_main_proc_fd()) < 0) {
612
return; /* XXXMB ARGH, we're hosed! */
615
if ( (lwp_fd = solaris_open_lwp(thr->md.lwpid, lwp_main_proc_fd)) < 0) {
617
close(lwp_main_proc_fd);
620
if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) {
621
/* Hopefully the thread just died... */
623
close(lwp_main_proc_fd);
626
while ( !(lwpstatus.pr_flags & PR_STOPPED) ) {
627
if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) {
628
PR_ASSERT(0); /* ARGH SOMETHING WRONG! */
631
solaris_msec_sleep(1);
633
solaris_record_regs(thr, &lwpstatus);
635
close(lwp_main_proc_fd);
640
void _MD_SuspendAll()
642
/* On solaris there are threads, and there are LWPs.
643
* Calling _PR_DoSingleThread would freeze all of the threads bound to LWPs
644
* but not necessarily stop all LWPs (for example if someone did
645
* an attachthread of a thread which was not bound to an LWP).
646
* So now go through all the LWPs for this process and freeze them.
648
* Note that if any thread which is capable of having the GC run on it must
649
* had better be a LWP with a single bound thread on it. Otherwise, this
650
* might not stop that thread from being run.
652
PRThread *current = _PR_MD_CURRENT_THREAD();
653
prstatus_t status, lwpstatus;
654
int result, index, lwp_fd;
655
lwpid_t me = _lwp_self();
657
int lwp_main_proc_fd;
659
solaris_preempt_off();
661
/* run at highest prio so I cannot be preempted */
662
thr_getprio(thr_self(), &gcprio);
663
thr_setprio(thr_self(), 0x7fffffff);
665
current->md.sp = (uint_t)&me; /* set my own stack pointer */
667
if ( (lwp_main_proc_fd = solaris_open_main_proc_fd()) < 0) {
669
solaris_preempt_on();
670
return; /* XXXMB ARGH, we're hosed! */
673
if ( (result = syscall(SYS_ioctl, lwp_main_proc_fd, PIOCSTATUS, &status)) < 0) {
676
goto failure; /* XXXMB ARGH, we're hosed! */
679
num_lwps = status.pr_nlwp;
681
if ( (all_lwps = (lwpid_t *)PR_MALLOC((num_lwps+1) * sizeof(lwpid_t)))==NULL) {
683
goto failure; /* XXXMB ARGH, we're hosed! */
686
if ( (result = syscall(SYS_ioctl, lwp_main_proc_fd, PIOCLWPIDS, all_lwps)) < 0) {
689
goto failure; /* XXXMB ARGH, we're hosed! */
692
for (index=0; index< num_lwps; index++) {
693
if (all_lwps[index] != me) {
694
if (_lwp_suspend(all_lwps[index]) < 0) {
695
/* could happen if lwp exited */
696
all_lwps[index] = me; /* dummy it up */
701
/* Turns out that lwp_suspend is not a blocking call.
702
* Go through the list and make sure they are all stopped.
704
for (index=0; index< num_lwps; index++) {
705
if (all_lwps[index] != me) {
706
if ( (lwp_fd = solaris_open_lwp(all_lwps[index], lwp_main_proc_fd)) < 0) {
710
goto failure; /* XXXMB ARGH, we're hosed! */
713
if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) {
714
/* Hopefully the thread just died... */
718
while ( !(lwpstatus.pr_flags & PR_STOPPED) ) {
719
if ( (result = syscall(SYS_ioctl, lwp_fd, PIOCSTATUS, &lwpstatus)) < 0) {
720
PR_ASSERT(0); /* ARGH SOMETHING WRONG! */
723
solaris_msec_sleep(1);
725
solaris_record_regs(&lwpstatus);
730
close(lwp_main_proc_fd);
734
solaris_preempt_on();
735
thr_setprio(thr_self(), gcprio);
736
close(lwp_main_proc_fd);
743
lwpid_t me = _lwp_self();
745
for (i=0; i < num_lwps; i++) {
746
if (all_lwps[i] == me)
748
if ( _lwp_continue(all_lwps[i]) < 0) {
749
PR_ASSERT(0); /* ARGH, we are hosed! */
753
/* restore priority and sigmask */
754
thr_setprio(thr_self(), gcprio);
755
solaris_preempt_on();
759
#endif /* OLD_CODE */
762
PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
765
(void) setjmp(CONTEXT(t));
767
*np = sizeof(CONTEXT(t)) / sizeof(PRWord);
768
return (PRWord *) CONTEXT(t);
771
PRWord *_MD_HomeGCRegisters(PRThread *t, PRIntn isCurrent, PRIntn *np)
774
(void) getcontext(CONTEXT(t));
777
return (PRWord*) &t->md.context.uc_mcontext.gregs[0];
779
#endif /* USE_SETJMP */
781
#else /* _PR_GLOBAL_THREADS_ONLY */
783
89
#if defined(_PR_LOCAL_THREADS_ONLY)
785
91
void _MD_EarlyInit(void)