diff options
Diffstat (limited to 'usr/src/lib/libc/port/threads/thr.c')
-rw-r--r-- | usr/src/lib/libc/port/threads/thr.c | 144 |
1 files changed, 68 insertions, 76 deletions
diff --git a/usr/src/lib/libc/port/threads/thr.c b/usr/src/lib/libc/port/threads/thr.c index 74a69e44f2..3f11ad1f2f 100644 --- a/usr/src/lib/libc/port/threads/thr.c +++ b/usr/src/lib/libc/port/threads/thr.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -28,9 +28,11 @@ #include "lint.h" #include "thr_uberdata.h" +#include <pthread.h> #include <procfs.h> #include <sys/uio.h> #include <ctype.h> +#include "libc.h" #undef errno extern int errno; @@ -204,68 +206,26 @@ hash_out(ulwp_t *ulwp, uberdata_t *udp) } } +/* + * Retain stack information for thread structures that are being recycled for + * new threads. All other members of the thread structure should be zeroed. + */ static void ulwp_clean(ulwp_t *ulwp) { - ulwp->ul_self = NULL; - ulwp->ul_rval = NULL; - ulwp->ul_lwpid = 0; - ulwp->ul_pri = 0; - ulwp->ul_mappedpri = 0; - ulwp->ul_policy = 0; - ulwp->ul_pri_mapped = 0; - ulwp->ul_mutator = 0; - ulwp->ul_pleasestop = 0; - ulwp->ul_stop = 0; - ulwp->ul_dead = 0; - ulwp->ul_unwind = 0; - ulwp->ul_detached = 0; - ulwp->ul_stopping = 0; - ulwp->ul_sp = 0; - ulwp->ul_critical = 0; - ulwp->ul_cancelable = 0; - ulwp->ul_preempt = 0; - ulwp->ul_sigsuspend = 0; - ulwp->ul_cancel_pending = 0; - ulwp->ul_cancel_disabled = 0; - ulwp->ul_cancel_async = 0; - ulwp->ul_save_async = 0; - ulwp->ul_cursig = 0; - ulwp->ul_created = 0; - ulwp->ul_replace = 0; - ulwp->ul_schedctl_called = NULL; - ulwp->ul_errno = 0; - ulwp->ul_errnop = NULL; - ulwp->ul_clnup_hdr = NULL; - ulwp->ul_schedctl = NULL; - ulwp->ul_bindflags = 0; - (void) _private_memset(&ulwp->ul_td_evbuf, 0, - sizeof (ulwp->ul_td_evbuf)); - ulwp->ul_td_events_enable = 0; - ulwp->ul_qtype = 0; - ulwp->ul_usropts = 0; - ulwp->ul_startpc = NULL; - ulwp->ul_startarg = NULL; - ulwp->ul_wchan = NULL; - ulwp->ul_link = NULL; - ulwp->ul_sleepq = NULL; - ulwp->ul_mxchain = NULL; - ulwp->ul_epri = 0; - ulwp->ul_emappedpri = 0; - /* PROBE_SUPPORT begin */ - ulwp->ul_tpdp = NULL; - /* PROBE_SUPPORT end */ - ulwp->ul_siglink = NULL; - (void) _private_memset(ulwp->ul_ftsd, 0, - sizeof (void *) * TSD_NFAST); - ulwp->ul_stsd = NULL; - (void) _private_memset(&ulwp->ul_spinlock, 0, - sizeof (ulwp->ul_spinlock)); - ulwp->ul_spin_lock_spin = 0; - ulwp->ul_spin_lock_spin2 = 0; - ulwp->ul_spin_lock_sleep = 0; - ulwp->ul_spin_lock_wakeup = 0; - ulwp->ul_ex_unwind = NULL; + caddr_t stk = ulwp->ul_stk; + size_t mapsiz = ulwp->ul_mapsiz; + size_t guardsize = ulwp->ul_guardsize; + uintptr_t stktop = ulwp->ul_stktop; + size_t stksiz = ulwp->ul_stksiz; + + (void) _private_memset(ulwp, 0, sizeof (*ulwp)); + + ulwp->ul_stk = stk; + ulwp->ul_mapsiz = mapsiz; + ulwp->ul_guardsize = guardsize; + ulwp->ul_stktop = stktop; + ulwp->ul_stksiz = stksiz; } static int stackprot; @@ -700,7 +660,6 @@ _thrp_create(void *stk, size_t stksize, void *(*func)(void *), void *arg, return (error); } self->ul_nocancel = 0; /* cancellation is now possible */ - ulwp->ul_nocancel = 0; udp->uberflags.uf_mt = 1; if (new_thread) *new_thread = tid; @@ -942,6 +901,7 @@ _thr_exit_common(void *status, int unwind) self->ul_save_async = 0; self->ul_cancelable = 0; self->ul_cancel_pending = 0; + set_cancel_pending_flag(self, 1); if (cancelled && cleanuphndlr != NULL) (*cleanuphndlr)(); @@ -1341,8 +1301,7 @@ libc_init(void) self->ul_dreturn = 0x81ca0000; /* return %o0 */ #endif - self->ul_stktop = - (uintptr_t)uc.uc_stack.ss_sp + uc.uc_stack.ss_size; + self->ul_stktop = (uintptr_t)uc.uc_stack.ss_sp + uc.uc_stack.ss_size; (void) _private_getrlimit(RLIMIT_STACK, &rl); self->ul_stksiz = rl.rlim_cur; self->ul_stk = (caddr_t)(self->ul_stktop - self->ul_stksiz); @@ -1484,6 +1443,13 @@ libc_init(void) if (setmask) (void) restore_signals(self); + /* + * Make private copies of __xpg4 and __xpg6 so libc can test + * them after this point without invoking the dynamic linker. + */ + libc__xpg4 = __xpg4; + libc__xpg6 = __xpg6; + /* PROBE_SUPPORT begin */ if (self->ul_primarymap && __tnf_probe_notify != NULL) __tnf_probe_notify(); @@ -1879,7 +1845,7 @@ top: */ while (ulwp && !ulwp->ul_dead && !ulwp->ul_stop && (ulwp->ul_pleasestop & whystopped)) { - (void) _cond_wait(cvp, mp); + (void) __cond_wait(cvp, mp); for (ulwp = udp->thr_hash_table[ix].hash_bucket; ulwp != NULL; ulwp = ulwp->ul_hash) { if (ulwp->ul_lwpid == tid) @@ -2223,6 +2189,15 @@ do_exit_critical() ASSERT(self->ul_critical == 0); } +/* + * _ti_bind_guard() and _ti_bind_clear() are called by the dynamic linker + * (ld.so.1) when it has do do something, like resolve a symbol to be called + * by the application or one of its libraries. _ti_bind_guard() is called + * on entry to ld.so.1, _ti_bind_clear() on exit from ld.so.1 back to the + * application. The dynamic linker gets special dispensation from libc to + * run in a critical region (all signals deferred and no thread suspension + * or forking allowed), and to be immune from cancellation for the duration. + */ int _ti_bind_guard(int bindflag) { @@ -2231,6 +2206,9 @@ _ti_bind_guard(int bindflag) if ((self->ul_bindflags & bindflag) == bindflag) return (0); enter_critical(self); + self->ul_save_state = self->ul_cancel_disabled; + self->ul_cancel_disabled = 1; + set_cancel_pending_flag(self, 0); self->ul_bindflags |= bindflag; return (1); } @@ -2243,6 +2221,8 @@ _ti_bind_clear(int bindflag) if ((self->ul_bindflags & bindflag) == 0) return (self->ul_bindflags); self->ul_bindflags &= ~bindflag; + self->ul_cancel_disabled = self->ul_save_state; + set_cancel_pending_flag(self, 0); exit_critical(self); return (self->ul_bindflags); } @@ -2443,7 +2423,7 @@ _thr_setstate(thread_t tid, int flag, gregset_t rs) int getlwpstatus(thread_t tid, struct lwpstatus *sp) { - extern ssize_t _pread(int, void *, size_t, off_t); + extern ssize_t __pread(int, void *, size_t, off_t); char buf[100]; int fd; @@ -2451,15 +2431,15 @@ getlwpstatus(thread_t tid, struct lwpstatus *sp) (void) strcpy(buf, "/proc/self/lwp/"); ultos((uint64_t)tid, 10, buf + strlen(buf)); (void) strcat(buf, "/lwpstatus"); - if ((fd = _open(buf, O_RDONLY, 0)) >= 0) { - while (_pread(fd, sp, sizeof (*sp), 0) == sizeof (*sp)) { + if ((fd = _private_open(buf, O_RDONLY, 0)) >= 0) { + while (__pread(fd, sp, sizeof (*sp), 0) == sizeof (*sp)) { if (sp->pr_flags & PR_STOPPED) { - (void) _close(fd); + (void) _private_close(fd); return (0); } lwp_yield(); /* give him a chance to stop */ } - (void) _close(fd); + (void) _private_close(fd); } return (-1); } @@ -2467,7 +2447,7 @@ getlwpstatus(thread_t tid, struct lwpstatus *sp) int putlwpregs(thread_t tid, prgregset_t prp) { - extern ssize_t _writev(int, const struct iovec *, int); + extern ssize_t __writev(int, const struct iovec *, int); char buf[100]; int fd; long dstop_sreg[2]; @@ -2478,7 +2458,7 @@ putlwpregs(thread_t tid, prgregset_t prp) (void) strcpy(buf, "/proc/self/lwp/"); ultos((uint64_t)tid, 10, buf + strlen(buf)); (void) strcat(buf, "/lwpctl"); - if ((fd = _open(buf, O_WRONLY, 0)) >= 0) { + if ((fd = _private_open(buf, O_WRONLY, 0)) >= 0) { dstop_sreg[0] = PCDSTOP; /* direct it to stop */ dstop_sreg[1] = PCSREG; /* set the registers */ iov[0].iov_base = (caddr_t)dstop_sreg; @@ -2489,11 +2469,11 @@ putlwpregs(thread_t tid, prgregset_t prp) run_null[1] = 0; iov[2].iov_base = (caddr_t)run_null; iov[2].iov_len = sizeof (run_null); - if (_writev(fd, iov, 3) >= 0) { - (void) _close(fd); + if (__writev(fd, iov, 3) >= 0) { + (void) _private_close(fd); return (0); } - (void) _close(fd); + (void) _private_close(fd); } return (-1); } @@ -2558,8 +2538,9 @@ _thr_setmutator(thread_t tid, int enabled) uberdata_t *udp = self->ul_uberdata; ulwp_t *ulwp; int error; + int cancel_state; - enabled = enabled?1:0; + enabled = enabled? 1 : 0; top: if (tid == 0) { ulwp = self; @@ -2579,8 +2560,11 @@ top: lmutex_lock(&mutatorslock); if (mutatorsbarrier) { ulwp_unlock(ulwp, udp); + (void) _pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, + &cancel_state); while (mutatorsbarrier) (void) _cond_wait(&mutatorscv, &mutatorslock); + (void) _pthread_setcancelstate(cancel_state, NULL); lmutex_unlock(&mutatorslock); goto top; } @@ -2601,14 +2585,17 @@ void _thr_mutators_barrier(int enabled) { int oldvalue; + int cancel_state; lmutex_lock(&mutatorslock); /* * Wait if trying to set the barrier while it is already set. */ + (void) _pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); while (mutatorsbarrier && enabled) (void) _cond_wait(&mutatorscv, &mutatorslock); + (void) _pthread_setcancelstate(cancel_state, NULL); oldvalue = mutatorsbarrier; mutatorsbarrier = enabled; @@ -2751,11 +2738,15 @@ _thr_wait_mutator(thread_t tid, int dontwait) { uberdata_t *udp = curthread->ul_uberdata; ulwp_t *ulwp; + int cancel_state; int error = 0; + (void) _pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); top: - if ((ulwp = find_lwp(tid)) == NULL) + if ((ulwp = find_lwp(tid)) == NULL) { + (void) _pthread_setcancelstate(cancel_state, NULL); return (ESRCH); + } if (!ulwp->ul_mutator) error = EINVAL; @@ -2772,6 +2763,7 @@ top: } ulwp_unlock(ulwp, udp); + (void) _pthread_setcancelstate(cancel_state, NULL); return (error); } |