summaryrefslogtreecommitdiff
path: root/lib/libc_r/uthread/pthread_private.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc_r/uthread/pthread_private.h')
-rw-r--r--lib/libc_r/uthread/pthread_private.h233
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 *);