diff options
Diffstat (limited to 'lib/libkse/thread/thr_private.h')
-rw-r--r-- | lib/libkse/thread/thr_private.h | 1294 |
1 files changed, 0 insertions, 1294 deletions
diff --git a/lib/libkse/thread/thr_private.h b/lib/libkse/thread/thr_private.h deleted file mode 100644 index 46f6e80..0000000 --- a/lib/libkse/thread/thr_private.h +++ /dev/null @@ -1,1294 +0,0 @@ -/* - * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Private thread definitions for the uthread kernel. - * - * $FreeBSD$ - */ - -#ifndef _THR_PRIVATE_H -#define _THR_PRIVATE_H - -/* - * Include files. - */ -#include <setjmp.h> -#include <signal.h> -#include <stdio.h> -#include <sys/queue.h> -#include <sys/types.h> -#include <sys/time.h> -#include <sys/cdefs.h> -#include <sys/kse.h> -#include <sched.h> -#include <ucontext.h> -#include <unistd.h> -#include <pthread.h> -#include <pthread_np.h> - -#ifndef LIBTHREAD_DB -#include "lock.h" -#include "pthread_md.h" -#endif - - -/* - * Evaluate the storage class specifier. - */ -#ifdef GLOBAL_PTHREAD_PRIVATE -#define SCLASS -#define SCLASS_PRESET(x...) = x -#else -#define SCLASS extern -#define SCLASS_PRESET(x...) -#endif - -/* - * Kernel fatal error handler macro. - */ -#define PANIC(string) _thr_exit(__FILE__, __LINE__, string) - - -/* Output debug messages like this: */ -#ifdef STDOUT_FILENO -#define stdout_debug(...) _thread_printf(STDOUT_FILENO, __VA_ARGS__) -#endif -#ifdef STDERR_FILENO -#define stderr_debug(...) _thread_printf(STDERR_FILENO, __VA_ARGS__) -#endif - -#define DBG_MUTEX 0x0001 -#define DBG_SIG 0x0002 -#define DBG_INFO_DUMP 0x0004 - -#ifdef _PTHREADS_INVARIANTS -#define THR_ASSERT(cond, msg) do { \ - if (!(cond)) \ - PANIC(msg); \ -} while (0) -#else -#define THR_ASSERT(cond, msg) -#endif - -/* - * State change macro without scheduling queue change: - */ -#define THR_SET_STATE(thrd, newstate) do { \ - (thrd)->state = newstate; \ - (thrd)->fname = __FILE__; \ - (thrd)->lineno = __LINE__; \ -} while (0) - - -#define TIMESPEC_ADD(dst, src, val) \ - do { \ - (dst)->tv_sec = (src)->tv_sec + (val)->tv_sec; \ - (dst)->tv_nsec = (src)->tv_nsec + (val)->tv_nsec; \ - if ((dst)->tv_nsec >= 1000000000) { \ - (dst)->tv_sec++; \ - (dst)->tv_nsec -= 1000000000; \ - } \ - } while (0) - -#define TIMESPEC_SUB(dst, src, val) \ - do { \ - (dst)->tv_sec = (src)->tv_sec - (val)->tv_sec; \ - (dst)->tv_nsec = (src)->tv_nsec - (val)->tv_nsec; \ - if ((dst)->tv_nsec < 0) { \ - (dst)->tv_sec--; \ - (dst)->tv_nsec += 1000000000; \ - } \ - } while (0) - -/* - * Priority queues. - * - * XXX It'd be nice if these were contained in uthread_priority_queue.[ch]. - */ -typedef struct pq_list { - TAILQ_HEAD(, pthread) pl_head; /* list of threads at this priority */ - TAILQ_ENTRY(pq_list) pl_link; /* link for queue of priority lists */ - int pl_prio; /* the priority of this list */ - int pl_queued; /* is this in the priority queue */ -} pq_list_t; - -typedef struct pq_queue { - TAILQ_HEAD(, pq_list) pq_queue; /* queue of priority lists */ - pq_list_t *pq_lists; /* array of all priority lists */ - int pq_size; /* number of priority lists */ -#define PQF_ACTIVE 0x0001 - int pq_flags; - int pq_threads; -} pq_queue_t; - -/* - * Each KSEG has a scheduling queue. For now, threads that exist in their - * own KSEG (system scope) will get a full priority queue. In the future - * this can be optimized for the single thread per KSEG case. - */ -struct sched_queue { - pq_queue_t sq_runq; - TAILQ_HEAD(, pthread) sq_waitq; /* waiting in userland */ -}; - -typedef struct kse_thr_mailbox *kse_critical_t; - -struct kse_group; - -#define MAX_KSE_LOCKLEVEL 5 -struct kse { - /* -- location and order specific items for gdb -- */ - struct kcb *k_kcb; - struct pthread *k_curthread; /* current thread */ - struct kse_group *k_kseg; /* parent KSEG */ - struct sched_queue *k_schedq; /* scheduling queue */ - /* -- end of location and order specific items -- */ - TAILQ_ENTRY(kse) k_qe; /* KSE list link entry */ - TAILQ_ENTRY(kse) k_kgqe; /* KSEG's KSE list entry */ - /* - * Items that are only modified by the kse, or that otherwise - * don't need to be locked when accessed - */ - struct lock k_lock; - struct lockuser k_lockusers[MAX_KSE_LOCKLEVEL]; - int k_locklevel; - stack_t k_stack; - int k_flags; -#define KF_STARTED 0x0001 /* kernel kse created */ -#define KF_INITIALIZED 0x0002 /* initialized on 1st upcall */ -#define KF_TERMINATED 0x0004 /* kse is terminated */ -#define KF_IDLE 0x0008 /* kse is idle */ -#define KF_SWITCH 0x0010 /* thread switch in UTS */ - int k_error; /* syscall errno in critical */ - int k_cpu; /* CPU ID when bound */ - int k_sigseqno; /* signal buffered count */ -}; - -#define KSE_SET_IDLE(kse) ((kse)->k_flags |= KF_IDLE) -#define KSE_CLEAR_IDLE(kse) ((kse)->k_flags &= ~KF_IDLE) -#define KSE_IS_IDLE(kse) (((kse)->k_flags & KF_IDLE) != 0) -#define KSE_SET_SWITCH(kse) ((kse)->k_flags |= KF_SWITCH) -#define KSE_CLEAR_SWITCH(kse) ((kse)->k_flags &= ~KF_SWITCH) -#define KSE_IS_SWITCH(kse) (((kse)->k_flags & KF_SWITCH) != 0) - -/* - * Each KSE group contains one or more KSEs in which threads can run. - * At least for now, there is one scheduling queue per KSE group; KSEs - * within the same KSE group compete for threads from the same scheduling - * queue. A scope system thread has one KSE in one KSE group; the group - * does not use its scheduling queue. - */ -struct kse_group { - TAILQ_HEAD(, kse) kg_kseq; /* list of KSEs in group */ - TAILQ_HEAD(, pthread) kg_threadq; /* list of threads in group */ - TAILQ_ENTRY(kse_group) kg_qe; /* link entry */ - struct sched_queue kg_schedq; /* scheduling queue */ - struct lock kg_lock; - int kg_threadcount; /* # of assigned threads */ - int kg_ksecount; /* # of assigned KSEs */ - int kg_idle_kses; - int kg_flags; -#define KGF_SINGLE_THREAD 0x0001 /* scope system kse group */ -#define KGF_SCHEDQ_INITED 0x0002 /* has an initialized schedq */ -}; - -/* - * Add/remove threads from a KSE's scheduling queue. - * For now the scheduling queue is hung off the KSEG. - */ -#define KSEG_THRQ_ADD(kseg, thr) \ -do { \ - TAILQ_INSERT_TAIL(&(kseg)->kg_threadq, thr, kle);\ - (kseg)->kg_threadcount++; \ -} while (0) - -#define KSEG_THRQ_REMOVE(kseg, thr) \ -do { \ - TAILQ_REMOVE(&(kseg)->kg_threadq, thr, kle); \ - (kseg)->kg_threadcount--; \ -} while (0) - - -/* - * Lock acquire and release for KSEs. - */ -#define KSE_LOCK_ACQUIRE(kse, lck) \ -do { \ - if ((kse)->k_locklevel < MAX_KSE_LOCKLEVEL) { \ - (kse)->k_locklevel++; \ - _lock_acquire((lck), \ - &(kse)->k_lockusers[(kse)->k_locklevel - 1], 0); \ - } \ - else \ - PANIC("Exceeded maximum lock level"); \ -} while (0) - -#define KSE_LOCK_RELEASE(kse, lck) \ -do { \ - if ((kse)->k_locklevel > 0) { \ - _lock_release((lck), \ - &(kse)->k_lockusers[(kse)->k_locklevel - 1]); \ - (kse)->k_locklevel--; \ - } \ -} while (0) - -/* - * Lock our own KSEG. - */ -#define KSE_LOCK(curkse) \ - KSE_LOCK_ACQUIRE(curkse, &(curkse)->k_kseg->kg_lock) -#define KSE_UNLOCK(curkse) \ - KSE_LOCK_RELEASE(curkse, &(curkse)->k_kseg->kg_lock) - -/* - * Lock a potentially different KSEG. - */ -#define KSE_SCHED_LOCK(curkse, kseg) \ - KSE_LOCK_ACQUIRE(curkse, &(kseg)->kg_lock) -#define KSE_SCHED_UNLOCK(curkse, kseg) \ - KSE_LOCK_RELEASE(curkse, &(kseg)->kg_lock) - -/* - * Waiting queue manipulation macros (using pqe link): - */ -#define KSE_WAITQ_REMOVE(kse, thrd) \ -do { \ - if (((thrd)->flags & THR_FLAGS_IN_WAITQ) != 0) { \ - TAILQ_REMOVE(&(kse)->k_schedq->sq_waitq, thrd, pqe); \ - (thrd)->flags &= ~THR_FLAGS_IN_WAITQ; \ - } \ -} while (0) -#define KSE_WAITQ_INSERT(kse, thrd) kse_waitq_insert(thrd) -#define KSE_WAITQ_FIRST(kse) TAILQ_FIRST(&(kse)->k_schedq->sq_waitq) - -#define KSE_WAKEUP(kse) kse_wakeup(&(kse)->k_kcb->kcb_kmbx) - -/* - * TailQ initialization values. - */ -#define TAILQ_INITIALIZER { NULL, NULL } - -/* - * lock initialization values. - */ -#define LCK_INITIALIZER { NULL, NULL, LCK_DEFAULT } - -struct pthread_mutex { - /* - * Lock for accesses to this structure. - */ - struct lock m_lock; - enum pthread_mutextype m_type; - int m_protocol; - TAILQ_HEAD(mutex_head, pthread) m_queue; - struct pthread *m_owner; - long m_flags; - int m_count; - int m_refcount; - - /* - * Used for priority inheritence and protection. - * - * m_prio - For priority inheritence, the highest active - * priority (threads locking the mutex inherit - * this priority). For priority protection, the - * ceiling priority of this mutex. - * m_saved_prio - mutex owners inherited priority before - * taking the mutex, restored when the owner - * unlocks the mutex. - */ - int m_prio; - int m_saved_prio; - - /* - * Link for list of all mutexes a thread currently owns. - */ - TAILQ_ENTRY(pthread_mutex) m_qe; -}; - -/* - * Flags for mutexes. - */ -#define MUTEX_FLAGS_PRIVATE 0x01 -#define MUTEX_FLAGS_INITED 0x02 -#define MUTEX_FLAGS_BUSY 0x04 - -/* - * Static mutex initialization values. - */ -#define PTHREAD_MUTEX_STATIC_INITIALIZER \ - { LCK_INITIALIZER, PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, \ - TAILQ_INITIALIZER, NULL, MUTEX_FLAGS_PRIVATE, 0, 0, 0, 0, \ - TAILQ_INITIALIZER } - -struct pthread_mutex_attr { - enum pthread_mutextype m_type; - int m_protocol; - int m_ceiling; - long m_flags; -}; - -#define PTHREAD_MUTEXATTR_STATIC_INITIALIZER \ - { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, MUTEX_FLAGS_PRIVATE } - -/* - * Condition variable definitions. - */ -enum pthread_cond_type { - COND_TYPE_FAST, - COND_TYPE_MAX -}; - -struct pthread_cond { - /* - * Lock for accesses to this structure. - */ - struct lock c_lock; - enum pthread_cond_type c_type; - TAILQ_HEAD(cond_head, pthread) c_queue; - struct pthread_mutex *c_mutex; - long c_flags; - long c_seqno; -}; - -struct pthread_cond_attr { - enum pthread_cond_type c_type; - long c_flags; -}; - -struct pthread_barrier { - pthread_mutex_t b_lock; - pthread_cond_t b_cond; - int b_count; - int b_waiters; - int b_generation; -}; - -struct pthread_barrierattr { - int pshared; -}; - -struct pthread_spinlock { - volatile int s_lock; - pthread_t s_owner; -}; - -/* - * Flags for condition variables. - */ -#define COND_FLAGS_PRIVATE 0x01 -#define COND_FLAGS_INITED 0x02 -#define COND_FLAGS_BUSY 0x04 - -/* - * Static cond initialization values. - */ -#define PTHREAD_COND_STATIC_INITIALIZER \ - { LCK_INITIALIZER, COND_TYPE_FAST, TAILQ_INITIALIZER, \ - NULL, NULL, 0, 0 } - -/* - * Cleanup definitions. - */ -struct pthread_cleanup { - struct pthread_cleanup *next; - void (*routine) (void *); - void *routine_arg; - int onstack; -}; - -#define THR_CLEANUP_PUSH(td, func, arg) { \ - struct pthread_cleanup __cup; \ - \ - __cup.routine = func; \ - __cup.routine_arg = arg; \ - __cup.onstack = 1; \ - __cup.next = (td)->cleanup; \ - (td)->cleanup = &__cup; - -#define THR_CLEANUP_POP(td, exec) \ - (td)->cleanup = __cup.next; \ - if ((exec) != 0) \ - __cup.routine(__cup.routine_arg); \ -} - -struct pthread_atfork { - TAILQ_ENTRY(pthread_atfork) qe; - void (*prepare)(void); - void (*parent)(void); - void (*child)(void); -}; - -struct pthread_attr { - int sched_policy; - int sched_inherit; - int sched_interval; - int prio; - int suspend; -#define THR_STACK_USER 0x100 /* 0xFF reserved for <pthread.h> */ -#define THR_SIGNAL_THREAD 0x200 /* This is a signal thread */ - int flags; - void *arg_attr; - void (*cleanup_attr) (void *); - void *stackaddr_attr; - size_t stacksize_attr; - size_t guardsize_attr; -}; - -/* - * Thread creation state attributes. - */ -#define THR_CREATE_RUNNING 0 -#define THR_CREATE_SUSPENDED 1 - -/* - * Miscellaneous definitions. - */ -#define THR_STACK32_DEFAULT (1 * 1024 * 1024) -#define THR_STACK64_DEFAULT (2 * 1024 * 1024) - -/* - * Maximum size of initial thread's stack. This perhaps deserves to be larger - * than the stacks of other threads, since many applications are likely to run - * almost entirely on this stack. - */ -#define THR_STACK32_INITIAL (2 * 1024 * 1024) -#define THR_STACK64_INITIAL (4 * 1024 * 1024) - -/* - * Define the different priority ranges. All applications have thread - * priorities constrained within 0-31. The threads library raises the - * priority when delivering signals in order to ensure that signal - * delivery happens (from the POSIX spec) "as soon as possible". - * In the future, the threads library will also be able to map specific - * threads into real-time (cooperating) processes or kernel threads. - * The RT and SIGNAL priorities will be used internally and added to - * thread base priorities so that the scheduling queue can handle both - * normal and RT priority threads with and without signal handling. - * - * The approach taken is that, within each class, signal delivery - * always has priority over thread execution. - */ -#define THR_DEFAULT_PRIORITY 15 -#define THR_MIN_PRIORITY 0 -#define THR_MAX_PRIORITY 31 /* 0x1F */ -#define THR_SIGNAL_PRIORITY 32 /* 0x20 */ -#define THR_RT_PRIORITY 64 /* 0x40 */ -#define THR_FIRST_PRIORITY THR_MIN_PRIORITY -#define THR_LAST_PRIORITY \ - (THR_MAX_PRIORITY + THR_SIGNAL_PRIORITY + THR_RT_PRIORITY) -#define THR_BASE_PRIORITY(prio) ((prio) & THR_MAX_PRIORITY) - -/* - * Clock resolution in microseconds. - */ -#define CLOCK_RES_USEC 10000 - -/* - * Time slice period in microseconds. - */ -#define TIMESLICE_USEC 20000 - -/* - * XXX - Define a thread-safe macro to get the current time of day - * which is updated at regular intervals by something. - * - * For now, we just make the system call to get the time. - */ -#define KSE_GET_TOD(curkse, tsp) \ -do { \ - *tsp = (curkse)->k_kcb->kcb_kmbx.km_timeofday; \ - if ((tsp)->tv_sec == 0) \ - clock_gettime(CLOCK_REALTIME, tsp); \ -} while (0) - -struct pthread_rwlockattr { - int pshared; -}; - -struct pthread_rwlock { - pthread_mutex_t lock; /* monitor lock */ - pthread_cond_t read_signal; - pthread_cond_t write_signal; - int state; /* 0 = idle >0 = # of readers -1 = writer */ - int blocked_writers; -}; - -/* - * Thread states. - */ -enum pthread_state { - PS_RUNNING, - PS_LOCKWAIT, - PS_MUTEX_WAIT, - PS_COND_WAIT, - PS_SLEEP_WAIT, - PS_SIGSUSPEND, - PS_SIGWAIT, - PS_JOIN, - PS_SUSPENDED, - PS_DEAD, - PS_DEADLOCK, - PS_STATE_MAX -}; - -struct sigwait_data { - sigset_t *waitset; - siginfo_t *siginfo; /* used to save siginfo for sigwaitinfo() */ -}; - -union pthread_wait_data { - pthread_mutex_t mutex; - pthread_cond_t cond; - struct lock *lock; - struct sigwait_data *sigwait; -}; - -/* - * Define a continuation routine that can be used to perform a - * transfer of control: - */ -typedef void (*thread_continuation_t) (void *); - -/* - * This stores a thread's state prior to running a signal handler. - * It is used when a signal is delivered to a thread blocked in - * userland. If the signal handler returns normally, the thread's - * state is restored from here. - */ -struct pthread_sigframe { - int psf_valid; - int psf_flags; - int psf_cancelflags; - int psf_interrupted; - int psf_timeout; - int psf_signo; - enum pthread_state psf_state; - union pthread_wait_data psf_wait_data; - struct timespec psf_wakeup_time; - sigset_t psf_sigset; - sigset_t psf_sigmask; - int psf_seqno; - thread_continuation_t psf_continuation; -}; - -struct join_status { - struct pthread *thread; - void *ret; - int error; -}; - -struct pthread_specific_elem { - void *data; - int seqno; -}; - -typedef void (*const_key_destructor_t)(const void *); -typedef void (*key_destructor_t)(void *); - -struct pthread_key { - volatile int allocated; - volatile int count; - int seqno; - key_destructor_t destructor; -}; - -#define MAX_THR_LOCKLEVEL 5 -/* - * Thread structure. - */ -struct pthread { - /* Thread control block */ - struct tcb *tcb; - - /* - * Magic value to help recognize a valid thread structure - * from an invalid one: - */ -#define THR_MAGIC ((u_int32_t) 0xd09ba115) - u_int32_t magic; - char *name; - u_int64_t uniqueid; /* for gdb */ - - /* Queue entry for list of all threads: */ - TAILQ_ENTRY(pthread) tle; /* link for all threads in process */ - TAILQ_ENTRY(pthread) kle; /* link for all threads in KSE/KSEG */ - - /* Queue entry for GC lists: */ - TAILQ_ENTRY(pthread) gcle; - - /* Hash queue entry */ - LIST_ENTRY(pthread) hle; - - /* - * Lock for accesses to this thread structure. - */ - struct lock lock; - struct lockuser lockusers[MAX_THR_LOCKLEVEL]; - int locklevel; - kse_critical_t critical[MAX_KSE_LOCKLEVEL]; - struct kse *kse; - struct kse_group *kseg; - - /* - * Thread start routine, argument, stack pointer and thread - * attributes. - */ - void *(*start_routine)(void *); - void *arg; - struct pthread_attr attr; - - int active; /* thread running */ - int blocked; /* thread blocked in kernel */ - int need_switchout; - - /* - * Used for tracking delivery of signal handlers. - */ - siginfo_t *siginfo; - thread_continuation_t sigbackout; - - /* - * Cancelability flags - the lower 2 bits are used by cancel - * definitions in pthread.h - */ -#define THR_AT_CANCEL_POINT 0x0004 -#define THR_CANCELLING 0x0008 -#define THR_CANCEL_NEEDED 0x0010 - int cancelflags; - - thread_continuation_t continuation; - - /* - * The thread's base and pending signal masks. The active - * signal mask is stored in the thread's context (in mailbox). - */ - sigset_t sigmask; - sigset_t sigpend; - sigset_t *oldsigmask; - volatile int check_pending; - int refcount; - - /* Thread state: */ - enum pthread_state state; - volatile int lock_switch; - - /* - * Number of microseconds accumulated by this thread when - * time slicing is active. - */ - long slice_usec; - - /* - * Time to wake up thread. This is used for sleeping threads and - * for any operation which may time out (such as select). - */ - struct timespec wakeup_time; - - /* TRUE if operation has timed out. */ - int timeout; - - /* - * Error variable used instead of errno. The function __error() - * returns a pointer to this. - */ - int error; - - /* - * The joiner is the thread that is joining to this thread. The - * join status keeps track of a join operation to another thread. - */ - struct pthread *joiner; - struct join_status join_status; - - /* - * The current thread can belong to only one scheduling queue at - * a time (ready or waiting queue). It can also belong to: - * - * o A queue of threads waiting for a mutex - * o A queue of threads waiting for a condition variable - * - * It is possible for a thread to belong to more than one of the - * above queues if it is handling a signal. A thread may only - * enter a mutex or condition variable queue when it is not - * being called from a signal handler. If a thread is a member - * of one of these queues when a signal handler is invoked, it - * must be removed from the queue before invoking the handler - * and then added back to the queue after return from the handler. - * - * Use pqe for the scheduling queue link (both ready and waiting), - * sqe for synchronization (mutex, condition variable, and join) - * queue links, and qe for all other links. - */ - TAILQ_ENTRY(pthread) pqe; /* priority, wait queues link */ - TAILQ_ENTRY(pthread) sqe; /* synchronization queue link */ - - /* Wait data. */ - union pthread_wait_data data; - - /* - * Set to TRUE if a blocking operation was - * interrupted by a signal: - */ - int interrupted; - - /* - * Set to non-zero when this thread has entered a critical - * region. We allow for recursive entries into critical regions. - */ - int critical_count; - - /* - * Set to TRUE if this thread should yield after leaving a - * critical region to check for signals, messages, etc. - */ - int critical_yield; - - int sflags; -#define THR_FLAGS_IN_SYNCQ 0x0001 - - /* Miscellaneous flags; only set with scheduling lock held. */ - int flags; -#define THR_FLAGS_PRIVATE 0x0001 -#define THR_FLAGS_IN_WAITQ 0x0002 /* in waiting queue using pqe link */ -#define THR_FLAGS_IN_RUNQ 0x0004 /* in run queue using pqe link */ -#define THR_FLAGS_EXITING 0x0008 /* thread is exiting */ -#define THR_FLAGS_SUSPENDED 0x0010 /* thread is suspended */ - - /* Thread list flags; only set with thread list lock held. */ -#define TLFLAGS_GC_SAFE 0x0001 /* thread safe for cleaning */ -#define TLFLAGS_IN_TDLIST 0x0002 /* thread in all thread list */ -#define TLFLAGS_IN_GCLIST 0x0004 /* thread in gc list */ - int tlflags; - - /* - * Base priority is the user setable and retrievable priority - * of the thread. It is only affected by explicit calls to - * set thread priority and upon thread creation via a thread - * attribute or default priority. - */ - char base_priority; - - /* - * Inherited priority is the priority a thread inherits by - * taking a priority inheritence or protection mutex. It - * is not affected by base priority changes. Inherited - * priority defaults to and remains 0 until a mutex is taken - * that is being waited on by any other thread whose priority - * is non-zero. - */ - char inherited_priority; - - /* - * Active priority is always the maximum of the threads base - * priority and inherited priority. When there is a change - * in either the base or inherited priority, the active - * priority must be recalculated. - */ - char active_priority; - - /* Number of priority ceiling or protection mutexes owned. */ - int priority_mutex_count; - - /* Number rwlocks rdlocks held. */ - int rdlock_count; - - /* - * Queue of currently owned mutexes. - */ - TAILQ_HEAD(, pthread_mutex) mutexq; - - void *ret; - struct pthread_specific_elem *specific; - int specific_data_count; - - /* Alternative stack for sigaltstack() */ - stack_t sigstk; - - /* - * Current locks bitmap for rtld. - */ - int rtld_bits; - - /* Cleanup handlers Link List */ - struct pthread_cleanup *cleanup; - const char *fname; /* Ptr to source file name */ - int lineno; /* Source line number. */ -}; - -/* - * Critical regions can also be detected by looking at the threads - * current lock level. Ensure these macros increment and decrement - * the lock levels such that locks can not be held with a lock level - * of 0. - */ -#define THR_IN_CRITICAL(thrd) \ - (((thrd)->locklevel > 0) || \ - ((thrd)->critical_count > 0)) - -#define THR_YIELD_CHECK(thrd) \ -do { \ - if (!THR_IN_CRITICAL(thrd)) { \ - if (__predict_false(_libkse_debug)) \ - _thr_debug_check_yield(thrd); \ - if ((thrd)->critical_yield != 0) \ - _thr_sched_switch(thrd); \ - if ((thrd)->check_pending != 0) \ - _thr_sig_check_pending(thrd); \ - } \ -} while (0) - -#define THR_LOCK_ACQUIRE(thrd, lck) \ -do { \ - if ((thrd)->locklevel < MAX_THR_LOCKLEVEL) { \ - THR_DEACTIVATE_LAST_LOCK(thrd); \ - (thrd)->locklevel++; \ - _lock_acquire((lck), \ - &(thrd)->lockusers[(thrd)->locklevel - 1], \ - (thrd)->active_priority); \ - } else \ - PANIC("Exceeded maximum lock level"); \ -} while (0) - -#define THR_LOCK_RELEASE(thrd, lck) \ -do { \ - if ((thrd)->locklevel > 0) { \ - _lock_release((lck), \ - &(thrd)->lockusers[(thrd)->locklevel - 1]); \ - (thrd)->locklevel--; \ - THR_ACTIVATE_LAST_LOCK(thrd); \ - if ((thrd)->locklevel == 0) \ - THR_YIELD_CHECK(thrd); \ - } \ -} while (0) - -#define THR_ACTIVATE_LAST_LOCK(thrd) \ -do { \ - if ((thrd)->locklevel > 0) \ - _lockuser_setactive( \ - &(thrd)->lockusers[(thrd)->locklevel - 1], 1); \ -} while (0) - -#define THR_DEACTIVATE_LAST_LOCK(thrd) \ -do { \ - if ((thrd)->locklevel > 0) \ - _lockuser_setactive( \ - &(thrd)->lockusers[(thrd)->locklevel - 1], 0); \ -} while (0) - -/* - * For now, threads will have their own lock separate from their - * KSE scheduling lock. - */ -#define THR_LOCK(thr) THR_LOCK_ACQUIRE(thr, &(thr)->lock) -#define THR_UNLOCK(thr) THR_LOCK_RELEASE(thr, &(thr)->lock) -#define THR_THREAD_LOCK(curthrd, thr) THR_LOCK_ACQUIRE(curthrd, &(thr)->lock) -#define THR_THREAD_UNLOCK(curthrd, thr) THR_LOCK_RELEASE(curthrd, &(thr)->lock) - -/* - * Priority queue manipulation macros (using pqe link). We use - * the thread's kseg link instead of the kse link because a thread - * does not (currently) have a statically assigned kse. - */ -#define THR_RUNQ_INSERT_HEAD(thrd) \ - _pq_insert_head(&(thrd)->kseg->kg_schedq.sq_runq, thrd) -#define THR_RUNQ_INSERT_TAIL(thrd) \ - _pq_insert_tail(&(thrd)->kseg->kg_schedq.sq_runq, thrd) -#define THR_RUNQ_REMOVE(thrd) \ - _pq_remove(&(thrd)->kseg->kg_schedq.sq_runq, thrd) - -/* - * Macros to insert/remove threads to the all thread list and - * the gc list. - */ -#define THR_LIST_ADD(thrd) do { \ - if (((thrd)->tlflags & TLFLAGS_IN_TDLIST) == 0) { \ - TAILQ_INSERT_HEAD(&_thread_list, thrd, tle); \ - _thr_hash_add(thrd); \ - (thrd)->tlflags |= TLFLAGS_IN_TDLIST; \ - } \ -} while (0) -#define THR_LIST_REMOVE(thrd) do { \ - if (((thrd)->tlflags & TLFLAGS_IN_TDLIST) != 0) { \ - TAILQ_REMOVE(&_thread_list, thrd, tle); \ - _thr_hash_remove(thrd); \ - (thrd)->tlflags &= ~TLFLAGS_IN_TDLIST; \ - } \ -} while (0) -#define THR_GCLIST_ADD(thrd) do { \ - if (((thrd)->tlflags & TLFLAGS_IN_GCLIST) == 0) { \ - TAILQ_INSERT_HEAD(&_thread_gc_list, thrd, gcle);\ - (thrd)->tlflags |= TLFLAGS_IN_GCLIST; \ - _gc_count++; \ - } \ -} while (0) -#define THR_GCLIST_REMOVE(thrd) do { \ - if (((thrd)->tlflags & TLFLAGS_IN_GCLIST) != 0) { \ - TAILQ_REMOVE(&_thread_gc_list, thrd, gcle); \ - (thrd)->tlflags &= ~TLFLAGS_IN_GCLIST; \ - _gc_count--; \ - } \ -} while (0) - -#define GC_NEEDED() (atomic_load_acq_int(&_gc_count) >= 5) - -/* - * Locking the scheduling queue for another thread uses that thread's - * KSEG lock. - */ -#define THR_SCHED_LOCK(curthr, thr) do { \ - (curthr)->critical[(curthr)->locklevel] = _kse_critical_enter(); \ - (curthr)->locklevel++; \ - KSE_SCHED_LOCK((curthr)->kse, (thr)->kseg); \ -} while (0) - -#define THR_SCHED_UNLOCK(curthr, thr) do { \ - KSE_SCHED_UNLOCK((curthr)->kse, (thr)->kseg); \ - (curthr)->locklevel--; \ - _kse_critical_leave((curthr)->critical[(curthr)->locklevel]); \ -} while (0) - -/* Take the scheduling lock with the intent to call the scheduler. */ -#define THR_LOCK_SWITCH(curthr) do { \ - (void)_kse_critical_enter(); \ - KSE_SCHED_LOCK((curthr)->kse, (curthr)->kseg); \ -} while (0) -#define THR_UNLOCK_SWITCH(curthr) do { \ - KSE_SCHED_UNLOCK((curthr)->kse, (curthr)->kseg);\ -} while (0) - -#define THR_CRITICAL_ENTER(thr) (thr)->critical_count++ -#define THR_CRITICAL_LEAVE(thr) do { \ - (thr)->critical_count--; \ - if (((thr)->critical_yield != 0) && \ - ((thr)->critical_count == 0)) { \ - (thr)->critical_yield = 0; \ - _thr_sched_switch(thr); \ - } \ -} while (0) - -#define THR_IS_ACTIVE(thrd) \ - ((thrd)->kse != NULL) && ((thrd)->kse->k_curthread == (thrd)) - -#define THR_IN_SYNCQ(thrd) (((thrd)->sflags & THR_FLAGS_IN_SYNCQ) != 0) - -#define THR_IS_SUSPENDED(thrd) \ - (((thrd)->state == PS_SUSPENDED) || \ - (((thrd)->flags & THR_FLAGS_SUSPENDED) != 0)) -#define THR_IS_EXITING(thrd) (((thrd)->flags & THR_FLAGS_EXITING) != 0) -#define DBG_CAN_RUN(thrd) (((thrd)->tcb->tcb_tmbx.tm_dflags & \ - TMDF_SUSPEND) == 0) - -extern int __isthreaded; - -static inline int -_kse_isthreaded(void) -{ - return (__isthreaded != 0); -} - -/* - * Global variables for the pthread kernel. - */ - -SCLASS void *_usrstack SCLASS_PRESET(NULL); -SCLASS struct kse *_kse_initial SCLASS_PRESET(NULL); -SCLASS struct pthread *_thr_initial SCLASS_PRESET(NULL); -/* For debugger */ -SCLASS int _libkse_debug SCLASS_PRESET(0); -SCLASS int _thread_activated SCLASS_PRESET(0); -SCLASS int _thread_scope_system SCLASS_PRESET(0); - -/* List of all threads: */ -SCLASS TAILQ_HEAD(, pthread) _thread_list - SCLASS_PRESET(TAILQ_HEAD_INITIALIZER(_thread_list)); - -/* List of threads needing GC: */ -SCLASS TAILQ_HEAD(, pthread) _thread_gc_list - SCLASS_PRESET(TAILQ_HEAD_INITIALIZER(_thread_gc_list)); - -SCLASS int _thread_active_threads SCLASS_PRESET(1); - -SCLASS TAILQ_HEAD(atfork_head, pthread_atfork) _thr_atfork_list; -SCLASS pthread_mutex_t _thr_atfork_mutex; - -/* Default thread attributes: */ -SCLASS struct pthread_attr _pthread_attr_default - SCLASS_PRESET({ - SCHED_RR, 0, TIMESLICE_USEC, THR_DEFAULT_PRIORITY, - THR_CREATE_RUNNING, PTHREAD_CREATE_JOINABLE, NULL, - NULL, NULL, /* stacksize */0, /* guardsize */0 - }); - -/* Default mutex attributes: */ -SCLASS struct pthread_mutex_attr _pthread_mutexattr_default - SCLASS_PRESET({PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, 0 }); - -/* Default condition variable attributes: */ -SCLASS struct pthread_cond_attr _pthread_condattr_default - SCLASS_PRESET({COND_TYPE_FAST, 0}); - -/* Clock resolution in usec. */ -SCLASS int _clock_res_usec SCLASS_PRESET(CLOCK_RES_USEC); - -/* Array of signal actions for this process: */ -SCLASS struct sigaction _thread_sigact[_SIG_MAXSIG]; - -/* - * Lock for above count of dummy handlers and for the process signal - * mask and pending signal sets. - */ -SCLASS struct lock _thread_signal_lock; - -/* Pending signals and mask for this process: */ -SCLASS sigset_t _thr_proc_sigpending; -SCLASS siginfo_t _thr_proc_siginfo[_SIG_MAXSIG]; - -SCLASS pid_t _thr_pid SCLASS_PRESET(0); - -/* Garbage collector lock. */ -SCLASS struct lock _gc_lock; -SCLASS int _gc_check SCLASS_PRESET(0); -SCLASS int _gc_count SCLASS_PRESET(0); - -SCLASS struct lock _mutex_static_lock; -SCLASS struct lock _rwlock_static_lock; -SCLASS struct lock _keytable_lock; -SCLASS struct lock _thread_list_lock; -SCLASS size_t _thr_guard_default; -SCLASS size_t _thr_stack_default; -SCLASS size_t _thr_stack_initial; -SCLASS int _thr_page_size; -SCLASS pthread_t _thr_sig_daemon; -SCLASS int _thr_debug_flags SCLASS_PRESET(0); - -/* Undefine the storage class and preset specifiers: */ -#undef SCLASS -#undef SCLASS_PRESET - - -/* - * Function prototype definitions. - */ -__BEGIN_DECLS -int _cond_reinit(pthread_cond_t *); -struct kse *_kse_alloc(struct pthread *, int sys_scope); -kse_critical_t _kse_critical_enter(void); -void _kse_critical_leave(kse_critical_t); -int _kse_in_critical(void); -void _kse_free(struct pthread *, struct kse *); -void _kse_init(void); -struct kse_group *_kseg_alloc(struct pthread *); -void _kse_lock_wait(struct lock *, struct lockuser *lu); -void _kse_lock_wakeup(struct lock *, struct lockuser *lu); -void _kse_single_thread(struct pthread *); -int _kse_setthreaded(int); -void _kseg_free(struct kse_group *); -int _mutex_cv_lock(pthread_mutex_t *); -int _mutex_cv_unlock(pthread_mutex_t *); -void _mutex_notify_priochange(struct pthread *, struct pthread *, int); -int _mutex_reinit(struct pthread_mutex *); -void _mutex_unlock_private(struct pthread *); -void _libpthread_init(struct pthread *); -int _pq_alloc(struct pq_queue *, int, int); -void _pq_free(struct pq_queue *); -int _pq_init(struct pq_queue *); -void _pq_remove(struct pq_queue *pq, struct pthread *); -void _pq_insert_head(struct pq_queue *pq, struct pthread *); -void _pq_insert_tail(struct pq_queue *pq, struct pthread *); -struct pthread *_pq_first(struct pq_queue *pq); -struct pthread *_pq_first_debug(struct pq_queue *pq); -void *_pthread_getspecific(pthread_key_t); -int _pthread_key_create(pthread_key_t *, void (*) (void *)); -int _pthread_key_delete(pthread_key_t); -int _pthread_mutex_destroy(pthread_mutex_t *); -int _pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *); -int _pthread_mutex_lock(pthread_mutex_t *); -int _pthread_mutex_trylock(pthread_mutex_t *); -int _pthread_mutex_unlock(pthread_mutex_t *); -int _pthread_mutexattr_init(pthread_mutexattr_t *); -int _pthread_mutexattr_destroy(pthread_mutexattr_t *); -int _pthread_mutexattr_settype(pthread_mutexattr_t *, int); -int _pthread_once(pthread_once_t *, void (*) (void)); -int _pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *); -int _pthread_rwlock_destroy (pthread_rwlock_t *); -struct pthread *_pthread_self(void); -int _pthread_setspecific(pthread_key_t, const void *); -void _pthread_yield(void); -void _pthread_cleanup_push(void (*routine) (void *), void *routine_arg); -void _pthread_cleanup_pop(int execute); -struct pthread *_thr_alloc(struct pthread *); -void _thr_exit(const char *, int, const char *) __dead2; -void _thr_exit_cleanup(void); -void _thr_lock_wait(struct lock *lock, struct lockuser *lu); -void _thr_lock_wakeup(struct lock *lock, struct lockuser *lu); -void _thr_mutex_reinit(pthread_mutex_t *); -int _thr_ref_add(struct pthread *, struct pthread *, int); -void _thr_ref_delete(struct pthread *, struct pthread *); -void _thr_rtld_init(void); -void _thr_rtld_fini(void); -int _thr_schedule_add(struct pthread *, struct pthread *); -void _thr_schedule_remove(struct pthread *, struct pthread *); -void _thr_setrunnable(struct pthread *curthread, struct pthread *thread); -struct kse_mailbox *_thr_setrunnable_unlocked(struct pthread *thread); -struct kse_mailbox *_thr_sig_add(struct pthread *, int, siginfo_t *); -void _thr_sig_dispatch(struct kse *, int, siginfo_t *); -int _thr_stack_alloc(struct pthread_attr *); -void _thr_stack_free(struct pthread_attr *); -void _thr_exit_cleanup(void); -void _thr_free(struct pthread *, struct pthread *); -void _thr_gc(struct pthread *); -void _thr_panic_exit(char *, int, char *); -void _thread_cleanupspecific(void); -void _thread_dump_info(void); -void _thread_printf(int, const char *, ...); -void _thr_sched_switch(struct pthread *); -void _thr_sched_switch_unlocked(struct pthread *); -void _thr_set_timeout(const struct timespec *); -void _thr_seterrno(struct pthread *, int); -void _thr_sig_handler(int, siginfo_t *, void *); -void _thr_sig_check_pending(struct pthread *); -void _thr_sig_rundown(struct pthread *, ucontext_t *); -void _thr_sig_send(struct pthread *pthread, int sig); -void _thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf); -void _thr_spinlock_init(void); -void _thr_cancel_enter(struct pthread *); -void _thr_cancel_leave(struct pthread *, int); -int _thr_setconcurrency(int new_level); -int _thr_setmaxconcurrency(void); -void _thr_critical_enter(struct pthread *); -void _thr_critical_leave(struct pthread *); -int _thr_start_sig_daemon(void); -int _thr_getprocsig(int sig, siginfo_t *siginfo); -int _thr_getprocsig_unlocked(int sig, siginfo_t *siginfo); -void _thr_signal_init(void); -void _thr_signal_deinit(void); -void _thr_hash_add(struct pthread *); -void _thr_hash_remove(struct pthread *); -struct pthread *_thr_hash_find(struct pthread *); -void _thr_finish_cancellation(void *arg); -int _thr_sigonstack(void *sp); -void _thr_debug_check_yield(struct pthread *); - -/* - * Aliases for _pthread functions. Should be called instead of - * originals if PLT replocation is unwanted at runtme. - */ -int _thr_cond_broadcast(pthread_cond_t *); -int _thr_cond_signal(pthread_cond_t *); -int _thr_cond_wait(pthread_cond_t *, pthread_mutex_t *); -int _thr_mutex_lock(pthread_mutex_t *); -int _thr_mutex_unlock(pthread_mutex_t *); -int _thr_rwlock_rdlock (pthread_rwlock_t *); -int _thr_rwlock_wrlock (pthread_rwlock_t *); -int _thr_rwlock_unlock (pthread_rwlock_t *); - -/* #include <sys/aio.h> */ -#ifdef _SYS_AIO_H_ -int __sys_aio_suspend(const struct aiocb * const[], int, const struct timespec *); -#endif - -/* #include <fcntl.h> */ -#ifdef _SYS_FCNTL_H_ -int __sys_fcntl(int, int, ...); -int __sys_open(const char *, int, ...); -#endif - -/* #include <sys/ioctl.h> */ -#ifdef _SYS_IOCTL_H_ -int __sys_ioctl(int, unsigned long, ...); -#endif - -/* #inclde <sched.h> */ -#ifdef _SCHED_H_ -int __sys_sched_yield(void); -#endif - -/* #include <signal.h> */ -#ifdef _SIGNAL_H_ -int __sys_kill(pid_t, int); -int __sys_sigaction(int, const struct sigaction *, struct sigaction *); -int __sys_sigpending(sigset_t *); -int __sys_sigprocmask(int, const sigset_t *, sigset_t *); -int __sys_sigsuspend(const sigset_t *); -int __sys_sigreturn(ucontext_t *); -int __sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *); -#endif - -/* #include <sys/socket.h> */ -#ifdef _SYS_SOCKET_H_ -int __sys_accept(int, struct sockaddr *, socklen_t *); -int __sys_connect(int, const struct sockaddr *, socklen_t); -int __sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *, - off_t *, int); -#endif - -/* #include <sys/uio.h> */ -#ifdef _SYS_UIO_H_ -ssize_t __sys_readv(int, const struct iovec *, int); -ssize_t __sys_writev(int, const struct iovec *, int); -#endif - -/* #include <time.h> */ -#ifdef _TIME_H_ -int __sys_nanosleep(const struct timespec *, struct timespec *); -#endif - -/* #include <unistd.h> */ -#ifdef _UNISTD_H_ -int __sys_close(int); -int __sys_execve(const char *, char * const *, char * const *); -int __sys_fork(void); -int __sys_fsync(int); -pid_t __sys_getpid(void); -int __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); -ssize_t __sys_read(int, void *, size_t); -ssize_t __sys_write(int, const void *, size_t); -void __sys_exit(int); -int __sys_sigwait(const sigset_t *, int *); -int __sys_sigtimedwait(const sigset_t *, siginfo_t *, const struct timespec *); -#endif - -/* #include <poll.h> */ -#ifdef _SYS_POLL_H_ -int __sys_poll(struct pollfd *, unsigned, int); -#endif - -/* #include <sys/mman.h> */ -#ifdef _SYS_MMAN_H_ -int __sys_msync(void *, size_t, int); -#endif - -static __inline int -_thr_dump_enabled(void) -{ - - return ((_thr_debug_flags & DBG_INFO_DUMP) != 0); -} - -#endif /* !_THR_PRIVATE_H */ |