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