diff options
Diffstat (limited to 'lib/libc_r/uthread/pthread_private.h')
-rw-r--r-- | lib/libc_r/uthread/pthread_private.h | 233 |
1 files changed, 210 insertions, 23 deletions
diff --git a/lib/libc_r/uthread/pthread_private.h b/lib/libc_r/uthread/pthread_private.h index 529c647fa57..7643b99a19c 100644 --- a/lib/libc_r/uthread/pthread_private.h +++ b/lib/libc_r/uthread/pthread_private.h @@ -31,7 +31,7 @@ * * Private thread definitions for the uthread kernel. * - * $OpenBSD: pthread_private.h,v 1.13 1999/02/16 16:44:07 millert Exp $ + * $OpenBSD: pthread_private.h,v 1.14 1999/05/26 00:18:21 d Exp $ * */ @@ -50,10 +50,17 @@ #include <sys/time.h> #include <sched.h> #include <spinlock.h> +#include <pthread_np.h> #ifndef _NO_UTHREAD_MACHDEP #include "uthread_machdep.h" #endif +#ifdef __OpenBSD__ +/* Steal TAILQ_FOREACH from FreeBSD's <sys/queue.h> */ +#define TAILQ_FOREACH(var, head, field) \ + for (var = TAILQ_FIRST(head); var; var = TAILQ_NEXT(var, field)) +#endif + /* * Kernel fatal error handler macro. */ @@ -63,16 +70,59 @@ #define stdout_debug(_x) _thread_sys_write(1,_x,strlen(_x)); #define stderr_debug(_x) _thread_sys_write(2,_x,strlen(_x)); + /* - * State change macro: + * Priority queue manipulation macros: */ -#define PTHREAD_NEW_STATE(thrd, newstate) { \ +#define PTHREAD_PRIOQ_INSERT_HEAD(thrd) _pq_insert_head(&_readyq,thrd) +#define PTHREAD_PRIOQ_INSERT_TAIL(thrd) _pq_insert_tail(&_readyq,thrd) +#define PTHREAD_PRIOQ_REMOVE(thrd) _pq_remove(&_readyq,thrd) +#define PTHREAD_PRIOQ_FIRST _pq_first(&_readyq) + +/* + * Waiting queue manipulation macros: + */ +#define PTHREAD_WAITQ_INSERT(thrd) TAILQ_INSERT_TAIL(&_waitingq,thrd,pqe) +#define PTHREAD_WAITQ_REMOVE(thrd) TAILQ_REMOVE(&_waitingq,thrd,pqe) + +/* + * State change macro without scheduling queue change: + */ +#define PTHREAD_SET_STATE(thrd, newstate) { \ (thrd)->state = newstate; \ (thrd)->fname = __FILE__; \ (thrd)->lineno = __LINE__; \ } /* + * State change macro with scheduling queue change - This must be + * called with preemption deferred (see thread_kern_sched_[un]defer). + */ +#define PTHREAD_NEW_STATE(thrd, newstate) { \ + if ((thrd)->state != newstate) { \ + if ((thrd)->state == PS_RUNNING) { \ + PTHREAD_PRIOQ_REMOVE(thrd); \ + PTHREAD_WAITQ_INSERT(thrd); \ + } else if (newstate == PS_RUNNING) { \ + PTHREAD_WAITQ_REMOVE(thrd); \ + PTHREAD_PRIOQ_INSERT_TAIL(thrd); \ + } \ + } \ + PTHREAD_SET_STATE(thrd, newstate); \ +} + +/* + * Define the signals to be used for scheduling. + */ +#if defined(_PTHREADS_COMPAT_SCHED) +#define _ITIMER_SCHED_TIMER ITIMER_VIRTUAL +#define _SCHED_SIGNAL SIGVTALRM +#else +#define _ITIMER_SCHED_TIMER ITIMER_PROF +#define _SCHED_SIGNAL SIGPROF +#endif + +/* * Queue definitions. */ struct pthread_queue { @@ -82,10 +132,34 @@ struct pthread_queue { }; /* + * 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 */ +} pq_queue_t; + + +/* * Static queue initialization values. */ #define PTHREAD_QUEUE_INITIALIZER { NULL, NULL, NULL } +/* + * TailQ initialization values. + */ +#define TAILQ_INITIALIZER { NULL, NULL } + /* * Mutex definitions. */ @@ -96,10 +170,31 @@ union pthread_mutex_data { struct pthread_mutex { enum pthread_mutextype m_type; - struct pthread_queue m_queue; + int m_protocol; + TAILQ_HEAD(mutex_head, pthread) m_queue; struct pthread *m_owner; union pthread_mutex_data m_data; long m_flags; + 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; /* * Lock for accesses to this structure. @@ -118,11 +213,13 @@ struct pthread_mutex { * Static mutex initialization values. */ #define PTHREAD_MUTEX_STATIC_INITIALIZER \ - { MUTEX_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, \ - NULL, { NULL }, MUTEX_FLAGS_INITED } + { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, TAILQ_INITIALIZER, \ + NULL, { NULL }, MUTEX_FLAGS_INITED, 0, 0, 0, TAILQ_INITIALIZER } struct pthread_mutex_attr { enum pthread_mutextype m_type; + int m_protocol; + int m_ceiling; long m_flags; }; @@ -135,15 +232,16 @@ enum pthread_cond_type { }; struct pthread_cond { - enum pthread_cond_type c_type; - struct pthread_queue c_queue; - void *c_data; - long c_flags; + enum pthread_cond_type c_type; + TAILQ_HEAD(cond_head, pthread) c_queue; + pthread_mutex_t c_mutex; + void *c_data; + long c_flags; /* * Lock for accesses to this structure. */ - spinlock_t lock; + spinlock_t lock; }; struct pthread_cond_attr { @@ -162,7 +260,8 @@ struct pthread_cond_attr { * Static cond initialization values. */ #define PTHREAD_COND_STATIC_INITIALIZER \ - { COND_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, NULL, COND_FLAGS_INITED } + { COND_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, NULL, NULL, \ + COND_FLAGS_INITED } /* * Cleanup definitions. @@ -174,7 +273,9 @@ struct pthread_cleanup { }; struct pthread_attr { - int schedparam_policy; + int sched_policy; + int sched_inherit; + int sched_interval; int prio; int suspend; int flags; @@ -256,9 +357,11 @@ enum pthread_state { PS_WAIT_WAIT, PS_SIGSUSPEND, PS_SIGWAIT, + PS_SPINBLOCK, PS_JOIN, PS_SUSPENDED, PS_DEAD, + PS_DEADLOCK, PS_STATE_MAX }; @@ -302,8 +405,8 @@ struct pthread_select_data { }; union pthread_wait_data { - pthread_mutex_t *mutex; - pthread_cond_t *cond; + pthread_mutex_t mutex; + pthread_cond_t cond; const sigset_t *sigwait; /* Waiting on a signal in sigwait */ struct { short fd; /* Used when thread waiting on fd */ @@ -311,6 +414,7 @@ union pthread_wait_data { const char *fname; /* Source file name for debugging.*/ } fd; struct pthread_select_data * select_data; + spinlock_t *spinlock; }; /* @@ -419,7 +523,11 @@ struct pthread { struct pthread_queue join_queue; /* - * The current thread can belong to only one queue at a time. + * The current thread can belong to only one scheduling queue + * at a time (ready or waiting queue). It can also belong to + * a queue of threads waiting on mutexes or condition variables. + * Use pqe for the scheduling queue link (both ready and waiting), + * and qe for other links (mutexes and condition variables). * * Pointer to queue (if any) on which the current thread is waiting. * @@ -431,8 +539,11 @@ struct pthread { /* Pointer to next element in queue. */ struct pthread *qnxt; + /* Priority queue entry for this thread: */ + TAILQ_ENTRY(pthread) pqe; + /* Queue entry for this thread: */ - TAILQ_ENTRY(pthread) qe; + TAILQ_ENTRY(pthread) qe; /* Wait data. */ union pthread_wait_data data; @@ -446,12 +557,61 @@ struct pthread { /* Signal number when in state PS_SIGWAIT: */ int signo; + /* + * Set to non-zero when this thread has deferred thread + * scheduling. We allow for recursive deferral. + */ + int sched_defer_count; + + /* + * Set to TRUE if this thread should yield after undeferring + * thread scheduling. + */ + int yield_on_sched_undefer; + /* Miscellaneous data. */ int flags; -#define PTHREAD_EXITING (0x0100) -#define PTHREAD_CANCELLING (0x0200) /* thread has been cancelled */ -#define PTHREAD_AT_CANCEL_POINT (0x0400) /* thread at cancel point */ - char pthread_priority; +#define PTHREAD_FLAGS_PRIVATE 0x0001 +#define PTHREAD_EXITING 0x0002 +#define PTHREAD_FLAGS_QUEUED 0x0004 /* in queue (qe is used) */ +#define PTHREAD_FLAGS_TRACE 0x0008 +#define PTHREAD_CANCELLING 0x0010 /* thread has been cancelled */ +#define PTHREAD_AT_CANCEL_POINT 0x0020 /* thread at cancel point */ + + /* + * 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 real or inherited priority, the active + * priority must be recalculated. + */ + char active_priority; + + /* Number of priority ceiling or protection mutexes owned. */ + int priority_mutex_count; + + /* + * Queue of currently owned mutexes. + */ + TAILQ_HEAD(, pthread_mutex) mutexq; + void *ret; const void **specific_data; int specific_data_count; @@ -484,6 +644,9 @@ extern struct pthread * volatile _thread_kern_threadp; /* Ptr to the thread structure for the running thread: */ extern struct pthread * volatile _thread_run; +/* Ptr to the thread structure for the last user thread to run: */ +extern struct pthread * volatile _last_user_thread; + /* * Ptr to the thread running in single-threaded mode or NULL if * running multi-threaded (default POSIX behaviour). @@ -528,6 +691,7 @@ extern int _pthread_stdio_flags[3]; /* File table information: */ extern struct fd_table_entry **_thread_fd_table; +extern const int dtablecount; extern int _thread_dtablesize; /* Garbage collector mutex and condition variable. */ @@ -540,6 +704,19 @@ extern pthread_cond_t _gc_cond; extern struct sigaction _thread_sigact[NSIG]; /* + * Scheduling queues: + */ +extern pq_queue_t _readyq; +typedef TAILQ_HEAD(, pthread) _waitingq_t; +extern _waitingq_t _waitingq; + +/* Indicates that the waitingq now has threads ready to run. */ +extern volatile int _waitingq_check_reqd; + +/* Thread switch hook. */ +extern pthread_switch_routine_t _sched_switch_hook; + +/* * Where SIGINFO writes thread states when /dev/tty cannot be opened */ #define INFO_DUMP_FILE "/tmp/uthread.dump" @@ -569,6 +746,14 @@ void _lock_thread(void); void _lock_thread_list(void); void _unlock_thread(void); void _unlock_thread_list(void); +int _mutex_cv_lock(pthread_mutex_t *); +int _mutex_cv_unlock(pthread_mutex_t *); +void _mutex_notify_priochange(struct pthread *); +int _pq_init(struct pq_queue *pq, int, int); +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); void _thread_exit(const char *, int, const char *) __attribute__((noreturn)); void _thread_fd_unlock(int, int); @@ -576,12 +761,14 @@ void _thread_fd_unlock_debug(int, int, char *, int); void *_thread_cleanup(pthread_t); void _thread_cleanupspecific(void); void _thread_dump_info(void); -void _thread_init(void) /* __attribute__((constructor)) */; +void _thread_init(void); void _thread_kern_sched(struct sigcontext *); void _thread_kern_sched_state(enum pthread_state, const char *, int); void _thread_kern_sched_state_unlock(enum pthread_state state, spinlock_t *lock, char *fname, int lineno); void _thread_kern_set_timeout(struct timespec *); +void _thread_kern_sched_defer(void); +void _thread_kern_sched_undefer(void); void _thread_sig_handler(int, int, struct sigcontext *); void _thread_start(void); void _thread_start_sig_handler(void); @@ -723,7 +910,7 @@ int _thread_sys_fchdir(int); int _thread_sys_fchown(int, uid_t, gid_t); int _thread_sys_fsync(int); int _thread_sys_ftruncate(int, off_t); -long _thread_sys_fpathconf(int, int); +long _thread_sys_fpathconf(int, int); int _thread_sys_pause(void); int _thread_sys_pipe(int *); int _thread_sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); |