727 lines
23 KiB
C
Executable File
727 lines
23 KiB
C
Executable File
/* Copyright (c) 1993 SMI */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SMI */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
#ifndef _LIBTHREAD_H
|
|
#define _LIBTHREAD_H
|
|
|
|
#pragma ident "@(#)libthread.h 1.82 95/10/06 SMI"
|
|
|
|
/*
|
|
* libthread.h:
|
|
* struct thread and struct lwp definitions.
|
|
*/
|
|
#include <signal.h>
|
|
#include <siginfo.h>
|
|
#include <sys/ucontext.h>
|
|
#include <sys/reg.h>
|
|
#include <sys/param.h>
|
|
#include <sys/asm_linkage.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <pthread.h>
|
|
#include <thread.h>
|
|
#include <sys/synch.h>
|
|
#include <synch32.h>
|
|
#include <sys/lwp.h>
|
|
#include <utrace.h>
|
|
#include <debug.h>
|
|
#include <machlibthread.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/*
|
|
* thread stack layout.
|
|
*
|
|
* ----------------- high address
|
|
* | |
|
|
* | struct thread |
|
|
* | |
|
|
* | |
|
|
* | |
|
|
* | tls |
|
|
* | |
|
|
* -----------------
|
|
* | | <- thread stack bottom
|
|
* | |
|
|
* | |
|
|
* | |
|
|
* | |
|
|
* ----------------- low address
|
|
*/
|
|
|
|
/*
|
|
* default stack allocation parameters
|
|
*
|
|
* DEFAULTSTACK is defined as 1mb
|
|
*/
|
|
#define DEFAULTSTACK 0x100000 /* 1 MB stacks */
|
|
#define DAEMON_STACK 0x2000 /* 8K stacks for daemons */
|
|
|
|
#define BPW 32 /* number of bits per word */
|
|
#define DEFAULTSTACKINCR 8
|
|
#define MAXSTACKS 16
|
|
#ifdef TLS
|
|
extern int _etls;
|
|
#define MINSTACK (SA(MINFRAME + (int)&_etls))
|
|
#else
|
|
#define MINSTACK (SA(sizeof (struct thread) + 512))
|
|
#endif
|
|
|
|
/*
|
|
* default stack cache definition.
|
|
*/
|
|
typedef struct _stkcache {
|
|
int size;
|
|
char *next;
|
|
int busy;
|
|
cond_t cv;
|
|
} stkcache_t;
|
|
|
|
extern stkcache_t _defaultstkcache;
|
|
extern mutex_t _stkcachelock;
|
|
|
|
/*
|
|
* thread priority range.
|
|
*/
|
|
#define THREAD_MIN_PRIORITY 0 /* minimum scheduling pri */
|
|
#define THREAD_MAX_PRIORITY 127 /* max scheduling priority */
|
|
#define NPRI (THREAD_MAX_PRIORITY - THREAD_MIN_PRIORITY+1)
|
|
#define MAXRUNWORD (NPRI/BPW)
|
|
#define IDLE_THREAD_PRI -1 /* idle thread's priority */
|
|
|
|
/*
|
|
* Is thread temporarily bound to this LWP?
|
|
*/
|
|
#define ISTEMPBOUND(t) (((t)->t_flag & T_TEMPBOUND))
|
|
|
|
/*
|
|
* used to implement a callout mechanism.
|
|
*/
|
|
typedef struct callo {
|
|
thread_t tid;
|
|
char flag;
|
|
char running;
|
|
cond_t waiting;
|
|
struct timeval time;
|
|
void (*func)();
|
|
int arg;
|
|
struct callo *forw;
|
|
struct callo *backw;
|
|
} callo_t;
|
|
|
|
/* callout flags */
|
|
#define CO_TIMER_OFF 0
|
|
#define CO_TIMEDOUT 1
|
|
#define CO_TIMER_ON 2
|
|
|
|
#define ISTIMEDOUT(x) ((x)->flag == CO_TIMEDOUT)
|
|
|
|
typedef char thstate_t;
|
|
|
|
/*
|
|
* thread internal structure
|
|
*
|
|
* READ THIS NOTE IF YOU'RE PLANNING ON ADDING ANYTHING TO THIS
|
|
* STRUCTURE:
|
|
* libaio is dependent on the size of struct thread. if you
|
|
* are enlarging its size, always make sure that the "structure
|
|
* aio_worker" contains enough padding to hold a thread struct.
|
|
* you'll see that the first field of this structure is a character
|
|
* array of some number of pad bytes. you'll find the aio_worker
|
|
* structure in lib/libaio/common/libaio.h.
|
|
*/
|
|
typedef struct thread {
|
|
struct thread *t_link; /* run/sleep queue */
|
|
char *t_stk; /* stack base */
|
|
unsigned int t_stksize; /* size of stack */
|
|
char *t_tls; /* pointer to thread local storage */
|
|
resumestate_t t_resumestate; /* any extra state needed by resume */
|
|
long t_startpc; /* start func called by thr_create() */
|
|
thread_t t_tid; /* thread id */
|
|
lwpid_t t_lwpid; /* lwp id */
|
|
int t_usropts; /* usr options, (THR_BOUND, ...) */
|
|
int t_flag; /* flags, (T_ALLOCSTK, T_PARK) */
|
|
_cleanup_t *t_clnup_hdr; /* head to cleanup handlers list */
|
|
int t_pri; /* scheduling priority */
|
|
/* Keep following 8 fields together. See _clean_thread() */
|
|
thstate_t t_state; /* thread state */
|
|
char t_nosig; /* block signal handlers */
|
|
char t_stop; /* stop thread when set */
|
|
char t_preempt; /* preempt thread when set */
|
|
char t_schedlocked; /* flag set, thread holding schedlock */
|
|
char t_bdirpend; /* pending directed bounced signals */
|
|
char t_pending; /* set when t_psig is not empty */
|
|
char t_sig; /* signal rcvd in critical section */
|
|
/* cancel stuff - keep follwing 4 fields togather */
|
|
char t_can_pending;
|
|
char t_can_state;
|
|
char t_can_type;
|
|
char t_cancelable;
|
|
/* cancel stuff word finish */
|
|
sigset_t t_hold; /* per thread signal mask */
|
|
sigset_t t_psig; /* pending signals */
|
|
sigset_t t_ssig; /* signals sent, still pending */
|
|
sigset_t t_bsig; /* sigs bounced to this thread's lwp */
|
|
char *t_wchan; /* sleep wchan */
|
|
void *t_exitstat; /* exit status - non-detached threads */
|
|
mutex_t *t_handoff; /* mutex hand off for cv_signal() */
|
|
lwp_sema_t t_park; /* used to park threads */
|
|
sigset_t t_olmask; /* lwp mask when deferred sig taken */
|
|
siginfo_t t_si; /* siginfo for deferred signal */
|
|
struct thread *t_idle; /* pointer to an idle thread */
|
|
struct callo t_itimer_callo; /* alarm callout (per thread) */
|
|
struct callo t_cv_callo; /* cv_timedwait callout (per thread) */
|
|
struct itimerval t_realitimer; /* real time interval timer */
|
|
struct thread *t_next; /* circular queue of all threads */
|
|
struct thread *t_prev;
|
|
/* only multiplexing threads use the following fields */
|
|
mutex_t t_lock; /* locked when loaded into a LWP */
|
|
struct thread *t_iforw; /* circular queue of idling threads */
|
|
struct thread *t_ibackw;
|
|
struct thread *t_forw; /* circular queue of ONPROC threads */
|
|
struct thread *t_backw;
|
|
int t_errno; /* thread specific errno */
|
|
int t_rtldbind; /* dynamic linking flags */
|
|
/* PROBE_SUPPORT begin */
|
|
void *t_tpdp; /* thread probe data pointer */
|
|
/* PROBE_SUPPORT end */
|
|
} uthread_t;
|
|
|
|
/*
|
|
* thread states
|
|
*/
|
|
#define TS_SLEEP 1
|
|
#define TS_RUN 2
|
|
#define TS_DISP 3
|
|
#define TS_ONPROC 4
|
|
#define TS_STOPPED 5
|
|
#define TS_ZOMB 6
|
|
|
|
/*
|
|
* t_flag values
|
|
*/
|
|
#define T_ALLOCSTK 0x1 /* thread library allocated thread's stack */
|
|
#define T_LWPDIRSIGS 0x2 /* thread has called setitimer(2) VIRT, PROF */
|
|
#define T_PARKED 0x4 /* thread is parked on its LWP */
|
|
#define T_PREEMPT 0x8 /* thread has a pending preemption */
|
|
#define T_DONTPREEMPT 0x10 /* suspend pre-emption until cleared */
|
|
#define T_INTR 0x20 /* sleep interrupted by an unmasked signal */
|
|
#define T_IDLETHREAD 0x40 /* thread is an idle thread */
|
|
#define T_INSIGLWP 0x80 /* thread is in siglwp handler */
|
|
#define T_IDLE 0x100 /* thread is idle */
|
|
#define T_OFFPROC 0x200 /* thread is dispatchable */
|
|
#define T_ZOMBIE 0x400 /* thread is on zombie queue */
|
|
#define T_SIGWAIT 0x800 /* thread is in a sigwait(2) */
|
|
#define T_TEMPBOUND 0x1000 /* thread is temporarily bound to the lwp */
|
|
#define T_INTERNAL 0x2000 /* an internal libthread daemon thread */
|
|
#define T_2BZOMBIE 0x4000 /* thread is on the way to zombie queue */
|
|
#define T_BSSIG 0x8000 /* thread's lwp has pending bounced signals */
|
|
#define T_WAITCV 0x10000 /* thread is/was asleep for a condition var */
|
|
#define T_EXUNWIND 0x20000 /* thread is exiting due to cancellation */
|
|
|
|
/* t_can_state values */
|
|
#define TC_DISABLE -1 /* disable cancellation */
|
|
#define TC_ENABLE 00 /* enable cancellation */
|
|
|
|
/* t_can_type values */
|
|
#define TC_ASYNCHRONOUS -1 /* async cancelable */
|
|
#define TC_DEFERRED 00 /* deferred cancelable */
|
|
|
|
/* t_cancelable values */
|
|
#define TC_CANCELABLE -1 /* thread is in cancellation point */
|
|
|
|
/* t_can_pending values */
|
|
#define TC_PENDING -1 /* cancellation pending on thread */
|
|
|
|
/*
|
|
* Checks if thread was created with the DETACHED flag set.
|
|
*/
|
|
#define DETACHED(t) ((t)->t_usropts & THR_DETACHED)
|
|
|
|
/*
|
|
* Is thread permanently bound to a LWP?
|
|
*/
|
|
#define ISBOUND(t) ((t)->t_usropts & THR_BOUND)
|
|
|
|
/*
|
|
* Is thread parked on its LWP?
|
|
*/
|
|
#define ISPARKED(t) ((t)->t_flag & T_PARKED)
|
|
|
|
/*
|
|
* Does this thread have a preemption pending ?
|
|
*/
|
|
#define PREEMPTED(t) ((t)->t_flag & T_PREEMPT)
|
|
|
|
/*
|
|
* Is this thread stopped ?
|
|
*/
|
|
#define STOPPED(t) ((t)->t_stop)
|
|
|
|
/*
|
|
* Was thread created to be an idle thread?
|
|
*/
|
|
#define IDLETHREAD(t) ((t)->t_flag & T_IDLETHREAD)
|
|
|
|
/*
|
|
* Is thread on idle queue?
|
|
*/
|
|
#define ON_IDLE_Q(t) ((t)->t_iforw)
|
|
|
|
/*
|
|
* Is thread at some cancellation point?
|
|
*/
|
|
#define CANCELABLE(t) ((t)->t_cancelable == TC_CANCELABLE)
|
|
|
|
/*
|
|
* Is thread cancellation pending?
|
|
*/
|
|
#define CANCELPENDING(t) ((t)->t_can_pending == TC_PENDING)
|
|
|
|
/*
|
|
* Is thread cancellation enabled/disable?
|
|
*/
|
|
#define CANCELENABLE(t) ((t)->t_can_state == TC_ENABLE)
|
|
#define CANCELDISABLE(t) ((t)->t_can_state == TC_DISABLE)
|
|
|
|
/*
|
|
* Is thread deferred/async cancelable?
|
|
*/
|
|
#define CANCELDEFERED(t) ((t)->t_can_type == TC_DEFERRED)
|
|
#define CANCELASYNC(t) ((t)->t_can_type == TC_ASYNCHRONOUS)
|
|
|
|
/*
|
|
* Is thread on/off the _onprocq ?
|
|
*/
|
|
#define ONPROCQ(t) ((t)->t_forw != NULL && (t)->t_backw != NULL)
|
|
#define OFFPROCQ(t) ((t)->t_forw == NULL && (t)->t_backw == (t)->t_forw)
|
|
|
|
/* Assumes p >= 0 */
|
|
#define HASH_PRIORITY(p, index) index = p - THREAD_MIN_PRIORITY; \
|
|
|
|
#define _lock_bucket(ix) \
|
|
if (ix != -1) _lmutex_lock(&(_allthreads[ix].lock)); else
|
|
|
|
#define _unlock_bucket(ix) \
|
|
if (ix != -1) _lmutex_unlock(&(_allthreads[ix].lock)); else
|
|
|
|
/* convert a thread_t to a struct thread pointer */
|
|
#define THREAD(x) (((x) == 0) ? curthread : (uthread_t *)_idtot(x))
|
|
/*
|
|
* A relative time increment used to set the absolute time "cond_eot" to be
|
|
* sufficiently far into the future. cond_eot is used to validate the timeout
|
|
* argument to cond_timedwait().
|
|
*/
|
|
#define COND_REL_EOT 50000000
|
|
|
|
/* convert a thread to its lwpid */
|
|
#define LWPID(t) (t)->t_lwpid
|
|
|
|
|
|
#define ALLTHR_TBLSIZ 512
|
|
#define HASH_TID(tid) ((tid) == 0 ? -1 : (tid) % ALLTHR_TBLSIZ)
|
|
|
|
typedef struct thrtab {
|
|
uthread_t *first;
|
|
mutex_t lock;
|
|
} thrtab_t;
|
|
|
|
extern thrtab_t _allthreads[]; /* doubly linked list of all threads */
|
|
extern thread_t _lasttid; /* monotonically increasing global tid count */
|
|
extern mutex_t _tidlock; /* protects access to _lasttid */
|
|
extern int _totalthreads; /* total number of threads created */
|
|
extern int _userthreads; /* number of user created threads */
|
|
extern int _u2bzombies; /* u threads on their way 2b zombies */
|
|
extern int _d2bzombies; /* daemon threads on their way 2b zombies */
|
|
extern long _idlethread; /* address of IDLETHREAD */
|
|
extern uthread_t *_nidle; /* list of idling threads */
|
|
extern int _nidlecnt; /* number of threads idling */
|
|
extern int _onprocq_size; /* size of onproc Q */
|
|
extern int _nagewakecnt; /* number of awakened aging threads */
|
|
extern int _naging; /* number of aging threads running */
|
|
extern int _minlwps; /* min number of idle lwps */
|
|
extern int _nlwps; /* number of lwps in this pool. */
|
|
extern int _ndie; /* number of lwps to delete from this pool. */
|
|
extern int _nrunnable; /* number of threads on the run queue */
|
|
extern int _nthreads; /* number of unbound threads */
|
|
extern int _sigwaitingset; /* 1 if sigwaiting enabled; 0 if disabled */
|
|
extern struct thread *_lowestpri_th; /* the lowest priority running thread */
|
|
extern lwp_mutex_t _schedlock; /* protects runqs and sleepqs */
|
|
extern uthread_t *_onprocq; /* circular queue of ONPROC threads */
|
|
extern uthread_t *_zombies; /* circular queue of zombie threads */
|
|
extern cond_t _zombied; /* waiting for zombie threads */
|
|
extern int _zombiecnt; /* nunber of zombied threads */
|
|
extern lwp_cond_t _suspended; /* waiting for thread to suspend */
|
|
extern int _reapcnt; /* number of threads to be reaped */
|
|
extern lwp_mutex_t _reaplock; /* reaper thread's lock */
|
|
extern lwp_cond_t _untilreaped; /* wait until _reapcnt < high mark */
|
|
extern int _lpagesize; /* libthread pagesize initialized in _t0init */
|
|
extern sigset_t _allmasked; /* all maskable signals except SIGLWP masked */
|
|
extern sigset_t _totalmasked; /* all maskable signals masked */
|
|
extern int _maxpriq; /* index of highest priority dispq */
|
|
extern long _dqactmap[]; /* bit map of priority queues */
|
|
|
|
extern int _timerset; /* interval timer is set if timerset == 1 */
|
|
extern thread_t _co_tid; /* thread that does the callout processing */
|
|
extern int _co_set; /* create only one thread to run callouts */
|
|
extern int _calloutcnt; /* number of pending callouts */
|
|
extern callo_t *_calloutp; /* pointer to the callout queue */
|
|
extern mutex_t _calloutlock; /* protects queue of callouts */
|
|
extern thread_t __dynamic_tid; /* bound thread that handles SIGWAITING */
|
|
extern lwp_cond_t _aging; /* condition on which threads age */
|
|
|
|
extern uthread_t *_sched_owner;
|
|
extern int _sched_ownerpc;
|
|
extern struct thread _thread;
|
|
extern struct thread *_t0; /* the initial thread */
|
|
|
|
extern int _libpthread_loaded; /* indicates whether libpthread is loaded */
|
|
extern struct sigaction __alarm_sigaction; /* global sigaction for SIGALRM */
|
|
extern int _first_thr_create;
|
|
|
|
#ifdef TLS
|
|
#ifndef NOTHREAD
|
|
#pragma unshared (_thread);
|
|
#endif
|
|
#define curthread (&_thread)
|
|
#else
|
|
extern uthread_t *_curthread();
|
|
#define curthread (_curthread())
|
|
#endif
|
|
|
|
|
|
/*
|
|
* global mutexes, read-write and condition locks.
|
|
*/
|
|
extern mutex_t _schedlock; /* protects runq and sleepq */
|
|
extern lwp_mutex_t _sighandlerlock; /* protects signal handlers */
|
|
extern rwlock_t _lrw_lock;
|
|
|
|
/*
|
|
* sleep-wakeup hashing: Each entry in slpq[] points
|
|
* to the front and back of a linked list of sleeping processes.
|
|
* Processes going to sleep go to the back of the appropriate
|
|
* sleep queue and wakeprocs wakes them from front to back (so the
|
|
* first process to go to sleep on a given channel will be the first
|
|
* to run after a wakeup on that channel).
|
|
* NSLEEPQ must be a power of 2. Sqhash(x) is used to index into
|
|
* slpq[] based on the sleep channel.
|
|
*/
|
|
|
|
#define NSLEEPQ 64
|
|
#define slpqhash(X) (&_slpq[((int)X >> 4) & (NSLEEPQ - 1)])
|
|
|
|
struct slpq {
|
|
struct thread *sq_first;
|
|
struct thread *sq_last;
|
|
};
|
|
|
|
extern struct slpq _slpq[];
|
|
|
|
/*
|
|
* Reserve one bucket for all threads with priorities > THREAD_MAX_PRIORITY
|
|
* or less than THREAD_MIN_PRIORITY.
|
|
* NOTE : Currently, thread_priority() returns an error if there is an
|
|
* attempt to set a thread's priority out of this range, so the extra
|
|
* bucket is not really used.
|
|
*/
|
|
#define DISPQ_SIZE (NPRI + 1)
|
|
|
|
typedef struct dispq {
|
|
struct thread *dq_first;
|
|
struct thread *dq_last;
|
|
} dispq_t;
|
|
|
|
extern dispq_t _dispq[];
|
|
|
|
typedef void (*PFrV) (void *); /* pointer to function returning void */
|
|
|
|
/*
|
|
* Information common to all threads' TSD.
|
|
*/
|
|
struct tsd_common {
|
|
unsigned int nkeys; /* number of used keys */
|
|
unsigned int max_keys; /* number of allocated keys */
|
|
PFrV *destructors; /* array of per-key destructor funcs */
|
|
rwlock_t lock; /* lock for the above */
|
|
};
|
|
|
|
extern struct tsd_common tsd_common;
|
|
|
|
|
|
extern sigset_t _allunmasked;
|
|
extern sigset_t _cantmask;
|
|
extern sigset_t _lcantmask;
|
|
extern sigset_t _cantreset;
|
|
extern sigset_t _pmask; /* virtual process signal mask */
|
|
extern mutex_t _pmasklock; /* lock for v. process signal mask */
|
|
extern sigset_t _bpending; /* signals pending reassignment */
|
|
extern mutex_t _bpendinglock; /* mutex protecting _bpending */
|
|
extern cond_t _sigwait_cv;
|
|
extern int _cond_eot;
|
|
extern mutex_t _tsslock;
|
|
|
|
extern sigset_t _ignoredefault;
|
|
|
|
/*
|
|
* Signal test and manipulation macros.
|
|
*/
|
|
#define sigdiffset(s1, s2)\
|
|
(s1)->__sigbits[0] &= ~((s2)->__sigbits[0]); \
|
|
(s1)->__sigbits[1] &= ~((s2)->__sigbits[1]); \
|
|
(s1)->__sigbits[2] &= ~((s2)->__sigbits[2]); \
|
|
(s1)->__sigbits[3] &= ~((s2)->__sigbits[3])
|
|
|
|
/* Mask all signal except - SIGSTOP/SIGKILL/SILWP/SIGCANCEL */
|
|
#define maskallsigs(s) sigfillset((s)); \
|
|
sigdiffset((s), &_cantmask)
|
|
|
|
/* Mask all signal except - SIGSTOP/SIGKILL */
|
|
#define masktotalsigs(s) sigfillset((s)); \
|
|
sigdiffset((s), &_lcantmask)
|
|
|
|
#define sigcmpset(x, y) (((x)->__sigbits[0] ^ (y)->__sigbits[0]) || \
|
|
((x)->__sigbits[1] ^ (y)->__sigbits[1]) || \
|
|
((x)->__sigbits[2] ^ (y)->__sigbits[2]) || \
|
|
((x)->__sigbits[3] ^ (y)->__sigbits[3]))
|
|
|
|
/*
|
|
* Are signals in "s" being manipulated in the mask (o = oldmask; n = newmask)?
|
|
* Return true if yes, otherwise false.
|
|
*/
|
|
#define changesigs(o, n, s)\
|
|
((((o)->__sigbits[0] ^ (n)->__sigbits[0]) & (s)->__sigbits[0]) || \
|
|
(((o)->__sigbits[1] ^ (n)->__sigbits[1]) & (s)->__sigbits[1]) || \
|
|
(((o)->__sigbits[2] ^ (n)->__sigbits[2]) & (s)->__sigbits[2]) || \
|
|
(((o)->__sigbits[3] ^ (n)->__sigbits[3]) & (s)->__sigbits[3]))
|
|
|
|
#define sigorset(s1, s2) (s1)->__sigbits[0] |= (s2)->__sigbits[0]; \
|
|
(s1)->__sigbits[1] |= (s2)->__sigbits[1]; \
|
|
(s1)->__sigbits[2] |= (s2)->__sigbits[2]; \
|
|
(s1)->__sigbits[3] |= (s2)->__sigbits[3];
|
|
|
|
#define sigisempty(s)\
|
|
((s)->__sigbits[0] == 0 && (s)->__sigbits[1] == 0 &&\
|
|
(s)->__sigbits[2] == 0 && (s)->__sigbits[3] == 0)
|
|
|
|
|
|
/*
|
|
* following macro copied from sys/signal.h since inside #ifdef _KERNEL there.
|
|
*/
|
|
#define sigmask(n) ((unsigned int)1 << (((n) - 1) & (32 - 1)))
|
|
|
|
/*
|
|
* masksmaller(sigset_t *m1, sigset_t *m2)
|
|
* return true if m1 is smaller (less restrictive) than m2
|
|
*/
|
|
#define masksmaller(m1, m2) \
|
|
((~((m1)->__sigbits[0]) & (m2)->__sigbits[0]) ||\
|
|
(~((m1)->__sigbits[1]) & (m2)->__sigbits[1]) ||\
|
|
(~((m1)->__sigbits[2]) & (m2)->__sigbits[2]) ||\
|
|
(~((m1)->__sigbits[3]) & (m2)->__sigbits[3]))
|
|
|
|
#define sigand(x, y) (\
|
|
((x)->__sigbits[0] & (y)->__sigbits[0]) ||\
|
|
((x)->__sigbits[1] & (y)->__sigbits[1]) ||\
|
|
((x)->__sigbits[2] & (y)->__sigbits[2]) ||\
|
|
((x)->__sigbits[3] & (y)->__sigbits[3]))
|
|
|
|
#define sigandset(a, x, y) \
|
|
(a)->__sigbits[0] = (x)->__sigbits[0] & (y)->__sigbits[0];\
|
|
(a)->__sigbits[1] = (x)->__sigbits[1] & (y)->__sigbits[1]; \
|
|
(a)->__sigbits[2] = (x)->__sigbits[2] & (y)->__sigbits[2]; \
|
|
(a)->__sigbits[3] = (x)->__sigbits[3] & (y)->__sigbits[3]
|
|
|
|
/*
|
|
* sparc v7 has no native swap instruction. It is emulated on the ss1s, ipcs,
|
|
* etc. So, use the SIGSEGV interpositioning solution to solve the
|
|
* mutex_unlock() problem of reading the waiter bit after the lock is freed.
|
|
* Add other architectures (say, arch_foo) here which do not have atomic swap
|
|
* instructions. This would result in the conditional define changing to:
|
|
* "#if defined (__sparc) || defined(sparc) || defined(arch_foo)"
|
|
*/
|
|
|
|
#if defined(__sparc) || defined(sparc)
|
|
extern __wrd; /* label in _mutex_unlock_asm() needed for SEGV handler */
|
|
#define NO_SWAP_INSTRUCTION
|
|
extern int __advance_pc_required(ucontext_t *, siginfo_t *);
|
|
extern int __munlock_segv(int, struct thread *, ucontext_t *);
|
|
void __libthread_segvhdlr(int sig, siginfo_t *sip, ucontext_t *uap,
|
|
sigset_t *omask);
|
|
extern struct sigaction __segv_sigaction; /* global sigaction for SEGV */
|
|
#endif
|
|
|
|
extern sigset_t __lwpdirsigs;
|
|
extern sigset_t _null_sigset;
|
|
sigset_t _tpmask;
|
|
|
|
#define dbg_sigaddset(m, s)
|
|
#define dbg_delset(m, s)
|
|
#define pmaskok(tm, pm) (1)
|
|
|
|
extern void (*_tsiguhandler[])();
|
|
|
|
/*
|
|
* ANSI PROTOTYPES of internal global functions
|
|
*/
|
|
|
|
|
|
uthread_t *_idtot(thread_t tid);
|
|
void _dynamiclwps();
|
|
void _mutex_sema_unlock(mutex_t *mp);
|
|
void _lmutex_unlock(mutex_t *mp);
|
|
int _lmutex_trylock(mutex_t *mp);
|
|
void _lmutex_lock(mutex_t *mp);
|
|
void _lprefork_handler();
|
|
void _lpostfork_child_handler();
|
|
void _lpostfork_parent_handler();
|
|
int _lpthread_atfork();
|
|
int _lrw_rdlock(rwlock_t *rwlp);
|
|
int _lrw_wrlock(rwlock_t *rwlp);
|
|
int _lrw_unlock(rwlock_t *rwlp);
|
|
int _thrp_kill_unlocked(uthread_t *t, int ix,
|
|
int sig, lwpid_t *lwpidp);
|
|
int _thr_main(void);
|
|
int _setcallout(callo_t *cop, thread_t tid, const struct timeval *tv,
|
|
void (*func)(), int arg);
|
|
int _rmcallout(callo_t *cop);
|
|
void _callin(int sig, siginfo_t *sip, ucontext_t *uap, sigset_t *omask);
|
|
void _t_block(caddr_t chan);
|
|
int _t_release(caddr_t chan, u_char *waiters, int);
|
|
void _t_release_all(caddr_t chan);
|
|
void _unsleep(struct thread *t);
|
|
void _setrun(struct thread *t);
|
|
void _dopreempt();
|
|
void _preempt(uthread_t *t, pri_t pri);
|
|
struct thread *_choose_thread(pri_t pri);
|
|
int _lwp_exec(struct thread *t, long npc, caddr_t sp, void (*fcn)(),
|
|
int flags, lwpid_t *retlwpid);
|
|
int _new_lwp(struct thread *t, void (*func)());
|
|
int _alloc_stack(int size, caddr_t *sp);
|
|
void _free_stack(caddr_t addr, int size);
|
|
int _swtch(int dontsave);
|
|
void _qswtch();
|
|
void _age();
|
|
void _onproc_deq(uthread_t *t);
|
|
void _onproc_enq(uthread_t *t);
|
|
void _unpark(uthread_t *t);
|
|
void _setrq(uthread_t *t);
|
|
int _dispdeq(uthread_t *t);
|
|
uthread_t *_idle_thread_create();
|
|
void _thread_destroy(uthread_t *t, int ix);
|
|
void _thread_free(uthread_t *t);
|
|
int _alloc_thread(caddr_t stk, int stksize, struct thread **tp);
|
|
int _thread_call(uthread_t *t, void (*fcn)(), void *arg);
|
|
void _thread_ret(struct thread *t, void (*fcn)());
|
|
void _thread_start();
|
|
void _reapq_add(uthread_t *t);
|
|
void _reaper_create();
|
|
void _reap_wait(cond_t *cvp);
|
|
void _reap_wait_cancel(cond_t *cvp);
|
|
void _reap_lock();
|
|
void _reap_unlock();
|
|
void _sigon();
|
|
void _sigoff();
|
|
void _t0init();
|
|
void _deliversigs(const sigset_t *sigs);
|
|
int _sigredirect(int sig);
|
|
void _siglwp(int sig, siginfo_t *sip, ucontext_t *uap);
|
|
void _sigcancel(int sig, siginfo_t *sip, ucontext_t *uap);
|
|
void _sigwaiting_enabled();
|
|
int _hibit(register unsigned long i);
|
|
int _fsig(sigset_t *s);
|
|
void _sigmaskset(sigset_t *s1, sigset_t *s2, sigset_t *s3);
|
|
int _blocking(sigset_t *sent, sigset_t *old, const sigset_t *new,
|
|
sigset_t *resend);
|
|
void _resume_ret(uthread_t *oldthread);
|
|
void _destroy_tsd(void);
|
|
void _resetlib(void);
|
|
int _assfail(char *, char *, int);
|
|
int _setsighandler(int sig, const struct sigaction *nact,
|
|
struct sigaction *oact);
|
|
void __sighandler_lock();
|
|
void __sighandler_unlock();
|
|
void _initsigs();
|
|
void _dynamic_create();
|
|
void _cancel(uthread_t *t);
|
|
void _canceloff(void);
|
|
void _cancelon(void);
|
|
void _prefork_handler();
|
|
void _postfork_parent_handler();
|
|
void _postfork_child_handler();
|
|
void _tcancel_all(void *arg);
|
|
void _thrp_exit();
|
|
void _thr_exit_common(void *sts, int ex);
|
|
extern int (*__sigtimedwait_trap)(const sigset_t *, siginfo_t *,
|
|
const struct timespec *);
|
|
extern int (*__sigsuspend_trap)(const sigset_t *);
|
|
|
|
/*
|
|
* prototype of all the exported functions of internal
|
|
* version of libthread calls. We need this since there
|
|
* is no synonyms_mt.h any more.
|
|
*/
|
|
|
|
int _cond_init(cond_t *cvp, int type, void *arg);
|
|
int _cond_destroy(cond_t *cvp);
|
|
int _cond_timedwait(cond_t *cvp, mutex_t *mp, timestruc_t *ts);
|
|
int _cond_wait(cond_t *cvp, mutex_t *mp);
|
|
int _cond_signal(cond_t *cvp);
|
|
int _cond_broadcast(cond_t *cvp);
|
|
|
|
int _mutex_init(mutex_t *mp, int type, void *arg);
|
|
int _mutex_destroy(mutex_t *mp);
|
|
int _mutex_lock(mutex_t *mp);
|
|
int _mutex_unlock(mutex_t *mp);
|
|
int _mutex_trylock(mutex_t *mp);
|
|
void _mutex_op_lock(mutex_t *mp);
|
|
void _mutex_op_unlock(mutex_t *mp);
|
|
|
|
int _rwlock_init(rwlock_t *rwlp, int type, void *arg);
|
|
int _rwlock_destroy(rwlock_t *rwlp);
|
|
int _rw_rdlock(rwlock_t *rwlp);
|
|
int _rw_wrlock(rwlock_t *rwlp);
|
|
int _rw_unlock(rwlock_t *rwlp);
|
|
int _rw_tryrdlock(rwlock_t *rwlp);
|
|
int _rw_trywrlock(rwlock_t *rwlp);
|
|
|
|
int _sema_init(sema_t *sp, unsigned int count, int type, void *arg);
|
|
int _sema_destroy(sema_t *sp);
|
|
int _sema_wait(sema_t *sp);
|
|
int _sema_trywait(sema_t *sp);
|
|
int _sema_post(sema_t *sp);
|
|
|
|
int _thr_create(void *stk, size_t stksize, void *(*func)(void *),
|
|
void *arg, long flags, thread_t *new_thread);
|
|
int _thrp_create(void *stk, size_t stksize, void *(*func)(void *),
|
|
void *arg, long flags, thread_t *new_thread, int prio);
|
|
int _thr_join(thread_t tid, thread_t *departed, void **status);
|
|
int _thr_setconcurrency(int n);
|
|
int _thr_getconcurrency();
|
|
void _thr_exit(void *status);
|
|
thread_t _thr_self();
|
|
int _thr_sigsetmask(int how, const sigset_t *set, sigset_t *oset);
|
|
int _thr_kill(thread_t tid, int sig);
|
|
int _thr_suspend(thread_t tid);
|
|
int _thr_continue(thread_t tid);
|
|
void _thr_yield();
|
|
int _thr_setprio(thread_t tid, int newpri);
|
|
int _thr_getprio(thread_t tid, int *pri);
|
|
int _thr_keycreate(thread_key_t *pkey, void (*destructor)(void *));
|
|
int _thr_key_delete(thread_key_t key);
|
|
int _thr_getspecific(thread_key_t key, void **valuep);
|
|
int _thr_setspecific(unsigned int key, void *value);
|
|
size_t _thr_min_stack();
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* _LIBTHREAD_H */
|