mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
In the words of the author:
o The polling mechanism for I/O readiness was changed from
select() to poll(). In additon, a wrapped version of poll()
is now provided.
o The wrapped select routine now converts each fd_set to a
poll array so that the thread scheduler doesn't have to
perform a bitwise search for selected fds each time file
descriptors are polled for I/O readiness.
o The thread scheduler was modified to use a new queue (_workq)
for threads that need work. Threads waiting for I/O readiness
and spinblocks are added to the work queue in addition to the
waiting queue. This reduces the time spent forming/searching
the array of file descriptors being polled.
o The waiting queue (_waitingq) is now maintained in order of
thread wakeup time. This allows the thread scheduler to
find the nearest wakeup time by looking at the first thread
in the queue instead of searching the entire queue.
o Removed file descriptor locking for select/poll routines. An
application should not rely on the threads library for providing
this locking; if necessary, the application should use mutexes
to protect selecting/polling of file descriptors.
o Retrieve and use the kernel clock rate/resolution at startup
instead of hardcoding the clock resolution to 10 msec (tested
with kernel running at 1000 HZ).
o All queues have been changed to use queue.h macros. These
include the queues of all threads, dead threads, and threads
waiting for file descriptor locks.
o Added reinitialization of the GC mutex and condition variable
after a fork. Also prevented reallocation of the ready queue
after a fork.
o Prevented the wrapped close routine from closing the thread
kernel pipes.
o Initialized file descriptor table for stdio entries at thread
init.
o Provided additional flags to indicate to what queues threads
belong.
o Moved TAILQ initialization for statically allocated mutex and
condition variables to after the spinlock.
o Added dispatching of signals to pthread_kill. Removing the
dispatching of signals from thread activation broke sigsuspend
when pthread_kill was used to send a signal to a thread.
o Temporarily set the state of a thread to PS_SUSPENDED when it
is first created and placed in the list of threads so that it
will not be accidentally scheduled before becoming a member
of one of the scheduling queues.
o Change the signal handler to queue signals to the thread kernel
pipe if the scheduling queues are protected. When scheduling
queues are unprotected, signals are then dequeued and handled.
o Ensured that all installed signal handlers block the scheduling
signal and that the scheduling signal handler blocks all
other signals. This ensures that the signal handler is only
interruptible for and by non-scheduling signals. An atomic
lock is used to decide which instance of the signal handler
will handle pending signals.
o Removed _lock_thread_list and _unlock_thread_list as they are
no longer used to protect the thread list.
o Added missing RCS IDs to modified files.
o Added checks for appropriate queue membership and activity when
adding, removing, and searching the scheduling queues. These
checks add very little overhead and are enabled when compiled
with _PTHREADS_INVARIANTS defined. Suggested and implemented
by Tor Egge with some modification by me.
o Close a race condition in uthread_close. (Tor Egge)
o Protect the scheduling queues while modifying them in
pthread_cond_signal and _thread_fd_unlock. (Tor Egge)
o Ensure that when a thread gets a mutex, the mutex is on that
threads list of owned mutexes. (Tor Egge)
o Set the kernel-in-scheduler flag in _thread_kern_sched_state
and _thread_kern_sched_state_unlock to prevent a scheduling
signal from calling the scheduler again. (Tor Egge)
o Don't use TAILQ_FOREACH macro while searching the waiting
queue for threads in a sigwait state, because a change of
state destroys the TAILQ link. It is actually safe to do
so, though, because once a sigwaiting thread is found, the
loop ends and the function returns. (Tor Egge)
o When dispatching signals to threads, make the thread inherit
the signal deferral flag of the currently running thread.
(Tor Egge)
Submitted by: Daniel Eischen <eischen@vigrid.com> and
Tor Egge <Tor.Egge@fast.no>
This commit is contained in:
parent
c207703465
commit
02292f131a
78 changed files with 5694 additions and 4466 deletions
|
|
@ -1,4 +1,4 @@
|
|||
# $Id: Makefile.inc,v 1.16 1998/09/30 06:36:55 jb Exp $
|
||||
# $Id: Makefile.inc,v 1.17 1999/03/23 05:07:54 jb Exp $
|
||||
|
||||
# uthread sources
|
||||
.PATH: ${.CURDIR}/uthread
|
||||
|
|
@ -73,8 +73,8 @@ SRCS+= \
|
|||
uthread_once.c \
|
||||
uthread_open.c \
|
||||
uthread_pipe.c \
|
||||
uthread_poll.c \
|
||||
uthread_priority_queue.c \
|
||||
uthread_queue.c \
|
||||
uthread_read.c \
|
||||
uthread_readv.c \
|
||||
uthread_recvfrom.c \
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
*
|
||||
* Private thread definitions for the uthread kernel.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _PTHREAD_PRIVATE_H
|
||||
|
|
@ -68,33 +69,88 @@
|
|||
|
||||
|
||||
/*
|
||||
* Priority queue manipulation macros:
|
||||
* Priority queue manipulation macros (using pqe link):
|
||||
*/
|
||||
#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)
|
||||
#define PTHREAD_PRIOQ_FIRST() _pq_first(&_readyq)
|
||||
|
||||
/*
|
||||
* Waiting queue manipulation macros:
|
||||
* Waiting queue manipulation macros (using pqe link):
|
||||
*/
|
||||
#define PTHREAD_WAITQ_INSERT(thrd) TAILQ_INSERT_TAIL(&_waitingq,thrd,pqe)
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
#define PTHREAD_WAITQ_REMOVE(thrd) _waitq_remove(thrd)
|
||||
#define PTHREAD_WAITQ_INSERT(thrd) _waitq_insert(thrd)
|
||||
#define PTHREAD_WAITQ_CLEARACTIVE() _waitq_clearactive()
|
||||
#define PTHREAD_WAITQ_SETACTIVE() _waitq_setactive()
|
||||
#else
|
||||
#define PTHREAD_WAITQ_REMOVE(thrd) TAILQ_REMOVE(&_waitingq,thrd,pqe)
|
||||
#define PTHREAD_WAITQ_INSERT(thrd) do { \
|
||||
if ((thrd)->wakeup_time.tv_sec == -1) \
|
||||
TAILQ_INSERT_TAIL(&_waitingq,thrd,pqe); \
|
||||
else { \
|
||||
pthread_t tid = TAILQ_FIRST(&_waitingq); \
|
||||
while ((tid != NULL) && (tid->wakeup_time.tv_sec != -1) && \
|
||||
((tid->wakeup_time.tv_sec < (thrd)->wakeup_time.tv_sec) || \
|
||||
((tid->wakeup_time.tv_sec == (thrd)->wakeup_time.tv_sec) && \
|
||||
(tid->wakeup_time.tv_nsec <= (thrd)->wakeup_time.tv_nsec)))) \
|
||||
tid = TAILQ_NEXT(tid, pqe); \
|
||||
if (tid == NULL) \
|
||||
TAILQ_INSERT_TAIL(&_waitingq,thrd,pqe); \
|
||||
else \
|
||||
TAILQ_INSERT_BEFORE(tid,thrd,pqe); \
|
||||
} \
|
||||
} while (0)
|
||||
#define PTHREAD_WAITQ_CLEARACTIVE()
|
||||
#define PTHREAD_WAITQ_SETACTIVE()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Work queue manipulation macros (using qe link):
|
||||
*/
|
||||
#define PTHREAD_WORKQ_INSERT(thrd) do { \
|
||||
TAILQ_INSERT_TAIL(&_workq,thrd,qe); \
|
||||
(thrd)->flags |= PTHREAD_FLAGS_IN_WORKQ; \
|
||||
} while (0)
|
||||
#define PTHREAD_WORKQ_REMOVE(thrd) do { \
|
||||
TAILQ_REMOVE(&_workq,thrd,qe); \
|
||||
(thrd)->flags &= ~PTHREAD_FLAGS_IN_WORKQ; \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* State change macro without scheduling queue change:
|
||||
*/
|
||||
#define PTHREAD_SET_STATE(thrd, newstate) { \
|
||||
#define PTHREAD_SET_STATE(thrd, newstate) do { \
|
||||
(thrd)->state = newstate; \
|
||||
(thrd)->fname = __FILE__; \
|
||||
(thrd)->lineno = __LINE__; \
|
||||
}
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* 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 defined(_PTHREADS_INVARIANTS)
|
||||
#define PTHREAD_NEW_STATE(thrd, newstate) do { \
|
||||
if (_thread_kern_new_state != 0) \
|
||||
PANIC("Recursive PTHREAD_NEW_STATE"); \
|
||||
_thread_kern_new_state = 1; \
|
||||
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); \
|
||||
} \
|
||||
} \
|
||||
_thread_kern_new_state = 0; \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
} while (0)
|
||||
#else
|
||||
#define PTHREAD_NEW_STATE(thrd, newstate) do { \
|
||||
if ((thrd)->state != newstate) { \
|
||||
if ((thrd)->state == PS_RUNNING) { \
|
||||
PTHREAD_PRIOQ_REMOVE(thrd); \
|
||||
|
|
@ -105,7 +161,8 @@
|
|||
} \
|
||||
} \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
}
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define the signals to be used for scheduling.
|
||||
|
|
@ -118,15 +175,6 @@
|
|||
#define _SCHED_SIGNAL SIGPROF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Queue definitions.
|
||||
*/
|
||||
struct pthread_queue {
|
||||
struct pthread *q_next;
|
||||
struct pthread *q_last;
|
||||
void *q_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* Priority queues.
|
||||
*
|
||||
|
|
@ -146,15 +194,10 @@ typedef struct pq_queue {
|
|||
} pq_queue_t;
|
||||
|
||||
|
||||
/*
|
||||
* Static queue initialization values.
|
||||
*/
|
||||
#define PTHREAD_QUEUE_INITIALIZER { NULL, NULL, NULL }
|
||||
|
||||
/*
|
||||
* TailQ initialization values.
|
||||
*/
|
||||
#define TAILQ_INITIALIZER { NULL, NULL }
|
||||
#define TAILQ_INITIALIZER { NULL, NULL }
|
||||
|
||||
/*
|
||||
* Mutex definitions.
|
||||
|
|
@ -257,7 +300,7 @@ struct pthread_cond_attr {
|
|||
* Static cond initialization values.
|
||||
*/
|
||||
#define PTHREAD_COND_STATIC_INITIALIZER \
|
||||
{ COND_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, NULL, NULL, \
|
||||
{ COND_TYPE_FAST, TAILQ_INITIALIZER, NULL, NULL, \
|
||||
0, _SPINLOCK_INITIALIZER }
|
||||
|
||||
/*
|
||||
|
|
@ -302,12 +345,6 @@ struct pthread_attr {
|
|||
*/
|
||||
#define CLOCK_RES_NSEC 10000000
|
||||
|
||||
/*
|
||||
* Number of microseconds between incremental priority updates for
|
||||
* threads that are ready to run, but denied being run.
|
||||
*/
|
||||
#define INC_PRIO_USEC 500000
|
||||
|
||||
/*
|
||||
* Time slice period in microseconds.
|
||||
*/
|
||||
|
|
@ -345,6 +382,7 @@ enum pthread_state {
|
|||
PS_FDR_WAIT,
|
||||
PS_FDW_WAIT,
|
||||
PS_FILE_WAIT,
|
||||
PS_POLL_WAIT,
|
||||
PS_SELECT_WAIT,
|
||||
PS_SLEEP_WAIT,
|
||||
PS_WAIT_WAIT,
|
||||
|
|
@ -377,8 +415,8 @@ struct fd_table_entry {
|
|||
* state of the lock on the file descriptor.
|
||||
*/
|
||||
spinlock_t lock;
|
||||
struct pthread_queue r_queue; /* Read queue. */
|
||||
struct pthread_queue w_queue; /* Write queue. */
|
||||
TAILQ_HEAD(, pthread) r_queue; /* Read queue. */
|
||||
TAILQ_HEAD(, pthread) w_queue; /* Write queue. */
|
||||
struct pthread *r_owner; /* Ptr to thread owning read lock. */
|
||||
struct pthread *w_owner; /* Ptr to thread owning write lock. */
|
||||
char *r_fname; /* Ptr to read lock source file name */
|
||||
|
|
@ -390,11 +428,9 @@ struct fd_table_entry {
|
|||
int flags; /* Flags used in open. */
|
||||
};
|
||||
|
||||
struct pthread_select_data {
|
||||
struct pthread_poll_data {
|
||||
int nfds;
|
||||
fd_set readfds;
|
||||
fd_set writefds;
|
||||
fd_set exceptfds;
|
||||
struct pollfd *fds;
|
||||
};
|
||||
|
||||
union pthread_wait_data {
|
||||
|
|
@ -406,7 +442,7 @@ union pthread_wait_data {
|
|||
short branch; /* Line number, for debugging. */
|
||||
char *fname; /* Source file name for debugging.*/
|
||||
} fd;
|
||||
struct pthread_select_data * select_data;
|
||||
struct pthread_poll_data * poll_data;
|
||||
spinlock_t *spinlock;
|
||||
};
|
||||
|
||||
|
|
@ -427,15 +463,11 @@ struct pthread {
|
|||
*/
|
||||
spinlock_t lock;
|
||||
|
||||
/*
|
||||
* Pointer to the next thread in the thread linked list.
|
||||
*/
|
||||
struct pthread *nxt;
|
||||
/* Queue entry for list of all threads: */
|
||||
TAILQ_ENTRY(pthread) tle;
|
||||
|
||||
/*
|
||||
* Pointer to the next thread in the dead thread linked list.
|
||||
*/
|
||||
struct pthread *nxt_dead;
|
||||
/* Queue entry for list of dead threads: */
|
||||
TAILQ_ENTRY(pthread) dle;
|
||||
|
||||
/*
|
||||
* Thread start routine, argument, stack pointer and thread
|
||||
|
|
@ -514,25 +546,25 @@ struct pthread {
|
|||
*/
|
||||
int error;
|
||||
|
||||
/* Join queue for waiting threads: */
|
||||
struct pthread_queue join_queue;
|
||||
/* Join queue head and link for waiting threads: */
|
||||
TAILQ_HEAD(join_head, pthread) join_queue;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* The current thread can belong to only one scheduling queue at
|
||||
* a time (ready or waiting queue). It can also belong to (only)
|
||||
* one of:
|
||||
*
|
||||
* o A queue of threads waiting for a mutex
|
||||
* o A queue of threads waiting for a condition variable
|
||||
* o A queue of threads waiting for another thread to terminate
|
||||
* (the join queue above)
|
||||
* o A queue of threads waiting for a file descriptor lock
|
||||
* o A queue of threads needing work done by the kernel thread
|
||||
* (waiting for a spinlock or file I/O)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* XXX The queuing should be changed to use the TAILQ entry below.
|
||||
* XXX For the time being, it's hybrid.
|
||||
* and qe for other links.
|
||||
*/
|
||||
struct pthread_queue *queue;
|
||||
|
||||
/* Pointer to next element in queue. */
|
||||
struct pthread *qnxt;
|
||||
|
||||
/* Priority queue entry for this thread: */
|
||||
TAILQ_ENTRY(pthread) pqe;
|
||||
|
|
@ -543,6 +575,11 @@ struct pthread {
|
|||
/* Wait data. */
|
||||
union pthread_wait_data data;
|
||||
|
||||
/*
|
||||
* Allocated for converting select into poll.
|
||||
*/
|
||||
struct pthread_poll_data poll_data;
|
||||
|
||||
/*
|
||||
* Set to TRUE if a blocking operation was
|
||||
* interrupted by a signal:
|
||||
|
|
@ -553,23 +590,26 @@ struct pthread {
|
|||
int signo;
|
||||
|
||||
/*
|
||||
* Set to non-zero when this thread has deferred thread
|
||||
* scheduling. We allow for recursive deferral.
|
||||
* Set to non-zero when this thread has deferred signals.
|
||||
* We allow for recursive deferral.
|
||||
*/
|
||||
int sched_defer_count;
|
||||
int sig_defer_count;
|
||||
|
||||
/*
|
||||
* Set to TRUE if this thread should yield after undeferring
|
||||
* thread scheduling.
|
||||
* signals.
|
||||
*/
|
||||
int yield_on_sched_undefer;
|
||||
int yield_on_sig_undefer;
|
||||
|
||||
/* Miscellaneous data. */
|
||||
int flags;
|
||||
#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_FLAGS_IN_CONDQ 0x0004 /* in condition queue using qe link*/
|
||||
#define PTHREAD_FLAGS_IN_WORKQ 0x0008 /* in work queue using qe link */
|
||||
#define PTHREAD_FLAGS_IN_WAITQ 0x0010 /* in waiting queue using pqe link*/
|
||||
#define PTHREAD_FLAGS_IN_PRIOQ 0x0020 /* in priority queue using pqe link*/
|
||||
#define PTHREAD_FLAGS_TRACE 0x0040 /* for debugging purposes */
|
||||
|
||||
/*
|
||||
* Base priority is the user setable and retrievable priority
|
||||
|
|
@ -592,7 +632,7 @@ struct pthread {
|
|||
/*
|
||||
* 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
|
||||
* in either the base or inherited priority, the active
|
||||
* priority must be recalculated.
|
||||
*/
|
||||
char active_priority;
|
||||
|
|
@ -649,10 +689,10 @@ SCLASS struct pthread * volatile _thread_single
|
|||
;
|
||||
#endif
|
||||
|
||||
/* Ptr to the first thread in the thread linked list: */
|
||||
SCLASS struct pthread * volatile _thread_link_list
|
||||
/* List of all threads: */
|
||||
SCLASS TAILQ_HEAD(, pthread) _thread_list
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= NULL;
|
||||
= TAILQ_HEAD_INITIALIZER(_thread_list);
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
|
|
@ -661,7 +701,7 @@ SCLASS struct pthread * volatile _thread_link_list
|
|||
* Array of kernel pipe file descriptors that are used to ensure that
|
||||
* no signals are missed in calls to _select.
|
||||
*/
|
||||
SCLASS int _thread_kern_pipe[2]
|
||||
SCLASS int _thread_kern_pipe[2]
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= {
|
||||
-1,
|
||||
|
|
@ -670,7 +710,7 @@ SCLASS int _thread_kern_pipe[2]
|
|||
#else
|
||||
;
|
||||
#endif
|
||||
SCLASS int _thread_kern_in_select
|
||||
SCLASS int volatile _queue_signals
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= 0;
|
||||
#else
|
||||
|
|
@ -692,9 +732,9 @@ SCLASS struct timeval kern_inc_prio_time
|
|||
#endif
|
||||
|
||||
/* Dead threads: */
|
||||
SCLASS struct pthread * volatile _thread_dead
|
||||
SCLASS TAILQ_HEAD(, pthread) _dead_list
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= NULL;
|
||||
= TAILQ_HEAD_INITIALIZER(_dead_list);
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
|
|
@ -747,6 +787,14 @@ SCLASS struct fd_table_entry **_thread_fd_table
|
|||
;
|
||||
#endif
|
||||
|
||||
/* Table for polling file descriptors: */
|
||||
SCLASS struct pollfd *_thread_pfd_table
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= NULL;
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
|
||||
SCLASS const int dtablecount
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= 4096/sizeof(struct fd_table_entry);
|
||||
|
|
@ -760,6 +808,13 @@ SCLASS int _thread_dtablesize /* Descriptor table size. */
|
|||
;
|
||||
#endif
|
||||
|
||||
SCLASS int _clock_res_nsec /* Clock resolution in nsec. */
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= CLOCK_RES_NSEC;
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
|
||||
/* Garbage collector mutex and condition variable. */
|
||||
SCLASS pthread_mutex_t _gc_mutex
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
|
|
@ -783,8 +838,20 @@ struct sigaction _thread_sigact[NSIG];
|
|||
SCLASS pq_queue_t _readyq;
|
||||
SCLASS TAILQ_HEAD(, pthread) _waitingq;
|
||||
|
||||
/* Indicates that the waitingq now has threads ready to run. */
|
||||
SCLASS volatile int _waitingq_check_reqd
|
||||
/*
|
||||
* Work queue:
|
||||
*/
|
||||
SCLASS TAILQ_HEAD(, pthread) _workq;
|
||||
|
||||
/* Tracks the number of threads blocked while waiting for a spinlock. */
|
||||
SCLASS volatile int _spinblock_count
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= 0
|
||||
#endif
|
||||
;
|
||||
|
||||
/* Indicates that the signal queue needs to be checked. */
|
||||
SCLASS volatile int _sigq_check_reqd
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= 0
|
||||
#endif
|
||||
|
|
@ -797,6 +864,13 @@ SCLASS pthread_switch_routine_t _sched_switch_hook
|
|||
#endif
|
||||
;
|
||||
|
||||
/* Used for _PTHREADS_INVARIANTS checking. */
|
||||
SCLASS int _thread_kern_new_state
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= 0
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
/* Undefine the storage class specifier: */
|
||||
#undef SCLASS
|
||||
|
|
@ -825,18 +899,23 @@ int _thread_fd_lock(int, int, struct timespec *);
|
|||
int _thread_fd_lock_debug(int, int, struct timespec *,char *fname,int lineno);
|
||||
void _dispatch_signals(void);
|
||||
void _thread_signal(pthread_t, int);
|
||||
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 *);
|
||||
int _mutex_reinit(pthread_mutex_t *);
|
||||
void _mutex_notify_priochange(struct pthread *);
|
||||
int _pq_init(struct pq_queue *pq, int, int);
|
||||
int _cond_reinit(pthread_cond_t *);
|
||||
int _pq_alloc(struct pq_queue *, int, int);
|
||||
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);
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
void _waitq_insert(pthread_t pthread);
|
||||
void _waitq_remove(pthread_t pthread);
|
||||
void _waitq_setactive(void);
|
||||
void _waitq_clearactive(void);
|
||||
#endif
|
||||
void _thread_exit(char *, int, char *);
|
||||
void _thread_fd_unlock(int, int);
|
||||
void _thread_fd_unlock_debug(int, int, char *, int);
|
||||
|
|
@ -849,18 +928,15 @@ void _thread_kern_sched_state(enum pthread_state,char *fname,int lineno);
|
|||
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_kern_sig_defer(void);
|
||||
void _thread_kern_sig_undefer(void);
|
||||
void _thread_sig_handler(int, int, struct sigcontext *);
|
||||
void _thread_sig_handle(int, struct sigcontext *);
|
||||
void _thread_sig_init(void);
|
||||
void _thread_start(void);
|
||||
void _thread_start_sig_handler(void);
|
||||
void _thread_seterrno(pthread_t,int);
|
||||
void _thread_queue_init(struct pthread_queue *);
|
||||
void _thread_queue_enq(struct pthread_queue *, struct pthread *);
|
||||
int _thread_queue_remove(struct pthread_queue *, struct pthread *);
|
||||
int _thread_fd_table_init(int fd);
|
||||
struct pthread *_thread_queue_get(struct pthread_queue *);
|
||||
struct pthread *_thread_queue_deq(struct pthread_queue *);
|
||||
pthread_addr_t _thread_gc(pthread_addr_t);
|
||||
|
||||
/* #include <signal.h> */
|
||||
|
|
@ -1036,6 +1112,11 @@ pid_t _thread_sys_waitpid(pid_t, int *, int);
|
|||
pid_t _thread_sys_wait3(int *, int, struct rusage *);
|
||||
pid_t _thread_sys_wait4(pid_t, int *, int, struct rusage *);
|
||||
#endif
|
||||
|
||||
/* #include <poll.h> */
|
||||
#ifdef _SYS_POLL_H_
|
||||
int _thread_sys_poll(struct pollfd *, unsigned, int);
|
||||
#endif
|
||||
__END_DECLS
|
||||
|
||||
#endif /* !_PTHREAD_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -45,12 +47,21 @@ close(int fd)
|
|||
int ret;
|
||||
int status;
|
||||
struct stat sb;
|
||||
struct fd_table_entry *entry;
|
||||
|
||||
/* Lock the file descriptor while the file is closed: */
|
||||
if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
|
||||
/* Get file descriptor status. */
|
||||
_thread_sys_fstat(fd, &sb);
|
||||
|
||||
if ((fd == _thread_kern_pipe[0]) || (fd == _thread_kern_pipe[1])) {
|
||||
/*
|
||||
* Don't allow silly programs to close the kernel pipe.
|
||||
*/
|
||||
errno = EBADF;
|
||||
ret = -1;
|
||||
}
|
||||
/*
|
||||
* Lock the file descriptor while the file is closed and get
|
||||
* the file descriptor status:
|
||||
*/
|
||||
else if (((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) &&
|
||||
((ret = _thread_sys_fstat(fd, &sb)) == 0)) {
|
||||
/*
|
||||
* Check if the file should be left as blocking.
|
||||
*
|
||||
|
|
@ -78,11 +89,14 @@ close(int fd)
|
|||
_thread_sys_fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
}
|
||||
|
||||
/* XXX: Assumes well behaved threads. */
|
||||
/* XXX: Defer real close to avoid race condition */
|
||||
entry = _thread_fd_table[fd];
|
||||
_thread_fd_table[fd] = NULL;
|
||||
free(entry);
|
||||
|
||||
/* Close the file descriptor: */
|
||||
ret = _thread_sys_close(fd);
|
||||
|
||||
free(_thread_fd_table[fd]);
|
||||
_thread_fd_table[fd] = NULL;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -44,6 +45,28 @@ static inline pthread_t cond_queue_deq(pthread_cond_t);
|
|||
static inline void cond_queue_remove(pthread_cond_t, pthread_t);
|
||||
static inline void cond_queue_enq(pthread_cond_t, pthread_t);
|
||||
|
||||
/* Reinitialize a condition variable to defaults. */
|
||||
int
|
||||
_cond_reinit(pthread_cond_t * cond)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (cond == NULL)
|
||||
ret = EINVAL;
|
||||
else if (*cond == NULL)
|
||||
ret = pthread_cond_init(cond, NULL);
|
||||
else {
|
||||
/*
|
||||
* Initialize the condition variable structure:
|
||||
*/
|
||||
TAILQ_INIT(&(*cond)->c_queue);
|
||||
(*cond)->c_flags = COND_FLAGS_INITED;
|
||||
(*cond)->c_type = COND_TYPE_FAST;
|
||||
(*cond)->c_mutex = NULL;
|
||||
memset(&(*cond)->lock, 0, sizeof((*cond)->lock));
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
|
||||
|
|
@ -146,6 +169,9 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
|
|||
*/
|
||||
else if (*cond != NULL ||
|
||||
(rval = pthread_cond_init(cond,NULL)) == 0) {
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
||||
/*
|
||||
* If the condvar was statically allocated, properly
|
||||
* initialize the tail queue.
|
||||
|
|
@ -155,9 +181,6 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
|
|||
(*cond)->c_flags |= COND_FLAGS_INITED;
|
||||
}
|
||||
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
||||
/* Process according to condition variable type: */
|
||||
switch ((*cond)->c_type) {
|
||||
/* Fast condition variable: */
|
||||
|
|
@ -247,6 +270,9 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
|
|||
*/
|
||||
else if (*cond != NULL ||
|
||||
(rval = pthread_cond_init(cond,NULL)) == 0) {
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
||||
/*
|
||||
* If the condvar was statically allocated, properly
|
||||
* initialize the tail queue.
|
||||
|
|
@ -256,10 +282,6 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
|
|||
(*cond)->c_flags |= COND_FLAGS_INITED;
|
||||
}
|
||||
|
||||
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
||||
/* Process according to condition variable type: */
|
||||
switch ((*cond)->c_type) {
|
||||
/* Fast condition variable: */
|
||||
|
|
@ -375,6 +397,12 @@ pthread_cond_signal(pthread_cond_t * cond)
|
|||
if (cond == NULL || *cond == NULL)
|
||||
rval = EINVAL;
|
||||
else {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
||||
|
|
@ -409,6 +437,12 @@ pthread_cond_signal(pthread_cond_t * cond)
|
|||
|
||||
/* Unlock the condition variable structure: */
|
||||
_SPINUNLOCK(&(*cond)->lock);
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
@ -425,14 +459,10 @@ pthread_cond_broadcast(pthread_cond_t * cond)
|
|||
rval = EINVAL;
|
||||
else {
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues. In addition, we must assure
|
||||
* that all threads currently waiting on the condition
|
||||
* variable are signaled and are not timedout by a
|
||||
* scheduling signal that causes a preemption.
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
|
@ -468,9 +498,11 @@ pthread_cond_broadcast(pthread_cond_t * cond)
|
|||
/* Unlock the condition variable structure: */
|
||||
_SPINUNLOCK(&(*cond)->lock);
|
||||
|
||||
/* Reenable preemption and yield if necessary.
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
@ -488,7 +520,7 @@ cond_queue_deq(pthread_cond_t cond)
|
|||
|
||||
if ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
|
||||
TAILQ_REMOVE(&cond->c_queue, pthread, qe);
|
||||
pthread->flags &= ~PTHREAD_FLAGS_QUEUED;
|
||||
pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
|
||||
}
|
||||
|
||||
return(pthread);
|
||||
|
|
@ -507,9 +539,9 @@ cond_queue_remove(pthread_cond_t cond, pthread_t pthread)
|
|||
* guard against removing the thread from the queue if
|
||||
* it isn't in the queue.
|
||||
*/
|
||||
if (pthread->flags & PTHREAD_FLAGS_QUEUED) {
|
||||
if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) {
|
||||
TAILQ_REMOVE(&cond->c_queue, pthread, qe);
|
||||
pthread->flags &= ~PTHREAD_FLAGS_QUEUED;
|
||||
pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -535,6 +567,6 @@ cond_queue_enq(pthread_cond_t cond, pthread_t pthread)
|
|||
tid = TAILQ_NEXT(tid, qe);
|
||||
TAILQ_INSERT_BEFORE(tid, pthread, qe);
|
||||
}
|
||||
pthread->flags |= PTHREAD_FLAGS_QUEUED;
|
||||
pthread->flags |= PTHREAD_FLAGS_IN_CONDQ;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -171,7 +172,7 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
|
|||
new_thread->inherited_priority = 0;
|
||||
|
||||
/* Initialise the join queue for the new thread: */
|
||||
_thread_queue_init(&(new_thread->join_queue));
|
||||
TAILQ_INIT(&(new_thread->join_queue));
|
||||
|
||||
/* Initialize the mutex queue: */
|
||||
TAILQ_INIT(&new_thread->mutexq);
|
||||
|
|
@ -179,46 +180,39 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
|
|||
/* Initialise hooks in the thread structure: */
|
||||
new_thread->specific_data = NULL;
|
||||
new_thread->cleanup = NULL;
|
||||
new_thread->queue = NULL;
|
||||
new_thread->qnxt = NULL;
|
||||
new_thread->flags = 0;
|
||||
new_thread->poll_data.nfds = 0;
|
||||
new_thread->poll_data.fds = NULL;
|
||||
|
||||
/* Lock the thread list: */
|
||||
_lock_thread_list();
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/*
|
||||
* Check if the garbage collector thread
|
||||
* needs to be started.
|
||||
*/
|
||||
f_gc = (_thread_link_list == _thread_initial);
|
||||
f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial);
|
||||
|
||||
/* Add the thread to the linked list of all threads: */
|
||||
new_thread->nxt = _thread_link_list;
|
||||
_thread_link_list = new_thread;
|
||||
|
||||
/* Unlock the thread list: */
|
||||
_unlock_thread_list();
|
||||
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues.
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
|
||||
|
||||
if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {
|
||||
new_thread->state = PS_SUSPENDED;
|
||||
PTHREAD_WAITQ_INSERT(new_thread);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
new_thread->state = PS_RUNNING;
|
||||
PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling
|
||||
* signal occurred while in the critical region.
|
||||
* Undefer and handle pending signals, yielding
|
||||
* if necessary.
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/* Return a pointer to the thread structure: */
|
||||
(*thread) = new_thread;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -53,23 +54,25 @@ pthread_detach(pthread_t pthread)
|
|||
pthread->attr.flags |= PTHREAD_DETACHED;
|
||||
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues.
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Enter a loop to bring all threads off the join queue: */
|
||||
while ((next_thread = _thread_queue_deq(&pthread->join_queue)) != NULL) {
|
||||
while ((next_thread = TAILQ_FIRST(&pthread->join_queue)) != NULL) {
|
||||
/* Remove the thread from the queue: */
|
||||
TAILQ_REMOVE(&pthread->join_queue, next_thread, qe);
|
||||
|
||||
/* Make the thread run: */
|
||||
PTHREAD_NEW_STATE(next_thread,PS_RUNNING);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling signal
|
||||
* occurred while in the critical region.
|
||||
* Undefer and handle pending signals, yielding if a
|
||||
* scheduling signal occurred while in the critical region.
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
} else
|
||||
/* Return an error: */
|
||||
rval = EINVAL;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -92,6 +93,9 @@ execve(const char *name, char *const * argv, char *const * envp)
|
|||
act.sa_mask = _thread_sigact[i - 1].sa_mask;
|
||||
act.sa_flags = _thread_sigact[i - 1].sa_flags;
|
||||
|
||||
/* Ensure the scheduling signal is masked: */
|
||||
sigaddset(&act.sa_mask, _SCHED_SIGNAL);
|
||||
|
||||
/* Change the signal action for the process: */
|
||||
_thread_sys_sigaction(i, &act, &oact);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -92,7 +93,12 @@ _thread_exit(char *fname, int lineno, char *string)
|
|||
_thread_sys_write(2, s, strlen(s));
|
||||
|
||||
/* Force this process to exit: */
|
||||
/* XXX - Do we want abort to be conditional on _PTHREADS_INVARIANTS? */
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
abort();
|
||||
#else
|
||||
_exit(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -129,22 +135,24 @@ pthread_exit(void *status)
|
|||
}
|
||||
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal. A change of
|
||||
* thread state modifies the waiting and priority queues.
|
||||
* Defer signals to protect the scheduling queues from access
|
||||
* by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Check if there are any threads joined to this one: */
|
||||
while ((pthread = _thread_queue_deq(&(_thread_run->join_queue))) != NULL) {
|
||||
while ((pthread = TAILQ_FIRST(&(_thread_run->join_queue))) != NULL) {
|
||||
/* Remove the thread from the queue: */
|
||||
TAILQ_REMOVE(&_thread_run->join_queue, pthread, qe);
|
||||
|
||||
/* Wake the joined thread and let it detach this thread: */
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling signal
|
||||
* occurred while in the critical region.
|
||||
* Undefer and handle pending signals, yielding if necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/*
|
||||
* Lock the garbage collector mutex to ensure that the garbage
|
||||
|
|
@ -154,8 +162,21 @@ pthread_exit(void *status)
|
|||
PANIC("Cannot lock gc mutex");
|
||||
|
||||
/* Add this thread to the list of dead threads. */
|
||||
_thread_run->nxt_dead = _thread_dead;
|
||||
_thread_dead = _thread_run;
|
||||
TAILQ_INSERT_HEAD(&_dead_list, _thread_run, dle);
|
||||
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from access
|
||||
* by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Remove this thread from the thread list: */
|
||||
TAILQ_REMOVE(&_thread_list, _thread_run, tle);
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/*
|
||||
* Signal the garbage collector thread that there is something
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: uthread_fd.c,v 1.9 1998/09/13 15:33:42 dt Exp $
|
||||
* $Id: uthread_fd.c,v 1.10 1999/03/23 05:07:55 jb Exp $
|
||||
*
|
||||
*/
|
||||
#include <errno.h>
|
||||
|
|
@ -84,14 +84,14 @@ _thread_fd_table_init(int fd)
|
|||
entry->w_owner = NULL;
|
||||
entry->r_fname = NULL;
|
||||
entry->w_fname = NULL;
|
||||
entry->r_lineno = 0;;
|
||||
entry->w_lineno = 0;;
|
||||
entry->r_lockcount = 0;;
|
||||
entry->w_lockcount = 0;;
|
||||
entry->r_lineno = 0;
|
||||
entry->w_lineno = 0;
|
||||
entry->r_lockcount = 0;
|
||||
entry->w_lockcount = 0;
|
||||
|
||||
/* Initialise the read/write queues: */
|
||||
_thread_queue_init(&entry->r_queue);
|
||||
_thread_queue_init(&entry->w_queue);
|
||||
TAILQ_INIT(&entry->r_queue);
|
||||
TAILQ_INIT(&entry->w_queue);
|
||||
|
||||
/* Get the flags for the file: */
|
||||
if (fd >= 3 && (entry->flags =
|
||||
|
|
@ -168,6 +168,12 @@ _thread_fd_unlock(int fd, int lock_type)
|
|||
* entry:
|
||||
*/
|
||||
if ((ret = _thread_fd_table_init(fd)) == 0) {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/*
|
||||
* Lock the file descriptor table entry to prevent
|
||||
* other threads for clashing with the current
|
||||
|
|
@ -195,8 +201,12 @@ _thread_fd_unlock(int fd, int lock_type)
|
|||
* Get the next thread in the queue for a
|
||||
* read lock on this file descriptor:
|
||||
*/
|
||||
else if ((_thread_fd_table[fd]->r_owner = _thread_queue_deq(&_thread_fd_table[fd]->r_queue)) == NULL) {
|
||||
else if ((_thread_fd_table[fd]->r_owner = TAILQ_FIRST(&_thread_fd_table[fd]->r_queue)) == NULL) {
|
||||
} else {
|
||||
/* Remove this thread from the queue: */
|
||||
TAILQ_REMOVE(&_thread_fd_table[fd]->r_queue,
|
||||
_thread_fd_table[fd]->r_owner, qe);
|
||||
|
||||
/*
|
||||
* Set the state of the new owner of
|
||||
* the thread to running:
|
||||
|
|
@ -233,8 +243,12 @@ _thread_fd_unlock(int fd, int lock_type)
|
|||
* Get the next thread in the queue for a
|
||||
* write lock on this file descriptor:
|
||||
*/
|
||||
else if ((_thread_fd_table[fd]->w_owner = _thread_queue_deq(&_thread_fd_table[fd]->w_queue)) == NULL) {
|
||||
else if ((_thread_fd_table[fd]->w_owner = TAILQ_FIRST(&_thread_fd_table[fd]->w_queue)) == NULL) {
|
||||
} else {
|
||||
/* Remove this thread from the queue: */
|
||||
TAILQ_REMOVE(&_thread_fd_table[fd]->w_queue,
|
||||
_thread_fd_table[fd]->w_owner, qe);
|
||||
|
||||
/*
|
||||
* Set the state of the new owner of
|
||||
* the thread to running:
|
||||
|
|
@ -254,6 +268,12 @@ _thread_fd_unlock(int fd, int lock_type)
|
|||
|
||||
/* Unlock the file descriptor table entry: */
|
||||
_SPINUNLOCK(&_thread_fd_table[fd]->lock);
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Nothing to return. */
|
||||
|
|
@ -295,7 +315,7 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout)
|
|||
* queue of threads waiting for a
|
||||
* read lock on this file descriptor:
|
||||
*/
|
||||
_thread_queue_enq(&_thread_fd_table[fd]->r_queue, _thread_run);
|
||||
TAILQ_INSERT_TAIL(&_thread_fd_table[fd]->r_queue, _thread_run, qe);
|
||||
|
||||
/*
|
||||
* Save the file descriptor details
|
||||
|
|
@ -368,7 +388,7 @@ _thread_fd_lock(int fd, int lock_type, struct timespec * timeout)
|
|||
* write lock on this file
|
||||
* descriptor:
|
||||
*/
|
||||
_thread_queue_enq(&_thread_fd_table[fd]->w_queue, _thread_run);
|
||||
TAILQ_INSERT_TAIL(&_thread_fd_table[fd]->w_queue, _thread_run, qe);
|
||||
|
||||
/*
|
||||
* Save the file descriptor details
|
||||
|
|
@ -439,6 +459,12 @@ _thread_fd_unlock_debug(int fd, int lock_type, char *fname, int lineno)
|
|||
* entry:
|
||||
*/
|
||||
if ((ret = _thread_fd_table_init(fd)) == 0) {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/*
|
||||
* Lock the file descriptor table entry to prevent
|
||||
* other threads for clashing with the current
|
||||
|
|
@ -466,8 +492,12 @@ _thread_fd_unlock_debug(int fd, int lock_type, char *fname, int lineno)
|
|||
* Get the next thread in the queue for a
|
||||
* read lock on this file descriptor:
|
||||
*/
|
||||
else if ((_thread_fd_table[fd]->r_owner = _thread_queue_deq(&_thread_fd_table[fd]->r_queue)) == NULL) {
|
||||
else if ((_thread_fd_table[fd]->r_owner = TAILQ_FIRST(&_thread_fd_table[fd]->r_queue)) == NULL) {
|
||||
} else {
|
||||
/* Remove this thread from the queue: */
|
||||
TAILQ_REMOVE(&_thread_fd_table[fd]->r_queue,
|
||||
_thread_fd_table[fd]->r_owner, qe);
|
||||
|
||||
/*
|
||||
* Set the state of the new owner of
|
||||
* the thread to running:
|
||||
|
|
@ -504,8 +534,12 @@ _thread_fd_unlock_debug(int fd, int lock_type, char *fname, int lineno)
|
|||
* Get the next thread in the queue for a
|
||||
* write lock on this file descriptor:
|
||||
*/
|
||||
else if ((_thread_fd_table[fd]->w_owner = _thread_queue_deq(&_thread_fd_table[fd]->w_queue)) == NULL) {
|
||||
else if ((_thread_fd_table[fd]->w_owner = TAILQ_FIRST(&_thread_fd_table[fd]->w_queue)) == NULL) {
|
||||
} else {
|
||||
/* Remove this thread from the queue: */
|
||||
TAILQ_REMOVE(&_thread_fd_table[fd]->w_queue,
|
||||
_thread_fd_table[fd]->w_owner, qe);
|
||||
|
||||
/*
|
||||
* Set the state of the new owner of
|
||||
* the thread to running:
|
||||
|
|
@ -525,6 +559,12 @@ _thread_fd_unlock_debug(int fd, int lock_type, char *fname, int lineno)
|
|||
|
||||
/* Unlock the file descriptor table entry: */
|
||||
_SPINUNLOCK(&_thread_fd_table[fd]->lock);
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary.
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Nothing to return. */
|
||||
|
|
@ -567,7 +607,7 @@ _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout,
|
|||
* queue of threads waiting for a
|
||||
* read lock on this file descriptor:
|
||||
*/
|
||||
_thread_queue_enq(&_thread_fd_table[fd]->r_queue, _thread_run);
|
||||
TAILQ_INSERT_TAIL(&_thread_fd_table[fd]->r_queue, _thread_run, qe);
|
||||
|
||||
/*
|
||||
* Save the file descriptor details
|
||||
|
|
@ -649,7 +689,7 @@ _thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout,
|
|||
* write lock on this file
|
||||
* descriptor:
|
||||
*/
|
||||
_thread_queue_enq(&_thread_fd_table[fd]->w_queue, _thread_run);
|
||||
TAILQ_INSERT_TAIL(&_thread_fd_table[fd]->w_queue, _thread_run, qe);
|
||||
|
||||
/*
|
||||
* Save the file descriptor details
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: uthread_file.c,v 1.5 1998/09/07 21:55:01 alex Exp $
|
||||
* $Id: uthread_file.c,v 1.6 1998/09/09 16:50:33 dt Exp $
|
||||
*
|
||||
* POSIX stdio FILE locking functions. These assume that the locking
|
||||
* is only required at FILE structure level, not at file descriptor
|
||||
|
|
@ -310,6 +310,12 @@ _funlockfile(FILE * fp)
|
|||
|
||||
/* Check if this is a real file: */
|
||||
if (fp->_file >= 0) {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the hash table: */
|
||||
_SPINLOCK(&hash_lock);
|
||||
|
||||
|
|
@ -356,6 +362,12 @@ _funlockfile(FILE * fp)
|
|||
|
||||
/* Unlock the hash table: */
|
||||
_SPINUNLOCK(&hash_lock);
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -46,20 +47,20 @@ _find_thread(pthread_t pthread)
|
|||
/* Invalid thread: */
|
||||
return(EINVAL);
|
||||
|
||||
/* Lock the thread list: */
|
||||
_lock_thread_list();
|
||||
/*
|
||||
* Defer signals to protect the thread list from access
|
||||
* by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Point to the first thread in the list: */
|
||||
pthread1 = _thread_link_list;
|
||||
|
||||
/* Search for the thread to join to: */
|
||||
while (pthread1 != NULL && pthread1 != pthread) {
|
||||
/* Point to the next thread: */
|
||||
pthread1 = pthread1->nxt;
|
||||
/* Search for the specified thread: */
|
||||
TAILQ_FOREACH(pthread1, &_thread_list, tle) {
|
||||
if (pthread == pthread1)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Unlock the thread list: */
|
||||
_unlock_thread_list();
|
||||
/* Undefer and handle pending signals, yielding if necessary: */
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/* Return zero if the thread exists: */
|
||||
return ((pthread1 != NULL) ? 0:ESRCH);
|
||||
|
|
@ -83,13 +84,10 @@ _find_dead_thread(pthread_t pthread)
|
|||
if (pthread_mutex_lock(&_gc_mutex) != 0)
|
||||
PANIC("Cannot lock gc mutex");
|
||||
|
||||
/* Point to the first thread in the list: */
|
||||
pthread1 = _thread_dead;
|
||||
|
||||
/* Search for the thread to join to: */
|
||||
while (pthread1 != NULL && pthread1 != pthread) {
|
||||
/* Point to the next thread: */
|
||||
pthread1 = pthread1->nxt_dead;
|
||||
/* Search for the specified thread: */
|
||||
TAILQ_FOREACH(pthread1, &_dead_list, dle) {
|
||||
if (pthread1 == pthread)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Unlock the garbage collector mutex: */
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
|
@ -44,10 +45,13 @@ fork(void)
|
|||
int i, flags;
|
||||
pid_t ret;
|
||||
pthread_t pthread;
|
||||
pthread_t pthread_next;
|
||||
pthread_t pthread_save;
|
||||
|
||||
/* Lock the thread list: */
|
||||
_lock_thread_list();
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from access
|
||||
* by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Fork a new process: */
|
||||
if ((ret = _thread_sys_fork()) != 0) {
|
||||
|
|
@ -88,45 +92,79 @@ fork(void)
|
|||
else if (_thread_sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
/* Abort this application: */
|
||||
abort();
|
||||
/* Initialize the ready queue: */
|
||||
} else if (_pq_init(&_readyq, PTHREAD_MIN_PRIORITY,
|
||||
PTHREAD_MAX_PRIORITY) != 0) {
|
||||
}
|
||||
/* Reinitialize the GC mutex: */
|
||||
else if (_mutex_reinit(&_gc_mutex) != 0) {
|
||||
/* Abort this application: */
|
||||
PANIC("Cannot allocate priority ready queue.");
|
||||
PANIC("Cannot initialize GC mutex for forked process");
|
||||
}
|
||||
/* Reinitialize the GC condition variable: */
|
||||
else if (_cond_reinit(&_gc_cond) != 0) {
|
||||
/* Abort this application: */
|
||||
PANIC("Cannot initialize GC condvar for forked process");
|
||||
}
|
||||
/* Initialize the ready queue: */
|
||||
else if (_pq_init(&_readyq) != 0) {
|
||||
/* Abort this application: */
|
||||
PANIC("Cannot initialize priority ready queue.");
|
||||
} else {
|
||||
/* Point to the first thread in the list: */
|
||||
pthread = _thread_link_list;
|
||||
|
||||
/*
|
||||
* Enter a loop to remove all threads other than
|
||||
* the running thread from the thread list:
|
||||
*/
|
||||
pthread = TAILQ_FIRST(&_thread_list);
|
||||
while (pthread != NULL) {
|
||||
pthread_next = pthread->nxt;
|
||||
if (pthread == _thread_run) {
|
||||
_thread_link_list = pthread;
|
||||
pthread->nxt = NULL;
|
||||
} else {
|
||||
if (pthread->attr.stackaddr_attr ==
|
||||
NULL && pthread->stack != NULL)
|
||||
/* Save the thread to be freed: */
|
||||
pthread_save = pthread;
|
||||
|
||||
/*
|
||||
* Advance to the next thread before
|
||||
* destroying the current thread:
|
||||
*/
|
||||
pthread = TAILQ_NEXT(pthread, dle);
|
||||
|
||||
/* Make sure this isn't the running thread: */
|
||||
if (pthread_save != _thread_run) {
|
||||
/* Remove this thread from the list: */
|
||||
TAILQ_REMOVE(&_thread_list,
|
||||
pthread_save, tle);
|
||||
|
||||
if (pthread_save->attr.stackaddr_attr ==
|
||||
NULL && pthread_save->stack != NULL)
|
||||
/*
|
||||
* Free the stack of the
|
||||
* dead thread:
|
||||
*/
|
||||
free(pthread->stack);
|
||||
free(pthread_save->stack);
|
||||
|
||||
if (pthread->specific_data != NULL)
|
||||
free(pthread->specific_data);
|
||||
if (pthread_save->specific_data != NULL)
|
||||
free(pthread_save->specific_data);
|
||||
|
||||
free(pthread);
|
||||
if (pthread_save->poll_data.fds != NULL)
|
||||
free(pthread_save->poll_data.fds);
|
||||
|
||||
free(pthread_save);
|
||||
}
|
||||
|
||||
/* Point to the next thread: */
|
||||
pthread = pthread_next;
|
||||
}
|
||||
|
||||
/* Re-init the waiting queues. */
|
||||
/* Re-init the dead thread list: */
|
||||
TAILQ_INIT(&_dead_list);
|
||||
|
||||
/* Re-init the waiting and work queues. */
|
||||
TAILQ_INIT(&_waitingq);
|
||||
TAILQ_INIT(&_workq);
|
||||
|
||||
/* Re-init the threads mutex queue: */
|
||||
TAILQ_INIT(&_thread_run->mutexq);
|
||||
|
||||
/* No spinlocks yet: */
|
||||
_spinblock_count = 0;
|
||||
|
||||
/* Don't queue signals yet: */
|
||||
_queue_signals = 0;
|
||||
|
||||
/* Initialize signal handling: */
|
||||
_thread_sig_init();
|
||||
|
||||
/* Initialize the scheduling switch hook routine: */
|
||||
_sched_switch_hook = NULL;
|
||||
|
|
@ -147,15 +185,17 @@ fork(void)
|
|||
_thread_fd_table[i]->w_lockcount = 0;;
|
||||
|
||||
/* Initialise the read/write queues: */
|
||||
_thread_queue_init(&_thread_fd_table[i]->r_queue);
|
||||
_thread_queue_init(&_thread_fd_table[i]->w_queue);
|
||||
TAILQ_INIT(&_thread_fd_table[i]->r_queue);
|
||||
TAILQ_INIT(&_thread_fd_table[i]->w_queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Unock the thread list: */
|
||||
_unlock_thread_list();
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/* Return the process ID: */
|
||||
return (ret);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: uthread_gc.c,v 1.2 1998/09/30 19:17:51 dt Exp $
|
||||
* $Id: uthread_gc.c,v 1.3 1999/03/23 05:07:55 jb Exp $
|
||||
*
|
||||
* Garbage collector thread. Frees memory allocated for dead threads.
|
||||
*
|
||||
|
|
@ -74,20 +74,26 @@ _thread_gc(pthread_addr_t arg)
|
|||
/* Dump thread info to file. */
|
||||
_thread_dump_info();
|
||||
|
||||
/* Lock the thread list: */
|
||||
_lock_thread_list();
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Check if this is the last running thread: */
|
||||
if (_thread_link_list == _thread_run &&
|
||||
_thread_link_list->nxt == NULL)
|
||||
if (TAILQ_FIRST(&_thread_list) == _thread_run &&
|
||||
TAILQ_NEXT(_thread_run, tle) == NULL)
|
||||
/*
|
||||
* This is the last thread, so it can exit
|
||||
* now.
|
||||
*/
|
||||
f_done = 1;
|
||||
|
||||
/* Unlock the thread list: */
|
||||
_unlock_thread_list();
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/*
|
||||
* Lock the garbage collector mutex which ensures that
|
||||
|
|
@ -100,48 +106,24 @@ _thread_gc(pthread_addr_t arg)
|
|||
p_stack = NULL;
|
||||
pthread_cln = NULL;
|
||||
|
||||
/* Point to the first dead thread (if there are any): */
|
||||
pthread = _thread_dead;
|
||||
|
||||
/* There is no previous dead thread: */
|
||||
pthread_prv = NULL;
|
||||
|
||||
/*
|
||||
* Enter a loop to search for the first dead thread that
|
||||
* has memory to free.
|
||||
*/
|
||||
while (p_stack == NULL && pthread_cln == NULL &&
|
||||
pthread != NULL) {
|
||||
/* Save a pointer to the next thread: */
|
||||
pthread_nxt = pthread->nxt_dead;
|
||||
|
||||
for (pthread = TAILQ_FIRST(&_dead_list);
|
||||
p_stack == NULL && pthread_cln == NULL && pthread != NULL;
|
||||
pthread = TAILQ_NEXT(pthread, dle)) {
|
||||
/* Check if the initial thread: */
|
||||
if (pthread == _thread_initial)
|
||||
if (pthread == _thread_initial) {
|
||||
/* Don't destroy the initial thread. */
|
||||
pthread_prv = pthread;
|
||||
|
||||
}
|
||||
/*
|
||||
* Check if this thread has detached:
|
||||
*/
|
||||
else if ((pthread->attr.flags &
|
||||
PTHREAD_DETACHED) != 0) {
|
||||
/*
|
||||
* Check if there is no previous dead
|
||||
* thread:
|
||||
*/
|
||||
if (pthread_prv == NULL)
|
||||
/*
|
||||
* The dead thread is at the head
|
||||
* of the list:
|
||||
*/
|
||||
_thread_dead = pthread_nxt;
|
||||
else
|
||||
/*
|
||||
* The dead thread is not at the
|
||||
* head of the list:
|
||||
*/
|
||||
pthread_prv->nxt_dead =
|
||||
pthread->nxt_dead;
|
||||
/* Remove this thread from the dead list: */
|
||||
TAILQ_REMOVE(&_dead_list, pthread, dle);
|
||||
|
||||
/*
|
||||
* Check if the stack was not specified by
|
||||
|
|
@ -162,14 +144,12 @@ _thread_gc(pthread_addr_t arg)
|
|||
* be freed outside the locks:
|
||||
*/
|
||||
pthread_cln = pthread;
|
||||
|
||||
} else {
|
||||
/*
|
||||
* This thread has not detached, so do
|
||||
* not destroy it:
|
||||
*/
|
||||
pthread_prv = pthread;
|
||||
|
||||
/*
|
||||
* not destroy it.
|
||||
*
|
||||
* Check if the stack was not specified by
|
||||
* the caller to pthread_create and has not
|
||||
* been destroyed yet:
|
||||
|
|
@ -189,9 +169,6 @@ _thread_gc(pthread_addr_t arg)
|
|||
pthread->stack = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Point to the next thread: */
|
||||
pthread = pthread_nxt;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -229,52 +206,12 @@ _thread_gc(pthread_addr_t arg)
|
|||
*/
|
||||
if (p_stack != NULL)
|
||||
free(p_stack);
|
||||
if (pthread_cln != NULL) {
|
||||
/* Lock the thread list: */
|
||||
_lock_thread_list();
|
||||
|
||||
/*
|
||||
* Check if the thread is at the head of the
|
||||
* linked list.
|
||||
*/
|
||||
if (_thread_link_list == pthread_cln)
|
||||
/* There is no previous thread: */
|
||||
_thread_link_list = pthread_cln->nxt;
|
||||
else {
|
||||
/* Point to the first thread in the list: */
|
||||
pthread = _thread_link_list;
|
||||
|
||||
/*
|
||||
* Enter a loop to find the thread in the
|
||||
* linked list before the thread that is
|
||||
* about to be freed.
|
||||
*/
|
||||
while (pthread != NULL &&
|
||||
pthread->nxt != pthread_cln)
|
||||
/* Point to the next thread: */
|
||||
pthread = pthread->nxt;
|
||||
|
||||
/* Check that a previous thread was found: */
|
||||
if (pthread != NULL) {
|
||||
/*
|
||||
* Point the previous thread to
|
||||
* the one after the thread being
|
||||
* freed:
|
||||
*/
|
||||
pthread->nxt = pthread_cln->nxt;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unlock the thread list: */
|
||||
_unlock_thread_list();
|
||||
|
||||
if (pthread_cln != NULL)
|
||||
/*
|
||||
* Free the memory allocated for the thread
|
||||
* structure.
|
||||
*/
|
||||
free(pthread_cln);
|
||||
}
|
||||
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -55,6 +56,7 @@ static const struct s_thread_info thread_info[] = {
|
|||
{PS_FDR_WAIT , "Waiting for read"},
|
||||
{PS_FDW_WAIT , "Waiting for write"},
|
||||
{PS_FILE_WAIT , "Waiting for FILE lock"},
|
||||
{PS_POLL_WAIT , "Waiting on poll"},
|
||||
{PS_SELECT_WAIT , "Waiting on select"},
|
||||
{PS_SLEEP_WAIT , "Sleeping"},
|
||||
{PS_WAIT_WAIT , "Waiting process"},
|
||||
|
|
@ -108,8 +110,7 @@ _thread_dump_info(void)
|
|||
_thread_sys_write(fd, s, strlen(s));
|
||||
|
||||
/* Enter a loop to report each thread in the global list: */
|
||||
for (pthread = _thread_link_list; pthread != NULL;
|
||||
pthread = pthread->nxt) {
|
||||
TAILQ_FOREACH(pthread, &_thread_list, tle) {
|
||||
/* Find the state: */
|
||||
for (j = 0; j < (sizeof(thread_info) /
|
||||
sizeof(struct s_thread_info)) - 1; j++)
|
||||
|
|
@ -214,8 +215,29 @@ _thread_dump_info(void)
|
|||
_thread_sys_write(fd, s, strlen(s));
|
||||
}
|
||||
|
||||
/* Output a header for threads in the work queue: */
|
||||
strcpy(s, "\n\n=============\nTHREADS IN WORKQ\n\n");
|
||||
_thread_sys_write(fd, s, strlen(s));
|
||||
|
||||
/* Enter a loop to report each thread in the waiting queue: */
|
||||
TAILQ_FOREACH (pthread, &_workq, qe) {
|
||||
/* Find the state: */
|
||||
for (j = 0; j < (sizeof(thread_info) /
|
||||
sizeof(struct s_thread_info)) - 1; j++)
|
||||
if (thread_info[j].state == pthread->state)
|
||||
break;
|
||||
/* Output a record for the current thread: */
|
||||
snprintf(s, sizeof(s),
|
||||
"--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
|
||||
pthread, (pthread->name == NULL) ?
|
||||
"":pthread->name, pthread->base_priority,
|
||||
thread_info[j].name,
|
||||
pthread->fname,pthread->lineno);
|
||||
_thread_sys_write(fd, s, strlen(s));
|
||||
}
|
||||
|
||||
/* Check if there are no dead threads: */
|
||||
if (_thread_dead == NULL) {
|
||||
if (TAILQ_FIRST(&_dead_list) == NULL) {
|
||||
/* Output a record: */
|
||||
strcpy(s, "\n\nTHERE ARE NO DEAD THREADS\n");
|
||||
_thread_sys_write(fd, s, strlen(s));
|
||||
|
|
@ -228,8 +250,7 @@ _thread_dump_info(void)
|
|||
* Enter a loop to report each thread in the global
|
||||
* dead thread list:
|
||||
*/
|
||||
for (pthread = _thread_dead; pthread != NULL;
|
||||
pthread = pthread->nxt_dead) {
|
||||
TAILQ_FOREACH(pthread, &_dead_list, dle) {
|
||||
/* Output a record for the current thread: */
|
||||
snprintf(s, sizeof(s),
|
||||
"Thread %p prio %3d [%s:%d]\n",
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/* Allocate space for global thread variables here: */
|
||||
|
|
@ -39,7 +40,9 @@
|
|||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ttycom.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -81,6 +84,9 @@ _thread_init(void)
|
|||
int fd;
|
||||
int flags;
|
||||
int i;
|
||||
int len;
|
||||
int mib[2];
|
||||
struct clockinfo clockinfo;
|
||||
struct sigaction act;
|
||||
|
||||
/* Check if this function has already been called: */
|
||||
|
|
@ -147,8 +153,8 @@ _thread_init(void)
|
|||
/* Abort this application: */
|
||||
PANIC("Cannot get kernel write pipe flags");
|
||||
}
|
||||
/* Initialize the ready queue: */
|
||||
else if (_pq_init(&_readyq, PTHREAD_MIN_PRIORITY, PTHREAD_MAX_PRIORITY) != 0) {
|
||||
/* Allocate and initialize the ready queue: */
|
||||
else if (_pq_alloc(&_readyq, PTHREAD_MIN_PRIORITY, PTHREAD_MAX_PRIORITY) != 0) {
|
||||
/* Abort this application: */
|
||||
PANIC("Cannot allocate priority ready queue.");
|
||||
}
|
||||
|
|
@ -165,8 +171,9 @@ _thread_init(void)
|
|||
_thread_kern_thread.flags = PTHREAD_FLAGS_PRIVATE;
|
||||
memset(_thread_initial, 0, sizeof(struct pthread));
|
||||
|
||||
/* Initialize the waiting queue: */
|
||||
/* Initialize the waiting and work queues: */
|
||||
TAILQ_INIT(&_waitingq);
|
||||
TAILQ_INIT(&_workq);
|
||||
|
||||
/* Initialize the scheduling switch hook routine: */
|
||||
_sched_switch_hook = NULL;
|
||||
|
|
@ -186,23 +193,23 @@ _thread_init(void)
|
|||
_thread_initial->state = PS_RUNNING;
|
||||
|
||||
/* Initialise the queue: */
|
||||
_thread_queue_init(&(_thread_initial->join_queue));
|
||||
TAILQ_INIT(&(_thread_initial->join_queue));
|
||||
|
||||
/* Initialize the owned mutex queue and count: */
|
||||
TAILQ_INIT(&(_thread_initial->mutexq));
|
||||
_thread_initial->priority_mutex_count = 0;
|
||||
|
||||
/* Initialise the rest of the fields: */
|
||||
_thread_initial->sched_defer_count = 0;
|
||||
_thread_initial->yield_on_sched_undefer = 0;
|
||||
_thread_initial->poll_data.nfds = 0;
|
||||
_thread_initial->poll_data.fds = NULL;
|
||||
_thread_initial->sig_defer_count = 0;
|
||||
_thread_initial->yield_on_sig_undefer = 0;
|
||||
_thread_initial->specific_data = NULL;
|
||||
_thread_initial->cleanup = NULL;
|
||||
_thread_initial->queue = NULL;
|
||||
_thread_initial->qnxt = NULL;
|
||||
_thread_initial->nxt = NULL;
|
||||
_thread_initial->flags = 0;
|
||||
_thread_initial->error = 0;
|
||||
_thread_link_list = _thread_initial;
|
||||
TAILQ_INIT(&_thread_list);
|
||||
TAILQ_INSERT_HEAD(&_thread_list, _thread_initial, tle);
|
||||
_thread_run = _thread_initial;
|
||||
|
||||
/* Initialise the global signal action structure: */
|
||||
|
|
@ -210,6 +217,9 @@ _thread_init(void)
|
|||
act.sa_handler = (void (*) ()) _thread_sig_handler;
|
||||
act.sa_flags = 0;
|
||||
|
||||
/* Initialize signal handling: */
|
||||
_thread_sig_init();
|
||||
|
||||
/* Enter a loop to get the existing signal status: */
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
/* Check for signals which cannot be trapped: */
|
||||
|
|
@ -241,6 +251,13 @@ _thread_init(void)
|
|||
PANIC("Cannot initialise signal handler");
|
||||
}
|
||||
|
||||
/* Get the kernel clockrate: */
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_CLOCKRATE;
|
||||
len = sizeof (struct clockinfo);
|
||||
if (sysctl(mib, 2, &clockinfo, &len, NULL, 0) == 0)
|
||||
_clock_res_nsec = clockinfo.tick * 1000;
|
||||
|
||||
/* Get the table size: */
|
||||
if ((_thread_dtablesize = getdtablesize()) < 0) {
|
||||
/*
|
||||
|
|
@ -256,6 +273,14 @@ _thread_init(void)
|
|||
* table, so abort this process.
|
||||
*/
|
||||
PANIC("Cannot allocate memory for file descriptor table");
|
||||
}
|
||||
/* Allocate memory for the pollfd table: */
|
||||
if ((_thread_pfd_table = (struct pollfd *) malloc(sizeof(struct pollfd) * _thread_dtablesize)) == NULL) {
|
||||
/*
|
||||
* Cannot allocate memory for the file descriptor
|
||||
* table, so abort this process.
|
||||
*/
|
||||
PANIC("Cannot allocate memory for pollfd table");
|
||||
} else {
|
||||
/*
|
||||
* Enter a loop to initialise the file descriptor
|
||||
|
|
@ -265,6 +290,14 @@ _thread_init(void)
|
|||
/* Initialise the file descriptor table: */
|
||||
_thread_fd_table[i] = NULL;
|
||||
}
|
||||
|
||||
/* Initialize stdio file descriptor table entries: */
|
||||
if ((_thread_fd_table_init(0) != 0) ||
|
||||
(_thread_fd_table_init(1) != 0) ||
|
||||
(_thread_fd_table_init(2) != 0)) {
|
||||
PANIC("Cannot initialize stdio file descriptor "
|
||||
"table entries");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -71,7 +72,7 @@ pthread_join(pthread_t pthread, void **thread_return)
|
|||
/* Check if the thread is not dead: */
|
||||
else if (pthread->state != PS_DEAD) {
|
||||
/* Add the running thread to the join queue: */
|
||||
_thread_queue_enq(&(pthread->join_queue), _thread_run);
|
||||
TAILQ_INSERT_TAIL(&(pthread->join_queue), _thread_run, qe);
|
||||
|
||||
/* Schedule the next thread: */
|
||||
_thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
|
@ -46,18 +47,18 @@ pthread_kill(pthread_t pthread, int sig)
|
|||
/* Invalid signal: */
|
||||
ret = EINVAL;
|
||||
|
||||
/* Ignored signals get dropped on the floor. */
|
||||
else if (_thread_sigact[sig - 1].sa_handler == SIG_IGN)
|
||||
ret = 0;
|
||||
|
||||
/* Find the thread in the list of active threads: */
|
||||
else if ((ret = _find_thread(pthread)) == 0) {
|
||||
/*
|
||||
* Ensure the thread is in the list of active threads, and the
|
||||
* signal is valid (signal 0 specifies error checking only) and
|
||||
* not being ignored:
|
||||
*/
|
||||
else if (((ret = _find_thread(pthread)) == 0) && (sig > 0) &&
|
||||
(_thread_sigact[sig - 1].sa_handler != SIG_IGN)) {
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues.
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
switch (pthread->state) {
|
||||
case PS_SIGSUSPEND:
|
||||
|
|
@ -90,15 +91,19 @@ pthread_kill(pthread_t pthread, int sig)
|
|||
sigaddset(&pthread->sigpend,sig);
|
||||
break;
|
||||
|
||||
case PS_SELECT_WAIT:
|
||||
case PS_FDR_WAIT:
|
||||
case PS_FDW_WAIT:
|
||||
case PS_POLL_WAIT:
|
||||
case PS_SLEEP_WAIT:
|
||||
case PS_SELECT_WAIT:
|
||||
if (!sigismember(&pthread->sigmask, sig) &&
|
||||
(_thread_sigact[sig - 1].sa_handler != SIG_IGN)) {
|
||||
/* Flag the operation as interrupted: */
|
||||
pthread->interrupted = 1;
|
||||
|
||||
if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
|
||||
PTHREAD_WORKQ_REMOVE(pthread);
|
||||
|
||||
/* Change the state of the thread to run: */
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
|
||||
|
|
@ -116,11 +121,43 @@ pthread_kill(pthread_t pthread, int sig)
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling signal
|
||||
* occurred while in the critical region.
|
||||
* Check that a custom handler is installed
|
||||
* and if the signal is not blocked:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
if (_thread_sigact[sig - 1].sa_handler != SIG_DFL &&
|
||||
_thread_sigact[sig - 1].sa_handler != SIG_IGN &&
|
||||
sigismember(&pthread->sigpend, sig) &&
|
||||
!sigismember(&pthread->sigmask, sig)) {
|
||||
pthread_t pthread_saved = _thread_run;
|
||||
|
||||
/* Current thread inside critical region? */
|
||||
if (_thread_run->sig_defer_count > 0)
|
||||
pthread->sig_defer_count++;
|
||||
|
||||
_thread_run = pthread;
|
||||
|
||||
/* Clear the pending signal: */
|
||||
sigdelset(&pthread->sigpend, sig);
|
||||
|
||||
/*
|
||||
* Dispatch the signal via the custom signal
|
||||
* handler:
|
||||
*/
|
||||
(*(_thread_sigact[sig - 1].sa_handler))(sig);
|
||||
|
||||
_thread_run = pthread_saved;
|
||||
|
||||
if (_thread_run->sig_defer_count > 0)
|
||||
pthread->sig_defer_count--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -39,6 +40,25 @@
|
|||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
#define _MUTEX_INIT_LINK(m) do { \
|
||||
(m)->m_qe.tqe_prev = NULL; \
|
||||
(m)->m_qe.tqe_next = NULL; \
|
||||
} while (0)
|
||||
#define _MUTEX_ASSERT_IS_OWNED(m) do { \
|
||||
if ((m)->m_qe.tqe_prev == NULL) \
|
||||
PANIC("mutex is not on list"); \
|
||||
} while (0)
|
||||
#define _MUTEX_ASSERT_NOT_OWNED(m) do { \
|
||||
if (((m)->m_qe.tqe_prev != NULL) || \
|
||||
((m)->m_qe.tqe_next != NULL)) \
|
||||
PANIC("mutex is on list"); \
|
||||
} while (0)
|
||||
#else
|
||||
#define _MUTEX_INIT_LINK(m)
|
||||
#define _MUTEX_ASSERT_IS_OWNED(m)
|
||||
#define _MUTEX_ASSERT_NOT_OWNED(m)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
|
|
@ -55,6 +75,34 @@ static inline void mutex_queue_enq(pthread_mutex_t, pthread_t);
|
|||
|
||||
static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER;
|
||||
|
||||
/* Reinitialize a mutex to defaults. */
|
||||
int
|
||||
_mutex_reinit(pthread_mutex_t * mutex)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (mutex == NULL)
|
||||
ret = EINVAL;
|
||||
else if (*mutex == NULL)
|
||||
ret = pthread_mutex_init(mutex, NULL);
|
||||
else {
|
||||
/*
|
||||
* Initialize the mutex structure:
|
||||
*/
|
||||
(*mutex)->m_type = PTHREAD_MUTEX_DEFAULT;
|
||||
(*mutex)->m_protocol = PTHREAD_PRIO_NONE;
|
||||
TAILQ_INIT(&(*mutex)->m_queue);
|
||||
(*mutex)->m_owner = NULL;
|
||||
(*mutex)->m_data.m_count = 0;
|
||||
(*mutex)->m_flags = MUTEX_FLAGS_INITED;
|
||||
(*mutex)->m_refcount = 0;
|
||||
(*mutex)->m_prio = 0;
|
||||
(*mutex)->m_saved_prio = 0;
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
memset(&(*mutex)->lock, 0, sizeof((*mutex)->lock));
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
pthread_mutex_init(pthread_mutex_t * mutex,
|
||||
|
|
@ -138,6 +186,7 @@ pthread_mutex_init(pthread_mutex_t * mutex,
|
|||
else
|
||||
pmutex->m_prio = 0;
|
||||
pmutex->m_saved_prio = 0;
|
||||
_MUTEX_INIT_LINK(pmutex);
|
||||
memset(&pmutex->lock, 0, sizeof(pmutex->lock));
|
||||
*mutex = pmutex;
|
||||
} else {
|
||||
|
|
@ -147,7 +196,7 @@ pthread_mutex_init(pthread_mutex_t * mutex,
|
|||
}
|
||||
}
|
||||
/* Return the completion status: */
|
||||
return (ret);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -177,6 +226,7 @@ pthread_mutex_destroy(pthread_mutex_t * mutex)
|
|||
* Free the memory allocated for the mutex
|
||||
* structure:
|
||||
*/
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
free(*mutex);
|
||||
|
||||
/*
|
||||
|
|
@ -221,29 +271,25 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
|
|||
* initialization:
|
||||
*/
|
||||
else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the mutex structure: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* If the mutex was statically allocated, properly
|
||||
* initialize the tail queue.
|
||||
*/
|
||||
if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
|
||||
TAILQ_INIT(&(*mutex)->m_queue);
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
(*mutex)->m_flags |= MUTEX_FLAGS_INITED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guard against being preempted by a scheduling signal.
|
||||
* To support priority inheritence mutexes, we need to
|
||||
* maintain lists of mutex ownerships for each thread as
|
||||
* well as lists of waiting threads for each mutex. In
|
||||
* order to propagate priorities we need to atomically
|
||||
* walk these lists and cannot rely on a single mutex
|
||||
* lock to provide protection against modification.
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
|
||||
/* Lock the mutex structure: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/* Process according to mutex type: */
|
||||
switch ((*mutex)->m_protocol) {
|
||||
/* Default POSIX mutex: */
|
||||
|
|
@ -254,6 +300,7 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
|
|||
(*mutex)->m_owner = _thread_run;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
} else if ((*mutex)->m_owner == _thread_run)
|
||||
|
|
@ -282,6 +329,7 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
|
|||
_thread_run->inherited_priority;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
} else if ((*mutex)->m_owner == _thread_run)
|
||||
|
|
@ -317,6 +365,7 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
|
|||
(*mutex)->m_prio;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
} else if ((*mutex)->m_owner == _thread_run)
|
||||
|
|
@ -337,10 +386,10 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
|
|||
_SPINUNLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* Renable preemption and yield if a scheduling signal
|
||||
* arrived while in the critical region:
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
@ -360,6 +409,15 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
* initialization:
|
||||
*/
|
||||
else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the mutex structure: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* If the mutex was statically allocated, properly
|
||||
* initialize the tail queue.
|
||||
|
|
@ -367,22 +425,9 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
|
||||
TAILQ_INIT(&(*mutex)->m_queue);
|
||||
(*mutex)->m_flags |= MUTEX_FLAGS_INITED;
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Guard against being preempted by a scheduling signal.
|
||||
* To support priority inheritence mutexes, we need to
|
||||
* maintain lists of mutex ownerships for each thread as
|
||||
* well as lists of waiting threads for each mutex. In
|
||||
* order to propagate priorities we need to atomically
|
||||
* walk these lists and cannot rely on a single mutex
|
||||
* lock to provide protection against modification.
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
|
||||
/* Lock the mutex structure: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/* Process according to mutex type: */
|
||||
switch ((*mutex)->m_protocol) {
|
||||
/* Default POSIX mutex: */
|
||||
|
|
@ -392,6 +437,7 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
(*mutex)->m_owner = _thread_run;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
|
||||
|
|
@ -419,12 +465,6 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
|
||||
/* Lock the mutex structure again: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* This thread is no longer waiting for
|
||||
* the mutex:
|
||||
*/
|
||||
_thread_run->data.mutex = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -449,6 +489,7 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
(*mutex)->m_prio;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
|
||||
|
|
@ -481,12 +522,6 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
|
||||
/* Lock the mutex structure again: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* This thread is no longer waiting for
|
||||
* the mutex:
|
||||
*/
|
||||
_thread_run->data.mutex = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -519,6 +554,7 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
(*mutex)->m_prio;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
} else if ((*mutex)->m_owner == _thread_run)
|
||||
|
|
@ -556,12 +592,6 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
*/
|
||||
ret = _thread_run->error;
|
||||
_thread_run->error = 0;
|
||||
|
||||
/*
|
||||
* This thread is no longer waiting for
|
||||
* the mutex:
|
||||
*/
|
||||
_thread_run->data.mutex = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -576,10 +606,10 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
_SPINUNLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* Renable preemption and yield if a scheduling signal
|
||||
* arrived while in the critical region:
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
@ -683,15 +713,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
ret = EINVAL;
|
||||
} else {
|
||||
/*
|
||||
* Guard against being preempted by a scheduling signal.
|
||||
* To support priority inheritence mutexes, we need to
|
||||
* maintain lists of mutex ownerships for each thread as
|
||||
* well as lists of waiting threads for each mutex. In
|
||||
* order to propagate priorities we need to atomically
|
||||
* walk these lists and cannot rely on a single mutex
|
||||
* lock to provide protection against modification.
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the mutex structure: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
|
@ -723,8 +748,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
(*mutex)->m_data.m_count = 0;
|
||||
|
||||
/* Remove the mutex from the threads queue. */
|
||||
_MUTEX_ASSERT_IS_OWNED(*mutex);
|
||||
TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
|
||||
(*mutex), m_qe);
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
|
||||
/*
|
||||
* Get the next thread from the queue of
|
||||
|
|
@ -738,6 +765,19 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
*/
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
|
||||
/*
|
||||
* Add the mutex to the threads list of
|
||||
* owned mutexes:
|
||||
*/
|
||||
TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq,
|
||||
(*mutex), m_qe);
|
||||
|
||||
/*
|
||||
* The owner is no longer waiting for
|
||||
* this mutex:
|
||||
*/
|
||||
(*mutex)->m_owner->data.mutex = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -784,8 +824,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
_thread_run->priority_mutex_count--;
|
||||
|
||||
/* Remove the mutex from the threads queue. */
|
||||
_MUTEX_ASSERT_IS_OWNED(*mutex);
|
||||
TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
|
||||
(*mutex), m_qe);
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
|
||||
/*
|
||||
* Get the next thread from the queue of threads
|
||||
|
|
@ -891,8 +933,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
_thread_run->priority_mutex_count--;
|
||||
|
||||
/* Remove the mutex from the threads queue. */
|
||||
_MUTEX_ASSERT_IS_OWNED(*mutex);
|
||||
TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
|
||||
(*mutex), m_qe);
|
||||
(*mutex), m_qe);
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
|
||||
/*
|
||||
* Enter a loop to find a waiting thread whose
|
||||
|
|
@ -913,6 +957,11 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
(*mutex)->m_owner->error = EINVAL;
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
/*
|
||||
* The thread is no longer waiting for
|
||||
* this mutex:
|
||||
*/
|
||||
(*mutex)->m_owner->data.mutex = NULL;
|
||||
}
|
||||
|
||||
/* Check for a new owner: */
|
||||
|
|
@ -978,10 +1027,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
_SPINUNLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* Renable preemption and yield if a scheduling signal
|
||||
* arrived while in the critical region:
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
@ -990,11 +1039,11 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
|
||||
|
||||
/*
|
||||
* This function is called when a change in base priority occurs
|
||||
* for a thread that is thread holding, or waiting for, a priority
|
||||
* protection or inheritence mutex. A change in a threads base
|
||||
* priority can effect changes to active priorities of other threads
|
||||
* and to the ordering of mutex locking by waiting threads.
|
||||
* This function is called when a change in base priority occurs for
|
||||
* a thread that is holding or waiting for a priority protection or
|
||||
* inheritence mutex. A change in a threads base priority can effect
|
||||
* changes to active priorities of other threads and to the ordering
|
||||
* of mutex locking by waiting threads.
|
||||
*
|
||||
* This must be called while thread scheduling is deferred.
|
||||
*/
|
||||
|
|
@ -1231,8 +1280,7 @@ mutex_rescan_owned (pthread_t pthread, pthread_mutex_t mutex)
|
|||
* If this thread is in the priority queue, it must be
|
||||
* removed and reinserted for its new priority.
|
||||
*/
|
||||
if ((pthread != _thread_run) &&
|
||||
(pthread->state == PS_RUNNING)) {
|
||||
if (pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) {
|
||||
/*
|
||||
* Remove the thread from the priority queue
|
||||
* before changing its priority:
|
||||
|
|
|
|||
95
lib/libc_r/uthread/uthread_poll.c
Normal file
95
lib/libc_r/uthread/uthread_poll.c
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 1999 Daniel Eischen <eischen@vigrid.com>
|
||||
* 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. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Daniel Eischen.
|
||||
* 4. 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 DANIEL EISCHEN 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <poll.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/fcntl.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
|
||||
|
||||
int
|
||||
poll(struct pollfd *fds, unsigned int nfds, int timeout)
|
||||
{
|
||||
struct timespec ts;
|
||||
int numfds = nfds;
|
||||
int i, ret = 0, found = 0;
|
||||
struct pthread_poll_data data;
|
||||
|
||||
if (numfds > _thread_dtablesize) {
|
||||
numfds = _thread_dtablesize;
|
||||
}
|
||||
/* Check if a timeout was specified: */
|
||||
if (timeout == INFTIM) {
|
||||
/* Wait for ever: */
|
||||
_thread_kern_set_timeout(NULL);
|
||||
} else if (timeout != 0) {
|
||||
/* Convert the timeout in msec to a timespec: */
|
||||
ts.tv_sec = timeout / 1000;
|
||||
ts.tv_nsec = (timeout % 1000) * 1000;
|
||||
|
||||
/* Set the wake up time: */
|
||||
_thread_kern_set_timeout(&ts);
|
||||
}
|
||||
|
||||
if (((ret = _thread_sys_poll(fds, numfds, 0)) == 0) && (timeout != 0)) {
|
||||
data.nfds = numfds;
|
||||
data.fds = fds;
|
||||
|
||||
/*
|
||||
* Clear revents in case of a timeout which leaves fds
|
||||
* unchanged:
|
||||
*/
|
||||
for (i = 0; i < numfds; i++) {
|
||||
fds[i].revents = 0;
|
||||
}
|
||||
|
||||
_thread_run->data.poll_data = &data;
|
||||
_thread_run->interrupted = 0;
|
||||
_thread_kern_sched_state(PS_POLL_WAIT, __FILE__, __LINE__);
|
||||
if (_thread_run->interrupted) {
|
||||
errno = EINTR;
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = data.nfds;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <sys/queue.h>
|
||||
|
|
@ -40,9 +41,51 @@
|
|||
/* Prototypes: */
|
||||
static void pq_insert_prio_list(pq_queue_t *pq, int prio);
|
||||
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
|
||||
static int _pq_active = 0;
|
||||
|
||||
#define _PQ_IN_SCHEDQ (PTHREAD_FLAGS_IN_PRIOQ | PTHREAD_FLAGS_IN_WAITQ | PTHREAD_FLAGS_IN_WORKQ)
|
||||
|
||||
#define _PQ_SET_ACTIVE() _pq_active = 1
|
||||
#define _PQ_CLEAR_ACTIVE() _pq_active = 0
|
||||
#define _PQ_ASSERT_ACTIVE(msg) do { \
|
||||
if (_pq_active == 0) \
|
||||
PANIC(msg); \
|
||||
} while (0)
|
||||
#define _PQ_ASSERT_INACTIVE(msg) do { \
|
||||
if (_pq_active != 0) \
|
||||
PANIC(msg); \
|
||||
} while (0)
|
||||
#define _PQ_ASSERT_IN_WAITQ(thrd, msg) do { \
|
||||
if (((thrd)->flags & PTHREAD_FLAGS_IN_WAITQ) == 0) \
|
||||
PANIC(msg); \
|
||||
} while (0)
|
||||
#define _PQ_ASSERT_IN_PRIOQ(thrd, msg) do { \
|
||||
if (((thrd)->flags & PTHREAD_FLAGS_IN_PRIOQ) == 0) \
|
||||
PANIC(msg); \
|
||||
} while (0)
|
||||
#define _PQ_ASSERT_NOT_QUEUED(thrd, msg) do { \
|
||||
if ((thrd)->flags & _PQ_IN_SCHEDQ) \
|
||||
PANIC(msg); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define _PQ_SET_ACTIVE()
|
||||
#define _PQ_CLEAR_ACTIVE()
|
||||
#define _PQ_ASSERT_ACTIVE(msg)
|
||||
#define _PQ_ASSERT_INACTIVE(msg)
|
||||
#define _PQ_ASSERT_IN_WAITQ(thrd, msg)
|
||||
#define _PQ_ASSERT_IN_PRIOQ(thrd, msg)
|
||||
#define _PQ_ASSERT_NOT_QUEUED(thrd, msg)
|
||||
#define _PQ_CHECK_PRIO()
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
_pq_init(pq_queue_t *pq, int minprio, int maxprio)
|
||||
_pq_alloc(pq_queue_t *pq, int minprio, int maxprio)
|
||||
{
|
||||
int i, ret = 0;
|
||||
int prioslots = maxprio - minprio + 1;
|
||||
|
|
@ -55,9 +98,27 @@ _pq_init(pq_queue_t *pq, int minprio, int maxprio)
|
|||
(pq_list_t *) malloc(sizeof(pq_list_t) * prioslots)) == NULL)
|
||||
ret = -1;
|
||||
|
||||
else {
|
||||
/* Remember the queue size: */
|
||||
pq->pq_size = prioslots;
|
||||
|
||||
ret = _pq_init(pq);
|
||||
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
_pq_init(pq_queue_t *pq)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
if ((pq == NULL) || (pq->pq_lists == NULL))
|
||||
ret = -1;
|
||||
|
||||
else {
|
||||
/* Initialize the queue for each priority slot: */
|
||||
for (i = 0; i < prioslots; i++) {
|
||||
for (i = 0; i < pq->pq_size; i++) {
|
||||
TAILQ_INIT(&pq->pq_lists[i].pl_head);
|
||||
pq->pq_lists[i].pl_prio = i;
|
||||
pq->pq_lists[i].pl_queued = 0;
|
||||
|
|
@ -65,9 +126,7 @@ _pq_init(pq_queue_t *pq, int minprio, int maxprio)
|
|||
|
||||
/* Initialize the priority queue: */
|
||||
TAILQ_INIT(&pq->pq_queue);
|
||||
|
||||
/* Remember the queue size: */
|
||||
pq->pq_size = prioslots;
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
|
@ -77,7 +136,27 @@ _pq_remove(pq_queue_t *pq, pthread_t pthread)
|
|||
{
|
||||
int prio = pthread->active_priority;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_pq_remove: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_IN_PRIOQ(pthread, "_pq_remove: Not in priority queue");
|
||||
|
||||
/*
|
||||
* Remove this thread from priority list. Note that if
|
||||
* the priority list becomes empty, it is not removed
|
||||
* from the priority queue because another thread may be
|
||||
* added to the priority list (resulting in a needless
|
||||
* removal/insertion). Priority lists are only removed
|
||||
* from the priority queue when _pq_first is called.
|
||||
*/
|
||||
TAILQ_REMOVE(&pq->pq_lists[prio].pl_head, pthread, pqe);
|
||||
|
||||
/* This thread is now longer in the priority queue. */
|
||||
pthread->flags &= ~PTHREAD_FLAGS_IN_PRIOQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -86,10 +165,23 @@ _pq_insert_head(pq_queue_t *pq, pthread_t pthread)
|
|||
{
|
||||
int prio = pthread->active_priority;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_pq_insert_head: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_NOT_QUEUED(pthread,
|
||||
"_pq_insert_head: Already in priority queue");
|
||||
|
||||
TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe);
|
||||
if (pq->pq_lists[prio].pl_queued == 0)
|
||||
/* Insert the list into the priority queue: */
|
||||
pq_insert_prio_list(pq, prio);
|
||||
|
||||
/* Mark this thread as being in the priority queue. */
|
||||
pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -98,10 +190,23 @@ _pq_insert_tail(pq_queue_t *pq, pthread_t pthread)
|
|||
{
|
||||
int prio = pthread->active_priority;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_pq_insert_tail: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_NOT_QUEUED(pthread,
|
||||
"_pq_insert_tail: Already in priority queue");
|
||||
|
||||
TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe);
|
||||
if (pq->pq_lists[prio].pl_queued == 0)
|
||||
/* Insert the list into the priority queue: */
|
||||
pq_insert_prio_list(pq, prio);
|
||||
|
||||
/* Mark this thread as being in the priority queue. */
|
||||
pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -111,6 +216,12 @@ _pq_first(pq_queue_t *pq)
|
|||
pq_list_t *pql;
|
||||
pthread_t pthread = NULL;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_pq_first: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
|
||||
while (((pql = TAILQ_FIRST(&pq->pq_queue)) != NULL) &&
|
||||
(pthread == NULL)) {
|
||||
if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) {
|
||||
|
|
@ -124,6 +235,8 @@ _pq_first(pq_queue_t *pq)
|
|||
pql->pl_queued = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
return (pthread);
|
||||
}
|
||||
|
||||
|
|
@ -133,10 +246,15 @@ pq_insert_prio_list(pq_queue_t *pq, int prio)
|
|||
{
|
||||
pq_list_t *pql;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_ACTIVE("pq_insert_prio_list: pq_active");
|
||||
|
||||
/*
|
||||
* The priority queue is in descending priority order. Start at
|
||||
* the beginning of the queue and find the list before which the
|
||||
* new list should to be inserted.
|
||||
* new list should be inserted.
|
||||
*/
|
||||
pql = TAILQ_FIRST(&pq->pq_queue);
|
||||
while ((pql != NULL) && (pql->pl_prio > prio))
|
||||
|
|
@ -152,4 +270,66 @@ pq_insert_prio_list(pq_queue_t *pq, int prio)
|
|||
pq->pq_lists[prio].pl_queued = 1;
|
||||
}
|
||||
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
void
|
||||
_waitq_insert(pthread_t pthread)
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_waitq_insert: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_NOT_QUEUED(pthread, "_waitq_insert: Already in queue");
|
||||
|
||||
if (pthread->wakeup_time.tv_sec == -1)
|
||||
TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe);
|
||||
else {
|
||||
tid = TAILQ_FIRST(&_waitingq);
|
||||
while ((tid != NULL) && (tid->wakeup_time.tv_sec != -1) &&
|
||||
((tid->wakeup_time.tv_sec < pthread->wakeup_time.tv_sec) ||
|
||||
((tid->wakeup_time.tv_sec == pthread->wakeup_time.tv_sec) &&
|
||||
(tid->wakeup_time.tv_nsec <= pthread->wakeup_time.tv_nsec))))
|
||||
tid = TAILQ_NEXT(tid, pqe);
|
||||
if (tid == NULL)
|
||||
TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe);
|
||||
else
|
||||
TAILQ_INSERT_BEFORE(tid, pthread, pqe);
|
||||
}
|
||||
pthread->flags |= PTHREAD_FLAGS_IN_WAITQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
|
||||
void
|
||||
_waitq_remove(pthread_t pthread)
|
||||
{
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_waitq_remove: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_IN_WAITQ(pthread, "_waitq_remove: Not in queue");
|
||||
|
||||
TAILQ_REMOVE(&_waitingq, pthread, pqe);
|
||||
pthread->flags &= ~PTHREAD_FLAGS_IN_WAITQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
|
||||
void
|
||||
_waitq_setactive(void)
|
||||
{
|
||||
_PQ_ASSERT_INACTIVE("_waitq_setactive: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
}
|
||||
|
||||
void
|
||||
_waitq_clearactive(void)
|
||||
{
|
||||
_PQ_ASSERT_ACTIVE("_waitq_clearactive: ! pq_active");
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1995 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. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by John Birrell.
|
||||
* 4. 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 REGENTS 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.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
|
||||
void
|
||||
_thread_queue_init(struct pthread_queue * queue)
|
||||
{
|
||||
/* Initialise the pointers in the queue structure: */
|
||||
queue->q_next = NULL;
|
||||
queue->q_last = NULL;
|
||||
queue->q_data = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
_thread_queue_enq(struct pthread_queue * queue, struct pthread * thread)
|
||||
{
|
||||
if (queue->q_last) {
|
||||
queue->q_last->qnxt = thread;
|
||||
} else {
|
||||
queue->q_next = thread;
|
||||
}
|
||||
queue->q_last = thread;
|
||||
thread->queue = queue;
|
||||
thread->qnxt = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
struct pthread *
|
||||
_thread_queue_get(struct pthread_queue * queue)
|
||||
{
|
||||
/* Return the pointer to the next thread in the queue: */
|
||||
return (queue->q_next);
|
||||
}
|
||||
|
||||
struct pthread *
|
||||
_thread_queue_deq(struct pthread_queue * queue)
|
||||
{
|
||||
struct pthread *thread = NULL;
|
||||
|
||||
if (queue->q_next) {
|
||||
thread = queue->q_next;
|
||||
if (!(queue->q_next = queue->q_next->qnxt)) {
|
||||
queue->q_last = NULL;
|
||||
}
|
||||
thread->queue = NULL;
|
||||
thread->qnxt = NULL;
|
||||
}
|
||||
return (thread);
|
||||
}
|
||||
|
||||
int
|
||||
_thread_queue_remove(struct pthread_queue * queue, struct pthread * thread)
|
||||
{
|
||||
struct pthread **current = &(queue->q_next);
|
||||
struct pthread *prev = NULL;
|
||||
int ret = -1;
|
||||
|
||||
while (*current) {
|
||||
if (*current == thread) {
|
||||
if ((*current)->qnxt) {
|
||||
*current = (*current)->qnxt;
|
||||
} else {
|
||||
queue->q_last = prev;
|
||||
*current = NULL;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
prev = *current;
|
||||
current = &((*current)->qnxt);
|
||||
}
|
||||
thread->queue = NULL;
|
||||
thread->qnxt = NULL;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
pthread_llist_remove(struct pthread ** llist, struct pthread * thread)
|
||||
{
|
||||
while (*llist) {
|
||||
if (*llist == thread) {
|
||||
*llist = thread->qnxt;
|
||||
return (0);
|
||||
}
|
||||
llist = &(*llist)->qnxt;
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -46,20 +47,19 @@ pthread_resume_np(pthread_t thread)
|
|||
/* The thread exists. Is it suspended? */
|
||||
if (thread->state != PS_SUSPENDED) {
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues.
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Allow the thread to run. */
|
||||
PTHREAD_NEW_STATE(thread,PS_RUNNING);
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling
|
||||
* signal occurred while in the critical region.
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
}
|
||||
return(ret);
|
||||
|
|
|
|||
|
|
@ -29,10 +29,13 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
|
@ -44,12 +47,10 @@ int
|
|||
select(int numfds, fd_set * readfds, fd_set * writefds,
|
||||
fd_set * exceptfds, struct timeval * timeout)
|
||||
{
|
||||
fd_set read_locks, write_locks, rdwr_locks;
|
||||
struct timespec ts;
|
||||
struct timeval zero_timeout = {0, 0};
|
||||
int i, ret = 0, got_all_locks = 1;
|
||||
int f_wait = 1;
|
||||
struct pthread_select_data data;
|
||||
int i, ret = 0, f_wait = 1;
|
||||
int pfd_index, got_one = 0, fd_count = 0;
|
||||
struct pthread_poll_data data;
|
||||
|
||||
if (numfds > _thread_dtablesize) {
|
||||
numfds = _thread_dtablesize;
|
||||
|
|
@ -68,112 +69,129 @@ select(int numfds, fd_set * readfds, fd_set * writefds,
|
|||
_thread_kern_set_timeout(NULL);
|
||||
}
|
||||
|
||||
FD_ZERO(&read_locks);
|
||||
FD_ZERO(&write_locks);
|
||||
FD_ZERO(&rdwr_locks);
|
||||
|
||||
/* lock readfds */
|
||||
/* Count the number of file descriptors to be polled: */
|
||||
if (readfds || writefds || exceptfds) {
|
||||
for (i = 0; i < numfds; i++) {
|
||||
if ((readfds && (FD_ISSET(i, readfds))) || (exceptfds && FD_ISSET(i, exceptfds))) {
|
||||
if (writefds && FD_ISSET(i, writefds)) {
|
||||
if ((ret = _FD_LOCK(i, FD_RDWR, NULL)) != 0) {
|
||||
got_all_locks = 0;
|
||||
break;
|
||||
}
|
||||
FD_SET(i, &rdwr_locks);
|
||||
} else {
|
||||
if ((ret = _FD_LOCK(i, FD_READ, NULL)) != 0) {
|
||||
got_all_locks = 0;
|
||||
break;
|
||||
}
|
||||
FD_SET(i, &read_locks);
|
||||
}
|
||||
} else {
|
||||
if (writefds && FD_ISSET(i, writefds)) {
|
||||
if ((ret = _FD_LOCK(i, FD_WRITE, NULL)) != 0) {
|
||||
got_all_locks = 0;
|
||||
break;
|
||||
}
|
||||
FD_SET(i, &write_locks);
|
||||
}
|
||||
if ((readfds && FD_ISSET(i, readfds)) ||
|
||||
(exceptfds && FD_ISSET(i, exceptfds)) ||
|
||||
(writefds && FD_ISSET(i, writefds))) {
|
||||
fd_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (got_all_locks) {
|
||||
data.nfds = numfds;
|
||||
FD_ZERO(&data.readfds);
|
||||
FD_ZERO(&data.writefds);
|
||||
FD_ZERO(&data.exceptfds);
|
||||
if (readfds != NULL) {
|
||||
memcpy(&data.readfds, readfds, sizeof(data.readfds));
|
||||
|
||||
/*
|
||||
* Allocate memory for poll data if it hasn't already been
|
||||
* allocated or if previously allocated memory is insufficient.
|
||||
*/
|
||||
if ((_thread_run->poll_data.fds == NULL) ||
|
||||
(_thread_run->poll_data.nfds < fd_count)) {
|
||||
data.fds = (struct pollfd *) realloc(_thread_run->poll_data.fds,
|
||||
sizeof(struct pollfd) * MAX(128, fd_count));
|
||||
if (data.fds == NULL) {
|
||||
errno = ENOMEM;
|
||||
ret = -1;
|
||||
}
|
||||
if (writefds != NULL) {
|
||||
memcpy(&data.writefds, writefds, sizeof(data.writefds));
|
||||
else {
|
||||
/*
|
||||
* Note that the threads poll data always
|
||||
* indicates what is allocated, not what is
|
||||
* currently being polled.
|
||||
*/
|
||||
_thread_run->poll_data.fds = data.fds;
|
||||
_thread_run->poll_data.nfds = MAX(128, fd_count);
|
||||
}
|
||||
if (exceptfds != NULL) {
|
||||
memcpy(&data.exceptfds, exceptfds, sizeof(data.exceptfds));
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* Setup the wait data. */
|
||||
data.fds = _thread_run->poll_data.fds;
|
||||
data.nfds = fd_count;
|
||||
|
||||
/*
|
||||
* Setup the array of pollfds. Optimize this by
|
||||
* running the loop in reverse and stopping when
|
||||
* the number of selected file descriptors is reached.
|
||||
*/
|
||||
for (i = numfds - 1, pfd_index = fd_count - 1;
|
||||
(i >= 0) && (pfd_index >= 0); i--) {
|
||||
data.fds[pfd_index].events = 0;
|
||||
if (readfds && FD_ISSET(i, readfds)) {
|
||||
data.fds[pfd_index].events = POLLRDNORM;
|
||||
}
|
||||
if (exceptfds && FD_ISSET(i, exceptfds)) {
|
||||
data.fds[pfd_index].events |= POLLRDBAND;
|
||||
}
|
||||
if (writefds && FD_ISSET(i, writefds)) {
|
||||
data.fds[pfd_index].events |= POLLWRNORM;
|
||||
}
|
||||
if (data.fds[pfd_index].events != 0) {
|
||||
/*
|
||||
* Set the file descriptor to be polled and
|
||||
* clear revents in case of a timeout which
|
||||
* leaves fds unchanged:
|
||||
*/
|
||||
data.fds[pfd_index].fd = i;
|
||||
data.fds[pfd_index].revents = 0;
|
||||
pfd_index--;
|
||||
}
|
||||
}
|
||||
if ((ret = _thread_sys_select(data.nfds, &data.readfds, &data.writefds, &data.exceptfds, &zero_timeout)) == 0 && f_wait) {
|
||||
data.nfds = numfds;
|
||||
FD_ZERO(&data.readfds);
|
||||
FD_ZERO(&data.writefds);
|
||||
FD_ZERO(&data.exceptfds);
|
||||
if (readfds != NULL) {
|
||||
memcpy(&data.readfds, readfds, sizeof(data.readfds));
|
||||
}
|
||||
if (writefds != NULL) {
|
||||
memcpy(&data.writefds, writefds, sizeof(data.writefds));
|
||||
}
|
||||
if (exceptfds != NULL) {
|
||||
memcpy(&data.exceptfds, exceptfds, sizeof(data.exceptfds));
|
||||
}
|
||||
_thread_run->data.select_data = &data;
|
||||
if (((ret = _thread_sys_poll(data.fds, data.nfds, 0)) == 0) &&
|
||||
(f_wait != 0)) {
|
||||
_thread_run->data.poll_data = &data;
|
||||
_thread_run->interrupted = 0;
|
||||
_thread_kern_sched_state(PS_SELECT_WAIT, __FILE__, __LINE__);
|
||||
if (_thread_run->interrupted) {
|
||||
errno = EINTR;
|
||||
data.nfds = 0;
|
||||
ret = -1;
|
||||
} else
|
||||
ret = data.nfds;
|
||||
}
|
||||
}
|
||||
/* clean up the locks */
|
||||
for (i = 0; i < numfds; i++)
|
||||
if (FD_ISSET(i, &read_locks))
|
||||
_FD_UNLOCK(i, FD_READ);
|
||||
for (i = 0; i < numfds; i++)
|
||||
if (FD_ISSET(i, &rdwr_locks))
|
||||
_FD_UNLOCK(i, FD_RDWR);
|
||||
for (i = 0; i < numfds; i++)
|
||||
if (FD_ISSET(i, &write_locks))
|
||||
_FD_UNLOCK(i, FD_WRITE);
|
||||
|
||||
if (ret >= 0) {
|
||||
if (readfds != NULL) {
|
||||
for (i = 0; i < numfds; i++) {
|
||||
if (FD_ISSET(i, readfds) &&
|
||||
!FD_ISSET(i, &data.readfds)) {
|
||||
FD_CLR(i, readfds);
|
||||
numfds = 0;
|
||||
for (i = 0; i < fd_count; i++) {
|
||||
/*
|
||||
* Check the results of the poll and clear
|
||||
* this file descriptor from the fdset if
|
||||
* the requested event wasn't ready.
|
||||
*/
|
||||
got_one = 0;
|
||||
if (readfds != NULL) {
|
||||
if (FD_ISSET(data.fds[i].fd, readfds)) {
|
||||
if (data.fds[i].revents & (POLLIN |
|
||||
POLLRDNORM))
|
||||
got_one = 1;
|
||||
else
|
||||
FD_CLR(data.fds[i].fd, readfds);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (writefds != NULL) {
|
||||
for (i = 0; i < numfds; i++) {
|
||||
if (FD_ISSET(i, writefds) &&
|
||||
!FD_ISSET(i, &data.writefds)) {
|
||||
FD_CLR(i, writefds);
|
||||
if (writefds != NULL) {
|
||||
if (FD_ISSET(data.fds[i].fd, writefds)) {
|
||||
if (data.fds[i].revents & (POLLOUT |
|
||||
POLLWRNORM | POLLWRBAND))
|
||||
got_one = 1;
|
||||
else
|
||||
FD_CLR(data.fds[i].fd,
|
||||
writefds);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exceptfds != NULL) {
|
||||
for (i = 0; i < numfds; i++) {
|
||||
if (FD_ISSET(i, exceptfds) &&
|
||||
!FD_ISSET(i, &data.exceptfds)) {
|
||||
FD_CLR(i, exceptfds);
|
||||
if (exceptfds != NULL) {
|
||||
if (FD_ISSET(data.fds[i].fd, exceptfds)) {
|
||||
if (data.fds[i].revents & (POLLRDBAND |
|
||||
POLLPRI | POLLHUP | POLLERR |
|
||||
POLLNVAL))
|
||||
got_one = 1;
|
||||
else
|
||||
FD_CLR(data.fds[i].fd,
|
||||
exceptfds);
|
||||
}
|
||||
}
|
||||
if (got_one)
|
||||
numfds++;
|
||||
}
|
||||
ret = numfds;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <sys/param.h>
|
||||
|
|
@ -50,10 +51,10 @@ pthread_setschedparam(pthread_t pthread, int policy, struct sched_param *param)
|
|||
/* Find the thread in the list of active threads: */
|
||||
else if ((ret = _find_thread(pthread)) == 0) {
|
||||
/*
|
||||
* Guard against being preempted by a scheduling
|
||||
* signal:
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
if (param->sched_priority != pthread->base_priority) {
|
||||
/*
|
||||
|
|
@ -61,8 +62,7 @@ pthread_setschedparam(pthread_t pthread, int policy, struct sched_param *param)
|
|||
* queue before any adjustments are made to its
|
||||
* active priority:
|
||||
*/
|
||||
if ((pthread != _thread_run) &&
|
||||
(pthread->state == PS_RUNNING)) {
|
||||
if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0) {
|
||||
in_readyq = 1;
|
||||
old_prio = pthread->active_priority;
|
||||
PTHREAD_PRIOQ_REMOVE(pthread);
|
||||
|
|
@ -103,10 +103,10 @@ pthread_setschedparam(pthread_t pthread, int policy, struct sched_param *param)
|
|||
pthread->attr.sched_policy = policy;
|
||||
|
||||
/*
|
||||
* Renable preemption and yield if a scheduling signal
|
||||
* arrived while in the critical region:
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -38,107 +39,51 @@
|
|||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
|
||||
/*
|
||||
* State change macro for signal handler:
|
||||
*/
|
||||
#define PTHREAD_SIG_NEW_STATE(thrd, newstate) { \
|
||||
if ((_thread_run->sched_defer_count == 0) && \
|
||||
(_thread_kern_in_sched == 0)) { \
|
||||
PTHREAD_NEW_STATE(thrd, newstate); \
|
||||
} else { \
|
||||
_waitingq_check_reqd = 1; \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Static variables: */
|
||||
static int volatile yield_on_unlock_thread = 0;
|
||||
static spinlock_t thread_link_list_lock = _SPINLOCK_INITIALIZER;
|
||||
static spinlock_t signal_lock = _SPINLOCK_INITIALIZER;
|
||||
unsigned int pending_sigs[NSIG];
|
||||
unsigned int handled_sigs[NSIG];
|
||||
int volatile check_pending = 0;
|
||||
|
||||
/* Lock the thread list: */
|
||||
/* Initialize signal handling facility: */
|
||||
void
|
||||
_lock_thread_list()
|
||||
_thread_sig_init(void)
|
||||
{
|
||||
/* Lock the thread list: */
|
||||
_SPINLOCK(&thread_link_list_lock);
|
||||
}
|
||||
int i;
|
||||
|
||||
/* Lock the thread list: */
|
||||
void
|
||||
_unlock_thread_list()
|
||||
{
|
||||
/* Unlock the thread list: */
|
||||
_SPINUNLOCK(&thread_link_list_lock);
|
||||
|
||||
/*
|
||||
* Check if a scheduler interrupt occurred while the thread
|
||||
* list was locked:
|
||||
*/
|
||||
if (yield_on_unlock_thread) {
|
||||
/* Reset the interrupt flag: */
|
||||
yield_on_unlock_thread = 0;
|
||||
|
||||
/* This thread has overstayed it's welcome: */
|
||||
sched_yield();
|
||||
/* Clear pending and handled signal counts: */
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
pending_sigs[i - 1] = 0;
|
||||
handled_sigs[i - 1] = 0;
|
||||
}
|
||||
|
||||
/* Clear the lock: */
|
||||
signal_lock.access_lock = 0;
|
||||
}
|
||||
|
||||
void
|
||||
_thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
||||
{
|
||||
char c;
|
||||
int i;
|
||||
pthread_t pthread;
|
||||
|
||||
/*
|
||||
* Check if the pthread kernel has unblocked signals (or is about to)
|
||||
* and was on its way into a _select when the current
|
||||
* signal interrupted it:
|
||||
*/
|
||||
if (_thread_kern_in_select) {
|
||||
/* Cast the signal number to a character variable: */
|
||||
c = sig;
|
||||
|
||||
/*
|
||||
* Write the signal number to the kernel pipe so that it will
|
||||
* be ready to read when this signal handler returns. This
|
||||
* means that the _select call will complete
|
||||
* immediately.
|
||||
*/
|
||||
_thread_sys_write(_thread_kern_pipe[1], &c, 1);
|
||||
}
|
||||
/* Check if the signal requires a dump of thread information: */
|
||||
if (sig == SIGINFO)
|
||||
/* Dump thread information to file: */
|
||||
_thread_dump_info();
|
||||
char c;
|
||||
int i;
|
||||
|
||||
/* Check if an interval timer signal: */
|
||||
else if (sig == _SCHED_SIGNAL) {
|
||||
/* Check if the scheduler interrupt has come at an
|
||||
* unfortunate time which one of the threads is
|
||||
* modifying the thread list:
|
||||
*/
|
||||
if (thread_link_list_lock.access_lock)
|
||||
if (sig == _SCHED_SIGNAL) {
|
||||
if (_thread_kern_in_sched != 0) {
|
||||
/*
|
||||
* Set a flag so that the thread that has
|
||||
* the lock yields when it unlocks the
|
||||
* thread list:
|
||||
* The scheduler is already running; ignore this
|
||||
* signal.
|
||||
*/
|
||||
yield_on_unlock_thread = 1;
|
||||
|
||||
}
|
||||
/*
|
||||
* Check if the scheduler interrupt has come when
|
||||
* the currently running thread has deferred thread
|
||||
* scheduling.
|
||||
* signals.
|
||||
*/
|
||||
else if (_thread_run->sched_defer_count)
|
||||
_thread_run->yield_on_sched_undefer = 1;
|
||||
else if (_thread_run->sig_defer_count > 0)
|
||||
_thread_run->yield_on_sig_undefer = 1;
|
||||
|
||||
/*
|
||||
* Check if the kernel has not been interrupted while
|
||||
* executing scheduler code:
|
||||
*/
|
||||
else if (!_thread_kern_in_sched) {
|
||||
else {
|
||||
/*
|
||||
* Schedule the next thread. This function is not
|
||||
* expected to return because it will do a longjmp
|
||||
|
|
@ -152,6 +97,72 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
|||
*/
|
||||
PANIC("Returned to signal function from scheduler");
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Check if the kernel has been interrupted while the scheduler
|
||||
* is accessing the scheduling queues or if there is a currently
|
||||
* running thread that has deferred signals.
|
||||
*/
|
||||
else if ((_queue_signals != 0) || ((_thread_kern_in_sched == 0) &&
|
||||
(_thread_run->sig_defer_count > 0))) {
|
||||
/* Cast the signal number to a character variable: */
|
||||
c = sig;
|
||||
|
||||
/*
|
||||
* Write the signal number to the kernel pipe so that it will
|
||||
* be ready to read when this signal handler returns.
|
||||
*/
|
||||
_thread_sys_write(_thread_kern_pipe[1], &c, 1);
|
||||
|
||||
/* Indicate that there are queued signals in the pipe. */
|
||||
_sigq_check_reqd = 1;
|
||||
}
|
||||
else {
|
||||
if (_atomic_lock(&signal_lock.access_lock)) {
|
||||
/* There is another signal handler running: */
|
||||
pending_sigs[sig - 1]++;
|
||||
check_pending = 1;
|
||||
}
|
||||
else {
|
||||
/* It's safe to handle the signal now. */
|
||||
_thread_sig_handle(sig, scp);
|
||||
|
||||
/* Reset the pending and handled count back to 0: */
|
||||
pending_sigs[sig - 1] = 0;
|
||||
handled_sigs[sig - 1] = 0;
|
||||
|
||||
signal_lock.access_lock = 0;
|
||||
}
|
||||
|
||||
/* Enter a loop to process pending signals: */
|
||||
while ((check_pending != 0) &&
|
||||
(_atomic_lock(&signal_lock.access_lock) == 0)) {
|
||||
check_pending = 0;
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (pending_sigs[i - 1] > handled_sigs[i - 1])
|
||||
_thread_sig_handle(i, scp);
|
||||
}
|
||||
signal_lock.access_lock = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_thread_sig_handle(int sig, struct sigcontext * scp)
|
||||
{
|
||||
int i;
|
||||
pthread_t pthread, pthread_next;
|
||||
|
||||
/* Check if the signal requires a dump of thread information: */
|
||||
if (sig == SIGINFO)
|
||||
/* Dump thread information to file: */
|
||||
_thread_dump_info();
|
||||
|
||||
/* Check if an interval timer signal: */
|
||||
else if (sig == _SCHED_SIGNAL) {
|
||||
/*
|
||||
* This shouldn't ever occur (should this panic?).
|
||||
*/
|
||||
} else {
|
||||
/* Check if a child has terminated: */
|
||||
if (sig == SIGCHLD) {
|
||||
|
|
@ -183,10 +194,9 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
|||
* Enter a loop to discard pending SIGCONT
|
||||
* signals:
|
||||
*/
|
||||
for (pthread = _thread_link_list;
|
||||
pthread != NULL;
|
||||
pthread = pthread->nxt)
|
||||
TAILQ_FOREACH(pthread, &_thread_list, tle) {
|
||||
sigdelset(&pthread->sigpend,SIGCONT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -196,11 +206,18 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
|||
* if there are multiple waiters, we'll give it to the
|
||||
* first one we find.
|
||||
*/
|
||||
TAILQ_FOREACH(pthread, &_waitingq, pqe) {
|
||||
for (pthread = TAILQ_FIRST(&_waitingq);
|
||||
pthread != NULL; pthread = pthread_next) {
|
||||
/*
|
||||
* Grab the next thread before possibly destroying
|
||||
* the link entry.
|
||||
*/
|
||||
pthread_next = TAILQ_NEXT(pthread, pqe);
|
||||
|
||||
if ((pthread->state == PS_SIGWAIT) &&
|
||||
sigismember(pthread->data.sigwait, sig)) {
|
||||
/* Change the state of the thread to run: */
|
||||
PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
|
||||
/* Return the signal number: */
|
||||
pthread->signo = sig;
|
||||
|
|
@ -219,10 +236,13 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
|||
* Enter a loop to process each thread in the linked
|
||||
* list:
|
||||
*/
|
||||
for (pthread = _thread_link_list; pthread != NULL;
|
||||
pthread = pthread->nxt) {
|
||||
TAILQ_FOREACH(pthread, &_thread_list, tle) {
|
||||
pthread_t pthread_saved = _thread_run;
|
||||
|
||||
/* Current thread inside critical region? */
|
||||
if (_thread_run->sig_defer_count > 0)
|
||||
pthread->sig_defer_count++;
|
||||
|
||||
_thread_run = pthread;
|
||||
_thread_signal(pthread,sig);
|
||||
|
||||
|
|
@ -232,6 +252,10 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
|||
*/
|
||||
_dispatch_signals();
|
||||
_thread_run = pthread_saved;
|
||||
|
||||
/* Current thread inside critical region? */
|
||||
if (_thread_run->sig_defer_count > 0)
|
||||
pthread->sig_defer_count--;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -284,7 +308,7 @@ _thread_signal(pthread_t pthread, int sig)
|
|||
pthread->interrupted = 1;
|
||||
|
||||
/* Change the state of the thread to run: */
|
||||
PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
|
||||
/* Return the signal number: */
|
||||
pthread->signo = sig;
|
||||
|
|
@ -296,6 +320,7 @@ _thread_signal(pthread_t pthread, int sig)
|
|||
*/
|
||||
case PS_FDR_WAIT:
|
||||
case PS_FDW_WAIT:
|
||||
case PS_POLL_WAIT:
|
||||
case PS_SLEEP_WAIT:
|
||||
case PS_SELECT_WAIT:
|
||||
if (sig != SIGCHLD ||
|
||||
|
|
@ -303,8 +328,11 @@ _thread_signal(pthread_t pthread, int sig)
|
|||
/* Flag the operation as interrupted: */
|
||||
pthread->interrupted = 1;
|
||||
|
||||
if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
|
||||
PTHREAD_WORKQ_REMOVE(pthread);
|
||||
|
||||
/* Change the state of the thread to run: */
|
||||
PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
|
||||
/* Return the signal number: */
|
||||
pthread->signo = sig;
|
||||
|
|
@ -319,7 +347,7 @@ _thread_signal(pthread_t pthread, int sig)
|
|||
if (!sigismember(&pthread->sigmask, sig) &&
|
||||
_thread_sigact[sig - 1].sa_handler != SIG_DFL) {
|
||||
/* Change the state of the thread to run: */
|
||||
PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
|
||||
/* Return the signal number: */
|
||||
pthread->signo = sig;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -77,6 +78,9 @@ sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
|
|||
gact.sa_mask = act->sa_mask;
|
||||
gact.sa_flags = 0;
|
||||
|
||||
/* Ensure the scheduling signal is masked: */
|
||||
sigaddset(&gact.sa_mask, _SCHED_SIGNAL);
|
||||
|
||||
/*
|
||||
* Check if the signal handler is being set to
|
||||
* the default or ignore handlers:
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -41,7 +42,7 @@ sigwait(const sigset_t * set, int *sig)
|
|||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
sigset_t tempset;
|
||||
sigset_t tempset, waitset;
|
||||
struct sigaction act;
|
||||
|
||||
/*
|
||||
|
|
@ -51,17 +52,23 @@ sigwait(const sigset_t * set, int *sig)
|
|||
act.sa_flags = SA_RESTART;
|
||||
act.sa_mask = *set;
|
||||
|
||||
/* Ensure the scheduling signal is masked: */
|
||||
sigaddset(&act.sa_mask, _SCHED_SIGNAL);
|
||||
|
||||
/*
|
||||
* These signals can't be waited on.
|
||||
* Initialize the set of signals that will be waited on:
|
||||
*/
|
||||
sigdelset(&act.sa_mask, SIGKILL);
|
||||
sigdelset(&act.sa_mask, SIGSTOP);
|
||||
sigdelset(&act.sa_mask, _SCHED_SIGNAL);
|
||||
sigdelset(&act.sa_mask, SIGCHLD);
|
||||
sigdelset(&act.sa_mask, SIGINFO);
|
||||
waitset = *set;
|
||||
|
||||
/* These signals can't be waited on. */
|
||||
sigdelset(&waitset, SIGKILL);
|
||||
sigdelset(&waitset, SIGSTOP);
|
||||
sigdelset(&waitset, _SCHED_SIGNAL);
|
||||
sigdelset(&waitset, SIGCHLD);
|
||||
sigdelset(&waitset, SIGINFO);
|
||||
|
||||
/* Check to see if a pending signal is in the wait mask. */
|
||||
if (tempset = (_thread_run->sigpend & act.sa_mask)) {
|
||||
if (tempset = (_thread_run->sigpend & waitset)) {
|
||||
/* Enter a loop to find a pending signal: */
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (sigismember (&tempset, i))
|
||||
|
|
@ -81,17 +88,17 @@ sigwait(const sigset_t * set, int *sig)
|
|||
* Enter a loop to find the signals that are SIG_DFL. For
|
||||
* these signals we must install a dummy signal handler in
|
||||
* order for the kernel to pass them in to us. POSIX says
|
||||
* that the application must explicitly install a dummy
|
||||
* that the _application_ must explicitly install a dummy
|
||||
* handler for signals that are SIG_IGN in order to sigwait
|
||||
* on them. Note that SIG_IGN signals are left in the
|
||||
* mask because a subsequent sigaction could enable an
|
||||
* ignored signal.
|
||||
*/
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (sigismember(&act.sa_mask, i)) {
|
||||
if (_thread_sigact[i - 1].sa_handler == SIG_DFL)
|
||||
if (_thread_sys_sigaction(i,&act,NULL) != 0)
|
||||
ret = -1;
|
||||
if (sigismember(&waitset, i) &&
|
||||
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
|
||||
if (_thread_sys_sigaction(i,&act,NULL) != 0)
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
|
|
@ -101,7 +108,7 @@ sigwait(const sigset_t * set, int *sig)
|
|||
* mask is independent of the threads signal mask
|
||||
* and requires separate storage.
|
||||
*/
|
||||
_thread_run->data.sigwait = &act.sa_mask;
|
||||
_thread_run->data.sigwait = &waitset;
|
||||
|
||||
/* Wait for a signal: */
|
||||
_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
|
||||
|
|
@ -119,7 +126,7 @@ sigwait(const sigset_t * set, int *sig)
|
|||
/* Restore the sigactions: */
|
||||
act.sa_handler = SIG_DFL;
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (sigismember(&act.sa_mask, i) &&
|
||||
if (sigismember(&waitset, i) &&
|
||||
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
|
||||
if (_thread_sys_sigaction(i,&act,NULL) != 0)
|
||||
ret = -1;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -52,20 +53,19 @@ pthread_suspend_np(pthread_t thread)
|
|||
}
|
||||
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues.
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Suspend the thread. */
|
||||
PTHREAD_NEW_STATE(thread,PS_SUSPENDED);
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling signal
|
||||
* occurred while in the critical region.
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# $Id: Makefile.inc,v 1.16 1998/09/30 06:36:55 jb Exp $
|
||||
# $Id: Makefile.inc,v 1.17 1999/03/23 05:07:54 jb Exp $
|
||||
|
||||
# uthread sources
|
||||
.PATH: ${.CURDIR}/uthread
|
||||
|
|
@ -73,8 +73,8 @@ SRCS+= \
|
|||
uthread_once.c \
|
||||
uthread_open.c \
|
||||
uthread_pipe.c \
|
||||
uthread_poll.c \
|
||||
uthread_priority_queue.c \
|
||||
uthread_queue.c \
|
||||
uthread_read.c \
|
||||
uthread_readv.c \
|
||||
uthread_recvfrom.c \
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -45,12 +47,21 @@ close(int fd)
|
|||
int ret;
|
||||
int status;
|
||||
struct stat sb;
|
||||
struct fd_table_entry *entry;
|
||||
|
||||
/* Lock the file descriptor while the file is closed: */
|
||||
if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
|
||||
/* Get file descriptor status. */
|
||||
_thread_sys_fstat(fd, &sb);
|
||||
|
||||
if ((fd == _thread_kern_pipe[0]) || (fd == _thread_kern_pipe[1])) {
|
||||
/*
|
||||
* Don't allow silly programs to close the kernel pipe.
|
||||
*/
|
||||
errno = EBADF;
|
||||
ret = -1;
|
||||
}
|
||||
/*
|
||||
* Lock the file descriptor while the file is closed and get
|
||||
* the file descriptor status:
|
||||
*/
|
||||
else if (((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) &&
|
||||
((ret = _thread_sys_fstat(fd, &sb)) == 0)) {
|
||||
/*
|
||||
* Check if the file should be left as blocking.
|
||||
*
|
||||
|
|
@ -78,11 +89,14 @@ close(int fd)
|
|||
_thread_sys_fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
}
|
||||
|
||||
/* XXX: Assumes well behaved threads. */
|
||||
/* XXX: Defer real close to avoid race condition */
|
||||
entry = _thread_fd_table[fd];
|
||||
_thread_fd_table[fd] = NULL;
|
||||
free(entry);
|
||||
|
||||
/* Close the file descriptor: */
|
||||
ret = _thread_sys_close(fd);
|
||||
|
||||
free(_thread_fd_table[fd]);
|
||||
_thread_fd_table[fd] = NULL;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -44,6 +45,28 @@ static inline pthread_t cond_queue_deq(pthread_cond_t);
|
|||
static inline void cond_queue_remove(pthread_cond_t, pthread_t);
|
||||
static inline void cond_queue_enq(pthread_cond_t, pthread_t);
|
||||
|
||||
/* Reinitialize a condition variable to defaults. */
|
||||
int
|
||||
_cond_reinit(pthread_cond_t * cond)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (cond == NULL)
|
||||
ret = EINVAL;
|
||||
else if (*cond == NULL)
|
||||
ret = pthread_cond_init(cond, NULL);
|
||||
else {
|
||||
/*
|
||||
* Initialize the condition variable structure:
|
||||
*/
|
||||
TAILQ_INIT(&(*cond)->c_queue);
|
||||
(*cond)->c_flags = COND_FLAGS_INITED;
|
||||
(*cond)->c_type = COND_TYPE_FAST;
|
||||
(*cond)->c_mutex = NULL;
|
||||
memset(&(*cond)->lock, 0, sizeof((*cond)->lock));
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
|
||||
|
|
@ -146,6 +169,9 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
|
|||
*/
|
||||
else if (*cond != NULL ||
|
||||
(rval = pthread_cond_init(cond,NULL)) == 0) {
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
||||
/*
|
||||
* If the condvar was statically allocated, properly
|
||||
* initialize the tail queue.
|
||||
|
|
@ -155,9 +181,6 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
|
|||
(*cond)->c_flags |= COND_FLAGS_INITED;
|
||||
}
|
||||
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
||||
/* Process according to condition variable type: */
|
||||
switch ((*cond)->c_type) {
|
||||
/* Fast condition variable: */
|
||||
|
|
@ -247,6 +270,9 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
|
|||
*/
|
||||
else if (*cond != NULL ||
|
||||
(rval = pthread_cond_init(cond,NULL)) == 0) {
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
||||
/*
|
||||
* If the condvar was statically allocated, properly
|
||||
* initialize the tail queue.
|
||||
|
|
@ -256,10 +282,6 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
|
|||
(*cond)->c_flags |= COND_FLAGS_INITED;
|
||||
}
|
||||
|
||||
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
||||
/* Process according to condition variable type: */
|
||||
switch ((*cond)->c_type) {
|
||||
/* Fast condition variable: */
|
||||
|
|
@ -375,6 +397,12 @@ pthread_cond_signal(pthread_cond_t * cond)
|
|||
if (cond == NULL || *cond == NULL)
|
||||
rval = EINVAL;
|
||||
else {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
||||
|
|
@ -409,6 +437,12 @@ pthread_cond_signal(pthread_cond_t * cond)
|
|||
|
||||
/* Unlock the condition variable structure: */
|
||||
_SPINUNLOCK(&(*cond)->lock);
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
@ -425,14 +459,10 @@ pthread_cond_broadcast(pthread_cond_t * cond)
|
|||
rval = EINVAL;
|
||||
else {
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues. In addition, we must assure
|
||||
* that all threads currently waiting on the condition
|
||||
* variable are signaled and are not timedout by a
|
||||
* scheduling signal that causes a preemption.
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
|
@ -468,9 +498,11 @@ pthread_cond_broadcast(pthread_cond_t * cond)
|
|||
/* Unlock the condition variable structure: */
|
||||
_SPINUNLOCK(&(*cond)->lock);
|
||||
|
||||
/* Reenable preemption and yield if necessary.
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
@ -488,7 +520,7 @@ cond_queue_deq(pthread_cond_t cond)
|
|||
|
||||
if ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
|
||||
TAILQ_REMOVE(&cond->c_queue, pthread, qe);
|
||||
pthread->flags &= ~PTHREAD_FLAGS_QUEUED;
|
||||
pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
|
||||
}
|
||||
|
||||
return(pthread);
|
||||
|
|
@ -507,9 +539,9 @@ cond_queue_remove(pthread_cond_t cond, pthread_t pthread)
|
|||
* guard against removing the thread from the queue if
|
||||
* it isn't in the queue.
|
||||
*/
|
||||
if (pthread->flags & PTHREAD_FLAGS_QUEUED) {
|
||||
if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) {
|
||||
TAILQ_REMOVE(&cond->c_queue, pthread, qe);
|
||||
pthread->flags &= ~PTHREAD_FLAGS_QUEUED;
|
||||
pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -535,6 +567,6 @@ cond_queue_enq(pthread_cond_t cond, pthread_t pthread)
|
|||
tid = TAILQ_NEXT(tid, qe);
|
||||
TAILQ_INSERT_BEFORE(tid, pthread, qe);
|
||||
}
|
||||
pthread->flags |= PTHREAD_FLAGS_QUEUED;
|
||||
pthread->flags |= PTHREAD_FLAGS_IN_CONDQ;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -171,7 +172,7 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
|
|||
new_thread->inherited_priority = 0;
|
||||
|
||||
/* Initialise the join queue for the new thread: */
|
||||
_thread_queue_init(&(new_thread->join_queue));
|
||||
TAILQ_INIT(&(new_thread->join_queue));
|
||||
|
||||
/* Initialize the mutex queue: */
|
||||
TAILQ_INIT(&new_thread->mutexq);
|
||||
|
|
@ -179,46 +180,39 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
|
|||
/* Initialise hooks in the thread structure: */
|
||||
new_thread->specific_data = NULL;
|
||||
new_thread->cleanup = NULL;
|
||||
new_thread->queue = NULL;
|
||||
new_thread->qnxt = NULL;
|
||||
new_thread->flags = 0;
|
||||
new_thread->poll_data.nfds = 0;
|
||||
new_thread->poll_data.fds = NULL;
|
||||
|
||||
/* Lock the thread list: */
|
||||
_lock_thread_list();
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/*
|
||||
* Check if the garbage collector thread
|
||||
* needs to be started.
|
||||
*/
|
||||
f_gc = (_thread_link_list == _thread_initial);
|
||||
f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial);
|
||||
|
||||
/* Add the thread to the linked list of all threads: */
|
||||
new_thread->nxt = _thread_link_list;
|
||||
_thread_link_list = new_thread;
|
||||
|
||||
/* Unlock the thread list: */
|
||||
_unlock_thread_list();
|
||||
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues.
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
|
||||
|
||||
if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {
|
||||
new_thread->state = PS_SUSPENDED;
|
||||
PTHREAD_WAITQ_INSERT(new_thread);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
new_thread->state = PS_RUNNING;
|
||||
PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling
|
||||
* signal occurred while in the critical region.
|
||||
* Undefer and handle pending signals, yielding
|
||||
* if necessary.
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/* Return a pointer to the thread structure: */
|
||||
(*thread) = new_thread;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -53,23 +54,25 @@ pthread_detach(pthread_t pthread)
|
|||
pthread->attr.flags |= PTHREAD_DETACHED;
|
||||
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues.
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Enter a loop to bring all threads off the join queue: */
|
||||
while ((next_thread = _thread_queue_deq(&pthread->join_queue)) != NULL) {
|
||||
while ((next_thread = TAILQ_FIRST(&pthread->join_queue)) != NULL) {
|
||||
/* Remove the thread from the queue: */
|
||||
TAILQ_REMOVE(&pthread->join_queue, next_thread, qe);
|
||||
|
||||
/* Make the thread run: */
|
||||
PTHREAD_NEW_STATE(next_thread,PS_RUNNING);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling signal
|
||||
* occurred while in the critical region.
|
||||
* Undefer and handle pending signals, yielding if a
|
||||
* scheduling signal occurred while in the critical region.
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
} else
|
||||
/* Return an error: */
|
||||
rval = EINVAL;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -92,7 +93,12 @@ _thread_exit(char *fname, int lineno, char *string)
|
|||
_thread_sys_write(2, s, strlen(s));
|
||||
|
||||
/* Force this process to exit: */
|
||||
/* XXX - Do we want abort to be conditional on _PTHREADS_INVARIANTS? */
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
abort();
|
||||
#else
|
||||
_exit(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -129,22 +135,24 @@ pthread_exit(void *status)
|
|||
}
|
||||
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal. A change of
|
||||
* thread state modifies the waiting and priority queues.
|
||||
* Defer signals to protect the scheduling queues from access
|
||||
* by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Check if there are any threads joined to this one: */
|
||||
while ((pthread = _thread_queue_deq(&(_thread_run->join_queue))) != NULL) {
|
||||
while ((pthread = TAILQ_FIRST(&(_thread_run->join_queue))) != NULL) {
|
||||
/* Remove the thread from the queue: */
|
||||
TAILQ_REMOVE(&_thread_run->join_queue, pthread, qe);
|
||||
|
||||
/* Wake the joined thread and let it detach this thread: */
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling signal
|
||||
* occurred while in the critical region.
|
||||
* Undefer and handle pending signals, yielding if necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/*
|
||||
* Lock the garbage collector mutex to ensure that the garbage
|
||||
|
|
@ -154,8 +162,21 @@ pthread_exit(void *status)
|
|||
PANIC("Cannot lock gc mutex");
|
||||
|
||||
/* Add this thread to the list of dead threads. */
|
||||
_thread_run->nxt_dead = _thread_dead;
|
||||
_thread_dead = _thread_run;
|
||||
TAILQ_INSERT_HEAD(&_dead_list, _thread_run, dle);
|
||||
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from access
|
||||
* by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Remove this thread from the thread list: */
|
||||
TAILQ_REMOVE(&_thread_list, _thread_run, tle);
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/*
|
||||
* Signal the garbage collector thread that there is something
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -46,20 +47,20 @@ _find_thread(pthread_t pthread)
|
|||
/* Invalid thread: */
|
||||
return(EINVAL);
|
||||
|
||||
/* Lock the thread list: */
|
||||
_lock_thread_list();
|
||||
/*
|
||||
* Defer signals to protect the thread list from access
|
||||
* by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Point to the first thread in the list: */
|
||||
pthread1 = _thread_link_list;
|
||||
|
||||
/* Search for the thread to join to: */
|
||||
while (pthread1 != NULL && pthread1 != pthread) {
|
||||
/* Point to the next thread: */
|
||||
pthread1 = pthread1->nxt;
|
||||
/* Search for the specified thread: */
|
||||
TAILQ_FOREACH(pthread1, &_thread_list, tle) {
|
||||
if (pthread == pthread1)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Unlock the thread list: */
|
||||
_unlock_thread_list();
|
||||
/* Undefer and handle pending signals, yielding if necessary: */
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/* Return zero if the thread exists: */
|
||||
return ((pthread1 != NULL) ? 0:ESRCH);
|
||||
|
|
@ -83,13 +84,10 @@ _find_dead_thread(pthread_t pthread)
|
|||
if (pthread_mutex_lock(&_gc_mutex) != 0)
|
||||
PANIC("Cannot lock gc mutex");
|
||||
|
||||
/* Point to the first thread in the list: */
|
||||
pthread1 = _thread_dead;
|
||||
|
||||
/* Search for the thread to join to: */
|
||||
while (pthread1 != NULL && pthread1 != pthread) {
|
||||
/* Point to the next thread: */
|
||||
pthread1 = pthread1->nxt_dead;
|
||||
/* Search for the specified thread: */
|
||||
TAILQ_FOREACH(pthread1, &_dead_list, dle) {
|
||||
if (pthread1 == pthread)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Unlock the garbage collector mutex: */
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
|
@ -44,10 +45,13 @@ fork(void)
|
|||
int i, flags;
|
||||
pid_t ret;
|
||||
pthread_t pthread;
|
||||
pthread_t pthread_next;
|
||||
pthread_t pthread_save;
|
||||
|
||||
/* Lock the thread list: */
|
||||
_lock_thread_list();
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from access
|
||||
* by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Fork a new process: */
|
||||
if ((ret = _thread_sys_fork()) != 0) {
|
||||
|
|
@ -88,45 +92,79 @@ fork(void)
|
|||
else if (_thread_sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
/* Abort this application: */
|
||||
abort();
|
||||
/* Initialize the ready queue: */
|
||||
} else if (_pq_init(&_readyq, PTHREAD_MIN_PRIORITY,
|
||||
PTHREAD_MAX_PRIORITY) != 0) {
|
||||
}
|
||||
/* Reinitialize the GC mutex: */
|
||||
else if (_mutex_reinit(&_gc_mutex) != 0) {
|
||||
/* Abort this application: */
|
||||
PANIC("Cannot allocate priority ready queue.");
|
||||
PANIC("Cannot initialize GC mutex for forked process");
|
||||
}
|
||||
/* Reinitialize the GC condition variable: */
|
||||
else if (_cond_reinit(&_gc_cond) != 0) {
|
||||
/* Abort this application: */
|
||||
PANIC("Cannot initialize GC condvar for forked process");
|
||||
}
|
||||
/* Initialize the ready queue: */
|
||||
else if (_pq_init(&_readyq) != 0) {
|
||||
/* Abort this application: */
|
||||
PANIC("Cannot initialize priority ready queue.");
|
||||
} else {
|
||||
/* Point to the first thread in the list: */
|
||||
pthread = _thread_link_list;
|
||||
|
||||
/*
|
||||
* Enter a loop to remove all threads other than
|
||||
* the running thread from the thread list:
|
||||
*/
|
||||
pthread = TAILQ_FIRST(&_thread_list);
|
||||
while (pthread != NULL) {
|
||||
pthread_next = pthread->nxt;
|
||||
if (pthread == _thread_run) {
|
||||
_thread_link_list = pthread;
|
||||
pthread->nxt = NULL;
|
||||
} else {
|
||||
if (pthread->attr.stackaddr_attr ==
|
||||
NULL && pthread->stack != NULL)
|
||||
/* Save the thread to be freed: */
|
||||
pthread_save = pthread;
|
||||
|
||||
/*
|
||||
* Advance to the next thread before
|
||||
* destroying the current thread:
|
||||
*/
|
||||
pthread = TAILQ_NEXT(pthread, dle);
|
||||
|
||||
/* Make sure this isn't the running thread: */
|
||||
if (pthread_save != _thread_run) {
|
||||
/* Remove this thread from the list: */
|
||||
TAILQ_REMOVE(&_thread_list,
|
||||
pthread_save, tle);
|
||||
|
||||
if (pthread_save->attr.stackaddr_attr ==
|
||||
NULL && pthread_save->stack != NULL)
|
||||
/*
|
||||
* Free the stack of the
|
||||
* dead thread:
|
||||
*/
|
||||
free(pthread->stack);
|
||||
free(pthread_save->stack);
|
||||
|
||||
if (pthread->specific_data != NULL)
|
||||
free(pthread->specific_data);
|
||||
if (pthread_save->specific_data != NULL)
|
||||
free(pthread_save->specific_data);
|
||||
|
||||
free(pthread);
|
||||
if (pthread_save->poll_data.fds != NULL)
|
||||
free(pthread_save->poll_data.fds);
|
||||
|
||||
free(pthread_save);
|
||||
}
|
||||
|
||||
/* Point to the next thread: */
|
||||
pthread = pthread_next;
|
||||
}
|
||||
|
||||
/* Re-init the waiting queues. */
|
||||
/* Re-init the dead thread list: */
|
||||
TAILQ_INIT(&_dead_list);
|
||||
|
||||
/* Re-init the waiting and work queues. */
|
||||
TAILQ_INIT(&_waitingq);
|
||||
TAILQ_INIT(&_workq);
|
||||
|
||||
/* Re-init the threads mutex queue: */
|
||||
TAILQ_INIT(&_thread_run->mutexq);
|
||||
|
||||
/* No spinlocks yet: */
|
||||
_spinblock_count = 0;
|
||||
|
||||
/* Don't queue signals yet: */
|
||||
_queue_signals = 0;
|
||||
|
||||
/* Initialize signal handling: */
|
||||
_thread_sig_init();
|
||||
|
||||
/* Initialize the scheduling switch hook routine: */
|
||||
_sched_switch_hook = NULL;
|
||||
|
|
@ -147,15 +185,17 @@ fork(void)
|
|||
_thread_fd_table[i]->w_lockcount = 0;;
|
||||
|
||||
/* Initialise the read/write queues: */
|
||||
_thread_queue_init(&_thread_fd_table[i]->r_queue);
|
||||
_thread_queue_init(&_thread_fd_table[i]->w_queue);
|
||||
TAILQ_INIT(&_thread_fd_table[i]->r_queue);
|
||||
TAILQ_INIT(&_thread_fd_table[i]->w_queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Unock the thread list: */
|
||||
_unlock_thread_list();
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/* Return the process ID: */
|
||||
return (ret);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -55,6 +56,7 @@ static const struct s_thread_info thread_info[] = {
|
|||
{PS_FDR_WAIT , "Waiting for read"},
|
||||
{PS_FDW_WAIT , "Waiting for write"},
|
||||
{PS_FILE_WAIT , "Waiting for FILE lock"},
|
||||
{PS_POLL_WAIT , "Waiting on poll"},
|
||||
{PS_SELECT_WAIT , "Waiting on select"},
|
||||
{PS_SLEEP_WAIT , "Sleeping"},
|
||||
{PS_WAIT_WAIT , "Waiting process"},
|
||||
|
|
@ -108,8 +110,7 @@ _thread_dump_info(void)
|
|||
_thread_sys_write(fd, s, strlen(s));
|
||||
|
||||
/* Enter a loop to report each thread in the global list: */
|
||||
for (pthread = _thread_link_list; pthread != NULL;
|
||||
pthread = pthread->nxt) {
|
||||
TAILQ_FOREACH(pthread, &_thread_list, tle) {
|
||||
/* Find the state: */
|
||||
for (j = 0; j < (sizeof(thread_info) /
|
||||
sizeof(struct s_thread_info)) - 1; j++)
|
||||
|
|
@ -214,8 +215,29 @@ _thread_dump_info(void)
|
|||
_thread_sys_write(fd, s, strlen(s));
|
||||
}
|
||||
|
||||
/* Output a header for threads in the work queue: */
|
||||
strcpy(s, "\n\n=============\nTHREADS IN WORKQ\n\n");
|
||||
_thread_sys_write(fd, s, strlen(s));
|
||||
|
||||
/* Enter a loop to report each thread in the waiting queue: */
|
||||
TAILQ_FOREACH (pthread, &_workq, qe) {
|
||||
/* Find the state: */
|
||||
for (j = 0; j < (sizeof(thread_info) /
|
||||
sizeof(struct s_thread_info)) - 1; j++)
|
||||
if (thread_info[j].state == pthread->state)
|
||||
break;
|
||||
/* Output a record for the current thread: */
|
||||
snprintf(s, sizeof(s),
|
||||
"--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
|
||||
pthread, (pthread->name == NULL) ?
|
||||
"":pthread->name, pthread->base_priority,
|
||||
thread_info[j].name,
|
||||
pthread->fname,pthread->lineno);
|
||||
_thread_sys_write(fd, s, strlen(s));
|
||||
}
|
||||
|
||||
/* Check if there are no dead threads: */
|
||||
if (_thread_dead == NULL) {
|
||||
if (TAILQ_FIRST(&_dead_list) == NULL) {
|
||||
/* Output a record: */
|
||||
strcpy(s, "\n\nTHERE ARE NO DEAD THREADS\n");
|
||||
_thread_sys_write(fd, s, strlen(s));
|
||||
|
|
@ -228,8 +250,7 @@ _thread_dump_info(void)
|
|||
* Enter a loop to report each thread in the global
|
||||
* dead thread list:
|
||||
*/
|
||||
for (pthread = _thread_dead; pthread != NULL;
|
||||
pthread = pthread->nxt_dead) {
|
||||
TAILQ_FOREACH(pthread, &_dead_list, dle) {
|
||||
/* Output a record for the current thread: */
|
||||
snprintf(s, sizeof(s),
|
||||
"Thread %p prio %3d [%s:%d]\n",
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/* Allocate space for global thread variables here: */
|
||||
|
|
@ -39,7 +40,9 @@
|
|||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ttycom.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -81,6 +84,9 @@ _thread_init(void)
|
|||
int fd;
|
||||
int flags;
|
||||
int i;
|
||||
int len;
|
||||
int mib[2];
|
||||
struct clockinfo clockinfo;
|
||||
struct sigaction act;
|
||||
|
||||
/* Check if this function has already been called: */
|
||||
|
|
@ -147,8 +153,8 @@ _thread_init(void)
|
|||
/* Abort this application: */
|
||||
PANIC("Cannot get kernel write pipe flags");
|
||||
}
|
||||
/* Initialize the ready queue: */
|
||||
else if (_pq_init(&_readyq, PTHREAD_MIN_PRIORITY, PTHREAD_MAX_PRIORITY) != 0) {
|
||||
/* Allocate and initialize the ready queue: */
|
||||
else if (_pq_alloc(&_readyq, PTHREAD_MIN_PRIORITY, PTHREAD_MAX_PRIORITY) != 0) {
|
||||
/* Abort this application: */
|
||||
PANIC("Cannot allocate priority ready queue.");
|
||||
}
|
||||
|
|
@ -165,8 +171,9 @@ _thread_init(void)
|
|||
_thread_kern_thread.flags = PTHREAD_FLAGS_PRIVATE;
|
||||
memset(_thread_initial, 0, sizeof(struct pthread));
|
||||
|
||||
/* Initialize the waiting queue: */
|
||||
/* Initialize the waiting and work queues: */
|
||||
TAILQ_INIT(&_waitingq);
|
||||
TAILQ_INIT(&_workq);
|
||||
|
||||
/* Initialize the scheduling switch hook routine: */
|
||||
_sched_switch_hook = NULL;
|
||||
|
|
@ -186,23 +193,23 @@ _thread_init(void)
|
|||
_thread_initial->state = PS_RUNNING;
|
||||
|
||||
/* Initialise the queue: */
|
||||
_thread_queue_init(&(_thread_initial->join_queue));
|
||||
TAILQ_INIT(&(_thread_initial->join_queue));
|
||||
|
||||
/* Initialize the owned mutex queue and count: */
|
||||
TAILQ_INIT(&(_thread_initial->mutexq));
|
||||
_thread_initial->priority_mutex_count = 0;
|
||||
|
||||
/* Initialise the rest of the fields: */
|
||||
_thread_initial->sched_defer_count = 0;
|
||||
_thread_initial->yield_on_sched_undefer = 0;
|
||||
_thread_initial->poll_data.nfds = 0;
|
||||
_thread_initial->poll_data.fds = NULL;
|
||||
_thread_initial->sig_defer_count = 0;
|
||||
_thread_initial->yield_on_sig_undefer = 0;
|
||||
_thread_initial->specific_data = NULL;
|
||||
_thread_initial->cleanup = NULL;
|
||||
_thread_initial->queue = NULL;
|
||||
_thread_initial->qnxt = NULL;
|
||||
_thread_initial->nxt = NULL;
|
||||
_thread_initial->flags = 0;
|
||||
_thread_initial->error = 0;
|
||||
_thread_link_list = _thread_initial;
|
||||
TAILQ_INIT(&_thread_list);
|
||||
TAILQ_INSERT_HEAD(&_thread_list, _thread_initial, tle);
|
||||
_thread_run = _thread_initial;
|
||||
|
||||
/* Initialise the global signal action structure: */
|
||||
|
|
@ -210,6 +217,9 @@ _thread_init(void)
|
|||
act.sa_handler = (void (*) ()) _thread_sig_handler;
|
||||
act.sa_flags = 0;
|
||||
|
||||
/* Initialize signal handling: */
|
||||
_thread_sig_init();
|
||||
|
||||
/* Enter a loop to get the existing signal status: */
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
/* Check for signals which cannot be trapped: */
|
||||
|
|
@ -241,6 +251,13 @@ _thread_init(void)
|
|||
PANIC("Cannot initialise signal handler");
|
||||
}
|
||||
|
||||
/* Get the kernel clockrate: */
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_CLOCKRATE;
|
||||
len = sizeof (struct clockinfo);
|
||||
if (sysctl(mib, 2, &clockinfo, &len, NULL, 0) == 0)
|
||||
_clock_res_nsec = clockinfo.tick * 1000;
|
||||
|
||||
/* Get the table size: */
|
||||
if ((_thread_dtablesize = getdtablesize()) < 0) {
|
||||
/*
|
||||
|
|
@ -256,6 +273,14 @@ _thread_init(void)
|
|||
* table, so abort this process.
|
||||
*/
|
||||
PANIC("Cannot allocate memory for file descriptor table");
|
||||
}
|
||||
/* Allocate memory for the pollfd table: */
|
||||
if ((_thread_pfd_table = (struct pollfd *) malloc(sizeof(struct pollfd) * _thread_dtablesize)) == NULL) {
|
||||
/*
|
||||
* Cannot allocate memory for the file descriptor
|
||||
* table, so abort this process.
|
||||
*/
|
||||
PANIC("Cannot allocate memory for pollfd table");
|
||||
} else {
|
||||
/*
|
||||
* Enter a loop to initialise the file descriptor
|
||||
|
|
@ -265,6 +290,14 @@ _thread_init(void)
|
|||
/* Initialise the file descriptor table: */
|
||||
_thread_fd_table[i] = NULL;
|
||||
}
|
||||
|
||||
/* Initialize stdio file descriptor table entries: */
|
||||
if ((_thread_fd_table_init(0) != 0) ||
|
||||
(_thread_fd_table_init(1) != 0) ||
|
||||
(_thread_fd_table_init(2) != 0)) {
|
||||
PANIC("Cannot initialize stdio file descriptor "
|
||||
"table entries");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -71,7 +72,7 @@ pthread_join(pthread_t pthread, void **thread_return)
|
|||
/* Check if the thread is not dead: */
|
||||
else if (pthread->state != PS_DEAD) {
|
||||
/* Add the running thread to the join queue: */
|
||||
_thread_queue_enq(&(pthread->join_queue), _thread_run);
|
||||
TAILQ_INSERT_TAIL(&(pthread->join_queue), _thread_run, qe);
|
||||
|
||||
/* Schedule the next thread: */
|
||||
_thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
|
@ -46,18 +47,18 @@ pthread_kill(pthread_t pthread, int sig)
|
|||
/* Invalid signal: */
|
||||
ret = EINVAL;
|
||||
|
||||
/* Ignored signals get dropped on the floor. */
|
||||
else if (_thread_sigact[sig - 1].sa_handler == SIG_IGN)
|
||||
ret = 0;
|
||||
|
||||
/* Find the thread in the list of active threads: */
|
||||
else if ((ret = _find_thread(pthread)) == 0) {
|
||||
/*
|
||||
* Ensure the thread is in the list of active threads, and the
|
||||
* signal is valid (signal 0 specifies error checking only) and
|
||||
* not being ignored:
|
||||
*/
|
||||
else if (((ret = _find_thread(pthread)) == 0) && (sig > 0) &&
|
||||
(_thread_sigact[sig - 1].sa_handler != SIG_IGN)) {
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues.
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
switch (pthread->state) {
|
||||
case PS_SIGSUSPEND:
|
||||
|
|
@ -90,15 +91,19 @@ pthread_kill(pthread_t pthread, int sig)
|
|||
sigaddset(&pthread->sigpend,sig);
|
||||
break;
|
||||
|
||||
case PS_SELECT_WAIT:
|
||||
case PS_FDR_WAIT:
|
||||
case PS_FDW_WAIT:
|
||||
case PS_POLL_WAIT:
|
||||
case PS_SLEEP_WAIT:
|
||||
case PS_SELECT_WAIT:
|
||||
if (!sigismember(&pthread->sigmask, sig) &&
|
||||
(_thread_sigact[sig - 1].sa_handler != SIG_IGN)) {
|
||||
/* Flag the operation as interrupted: */
|
||||
pthread->interrupted = 1;
|
||||
|
||||
if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
|
||||
PTHREAD_WORKQ_REMOVE(pthread);
|
||||
|
||||
/* Change the state of the thread to run: */
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
|
||||
|
|
@ -116,11 +121,43 @@ pthread_kill(pthread_t pthread, int sig)
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling signal
|
||||
* occurred while in the critical region.
|
||||
* Check that a custom handler is installed
|
||||
* and if the signal is not blocked:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
if (_thread_sigact[sig - 1].sa_handler != SIG_DFL &&
|
||||
_thread_sigact[sig - 1].sa_handler != SIG_IGN &&
|
||||
sigismember(&pthread->sigpend, sig) &&
|
||||
!sigismember(&pthread->sigmask, sig)) {
|
||||
pthread_t pthread_saved = _thread_run;
|
||||
|
||||
/* Current thread inside critical region? */
|
||||
if (_thread_run->sig_defer_count > 0)
|
||||
pthread->sig_defer_count++;
|
||||
|
||||
_thread_run = pthread;
|
||||
|
||||
/* Clear the pending signal: */
|
||||
sigdelset(&pthread->sigpend, sig);
|
||||
|
||||
/*
|
||||
* Dispatch the signal via the custom signal
|
||||
* handler:
|
||||
*/
|
||||
(*(_thread_sigact[sig - 1].sa_handler))(sig);
|
||||
|
||||
_thread_run = pthread_saved;
|
||||
|
||||
if (_thread_run->sig_defer_count > 0)
|
||||
pthread->sig_defer_count--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -39,6 +40,25 @@
|
|||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
#define _MUTEX_INIT_LINK(m) do { \
|
||||
(m)->m_qe.tqe_prev = NULL; \
|
||||
(m)->m_qe.tqe_next = NULL; \
|
||||
} while (0)
|
||||
#define _MUTEX_ASSERT_IS_OWNED(m) do { \
|
||||
if ((m)->m_qe.tqe_prev == NULL) \
|
||||
PANIC("mutex is not on list"); \
|
||||
} while (0)
|
||||
#define _MUTEX_ASSERT_NOT_OWNED(m) do { \
|
||||
if (((m)->m_qe.tqe_prev != NULL) || \
|
||||
((m)->m_qe.tqe_next != NULL)) \
|
||||
PANIC("mutex is on list"); \
|
||||
} while (0)
|
||||
#else
|
||||
#define _MUTEX_INIT_LINK(m)
|
||||
#define _MUTEX_ASSERT_IS_OWNED(m)
|
||||
#define _MUTEX_ASSERT_NOT_OWNED(m)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
|
|
@ -55,6 +75,34 @@ static inline void mutex_queue_enq(pthread_mutex_t, pthread_t);
|
|||
|
||||
static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER;
|
||||
|
||||
/* Reinitialize a mutex to defaults. */
|
||||
int
|
||||
_mutex_reinit(pthread_mutex_t * mutex)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (mutex == NULL)
|
||||
ret = EINVAL;
|
||||
else if (*mutex == NULL)
|
||||
ret = pthread_mutex_init(mutex, NULL);
|
||||
else {
|
||||
/*
|
||||
* Initialize the mutex structure:
|
||||
*/
|
||||
(*mutex)->m_type = PTHREAD_MUTEX_DEFAULT;
|
||||
(*mutex)->m_protocol = PTHREAD_PRIO_NONE;
|
||||
TAILQ_INIT(&(*mutex)->m_queue);
|
||||
(*mutex)->m_owner = NULL;
|
||||
(*mutex)->m_data.m_count = 0;
|
||||
(*mutex)->m_flags = MUTEX_FLAGS_INITED;
|
||||
(*mutex)->m_refcount = 0;
|
||||
(*mutex)->m_prio = 0;
|
||||
(*mutex)->m_saved_prio = 0;
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
memset(&(*mutex)->lock, 0, sizeof((*mutex)->lock));
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
pthread_mutex_init(pthread_mutex_t * mutex,
|
||||
|
|
@ -138,6 +186,7 @@ pthread_mutex_init(pthread_mutex_t * mutex,
|
|||
else
|
||||
pmutex->m_prio = 0;
|
||||
pmutex->m_saved_prio = 0;
|
||||
_MUTEX_INIT_LINK(pmutex);
|
||||
memset(&pmutex->lock, 0, sizeof(pmutex->lock));
|
||||
*mutex = pmutex;
|
||||
} else {
|
||||
|
|
@ -147,7 +196,7 @@ pthread_mutex_init(pthread_mutex_t * mutex,
|
|||
}
|
||||
}
|
||||
/* Return the completion status: */
|
||||
return (ret);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -177,6 +226,7 @@ pthread_mutex_destroy(pthread_mutex_t * mutex)
|
|||
* Free the memory allocated for the mutex
|
||||
* structure:
|
||||
*/
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
free(*mutex);
|
||||
|
||||
/*
|
||||
|
|
@ -221,29 +271,25 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
|
|||
* initialization:
|
||||
*/
|
||||
else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the mutex structure: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* If the mutex was statically allocated, properly
|
||||
* initialize the tail queue.
|
||||
*/
|
||||
if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
|
||||
TAILQ_INIT(&(*mutex)->m_queue);
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
(*mutex)->m_flags |= MUTEX_FLAGS_INITED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guard against being preempted by a scheduling signal.
|
||||
* To support priority inheritence mutexes, we need to
|
||||
* maintain lists of mutex ownerships for each thread as
|
||||
* well as lists of waiting threads for each mutex. In
|
||||
* order to propagate priorities we need to atomically
|
||||
* walk these lists and cannot rely on a single mutex
|
||||
* lock to provide protection against modification.
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
|
||||
/* Lock the mutex structure: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/* Process according to mutex type: */
|
||||
switch ((*mutex)->m_protocol) {
|
||||
/* Default POSIX mutex: */
|
||||
|
|
@ -254,6 +300,7 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
|
|||
(*mutex)->m_owner = _thread_run;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
} else if ((*mutex)->m_owner == _thread_run)
|
||||
|
|
@ -282,6 +329,7 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
|
|||
_thread_run->inherited_priority;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
} else if ((*mutex)->m_owner == _thread_run)
|
||||
|
|
@ -317,6 +365,7 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
|
|||
(*mutex)->m_prio;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
} else if ((*mutex)->m_owner == _thread_run)
|
||||
|
|
@ -337,10 +386,10 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
|
|||
_SPINUNLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* Renable preemption and yield if a scheduling signal
|
||||
* arrived while in the critical region:
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
@ -360,6 +409,15 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
* initialization:
|
||||
*/
|
||||
else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the mutex structure: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* If the mutex was statically allocated, properly
|
||||
* initialize the tail queue.
|
||||
|
|
@ -367,22 +425,9 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
|
||||
TAILQ_INIT(&(*mutex)->m_queue);
|
||||
(*mutex)->m_flags |= MUTEX_FLAGS_INITED;
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Guard against being preempted by a scheduling signal.
|
||||
* To support priority inheritence mutexes, we need to
|
||||
* maintain lists of mutex ownerships for each thread as
|
||||
* well as lists of waiting threads for each mutex. In
|
||||
* order to propagate priorities we need to atomically
|
||||
* walk these lists and cannot rely on a single mutex
|
||||
* lock to provide protection against modification.
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
|
||||
/* Lock the mutex structure: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/* Process according to mutex type: */
|
||||
switch ((*mutex)->m_protocol) {
|
||||
/* Default POSIX mutex: */
|
||||
|
|
@ -392,6 +437,7 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
(*mutex)->m_owner = _thread_run;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
|
||||
|
|
@ -419,12 +465,6 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
|
||||
/* Lock the mutex structure again: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* This thread is no longer waiting for
|
||||
* the mutex:
|
||||
*/
|
||||
_thread_run->data.mutex = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -449,6 +489,7 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
(*mutex)->m_prio;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
|
||||
|
|
@ -481,12 +522,6 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
|
||||
/* Lock the mutex structure again: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* This thread is no longer waiting for
|
||||
* the mutex:
|
||||
*/
|
||||
_thread_run->data.mutex = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -519,6 +554,7 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
(*mutex)->m_prio;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
} else if ((*mutex)->m_owner == _thread_run)
|
||||
|
|
@ -556,12 +592,6 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
*/
|
||||
ret = _thread_run->error;
|
||||
_thread_run->error = 0;
|
||||
|
||||
/*
|
||||
* This thread is no longer waiting for
|
||||
* the mutex:
|
||||
*/
|
||||
_thread_run->data.mutex = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -576,10 +606,10 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
_SPINUNLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* Renable preemption and yield if a scheduling signal
|
||||
* arrived while in the critical region:
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
@ -683,15 +713,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
ret = EINVAL;
|
||||
} else {
|
||||
/*
|
||||
* Guard against being preempted by a scheduling signal.
|
||||
* To support priority inheritence mutexes, we need to
|
||||
* maintain lists of mutex ownerships for each thread as
|
||||
* well as lists of waiting threads for each mutex. In
|
||||
* order to propagate priorities we need to atomically
|
||||
* walk these lists and cannot rely on a single mutex
|
||||
* lock to provide protection against modification.
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the mutex structure: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
|
@ -723,8 +748,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
(*mutex)->m_data.m_count = 0;
|
||||
|
||||
/* Remove the mutex from the threads queue. */
|
||||
_MUTEX_ASSERT_IS_OWNED(*mutex);
|
||||
TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
|
||||
(*mutex), m_qe);
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
|
||||
/*
|
||||
* Get the next thread from the queue of
|
||||
|
|
@ -738,6 +765,19 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
*/
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
|
||||
/*
|
||||
* Add the mutex to the threads list of
|
||||
* owned mutexes:
|
||||
*/
|
||||
TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq,
|
||||
(*mutex), m_qe);
|
||||
|
||||
/*
|
||||
* The owner is no longer waiting for
|
||||
* this mutex:
|
||||
*/
|
||||
(*mutex)->m_owner->data.mutex = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -784,8 +824,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
_thread_run->priority_mutex_count--;
|
||||
|
||||
/* Remove the mutex from the threads queue. */
|
||||
_MUTEX_ASSERT_IS_OWNED(*mutex);
|
||||
TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
|
||||
(*mutex), m_qe);
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
|
||||
/*
|
||||
* Get the next thread from the queue of threads
|
||||
|
|
@ -891,8 +933,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
_thread_run->priority_mutex_count--;
|
||||
|
||||
/* Remove the mutex from the threads queue. */
|
||||
_MUTEX_ASSERT_IS_OWNED(*mutex);
|
||||
TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
|
||||
(*mutex), m_qe);
|
||||
(*mutex), m_qe);
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
|
||||
/*
|
||||
* Enter a loop to find a waiting thread whose
|
||||
|
|
@ -913,6 +957,11 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
(*mutex)->m_owner->error = EINVAL;
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
/*
|
||||
* The thread is no longer waiting for
|
||||
* this mutex:
|
||||
*/
|
||||
(*mutex)->m_owner->data.mutex = NULL;
|
||||
}
|
||||
|
||||
/* Check for a new owner: */
|
||||
|
|
@ -978,10 +1027,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
_SPINUNLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* Renable preemption and yield if a scheduling signal
|
||||
* arrived while in the critical region:
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
@ -990,11 +1039,11 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
|
||||
|
||||
/*
|
||||
* This function is called when a change in base priority occurs
|
||||
* for a thread that is thread holding, or waiting for, a priority
|
||||
* protection or inheritence mutex. A change in a threads base
|
||||
* priority can effect changes to active priorities of other threads
|
||||
* and to the ordering of mutex locking by waiting threads.
|
||||
* This function is called when a change in base priority occurs for
|
||||
* a thread that is holding or waiting for a priority protection or
|
||||
* inheritence mutex. A change in a threads base priority can effect
|
||||
* changes to active priorities of other threads and to the ordering
|
||||
* of mutex locking by waiting threads.
|
||||
*
|
||||
* This must be called while thread scheduling is deferred.
|
||||
*/
|
||||
|
|
@ -1231,8 +1280,7 @@ mutex_rescan_owned (pthread_t pthread, pthread_mutex_t mutex)
|
|||
* If this thread is in the priority queue, it must be
|
||||
* removed and reinserted for its new priority.
|
||||
*/
|
||||
if ((pthread != _thread_run) &&
|
||||
(pthread->state == PS_RUNNING)) {
|
||||
if (pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) {
|
||||
/*
|
||||
* Remove the thread from the priority queue
|
||||
* before changing its priority:
|
||||
|
|
|
|||
95
lib/libkse/thread/thr_poll.c
Normal file
95
lib/libkse/thread/thr_poll.c
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 1999 Daniel Eischen <eischen@vigrid.com>
|
||||
* 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. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Daniel Eischen.
|
||||
* 4. 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 DANIEL EISCHEN 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <poll.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/fcntl.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
|
||||
|
||||
int
|
||||
poll(struct pollfd *fds, unsigned int nfds, int timeout)
|
||||
{
|
||||
struct timespec ts;
|
||||
int numfds = nfds;
|
||||
int i, ret = 0, found = 0;
|
||||
struct pthread_poll_data data;
|
||||
|
||||
if (numfds > _thread_dtablesize) {
|
||||
numfds = _thread_dtablesize;
|
||||
}
|
||||
/* Check if a timeout was specified: */
|
||||
if (timeout == INFTIM) {
|
||||
/* Wait for ever: */
|
||||
_thread_kern_set_timeout(NULL);
|
||||
} else if (timeout != 0) {
|
||||
/* Convert the timeout in msec to a timespec: */
|
||||
ts.tv_sec = timeout / 1000;
|
||||
ts.tv_nsec = (timeout % 1000) * 1000;
|
||||
|
||||
/* Set the wake up time: */
|
||||
_thread_kern_set_timeout(&ts);
|
||||
}
|
||||
|
||||
if (((ret = _thread_sys_poll(fds, numfds, 0)) == 0) && (timeout != 0)) {
|
||||
data.nfds = numfds;
|
||||
data.fds = fds;
|
||||
|
||||
/*
|
||||
* Clear revents in case of a timeout which leaves fds
|
||||
* unchanged:
|
||||
*/
|
||||
for (i = 0; i < numfds; i++) {
|
||||
fds[i].revents = 0;
|
||||
}
|
||||
|
||||
_thread_run->data.poll_data = &data;
|
||||
_thread_run->interrupted = 0;
|
||||
_thread_kern_sched_state(PS_POLL_WAIT, __FILE__, __LINE__);
|
||||
if (_thread_run->interrupted) {
|
||||
errno = EINTR;
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = data.nfds;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <sys/queue.h>
|
||||
|
|
@ -40,9 +41,51 @@
|
|||
/* Prototypes: */
|
||||
static void pq_insert_prio_list(pq_queue_t *pq, int prio);
|
||||
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
|
||||
static int _pq_active = 0;
|
||||
|
||||
#define _PQ_IN_SCHEDQ (PTHREAD_FLAGS_IN_PRIOQ | PTHREAD_FLAGS_IN_WAITQ | PTHREAD_FLAGS_IN_WORKQ)
|
||||
|
||||
#define _PQ_SET_ACTIVE() _pq_active = 1
|
||||
#define _PQ_CLEAR_ACTIVE() _pq_active = 0
|
||||
#define _PQ_ASSERT_ACTIVE(msg) do { \
|
||||
if (_pq_active == 0) \
|
||||
PANIC(msg); \
|
||||
} while (0)
|
||||
#define _PQ_ASSERT_INACTIVE(msg) do { \
|
||||
if (_pq_active != 0) \
|
||||
PANIC(msg); \
|
||||
} while (0)
|
||||
#define _PQ_ASSERT_IN_WAITQ(thrd, msg) do { \
|
||||
if (((thrd)->flags & PTHREAD_FLAGS_IN_WAITQ) == 0) \
|
||||
PANIC(msg); \
|
||||
} while (0)
|
||||
#define _PQ_ASSERT_IN_PRIOQ(thrd, msg) do { \
|
||||
if (((thrd)->flags & PTHREAD_FLAGS_IN_PRIOQ) == 0) \
|
||||
PANIC(msg); \
|
||||
} while (0)
|
||||
#define _PQ_ASSERT_NOT_QUEUED(thrd, msg) do { \
|
||||
if ((thrd)->flags & _PQ_IN_SCHEDQ) \
|
||||
PANIC(msg); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define _PQ_SET_ACTIVE()
|
||||
#define _PQ_CLEAR_ACTIVE()
|
||||
#define _PQ_ASSERT_ACTIVE(msg)
|
||||
#define _PQ_ASSERT_INACTIVE(msg)
|
||||
#define _PQ_ASSERT_IN_WAITQ(thrd, msg)
|
||||
#define _PQ_ASSERT_IN_PRIOQ(thrd, msg)
|
||||
#define _PQ_ASSERT_NOT_QUEUED(thrd, msg)
|
||||
#define _PQ_CHECK_PRIO()
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
_pq_init(pq_queue_t *pq, int minprio, int maxprio)
|
||||
_pq_alloc(pq_queue_t *pq, int minprio, int maxprio)
|
||||
{
|
||||
int i, ret = 0;
|
||||
int prioslots = maxprio - minprio + 1;
|
||||
|
|
@ -55,9 +98,27 @@ _pq_init(pq_queue_t *pq, int minprio, int maxprio)
|
|||
(pq_list_t *) malloc(sizeof(pq_list_t) * prioslots)) == NULL)
|
||||
ret = -1;
|
||||
|
||||
else {
|
||||
/* Remember the queue size: */
|
||||
pq->pq_size = prioslots;
|
||||
|
||||
ret = _pq_init(pq);
|
||||
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
_pq_init(pq_queue_t *pq)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
if ((pq == NULL) || (pq->pq_lists == NULL))
|
||||
ret = -1;
|
||||
|
||||
else {
|
||||
/* Initialize the queue for each priority slot: */
|
||||
for (i = 0; i < prioslots; i++) {
|
||||
for (i = 0; i < pq->pq_size; i++) {
|
||||
TAILQ_INIT(&pq->pq_lists[i].pl_head);
|
||||
pq->pq_lists[i].pl_prio = i;
|
||||
pq->pq_lists[i].pl_queued = 0;
|
||||
|
|
@ -65,9 +126,7 @@ _pq_init(pq_queue_t *pq, int minprio, int maxprio)
|
|||
|
||||
/* Initialize the priority queue: */
|
||||
TAILQ_INIT(&pq->pq_queue);
|
||||
|
||||
/* Remember the queue size: */
|
||||
pq->pq_size = prioslots;
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
|
@ -77,7 +136,27 @@ _pq_remove(pq_queue_t *pq, pthread_t pthread)
|
|||
{
|
||||
int prio = pthread->active_priority;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_pq_remove: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_IN_PRIOQ(pthread, "_pq_remove: Not in priority queue");
|
||||
|
||||
/*
|
||||
* Remove this thread from priority list. Note that if
|
||||
* the priority list becomes empty, it is not removed
|
||||
* from the priority queue because another thread may be
|
||||
* added to the priority list (resulting in a needless
|
||||
* removal/insertion). Priority lists are only removed
|
||||
* from the priority queue when _pq_first is called.
|
||||
*/
|
||||
TAILQ_REMOVE(&pq->pq_lists[prio].pl_head, pthread, pqe);
|
||||
|
||||
/* This thread is now longer in the priority queue. */
|
||||
pthread->flags &= ~PTHREAD_FLAGS_IN_PRIOQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -86,10 +165,23 @@ _pq_insert_head(pq_queue_t *pq, pthread_t pthread)
|
|||
{
|
||||
int prio = pthread->active_priority;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_pq_insert_head: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_NOT_QUEUED(pthread,
|
||||
"_pq_insert_head: Already in priority queue");
|
||||
|
||||
TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe);
|
||||
if (pq->pq_lists[prio].pl_queued == 0)
|
||||
/* Insert the list into the priority queue: */
|
||||
pq_insert_prio_list(pq, prio);
|
||||
|
||||
/* Mark this thread as being in the priority queue. */
|
||||
pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -98,10 +190,23 @@ _pq_insert_tail(pq_queue_t *pq, pthread_t pthread)
|
|||
{
|
||||
int prio = pthread->active_priority;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_pq_insert_tail: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_NOT_QUEUED(pthread,
|
||||
"_pq_insert_tail: Already in priority queue");
|
||||
|
||||
TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe);
|
||||
if (pq->pq_lists[prio].pl_queued == 0)
|
||||
/* Insert the list into the priority queue: */
|
||||
pq_insert_prio_list(pq, prio);
|
||||
|
||||
/* Mark this thread as being in the priority queue. */
|
||||
pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -111,6 +216,12 @@ _pq_first(pq_queue_t *pq)
|
|||
pq_list_t *pql;
|
||||
pthread_t pthread = NULL;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_pq_first: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
|
||||
while (((pql = TAILQ_FIRST(&pq->pq_queue)) != NULL) &&
|
||||
(pthread == NULL)) {
|
||||
if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) {
|
||||
|
|
@ -124,6 +235,8 @@ _pq_first(pq_queue_t *pq)
|
|||
pql->pl_queued = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
return (pthread);
|
||||
}
|
||||
|
||||
|
|
@ -133,10 +246,15 @@ pq_insert_prio_list(pq_queue_t *pq, int prio)
|
|||
{
|
||||
pq_list_t *pql;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_ACTIVE("pq_insert_prio_list: pq_active");
|
||||
|
||||
/*
|
||||
* The priority queue is in descending priority order. Start at
|
||||
* the beginning of the queue and find the list before which the
|
||||
* new list should to be inserted.
|
||||
* new list should be inserted.
|
||||
*/
|
||||
pql = TAILQ_FIRST(&pq->pq_queue);
|
||||
while ((pql != NULL) && (pql->pl_prio > prio))
|
||||
|
|
@ -152,4 +270,66 @@ pq_insert_prio_list(pq_queue_t *pq, int prio)
|
|||
pq->pq_lists[prio].pl_queued = 1;
|
||||
}
|
||||
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
void
|
||||
_waitq_insert(pthread_t pthread)
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_waitq_insert: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_NOT_QUEUED(pthread, "_waitq_insert: Already in queue");
|
||||
|
||||
if (pthread->wakeup_time.tv_sec == -1)
|
||||
TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe);
|
||||
else {
|
||||
tid = TAILQ_FIRST(&_waitingq);
|
||||
while ((tid != NULL) && (tid->wakeup_time.tv_sec != -1) &&
|
||||
((tid->wakeup_time.tv_sec < pthread->wakeup_time.tv_sec) ||
|
||||
((tid->wakeup_time.tv_sec == pthread->wakeup_time.tv_sec) &&
|
||||
(tid->wakeup_time.tv_nsec <= pthread->wakeup_time.tv_nsec))))
|
||||
tid = TAILQ_NEXT(tid, pqe);
|
||||
if (tid == NULL)
|
||||
TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe);
|
||||
else
|
||||
TAILQ_INSERT_BEFORE(tid, pthread, pqe);
|
||||
}
|
||||
pthread->flags |= PTHREAD_FLAGS_IN_WAITQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
|
||||
void
|
||||
_waitq_remove(pthread_t pthread)
|
||||
{
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_waitq_remove: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_IN_WAITQ(pthread, "_waitq_remove: Not in queue");
|
||||
|
||||
TAILQ_REMOVE(&_waitingq, pthread, pqe);
|
||||
pthread->flags &= ~PTHREAD_FLAGS_IN_WAITQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
|
||||
void
|
||||
_waitq_setactive(void)
|
||||
{
|
||||
_PQ_ASSERT_INACTIVE("_waitq_setactive: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
}
|
||||
|
||||
void
|
||||
_waitq_clearactive(void)
|
||||
{
|
||||
_PQ_ASSERT_ACTIVE("_waitq_clearactive: ! pq_active");
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
*
|
||||
* Private thread definitions for the uthread kernel.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _PTHREAD_PRIVATE_H
|
||||
|
|
@ -68,33 +69,88 @@
|
|||
|
||||
|
||||
/*
|
||||
* Priority queue manipulation macros:
|
||||
* Priority queue manipulation macros (using pqe link):
|
||||
*/
|
||||
#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)
|
||||
#define PTHREAD_PRIOQ_FIRST() _pq_first(&_readyq)
|
||||
|
||||
/*
|
||||
* Waiting queue manipulation macros:
|
||||
* Waiting queue manipulation macros (using pqe link):
|
||||
*/
|
||||
#define PTHREAD_WAITQ_INSERT(thrd) TAILQ_INSERT_TAIL(&_waitingq,thrd,pqe)
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
#define PTHREAD_WAITQ_REMOVE(thrd) _waitq_remove(thrd)
|
||||
#define PTHREAD_WAITQ_INSERT(thrd) _waitq_insert(thrd)
|
||||
#define PTHREAD_WAITQ_CLEARACTIVE() _waitq_clearactive()
|
||||
#define PTHREAD_WAITQ_SETACTIVE() _waitq_setactive()
|
||||
#else
|
||||
#define PTHREAD_WAITQ_REMOVE(thrd) TAILQ_REMOVE(&_waitingq,thrd,pqe)
|
||||
#define PTHREAD_WAITQ_INSERT(thrd) do { \
|
||||
if ((thrd)->wakeup_time.tv_sec == -1) \
|
||||
TAILQ_INSERT_TAIL(&_waitingq,thrd,pqe); \
|
||||
else { \
|
||||
pthread_t tid = TAILQ_FIRST(&_waitingq); \
|
||||
while ((tid != NULL) && (tid->wakeup_time.tv_sec != -1) && \
|
||||
((tid->wakeup_time.tv_sec < (thrd)->wakeup_time.tv_sec) || \
|
||||
((tid->wakeup_time.tv_sec == (thrd)->wakeup_time.tv_sec) && \
|
||||
(tid->wakeup_time.tv_nsec <= (thrd)->wakeup_time.tv_nsec)))) \
|
||||
tid = TAILQ_NEXT(tid, pqe); \
|
||||
if (tid == NULL) \
|
||||
TAILQ_INSERT_TAIL(&_waitingq,thrd,pqe); \
|
||||
else \
|
||||
TAILQ_INSERT_BEFORE(tid,thrd,pqe); \
|
||||
} \
|
||||
} while (0)
|
||||
#define PTHREAD_WAITQ_CLEARACTIVE()
|
||||
#define PTHREAD_WAITQ_SETACTIVE()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Work queue manipulation macros (using qe link):
|
||||
*/
|
||||
#define PTHREAD_WORKQ_INSERT(thrd) do { \
|
||||
TAILQ_INSERT_TAIL(&_workq,thrd,qe); \
|
||||
(thrd)->flags |= PTHREAD_FLAGS_IN_WORKQ; \
|
||||
} while (0)
|
||||
#define PTHREAD_WORKQ_REMOVE(thrd) do { \
|
||||
TAILQ_REMOVE(&_workq,thrd,qe); \
|
||||
(thrd)->flags &= ~PTHREAD_FLAGS_IN_WORKQ; \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* State change macro without scheduling queue change:
|
||||
*/
|
||||
#define PTHREAD_SET_STATE(thrd, newstate) { \
|
||||
#define PTHREAD_SET_STATE(thrd, newstate) do { \
|
||||
(thrd)->state = newstate; \
|
||||
(thrd)->fname = __FILE__; \
|
||||
(thrd)->lineno = __LINE__; \
|
||||
}
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* 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 defined(_PTHREADS_INVARIANTS)
|
||||
#define PTHREAD_NEW_STATE(thrd, newstate) do { \
|
||||
if (_thread_kern_new_state != 0) \
|
||||
PANIC("Recursive PTHREAD_NEW_STATE"); \
|
||||
_thread_kern_new_state = 1; \
|
||||
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); \
|
||||
} \
|
||||
} \
|
||||
_thread_kern_new_state = 0; \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
} while (0)
|
||||
#else
|
||||
#define PTHREAD_NEW_STATE(thrd, newstate) do { \
|
||||
if ((thrd)->state != newstate) { \
|
||||
if ((thrd)->state == PS_RUNNING) { \
|
||||
PTHREAD_PRIOQ_REMOVE(thrd); \
|
||||
|
|
@ -105,7 +161,8 @@
|
|||
} \
|
||||
} \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
}
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define the signals to be used for scheduling.
|
||||
|
|
@ -118,15 +175,6 @@
|
|||
#define _SCHED_SIGNAL SIGPROF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Queue definitions.
|
||||
*/
|
||||
struct pthread_queue {
|
||||
struct pthread *q_next;
|
||||
struct pthread *q_last;
|
||||
void *q_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* Priority queues.
|
||||
*
|
||||
|
|
@ -146,15 +194,10 @@ typedef struct pq_queue {
|
|||
} pq_queue_t;
|
||||
|
||||
|
||||
/*
|
||||
* Static queue initialization values.
|
||||
*/
|
||||
#define PTHREAD_QUEUE_INITIALIZER { NULL, NULL, NULL }
|
||||
|
||||
/*
|
||||
* TailQ initialization values.
|
||||
*/
|
||||
#define TAILQ_INITIALIZER { NULL, NULL }
|
||||
#define TAILQ_INITIALIZER { NULL, NULL }
|
||||
|
||||
/*
|
||||
* Mutex definitions.
|
||||
|
|
@ -257,7 +300,7 @@ struct pthread_cond_attr {
|
|||
* Static cond initialization values.
|
||||
*/
|
||||
#define PTHREAD_COND_STATIC_INITIALIZER \
|
||||
{ COND_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, NULL, NULL, \
|
||||
{ COND_TYPE_FAST, TAILQ_INITIALIZER, NULL, NULL, \
|
||||
0, _SPINLOCK_INITIALIZER }
|
||||
|
||||
/*
|
||||
|
|
@ -302,12 +345,6 @@ struct pthread_attr {
|
|||
*/
|
||||
#define CLOCK_RES_NSEC 10000000
|
||||
|
||||
/*
|
||||
* Number of microseconds between incremental priority updates for
|
||||
* threads that are ready to run, but denied being run.
|
||||
*/
|
||||
#define INC_PRIO_USEC 500000
|
||||
|
||||
/*
|
||||
* Time slice period in microseconds.
|
||||
*/
|
||||
|
|
@ -345,6 +382,7 @@ enum pthread_state {
|
|||
PS_FDR_WAIT,
|
||||
PS_FDW_WAIT,
|
||||
PS_FILE_WAIT,
|
||||
PS_POLL_WAIT,
|
||||
PS_SELECT_WAIT,
|
||||
PS_SLEEP_WAIT,
|
||||
PS_WAIT_WAIT,
|
||||
|
|
@ -377,8 +415,8 @@ struct fd_table_entry {
|
|||
* state of the lock on the file descriptor.
|
||||
*/
|
||||
spinlock_t lock;
|
||||
struct pthread_queue r_queue; /* Read queue. */
|
||||
struct pthread_queue w_queue; /* Write queue. */
|
||||
TAILQ_HEAD(, pthread) r_queue; /* Read queue. */
|
||||
TAILQ_HEAD(, pthread) w_queue; /* Write queue. */
|
||||
struct pthread *r_owner; /* Ptr to thread owning read lock. */
|
||||
struct pthread *w_owner; /* Ptr to thread owning write lock. */
|
||||
char *r_fname; /* Ptr to read lock source file name */
|
||||
|
|
@ -390,11 +428,9 @@ struct fd_table_entry {
|
|||
int flags; /* Flags used in open. */
|
||||
};
|
||||
|
||||
struct pthread_select_data {
|
||||
struct pthread_poll_data {
|
||||
int nfds;
|
||||
fd_set readfds;
|
||||
fd_set writefds;
|
||||
fd_set exceptfds;
|
||||
struct pollfd *fds;
|
||||
};
|
||||
|
||||
union pthread_wait_data {
|
||||
|
|
@ -406,7 +442,7 @@ union pthread_wait_data {
|
|||
short branch; /* Line number, for debugging. */
|
||||
char *fname; /* Source file name for debugging.*/
|
||||
} fd;
|
||||
struct pthread_select_data * select_data;
|
||||
struct pthread_poll_data * poll_data;
|
||||
spinlock_t *spinlock;
|
||||
};
|
||||
|
||||
|
|
@ -427,15 +463,11 @@ struct pthread {
|
|||
*/
|
||||
spinlock_t lock;
|
||||
|
||||
/*
|
||||
* Pointer to the next thread in the thread linked list.
|
||||
*/
|
||||
struct pthread *nxt;
|
||||
/* Queue entry for list of all threads: */
|
||||
TAILQ_ENTRY(pthread) tle;
|
||||
|
||||
/*
|
||||
* Pointer to the next thread in the dead thread linked list.
|
||||
*/
|
||||
struct pthread *nxt_dead;
|
||||
/* Queue entry for list of dead threads: */
|
||||
TAILQ_ENTRY(pthread) dle;
|
||||
|
||||
/*
|
||||
* Thread start routine, argument, stack pointer and thread
|
||||
|
|
@ -514,25 +546,25 @@ struct pthread {
|
|||
*/
|
||||
int error;
|
||||
|
||||
/* Join queue for waiting threads: */
|
||||
struct pthread_queue join_queue;
|
||||
/* Join queue head and link for waiting threads: */
|
||||
TAILQ_HEAD(join_head, pthread) join_queue;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* The current thread can belong to only one scheduling queue at
|
||||
* a time (ready or waiting queue). It can also belong to (only)
|
||||
* one of:
|
||||
*
|
||||
* o A queue of threads waiting for a mutex
|
||||
* o A queue of threads waiting for a condition variable
|
||||
* o A queue of threads waiting for another thread to terminate
|
||||
* (the join queue above)
|
||||
* o A queue of threads waiting for a file descriptor lock
|
||||
* o A queue of threads needing work done by the kernel thread
|
||||
* (waiting for a spinlock or file I/O)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* XXX The queuing should be changed to use the TAILQ entry below.
|
||||
* XXX For the time being, it's hybrid.
|
||||
* and qe for other links.
|
||||
*/
|
||||
struct pthread_queue *queue;
|
||||
|
||||
/* Pointer to next element in queue. */
|
||||
struct pthread *qnxt;
|
||||
|
||||
/* Priority queue entry for this thread: */
|
||||
TAILQ_ENTRY(pthread) pqe;
|
||||
|
|
@ -543,6 +575,11 @@ struct pthread {
|
|||
/* Wait data. */
|
||||
union pthread_wait_data data;
|
||||
|
||||
/*
|
||||
* Allocated for converting select into poll.
|
||||
*/
|
||||
struct pthread_poll_data poll_data;
|
||||
|
||||
/*
|
||||
* Set to TRUE if a blocking operation was
|
||||
* interrupted by a signal:
|
||||
|
|
@ -553,23 +590,26 @@ struct pthread {
|
|||
int signo;
|
||||
|
||||
/*
|
||||
* Set to non-zero when this thread has deferred thread
|
||||
* scheduling. We allow for recursive deferral.
|
||||
* Set to non-zero when this thread has deferred signals.
|
||||
* We allow for recursive deferral.
|
||||
*/
|
||||
int sched_defer_count;
|
||||
int sig_defer_count;
|
||||
|
||||
/*
|
||||
* Set to TRUE if this thread should yield after undeferring
|
||||
* thread scheduling.
|
||||
* signals.
|
||||
*/
|
||||
int yield_on_sched_undefer;
|
||||
int yield_on_sig_undefer;
|
||||
|
||||
/* Miscellaneous data. */
|
||||
int flags;
|
||||
#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_FLAGS_IN_CONDQ 0x0004 /* in condition queue using qe link*/
|
||||
#define PTHREAD_FLAGS_IN_WORKQ 0x0008 /* in work queue using qe link */
|
||||
#define PTHREAD_FLAGS_IN_WAITQ 0x0010 /* in waiting queue using pqe link*/
|
||||
#define PTHREAD_FLAGS_IN_PRIOQ 0x0020 /* in priority queue using pqe link*/
|
||||
#define PTHREAD_FLAGS_TRACE 0x0040 /* for debugging purposes */
|
||||
|
||||
/*
|
||||
* Base priority is the user setable and retrievable priority
|
||||
|
|
@ -592,7 +632,7 @@ struct pthread {
|
|||
/*
|
||||
* 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
|
||||
* in either the base or inherited priority, the active
|
||||
* priority must be recalculated.
|
||||
*/
|
||||
char active_priority;
|
||||
|
|
@ -649,10 +689,10 @@ SCLASS struct pthread * volatile _thread_single
|
|||
;
|
||||
#endif
|
||||
|
||||
/* Ptr to the first thread in the thread linked list: */
|
||||
SCLASS struct pthread * volatile _thread_link_list
|
||||
/* List of all threads: */
|
||||
SCLASS TAILQ_HEAD(, pthread) _thread_list
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= NULL;
|
||||
= TAILQ_HEAD_INITIALIZER(_thread_list);
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
|
|
@ -661,7 +701,7 @@ SCLASS struct pthread * volatile _thread_link_list
|
|||
* Array of kernel pipe file descriptors that are used to ensure that
|
||||
* no signals are missed in calls to _select.
|
||||
*/
|
||||
SCLASS int _thread_kern_pipe[2]
|
||||
SCLASS int _thread_kern_pipe[2]
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= {
|
||||
-1,
|
||||
|
|
@ -670,7 +710,7 @@ SCLASS int _thread_kern_pipe[2]
|
|||
#else
|
||||
;
|
||||
#endif
|
||||
SCLASS int _thread_kern_in_select
|
||||
SCLASS int volatile _queue_signals
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= 0;
|
||||
#else
|
||||
|
|
@ -692,9 +732,9 @@ SCLASS struct timeval kern_inc_prio_time
|
|||
#endif
|
||||
|
||||
/* Dead threads: */
|
||||
SCLASS struct pthread * volatile _thread_dead
|
||||
SCLASS TAILQ_HEAD(, pthread) _dead_list
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= NULL;
|
||||
= TAILQ_HEAD_INITIALIZER(_dead_list);
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
|
|
@ -747,6 +787,14 @@ SCLASS struct fd_table_entry **_thread_fd_table
|
|||
;
|
||||
#endif
|
||||
|
||||
/* Table for polling file descriptors: */
|
||||
SCLASS struct pollfd *_thread_pfd_table
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= NULL;
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
|
||||
SCLASS const int dtablecount
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= 4096/sizeof(struct fd_table_entry);
|
||||
|
|
@ -760,6 +808,13 @@ SCLASS int _thread_dtablesize /* Descriptor table size. */
|
|||
;
|
||||
#endif
|
||||
|
||||
SCLASS int _clock_res_nsec /* Clock resolution in nsec. */
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= CLOCK_RES_NSEC;
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
|
||||
/* Garbage collector mutex and condition variable. */
|
||||
SCLASS pthread_mutex_t _gc_mutex
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
|
|
@ -783,8 +838,20 @@ struct sigaction _thread_sigact[NSIG];
|
|||
SCLASS pq_queue_t _readyq;
|
||||
SCLASS TAILQ_HEAD(, pthread) _waitingq;
|
||||
|
||||
/* Indicates that the waitingq now has threads ready to run. */
|
||||
SCLASS volatile int _waitingq_check_reqd
|
||||
/*
|
||||
* Work queue:
|
||||
*/
|
||||
SCLASS TAILQ_HEAD(, pthread) _workq;
|
||||
|
||||
/* Tracks the number of threads blocked while waiting for a spinlock. */
|
||||
SCLASS volatile int _spinblock_count
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= 0
|
||||
#endif
|
||||
;
|
||||
|
||||
/* Indicates that the signal queue needs to be checked. */
|
||||
SCLASS volatile int _sigq_check_reqd
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= 0
|
||||
#endif
|
||||
|
|
@ -797,6 +864,13 @@ SCLASS pthread_switch_routine_t _sched_switch_hook
|
|||
#endif
|
||||
;
|
||||
|
||||
/* Used for _PTHREADS_INVARIANTS checking. */
|
||||
SCLASS int _thread_kern_new_state
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= 0
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
/* Undefine the storage class specifier: */
|
||||
#undef SCLASS
|
||||
|
|
@ -825,18 +899,23 @@ int _thread_fd_lock(int, int, struct timespec *);
|
|||
int _thread_fd_lock_debug(int, int, struct timespec *,char *fname,int lineno);
|
||||
void _dispatch_signals(void);
|
||||
void _thread_signal(pthread_t, int);
|
||||
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 *);
|
||||
int _mutex_reinit(pthread_mutex_t *);
|
||||
void _mutex_notify_priochange(struct pthread *);
|
||||
int _pq_init(struct pq_queue *pq, int, int);
|
||||
int _cond_reinit(pthread_cond_t *);
|
||||
int _pq_alloc(struct pq_queue *, int, int);
|
||||
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);
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
void _waitq_insert(pthread_t pthread);
|
||||
void _waitq_remove(pthread_t pthread);
|
||||
void _waitq_setactive(void);
|
||||
void _waitq_clearactive(void);
|
||||
#endif
|
||||
void _thread_exit(char *, int, char *);
|
||||
void _thread_fd_unlock(int, int);
|
||||
void _thread_fd_unlock_debug(int, int, char *, int);
|
||||
|
|
@ -849,18 +928,15 @@ void _thread_kern_sched_state(enum pthread_state,char *fname,int lineno);
|
|||
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_kern_sig_defer(void);
|
||||
void _thread_kern_sig_undefer(void);
|
||||
void _thread_sig_handler(int, int, struct sigcontext *);
|
||||
void _thread_sig_handle(int, struct sigcontext *);
|
||||
void _thread_sig_init(void);
|
||||
void _thread_start(void);
|
||||
void _thread_start_sig_handler(void);
|
||||
void _thread_seterrno(pthread_t,int);
|
||||
void _thread_queue_init(struct pthread_queue *);
|
||||
void _thread_queue_enq(struct pthread_queue *, struct pthread *);
|
||||
int _thread_queue_remove(struct pthread_queue *, struct pthread *);
|
||||
int _thread_fd_table_init(int fd);
|
||||
struct pthread *_thread_queue_get(struct pthread_queue *);
|
||||
struct pthread *_thread_queue_deq(struct pthread_queue *);
|
||||
pthread_addr_t _thread_gc(pthread_addr_t);
|
||||
|
||||
/* #include <signal.h> */
|
||||
|
|
@ -1036,6 +1112,11 @@ pid_t _thread_sys_waitpid(pid_t, int *, int);
|
|||
pid_t _thread_sys_wait3(int *, int, struct rusage *);
|
||||
pid_t _thread_sys_wait4(pid_t, int *, int, struct rusage *);
|
||||
#endif
|
||||
|
||||
/* #include <poll.h> */
|
||||
#ifdef _SYS_POLL_H_
|
||||
int _thread_sys_poll(struct pollfd *, unsigned, int);
|
||||
#endif
|
||||
__END_DECLS
|
||||
|
||||
#endif /* !_PTHREAD_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -46,20 +47,19 @@ pthread_resume_np(pthread_t thread)
|
|||
/* The thread exists. Is it suspended? */
|
||||
if (thread->state != PS_SUSPENDED) {
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues.
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Allow the thread to run. */
|
||||
PTHREAD_NEW_STATE(thread,PS_RUNNING);
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling
|
||||
* signal occurred while in the critical region.
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
}
|
||||
return(ret);
|
||||
|
|
|
|||
|
|
@ -29,10 +29,13 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
|
@ -44,12 +47,10 @@ int
|
|||
select(int numfds, fd_set * readfds, fd_set * writefds,
|
||||
fd_set * exceptfds, struct timeval * timeout)
|
||||
{
|
||||
fd_set read_locks, write_locks, rdwr_locks;
|
||||
struct timespec ts;
|
||||
struct timeval zero_timeout = {0, 0};
|
||||
int i, ret = 0, got_all_locks = 1;
|
||||
int f_wait = 1;
|
||||
struct pthread_select_data data;
|
||||
int i, ret = 0, f_wait = 1;
|
||||
int pfd_index, got_one = 0, fd_count = 0;
|
||||
struct pthread_poll_data data;
|
||||
|
||||
if (numfds > _thread_dtablesize) {
|
||||
numfds = _thread_dtablesize;
|
||||
|
|
@ -68,112 +69,129 @@ select(int numfds, fd_set * readfds, fd_set * writefds,
|
|||
_thread_kern_set_timeout(NULL);
|
||||
}
|
||||
|
||||
FD_ZERO(&read_locks);
|
||||
FD_ZERO(&write_locks);
|
||||
FD_ZERO(&rdwr_locks);
|
||||
|
||||
/* lock readfds */
|
||||
/* Count the number of file descriptors to be polled: */
|
||||
if (readfds || writefds || exceptfds) {
|
||||
for (i = 0; i < numfds; i++) {
|
||||
if ((readfds && (FD_ISSET(i, readfds))) || (exceptfds && FD_ISSET(i, exceptfds))) {
|
||||
if (writefds && FD_ISSET(i, writefds)) {
|
||||
if ((ret = _FD_LOCK(i, FD_RDWR, NULL)) != 0) {
|
||||
got_all_locks = 0;
|
||||
break;
|
||||
}
|
||||
FD_SET(i, &rdwr_locks);
|
||||
} else {
|
||||
if ((ret = _FD_LOCK(i, FD_READ, NULL)) != 0) {
|
||||
got_all_locks = 0;
|
||||
break;
|
||||
}
|
||||
FD_SET(i, &read_locks);
|
||||
}
|
||||
} else {
|
||||
if (writefds && FD_ISSET(i, writefds)) {
|
||||
if ((ret = _FD_LOCK(i, FD_WRITE, NULL)) != 0) {
|
||||
got_all_locks = 0;
|
||||
break;
|
||||
}
|
||||
FD_SET(i, &write_locks);
|
||||
}
|
||||
if ((readfds && FD_ISSET(i, readfds)) ||
|
||||
(exceptfds && FD_ISSET(i, exceptfds)) ||
|
||||
(writefds && FD_ISSET(i, writefds))) {
|
||||
fd_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (got_all_locks) {
|
||||
data.nfds = numfds;
|
||||
FD_ZERO(&data.readfds);
|
||||
FD_ZERO(&data.writefds);
|
||||
FD_ZERO(&data.exceptfds);
|
||||
if (readfds != NULL) {
|
||||
memcpy(&data.readfds, readfds, sizeof(data.readfds));
|
||||
|
||||
/*
|
||||
* Allocate memory for poll data if it hasn't already been
|
||||
* allocated or if previously allocated memory is insufficient.
|
||||
*/
|
||||
if ((_thread_run->poll_data.fds == NULL) ||
|
||||
(_thread_run->poll_data.nfds < fd_count)) {
|
||||
data.fds = (struct pollfd *) realloc(_thread_run->poll_data.fds,
|
||||
sizeof(struct pollfd) * MAX(128, fd_count));
|
||||
if (data.fds == NULL) {
|
||||
errno = ENOMEM;
|
||||
ret = -1;
|
||||
}
|
||||
if (writefds != NULL) {
|
||||
memcpy(&data.writefds, writefds, sizeof(data.writefds));
|
||||
else {
|
||||
/*
|
||||
* Note that the threads poll data always
|
||||
* indicates what is allocated, not what is
|
||||
* currently being polled.
|
||||
*/
|
||||
_thread_run->poll_data.fds = data.fds;
|
||||
_thread_run->poll_data.nfds = MAX(128, fd_count);
|
||||
}
|
||||
if (exceptfds != NULL) {
|
||||
memcpy(&data.exceptfds, exceptfds, sizeof(data.exceptfds));
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* Setup the wait data. */
|
||||
data.fds = _thread_run->poll_data.fds;
|
||||
data.nfds = fd_count;
|
||||
|
||||
/*
|
||||
* Setup the array of pollfds. Optimize this by
|
||||
* running the loop in reverse and stopping when
|
||||
* the number of selected file descriptors is reached.
|
||||
*/
|
||||
for (i = numfds - 1, pfd_index = fd_count - 1;
|
||||
(i >= 0) && (pfd_index >= 0); i--) {
|
||||
data.fds[pfd_index].events = 0;
|
||||
if (readfds && FD_ISSET(i, readfds)) {
|
||||
data.fds[pfd_index].events = POLLRDNORM;
|
||||
}
|
||||
if (exceptfds && FD_ISSET(i, exceptfds)) {
|
||||
data.fds[pfd_index].events |= POLLRDBAND;
|
||||
}
|
||||
if (writefds && FD_ISSET(i, writefds)) {
|
||||
data.fds[pfd_index].events |= POLLWRNORM;
|
||||
}
|
||||
if (data.fds[pfd_index].events != 0) {
|
||||
/*
|
||||
* Set the file descriptor to be polled and
|
||||
* clear revents in case of a timeout which
|
||||
* leaves fds unchanged:
|
||||
*/
|
||||
data.fds[pfd_index].fd = i;
|
||||
data.fds[pfd_index].revents = 0;
|
||||
pfd_index--;
|
||||
}
|
||||
}
|
||||
if ((ret = _thread_sys_select(data.nfds, &data.readfds, &data.writefds, &data.exceptfds, &zero_timeout)) == 0 && f_wait) {
|
||||
data.nfds = numfds;
|
||||
FD_ZERO(&data.readfds);
|
||||
FD_ZERO(&data.writefds);
|
||||
FD_ZERO(&data.exceptfds);
|
||||
if (readfds != NULL) {
|
||||
memcpy(&data.readfds, readfds, sizeof(data.readfds));
|
||||
}
|
||||
if (writefds != NULL) {
|
||||
memcpy(&data.writefds, writefds, sizeof(data.writefds));
|
||||
}
|
||||
if (exceptfds != NULL) {
|
||||
memcpy(&data.exceptfds, exceptfds, sizeof(data.exceptfds));
|
||||
}
|
||||
_thread_run->data.select_data = &data;
|
||||
if (((ret = _thread_sys_poll(data.fds, data.nfds, 0)) == 0) &&
|
||||
(f_wait != 0)) {
|
||||
_thread_run->data.poll_data = &data;
|
||||
_thread_run->interrupted = 0;
|
||||
_thread_kern_sched_state(PS_SELECT_WAIT, __FILE__, __LINE__);
|
||||
if (_thread_run->interrupted) {
|
||||
errno = EINTR;
|
||||
data.nfds = 0;
|
||||
ret = -1;
|
||||
} else
|
||||
ret = data.nfds;
|
||||
}
|
||||
}
|
||||
/* clean up the locks */
|
||||
for (i = 0; i < numfds; i++)
|
||||
if (FD_ISSET(i, &read_locks))
|
||||
_FD_UNLOCK(i, FD_READ);
|
||||
for (i = 0; i < numfds; i++)
|
||||
if (FD_ISSET(i, &rdwr_locks))
|
||||
_FD_UNLOCK(i, FD_RDWR);
|
||||
for (i = 0; i < numfds; i++)
|
||||
if (FD_ISSET(i, &write_locks))
|
||||
_FD_UNLOCK(i, FD_WRITE);
|
||||
|
||||
if (ret >= 0) {
|
||||
if (readfds != NULL) {
|
||||
for (i = 0; i < numfds; i++) {
|
||||
if (FD_ISSET(i, readfds) &&
|
||||
!FD_ISSET(i, &data.readfds)) {
|
||||
FD_CLR(i, readfds);
|
||||
numfds = 0;
|
||||
for (i = 0; i < fd_count; i++) {
|
||||
/*
|
||||
* Check the results of the poll and clear
|
||||
* this file descriptor from the fdset if
|
||||
* the requested event wasn't ready.
|
||||
*/
|
||||
got_one = 0;
|
||||
if (readfds != NULL) {
|
||||
if (FD_ISSET(data.fds[i].fd, readfds)) {
|
||||
if (data.fds[i].revents & (POLLIN |
|
||||
POLLRDNORM))
|
||||
got_one = 1;
|
||||
else
|
||||
FD_CLR(data.fds[i].fd, readfds);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (writefds != NULL) {
|
||||
for (i = 0; i < numfds; i++) {
|
||||
if (FD_ISSET(i, writefds) &&
|
||||
!FD_ISSET(i, &data.writefds)) {
|
||||
FD_CLR(i, writefds);
|
||||
if (writefds != NULL) {
|
||||
if (FD_ISSET(data.fds[i].fd, writefds)) {
|
||||
if (data.fds[i].revents & (POLLOUT |
|
||||
POLLWRNORM | POLLWRBAND))
|
||||
got_one = 1;
|
||||
else
|
||||
FD_CLR(data.fds[i].fd,
|
||||
writefds);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exceptfds != NULL) {
|
||||
for (i = 0; i < numfds; i++) {
|
||||
if (FD_ISSET(i, exceptfds) &&
|
||||
!FD_ISSET(i, &data.exceptfds)) {
|
||||
FD_CLR(i, exceptfds);
|
||||
if (exceptfds != NULL) {
|
||||
if (FD_ISSET(data.fds[i].fd, exceptfds)) {
|
||||
if (data.fds[i].revents & (POLLRDBAND |
|
||||
POLLPRI | POLLHUP | POLLERR |
|
||||
POLLNVAL))
|
||||
got_one = 1;
|
||||
else
|
||||
FD_CLR(data.fds[i].fd,
|
||||
exceptfds);
|
||||
}
|
||||
}
|
||||
if (got_one)
|
||||
numfds++;
|
||||
}
|
||||
ret = numfds;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <sys/param.h>
|
||||
|
|
@ -50,10 +51,10 @@ pthread_setschedparam(pthread_t pthread, int policy, struct sched_param *param)
|
|||
/* Find the thread in the list of active threads: */
|
||||
else if ((ret = _find_thread(pthread)) == 0) {
|
||||
/*
|
||||
* Guard against being preempted by a scheduling
|
||||
* signal:
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
if (param->sched_priority != pthread->base_priority) {
|
||||
/*
|
||||
|
|
@ -61,8 +62,7 @@ pthread_setschedparam(pthread_t pthread, int policy, struct sched_param *param)
|
|||
* queue before any adjustments are made to its
|
||||
* active priority:
|
||||
*/
|
||||
if ((pthread != _thread_run) &&
|
||||
(pthread->state == PS_RUNNING)) {
|
||||
if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0) {
|
||||
in_readyq = 1;
|
||||
old_prio = pthread->active_priority;
|
||||
PTHREAD_PRIOQ_REMOVE(pthread);
|
||||
|
|
@ -103,10 +103,10 @@ pthread_setschedparam(pthread_t pthread, int policy, struct sched_param *param)
|
|||
pthread->attr.sched_policy = policy;
|
||||
|
||||
/*
|
||||
* Renable preemption and yield if a scheduling signal
|
||||
* arrived while in the critical region:
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -38,107 +39,51 @@
|
|||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
|
||||
/*
|
||||
* State change macro for signal handler:
|
||||
*/
|
||||
#define PTHREAD_SIG_NEW_STATE(thrd, newstate) { \
|
||||
if ((_thread_run->sched_defer_count == 0) && \
|
||||
(_thread_kern_in_sched == 0)) { \
|
||||
PTHREAD_NEW_STATE(thrd, newstate); \
|
||||
} else { \
|
||||
_waitingq_check_reqd = 1; \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Static variables: */
|
||||
static int volatile yield_on_unlock_thread = 0;
|
||||
static spinlock_t thread_link_list_lock = _SPINLOCK_INITIALIZER;
|
||||
static spinlock_t signal_lock = _SPINLOCK_INITIALIZER;
|
||||
unsigned int pending_sigs[NSIG];
|
||||
unsigned int handled_sigs[NSIG];
|
||||
int volatile check_pending = 0;
|
||||
|
||||
/* Lock the thread list: */
|
||||
/* Initialize signal handling facility: */
|
||||
void
|
||||
_lock_thread_list()
|
||||
_thread_sig_init(void)
|
||||
{
|
||||
/* Lock the thread list: */
|
||||
_SPINLOCK(&thread_link_list_lock);
|
||||
}
|
||||
int i;
|
||||
|
||||
/* Lock the thread list: */
|
||||
void
|
||||
_unlock_thread_list()
|
||||
{
|
||||
/* Unlock the thread list: */
|
||||
_SPINUNLOCK(&thread_link_list_lock);
|
||||
|
||||
/*
|
||||
* Check if a scheduler interrupt occurred while the thread
|
||||
* list was locked:
|
||||
*/
|
||||
if (yield_on_unlock_thread) {
|
||||
/* Reset the interrupt flag: */
|
||||
yield_on_unlock_thread = 0;
|
||||
|
||||
/* This thread has overstayed it's welcome: */
|
||||
sched_yield();
|
||||
/* Clear pending and handled signal counts: */
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
pending_sigs[i - 1] = 0;
|
||||
handled_sigs[i - 1] = 0;
|
||||
}
|
||||
|
||||
/* Clear the lock: */
|
||||
signal_lock.access_lock = 0;
|
||||
}
|
||||
|
||||
void
|
||||
_thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
||||
{
|
||||
char c;
|
||||
int i;
|
||||
pthread_t pthread;
|
||||
|
||||
/*
|
||||
* Check if the pthread kernel has unblocked signals (or is about to)
|
||||
* and was on its way into a _select when the current
|
||||
* signal interrupted it:
|
||||
*/
|
||||
if (_thread_kern_in_select) {
|
||||
/* Cast the signal number to a character variable: */
|
||||
c = sig;
|
||||
|
||||
/*
|
||||
* Write the signal number to the kernel pipe so that it will
|
||||
* be ready to read when this signal handler returns. This
|
||||
* means that the _select call will complete
|
||||
* immediately.
|
||||
*/
|
||||
_thread_sys_write(_thread_kern_pipe[1], &c, 1);
|
||||
}
|
||||
/* Check if the signal requires a dump of thread information: */
|
||||
if (sig == SIGINFO)
|
||||
/* Dump thread information to file: */
|
||||
_thread_dump_info();
|
||||
char c;
|
||||
int i;
|
||||
|
||||
/* Check if an interval timer signal: */
|
||||
else if (sig == _SCHED_SIGNAL) {
|
||||
/* Check if the scheduler interrupt has come at an
|
||||
* unfortunate time which one of the threads is
|
||||
* modifying the thread list:
|
||||
*/
|
||||
if (thread_link_list_lock.access_lock)
|
||||
if (sig == _SCHED_SIGNAL) {
|
||||
if (_thread_kern_in_sched != 0) {
|
||||
/*
|
||||
* Set a flag so that the thread that has
|
||||
* the lock yields when it unlocks the
|
||||
* thread list:
|
||||
* The scheduler is already running; ignore this
|
||||
* signal.
|
||||
*/
|
||||
yield_on_unlock_thread = 1;
|
||||
|
||||
}
|
||||
/*
|
||||
* Check if the scheduler interrupt has come when
|
||||
* the currently running thread has deferred thread
|
||||
* scheduling.
|
||||
* signals.
|
||||
*/
|
||||
else if (_thread_run->sched_defer_count)
|
||||
_thread_run->yield_on_sched_undefer = 1;
|
||||
else if (_thread_run->sig_defer_count > 0)
|
||||
_thread_run->yield_on_sig_undefer = 1;
|
||||
|
||||
/*
|
||||
* Check if the kernel has not been interrupted while
|
||||
* executing scheduler code:
|
||||
*/
|
||||
else if (!_thread_kern_in_sched) {
|
||||
else {
|
||||
/*
|
||||
* Schedule the next thread. This function is not
|
||||
* expected to return because it will do a longjmp
|
||||
|
|
@ -152,6 +97,72 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
|||
*/
|
||||
PANIC("Returned to signal function from scheduler");
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Check if the kernel has been interrupted while the scheduler
|
||||
* is accessing the scheduling queues or if there is a currently
|
||||
* running thread that has deferred signals.
|
||||
*/
|
||||
else if ((_queue_signals != 0) || ((_thread_kern_in_sched == 0) &&
|
||||
(_thread_run->sig_defer_count > 0))) {
|
||||
/* Cast the signal number to a character variable: */
|
||||
c = sig;
|
||||
|
||||
/*
|
||||
* Write the signal number to the kernel pipe so that it will
|
||||
* be ready to read when this signal handler returns.
|
||||
*/
|
||||
_thread_sys_write(_thread_kern_pipe[1], &c, 1);
|
||||
|
||||
/* Indicate that there are queued signals in the pipe. */
|
||||
_sigq_check_reqd = 1;
|
||||
}
|
||||
else {
|
||||
if (_atomic_lock(&signal_lock.access_lock)) {
|
||||
/* There is another signal handler running: */
|
||||
pending_sigs[sig - 1]++;
|
||||
check_pending = 1;
|
||||
}
|
||||
else {
|
||||
/* It's safe to handle the signal now. */
|
||||
_thread_sig_handle(sig, scp);
|
||||
|
||||
/* Reset the pending and handled count back to 0: */
|
||||
pending_sigs[sig - 1] = 0;
|
||||
handled_sigs[sig - 1] = 0;
|
||||
|
||||
signal_lock.access_lock = 0;
|
||||
}
|
||||
|
||||
/* Enter a loop to process pending signals: */
|
||||
while ((check_pending != 0) &&
|
||||
(_atomic_lock(&signal_lock.access_lock) == 0)) {
|
||||
check_pending = 0;
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (pending_sigs[i - 1] > handled_sigs[i - 1])
|
||||
_thread_sig_handle(i, scp);
|
||||
}
|
||||
signal_lock.access_lock = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_thread_sig_handle(int sig, struct sigcontext * scp)
|
||||
{
|
||||
int i;
|
||||
pthread_t pthread, pthread_next;
|
||||
|
||||
/* Check if the signal requires a dump of thread information: */
|
||||
if (sig == SIGINFO)
|
||||
/* Dump thread information to file: */
|
||||
_thread_dump_info();
|
||||
|
||||
/* Check if an interval timer signal: */
|
||||
else if (sig == _SCHED_SIGNAL) {
|
||||
/*
|
||||
* This shouldn't ever occur (should this panic?).
|
||||
*/
|
||||
} else {
|
||||
/* Check if a child has terminated: */
|
||||
if (sig == SIGCHLD) {
|
||||
|
|
@ -183,10 +194,9 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
|||
* Enter a loop to discard pending SIGCONT
|
||||
* signals:
|
||||
*/
|
||||
for (pthread = _thread_link_list;
|
||||
pthread != NULL;
|
||||
pthread = pthread->nxt)
|
||||
TAILQ_FOREACH(pthread, &_thread_list, tle) {
|
||||
sigdelset(&pthread->sigpend,SIGCONT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -196,11 +206,18 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
|||
* if there are multiple waiters, we'll give it to the
|
||||
* first one we find.
|
||||
*/
|
||||
TAILQ_FOREACH(pthread, &_waitingq, pqe) {
|
||||
for (pthread = TAILQ_FIRST(&_waitingq);
|
||||
pthread != NULL; pthread = pthread_next) {
|
||||
/*
|
||||
* Grab the next thread before possibly destroying
|
||||
* the link entry.
|
||||
*/
|
||||
pthread_next = TAILQ_NEXT(pthread, pqe);
|
||||
|
||||
if ((pthread->state == PS_SIGWAIT) &&
|
||||
sigismember(pthread->data.sigwait, sig)) {
|
||||
/* Change the state of the thread to run: */
|
||||
PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
|
||||
/* Return the signal number: */
|
||||
pthread->signo = sig;
|
||||
|
|
@ -219,10 +236,13 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
|||
* Enter a loop to process each thread in the linked
|
||||
* list:
|
||||
*/
|
||||
for (pthread = _thread_link_list; pthread != NULL;
|
||||
pthread = pthread->nxt) {
|
||||
TAILQ_FOREACH(pthread, &_thread_list, tle) {
|
||||
pthread_t pthread_saved = _thread_run;
|
||||
|
||||
/* Current thread inside critical region? */
|
||||
if (_thread_run->sig_defer_count > 0)
|
||||
pthread->sig_defer_count++;
|
||||
|
||||
_thread_run = pthread;
|
||||
_thread_signal(pthread,sig);
|
||||
|
||||
|
|
@ -232,6 +252,10 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
|||
*/
|
||||
_dispatch_signals();
|
||||
_thread_run = pthread_saved;
|
||||
|
||||
/* Current thread inside critical region? */
|
||||
if (_thread_run->sig_defer_count > 0)
|
||||
pthread->sig_defer_count--;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -284,7 +308,7 @@ _thread_signal(pthread_t pthread, int sig)
|
|||
pthread->interrupted = 1;
|
||||
|
||||
/* Change the state of the thread to run: */
|
||||
PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
|
||||
/* Return the signal number: */
|
||||
pthread->signo = sig;
|
||||
|
|
@ -296,6 +320,7 @@ _thread_signal(pthread_t pthread, int sig)
|
|||
*/
|
||||
case PS_FDR_WAIT:
|
||||
case PS_FDW_WAIT:
|
||||
case PS_POLL_WAIT:
|
||||
case PS_SLEEP_WAIT:
|
||||
case PS_SELECT_WAIT:
|
||||
if (sig != SIGCHLD ||
|
||||
|
|
@ -303,8 +328,11 @@ _thread_signal(pthread_t pthread, int sig)
|
|||
/* Flag the operation as interrupted: */
|
||||
pthread->interrupted = 1;
|
||||
|
||||
if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
|
||||
PTHREAD_WORKQ_REMOVE(pthread);
|
||||
|
||||
/* Change the state of the thread to run: */
|
||||
PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
|
||||
/* Return the signal number: */
|
||||
pthread->signo = sig;
|
||||
|
|
@ -319,7 +347,7 @@ _thread_signal(pthread_t pthread, int sig)
|
|||
if (!sigismember(&pthread->sigmask, sig) &&
|
||||
_thread_sigact[sig - 1].sa_handler != SIG_DFL) {
|
||||
/* Change the state of the thread to run: */
|
||||
PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
|
||||
/* Return the signal number: */
|
||||
pthread->signo = sig;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -77,6 +78,9 @@ sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
|
|||
gact.sa_mask = act->sa_mask;
|
||||
gact.sa_flags = 0;
|
||||
|
||||
/* Ensure the scheduling signal is masked: */
|
||||
sigaddset(&gact.sa_mask, _SCHED_SIGNAL);
|
||||
|
||||
/*
|
||||
* Check if the signal handler is being set to
|
||||
* the default or ignore handlers:
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -41,7 +42,7 @@ sigwait(const sigset_t * set, int *sig)
|
|||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
sigset_t tempset;
|
||||
sigset_t tempset, waitset;
|
||||
struct sigaction act;
|
||||
|
||||
/*
|
||||
|
|
@ -51,17 +52,23 @@ sigwait(const sigset_t * set, int *sig)
|
|||
act.sa_flags = SA_RESTART;
|
||||
act.sa_mask = *set;
|
||||
|
||||
/* Ensure the scheduling signal is masked: */
|
||||
sigaddset(&act.sa_mask, _SCHED_SIGNAL);
|
||||
|
||||
/*
|
||||
* These signals can't be waited on.
|
||||
* Initialize the set of signals that will be waited on:
|
||||
*/
|
||||
sigdelset(&act.sa_mask, SIGKILL);
|
||||
sigdelset(&act.sa_mask, SIGSTOP);
|
||||
sigdelset(&act.sa_mask, _SCHED_SIGNAL);
|
||||
sigdelset(&act.sa_mask, SIGCHLD);
|
||||
sigdelset(&act.sa_mask, SIGINFO);
|
||||
waitset = *set;
|
||||
|
||||
/* These signals can't be waited on. */
|
||||
sigdelset(&waitset, SIGKILL);
|
||||
sigdelset(&waitset, SIGSTOP);
|
||||
sigdelset(&waitset, _SCHED_SIGNAL);
|
||||
sigdelset(&waitset, SIGCHLD);
|
||||
sigdelset(&waitset, SIGINFO);
|
||||
|
||||
/* Check to see if a pending signal is in the wait mask. */
|
||||
if (tempset = (_thread_run->sigpend & act.sa_mask)) {
|
||||
if (tempset = (_thread_run->sigpend & waitset)) {
|
||||
/* Enter a loop to find a pending signal: */
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (sigismember (&tempset, i))
|
||||
|
|
@ -81,17 +88,17 @@ sigwait(const sigset_t * set, int *sig)
|
|||
* Enter a loop to find the signals that are SIG_DFL. For
|
||||
* these signals we must install a dummy signal handler in
|
||||
* order for the kernel to pass them in to us. POSIX says
|
||||
* that the application must explicitly install a dummy
|
||||
* that the _application_ must explicitly install a dummy
|
||||
* handler for signals that are SIG_IGN in order to sigwait
|
||||
* on them. Note that SIG_IGN signals are left in the
|
||||
* mask because a subsequent sigaction could enable an
|
||||
* ignored signal.
|
||||
*/
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (sigismember(&act.sa_mask, i)) {
|
||||
if (_thread_sigact[i - 1].sa_handler == SIG_DFL)
|
||||
if (_thread_sys_sigaction(i,&act,NULL) != 0)
|
||||
ret = -1;
|
||||
if (sigismember(&waitset, i) &&
|
||||
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
|
||||
if (_thread_sys_sigaction(i,&act,NULL) != 0)
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
|
|
@ -101,7 +108,7 @@ sigwait(const sigset_t * set, int *sig)
|
|||
* mask is independent of the threads signal mask
|
||||
* and requires separate storage.
|
||||
*/
|
||||
_thread_run->data.sigwait = &act.sa_mask;
|
||||
_thread_run->data.sigwait = &waitset;
|
||||
|
||||
/* Wait for a signal: */
|
||||
_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
|
||||
|
|
@ -119,7 +126,7 @@ sigwait(const sigset_t * set, int *sig)
|
|||
/* Restore the sigactions: */
|
||||
act.sa_handler = SIG_DFL;
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (sigismember(&act.sa_mask, i) &&
|
||||
if (sigismember(&waitset, i) &&
|
||||
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
|
||||
if (_thread_sys_sigaction(i,&act,NULL) != 0)
|
||||
ret = -1;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -52,20 +53,19 @@ pthread_suspend_np(pthread_t thread)
|
|||
}
|
||||
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues.
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Suspend the thread. */
|
||||
PTHREAD_NEW_STATE(thread,PS_SUSPENDED);
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling signal
|
||||
* occurred while in the critical region.
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# $Id: Makefile.inc,v 1.16 1998/09/30 06:36:55 jb Exp $
|
||||
# $Id: Makefile.inc,v 1.17 1999/03/23 05:07:54 jb Exp $
|
||||
|
||||
# uthread sources
|
||||
.PATH: ${.CURDIR}/uthread
|
||||
|
|
@ -73,8 +73,8 @@ SRCS+= \
|
|||
uthread_once.c \
|
||||
uthread_open.c \
|
||||
uthread_pipe.c \
|
||||
uthread_poll.c \
|
||||
uthread_priority_queue.c \
|
||||
uthread_queue.c \
|
||||
uthread_read.c \
|
||||
uthread_readv.c \
|
||||
uthread_recvfrom.c \
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -45,12 +47,21 @@ close(int fd)
|
|||
int ret;
|
||||
int status;
|
||||
struct stat sb;
|
||||
struct fd_table_entry *entry;
|
||||
|
||||
/* Lock the file descriptor while the file is closed: */
|
||||
if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
|
||||
/* Get file descriptor status. */
|
||||
_thread_sys_fstat(fd, &sb);
|
||||
|
||||
if ((fd == _thread_kern_pipe[0]) || (fd == _thread_kern_pipe[1])) {
|
||||
/*
|
||||
* Don't allow silly programs to close the kernel pipe.
|
||||
*/
|
||||
errno = EBADF;
|
||||
ret = -1;
|
||||
}
|
||||
/*
|
||||
* Lock the file descriptor while the file is closed and get
|
||||
* the file descriptor status:
|
||||
*/
|
||||
else if (((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) &&
|
||||
((ret = _thread_sys_fstat(fd, &sb)) == 0)) {
|
||||
/*
|
||||
* Check if the file should be left as blocking.
|
||||
*
|
||||
|
|
@ -78,11 +89,14 @@ close(int fd)
|
|||
_thread_sys_fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
}
|
||||
|
||||
/* XXX: Assumes well behaved threads. */
|
||||
/* XXX: Defer real close to avoid race condition */
|
||||
entry = _thread_fd_table[fd];
|
||||
_thread_fd_table[fd] = NULL;
|
||||
free(entry);
|
||||
|
||||
/* Close the file descriptor: */
|
||||
ret = _thread_sys_close(fd);
|
||||
|
||||
free(_thread_fd_table[fd]);
|
||||
_thread_fd_table[fd] = NULL;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -44,6 +45,28 @@ static inline pthread_t cond_queue_deq(pthread_cond_t);
|
|||
static inline void cond_queue_remove(pthread_cond_t, pthread_t);
|
||||
static inline void cond_queue_enq(pthread_cond_t, pthread_t);
|
||||
|
||||
/* Reinitialize a condition variable to defaults. */
|
||||
int
|
||||
_cond_reinit(pthread_cond_t * cond)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (cond == NULL)
|
||||
ret = EINVAL;
|
||||
else if (*cond == NULL)
|
||||
ret = pthread_cond_init(cond, NULL);
|
||||
else {
|
||||
/*
|
||||
* Initialize the condition variable structure:
|
||||
*/
|
||||
TAILQ_INIT(&(*cond)->c_queue);
|
||||
(*cond)->c_flags = COND_FLAGS_INITED;
|
||||
(*cond)->c_type = COND_TYPE_FAST;
|
||||
(*cond)->c_mutex = NULL;
|
||||
memset(&(*cond)->lock, 0, sizeof((*cond)->lock));
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
|
||||
|
|
@ -146,6 +169,9 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
|
|||
*/
|
||||
else if (*cond != NULL ||
|
||||
(rval = pthread_cond_init(cond,NULL)) == 0) {
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
||||
/*
|
||||
* If the condvar was statically allocated, properly
|
||||
* initialize the tail queue.
|
||||
|
|
@ -155,9 +181,6 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
|
|||
(*cond)->c_flags |= COND_FLAGS_INITED;
|
||||
}
|
||||
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
||||
/* Process according to condition variable type: */
|
||||
switch ((*cond)->c_type) {
|
||||
/* Fast condition variable: */
|
||||
|
|
@ -247,6 +270,9 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
|
|||
*/
|
||||
else if (*cond != NULL ||
|
||||
(rval = pthread_cond_init(cond,NULL)) == 0) {
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
||||
/*
|
||||
* If the condvar was statically allocated, properly
|
||||
* initialize the tail queue.
|
||||
|
|
@ -256,10 +282,6 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
|
|||
(*cond)->c_flags |= COND_FLAGS_INITED;
|
||||
}
|
||||
|
||||
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
||||
/* Process according to condition variable type: */
|
||||
switch ((*cond)->c_type) {
|
||||
/* Fast condition variable: */
|
||||
|
|
@ -375,6 +397,12 @@ pthread_cond_signal(pthread_cond_t * cond)
|
|||
if (cond == NULL || *cond == NULL)
|
||||
rval = EINVAL;
|
||||
else {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
||||
|
|
@ -409,6 +437,12 @@ pthread_cond_signal(pthread_cond_t * cond)
|
|||
|
||||
/* Unlock the condition variable structure: */
|
||||
_SPINUNLOCK(&(*cond)->lock);
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
@ -425,14 +459,10 @@ pthread_cond_broadcast(pthread_cond_t * cond)
|
|||
rval = EINVAL;
|
||||
else {
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues. In addition, we must assure
|
||||
* that all threads currently waiting on the condition
|
||||
* variable are signaled and are not timedout by a
|
||||
* scheduling signal that causes a preemption.
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the condition variable structure: */
|
||||
_SPINLOCK(&(*cond)->lock);
|
||||
|
|
@ -468,9 +498,11 @@ pthread_cond_broadcast(pthread_cond_t * cond)
|
|||
/* Unlock the condition variable structure: */
|
||||
_SPINUNLOCK(&(*cond)->lock);
|
||||
|
||||
/* Reenable preemption and yield if necessary.
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
@ -488,7 +520,7 @@ cond_queue_deq(pthread_cond_t cond)
|
|||
|
||||
if ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
|
||||
TAILQ_REMOVE(&cond->c_queue, pthread, qe);
|
||||
pthread->flags &= ~PTHREAD_FLAGS_QUEUED;
|
||||
pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
|
||||
}
|
||||
|
||||
return(pthread);
|
||||
|
|
@ -507,9 +539,9 @@ cond_queue_remove(pthread_cond_t cond, pthread_t pthread)
|
|||
* guard against removing the thread from the queue if
|
||||
* it isn't in the queue.
|
||||
*/
|
||||
if (pthread->flags & PTHREAD_FLAGS_QUEUED) {
|
||||
if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) {
|
||||
TAILQ_REMOVE(&cond->c_queue, pthread, qe);
|
||||
pthread->flags &= ~PTHREAD_FLAGS_QUEUED;
|
||||
pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -535,6 +567,6 @@ cond_queue_enq(pthread_cond_t cond, pthread_t pthread)
|
|||
tid = TAILQ_NEXT(tid, qe);
|
||||
TAILQ_INSERT_BEFORE(tid, pthread, qe);
|
||||
}
|
||||
pthread->flags |= PTHREAD_FLAGS_QUEUED;
|
||||
pthread->flags |= PTHREAD_FLAGS_IN_CONDQ;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -171,7 +172,7 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
|
|||
new_thread->inherited_priority = 0;
|
||||
|
||||
/* Initialise the join queue for the new thread: */
|
||||
_thread_queue_init(&(new_thread->join_queue));
|
||||
TAILQ_INIT(&(new_thread->join_queue));
|
||||
|
||||
/* Initialize the mutex queue: */
|
||||
TAILQ_INIT(&new_thread->mutexq);
|
||||
|
|
@ -179,46 +180,39 @@ pthread_create(pthread_t * thread, const pthread_attr_t * attr,
|
|||
/* Initialise hooks in the thread structure: */
|
||||
new_thread->specific_data = NULL;
|
||||
new_thread->cleanup = NULL;
|
||||
new_thread->queue = NULL;
|
||||
new_thread->qnxt = NULL;
|
||||
new_thread->flags = 0;
|
||||
new_thread->poll_data.nfds = 0;
|
||||
new_thread->poll_data.fds = NULL;
|
||||
|
||||
/* Lock the thread list: */
|
||||
_lock_thread_list();
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/*
|
||||
* Check if the garbage collector thread
|
||||
* needs to be started.
|
||||
*/
|
||||
f_gc = (_thread_link_list == _thread_initial);
|
||||
f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial);
|
||||
|
||||
/* Add the thread to the linked list of all threads: */
|
||||
new_thread->nxt = _thread_link_list;
|
||||
_thread_link_list = new_thread;
|
||||
|
||||
/* Unlock the thread list: */
|
||||
_unlock_thread_list();
|
||||
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues.
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle);
|
||||
|
||||
if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {
|
||||
new_thread->state = PS_SUSPENDED;
|
||||
PTHREAD_WAITQ_INSERT(new_thread);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
new_thread->state = PS_RUNNING;
|
||||
PTHREAD_PRIOQ_INSERT_TAIL(new_thread);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling
|
||||
* signal occurred while in the critical region.
|
||||
* Undefer and handle pending signals, yielding
|
||||
* if necessary.
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/* Return a pointer to the thread structure: */
|
||||
(*thread) = new_thread;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -53,23 +54,25 @@ pthread_detach(pthread_t pthread)
|
|||
pthread->attr.flags |= PTHREAD_DETACHED;
|
||||
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues.
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Enter a loop to bring all threads off the join queue: */
|
||||
while ((next_thread = _thread_queue_deq(&pthread->join_queue)) != NULL) {
|
||||
while ((next_thread = TAILQ_FIRST(&pthread->join_queue)) != NULL) {
|
||||
/* Remove the thread from the queue: */
|
||||
TAILQ_REMOVE(&pthread->join_queue, next_thread, qe);
|
||||
|
||||
/* Make the thread run: */
|
||||
PTHREAD_NEW_STATE(next_thread,PS_RUNNING);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling signal
|
||||
* occurred while in the critical region.
|
||||
* Undefer and handle pending signals, yielding if a
|
||||
* scheduling signal occurred while in the critical region.
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
} else
|
||||
/* Return an error: */
|
||||
rval = EINVAL;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -92,7 +93,12 @@ _thread_exit(char *fname, int lineno, char *string)
|
|||
_thread_sys_write(2, s, strlen(s));
|
||||
|
||||
/* Force this process to exit: */
|
||||
/* XXX - Do we want abort to be conditional on _PTHREADS_INVARIANTS? */
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
abort();
|
||||
#else
|
||||
_exit(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -129,22 +135,24 @@ pthread_exit(void *status)
|
|||
}
|
||||
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal. A change of
|
||||
* thread state modifies the waiting and priority queues.
|
||||
* Defer signals to protect the scheduling queues from access
|
||||
* by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Check if there are any threads joined to this one: */
|
||||
while ((pthread = _thread_queue_deq(&(_thread_run->join_queue))) != NULL) {
|
||||
while ((pthread = TAILQ_FIRST(&(_thread_run->join_queue))) != NULL) {
|
||||
/* Remove the thread from the queue: */
|
||||
TAILQ_REMOVE(&_thread_run->join_queue, pthread, qe);
|
||||
|
||||
/* Wake the joined thread and let it detach this thread: */
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling signal
|
||||
* occurred while in the critical region.
|
||||
* Undefer and handle pending signals, yielding if necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/*
|
||||
* Lock the garbage collector mutex to ensure that the garbage
|
||||
|
|
@ -154,8 +162,21 @@ pthread_exit(void *status)
|
|||
PANIC("Cannot lock gc mutex");
|
||||
|
||||
/* Add this thread to the list of dead threads. */
|
||||
_thread_run->nxt_dead = _thread_dead;
|
||||
_thread_dead = _thread_run;
|
||||
TAILQ_INSERT_HEAD(&_dead_list, _thread_run, dle);
|
||||
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from access
|
||||
* by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Remove this thread from the thread list: */
|
||||
TAILQ_REMOVE(&_thread_list, _thread_run, tle);
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/*
|
||||
* Signal the garbage collector thread that there is something
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -46,20 +47,20 @@ _find_thread(pthread_t pthread)
|
|||
/* Invalid thread: */
|
||||
return(EINVAL);
|
||||
|
||||
/* Lock the thread list: */
|
||||
_lock_thread_list();
|
||||
/*
|
||||
* Defer signals to protect the thread list from access
|
||||
* by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Point to the first thread in the list: */
|
||||
pthread1 = _thread_link_list;
|
||||
|
||||
/* Search for the thread to join to: */
|
||||
while (pthread1 != NULL && pthread1 != pthread) {
|
||||
/* Point to the next thread: */
|
||||
pthread1 = pthread1->nxt;
|
||||
/* Search for the specified thread: */
|
||||
TAILQ_FOREACH(pthread1, &_thread_list, tle) {
|
||||
if (pthread == pthread1)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Unlock the thread list: */
|
||||
_unlock_thread_list();
|
||||
/* Undefer and handle pending signals, yielding if necessary: */
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/* Return zero if the thread exists: */
|
||||
return ((pthread1 != NULL) ? 0:ESRCH);
|
||||
|
|
@ -83,13 +84,10 @@ _find_dead_thread(pthread_t pthread)
|
|||
if (pthread_mutex_lock(&_gc_mutex) != 0)
|
||||
PANIC("Cannot lock gc mutex");
|
||||
|
||||
/* Point to the first thread in the list: */
|
||||
pthread1 = _thread_dead;
|
||||
|
||||
/* Search for the thread to join to: */
|
||||
while (pthread1 != NULL && pthread1 != pthread) {
|
||||
/* Point to the next thread: */
|
||||
pthread1 = pthread1->nxt_dead;
|
||||
/* Search for the specified thread: */
|
||||
TAILQ_FOREACH(pthread1, &_dead_list, dle) {
|
||||
if (pthread1 == pthread)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Unlock the garbage collector mutex: */
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
|
@ -44,10 +45,13 @@ fork(void)
|
|||
int i, flags;
|
||||
pid_t ret;
|
||||
pthread_t pthread;
|
||||
pthread_t pthread_next;
|
||||
pthread_t pthread_save;
|
||||
|
||||
/* Lock the thread list: */
|
||||
_lock_thread_list();
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from access
|
||||
* by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Fork a new process: */
|
||||
if ((ret = _thread_sys_fork()) != 0) {
|
||||
|
|
@ -88,45 +92,79 @@ fork(void)
|
|||
else if (_thread_sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||
/* Abort this application: */
|
||||
abort();
|
||||
/* Initialize the ready queue: */
|
||||
} else if (_pq_init(&_readyq, PTHREAD_MIN_PRIORITY,
|
||||
PTHREAD_MAX_PRIORITY) != 0) {
|
||||
}
|
||||
/* Reinitialize the GC mutex: */
|
||||
else if (_mutex_reinit(&_gc_mutex) != 0) {
|
||||
/* Abort this application: */
|
||||
PANIC("Cannot allocate priority ready queue.");
|
||||
PANIC("Cannot initialize GC mutex for forked process");
|
||||
}
|
||||
/* Reinitialize the GC condition variable: */
|
||||
else if (_cond_reinit(&_gc_cond) != 0) {
|
||||
/* Abort this application: */
|
||||
PANIC("Cannot initialize GC condvar for forked process");
|
||||
}
|
||||
/* Initialize the ready queue: */
|
||||
else if (_pq_init(&_readyq) != 0) {
|
||||
/* Abort this application: */
|
||||
PANIC("Cannot initialize priority ready queue.");
|
||||
} else {
|
||||
/* Point to the first thread in the list: */
|
||||
pthread = _thread_link_list;
|
||||
|
||||
/*
|
||||
* Enter a loop to remove all threads other than
|
||||
* the running thread from the thread list:
|
||||
*/
|
||||
pthread = TAILQ_FIRST(&_thread_list);
|
||||
while (pthread != NULL) {
|
||||
pthread_next = pthread->nxt;
|
||||
if (pthread == _thread_run) {
|
||||
_thread_link_list = pthread;
|
||||
pthread->nxt = NULL;
|
||||
} else {
|
||||
if (pthread->attr.stackaddr_attr ==
|
||||
NULL && pthread->stack != NULL)
|
||||
/* Save the thread to be freed: */
|
||||
pthread_save = pthread;
|
||||
|
||||
/*
|
||||
* Advance to the next thread before
|
||||
* destroying the current thread:
|
||||
*/
|
||||
pthread = TAILQ_NEXT(pthread, dle);
|
||||
|
||||
/* Make sure this isn't the running thread: */
|
||||
if (pthread_save != _thread_run) {
|
||||
/* Remove this thread from the list: */
|
||||
TAILQ_REMOVE(&_thread_list,
|
||||
pthread_save, tle);
|
||||
|
||||
if (pthread_save->attr.stackaddr_attr ==
|
||||
NULL && pthread_save->stack != NULL)
|
||||
/*
|
||||
* Free the stack of the
|
||||
* dead thread:
|
||||
*/
|
||||
free(pthread->stack);
|
||||
free(pthread_save->stack);
|
||||
|
||||
if (pthread->specific_data != NULL)
|
||||
free(pthread->specific_data);
|
||||
if (pthread_save->specific_data != NULL)
|
||||
free(pthread_save->specific_data);
|
||||
|
||||
free(pthread);
|
||||
if (pthread_save->poll_data.fds != NULL)
|
||||
free(pthread_save->poll_data.fds);
|
||||
|
||||
free(pthread_save);
|
||||
}
|
||||
|
||||
/* Point to the next thread: */
|
||||
pthread = pthread_next;
|
||||
}
|
||||
|
||||
/* Re-init the waiting queues. */
|
||||
/* Re-init the dead thread list: */
|
||||
TAILQ_INIT(&_dead_list);
|
||||
|
||||
/* Re-init the waiting and work queues. */
|
||||
TAILQ_INIT(&_waitingq);
|
||||
TAILQ_INIT(&_workq);
|
||||
|
||||
/* Re-init the threads mutex queue: */
|
||||
TAILQ_INIT(&_thread_run->mutexq);
|
||||
|
||||
/* No spinlocks yet: */
|
||||
_spinblock_count = 0;
|
||||
|
||||
/* Don't queue signals yet: */
|
||||
_queue_signals = 0;
|
||||
|
||||
/* Initialize signal handling: */
|
||||
_thread_sig_init();
|
||||
|
||||
/* Initialize the scheduling switch hook routine: */
|
||||
_sched_switch_hook = NULL;
|
||||
|
|
@ -147,15 +185,17 @@ fork(void)
|
|||
_thread_fd_table[i]->w_lockcount = 0;;
|
||||
|
||||
/* Initialise the read/write queues: */
|
||||
_thread_queue_init(&_thread_fd_table[i]->r_queue);
|
||||
_thread_queue_init(&_thread_fd_table[i]->w_queue);
|
||||
TAILQ_INIT(&_thread_fd_table[i]->r_queue);
|
||||
TAILQ_INIT(&_thread_fd_table[i]->w_queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Unock the thread list: */
|
||||
_unlock_thread_list();
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/* Return the process ID: */
|
||||
return (ret);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: uthread_gc.c,v 1.2 1998/09/30 19:17:51 dt Exp $
|
||||
* $Id: uthread_gc.c,v 1.3 1999/03/23 05:07:55 jb Exp $
|
||||
*
|
||||
* Garbage collector thread. Frees memory allocated for dead threads.
|
||||
*
|
||||
|
|
@ -74,20 +74,26 @@ _thread_gc(pthread_addr_t arg)
|
|||
/* Dump thread info to file. */
|
||||
_thread_dump_info();
|
||||
|
||||
/* Lock the thread list: */
|
||||
_lock_thread_list();
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Check if this is the last running thread: */
|
||||
if (_thread_link_list == _thread_run &&
|
||||
_thread_link_list->nxt == NULL)
|
||||
if (TAILQ_FIRST(&_thread_list) == _thread_run &&
|
||||
TAILQ_NEXT(_thread_run, tle) == NULL)
|
||||
/*
|
||||
* This is the last thread, so it can exit
|
||||
* now.
|
||||
*/
|
||||
f_done = 1;
|
||||
|
||||
/* Unlock the thread list: */
|
||||
_unlock_thread_list();
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
|
||||
/*
|
||||
* Lock the garbage collector mutex which ensures that
|
||||
|
|
@ -100,48 +106,24 @@ _thread_gc(pthread_addr_t arg)
|
|||
p_stack = NULL;
|
||||
pthread_cln = NULL;
|
||||
|
||||
/* Point to the first dead thread (if there are any): */
|
||||
pthread = _thread_dead;
|
||||
|
||||
/* There is no previous dead thread: */
|
||||
pthread_prv = NULL;
|
||||
|
||||
/*
|
||||
* Enter a loop to search for the first dead thread that
|
||||
* has memory to free.
|
||||
*/
|
||||
while (p_stack == NULL && pthread_cln == NULL &&
|
||||
pthread != NULL) {
|
||||
/* Save a pointer to the next thread: */
|
||||
pthread_nxt = pthread->nxt_dead;
|
||||
|
||||
for (pthread = TAILQ_FIRST(&_dead_list);
|
||||
p_stack == NULL && pthread_cln == NULL && pthread != NULL;
|
||||
pthread = TAILQ_NEXT(pthread, dle)) {
|
||||
/* Check if the initial thread: */
|
||||
if (pthread == _thread_initial)
|
||||
if (pthread == _thread_initial) {
|
||||
/* Don't destroy the initial thread. */
|
||||
pthread_prv = pthread;
|
||||
|
||||
}
|
||||
/*
|
||||
* Check if this thread has detached:
|
||||
*/
|
||||
else if ((pthread->attr.flags &
|
||||
PTHREAD_DETACHED) != 0) {
|
||||
/*
|
||||
* Check if there is no previous dead
|
||||
* thread:
|
||||
*/
|
||||
if (pthread_prv == NULL)
|
||||
/*
|
||||
* The dead thread is at the head
|
||||
* of the list:
|
||||
*/
|
||||
_thread_dead = pthread_nxt;
|
||||
else
|
||||
/*
|
||||
* The dead thread is not at the
|
||||
* head of the list:
|
||||
*/
|
||||
pthread_prv->nxt_dead =
|
||||
pthread->nxt_dead;
|
||||
/* Remove this thread from the dead list: */
|
||||
TAILQ_REMOVE(&_dead_list, pthread, dle);
|
||||
|
||||
/*
|
||||
* Check if the stack was not specified by
|
||||
|
|
@ -162,14 +144,12 @@ _thread_gc(pthread_addr_t arg)
|
|||
* be freed outside the locks:
|
||||
*/
|
||||
pthread_cln = pthread;
|
||||
|
||||
} else {
|
||||
/*
|
||||
* This thread has not detached, so do
|
||||
* not destroy it:
|
||||
*/
|
||||
pthread_prv = pthread;
|
||||
|
||||
/*
|
||||
* not destroy it.
|
||||
*
|
||||
* Check if the stack was not specified by
|
||||
* the caller to pthread_create and has not
|
||||
* been destroyed yet:
|
||||
|
|
@ -189,9 +169,6 @@ _thread_gc(pthread_addr_t arg)
|
|||
pthread->stack = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Point to the next thread: */
|
||||
pthread = pthread_nxt;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -229,52 +206,12 @@ _thread_gc(pthread_addr_t arg)
|
|||
*/
|
||||
if (p_stack != NULL)
|
||||
free(p_stack);
|
||||
if (pthread_cln != NULL) {
|
||||
/* Lock the thread list: */
|
||||
_lock_thread_list();
|
||||
|
||||
/*
|
||||
* Check if the thread is at the head of the
|
||||
* linked list.
|
||||
*/
|
||||
if (_thread_link_list == pthread_cln)
|
||||
/* There is no previous thread: */
|
||||
_thread_link_list = pthread_cln->nxt;
|
||||
else {
|
||||
/* Point to the first thread in the list: */
|
||||
pthread = _thread_link_list;
|
||||
|
||||
/*
|
||||
* Enter a loop to find the thread in the
|
||||
* linked list before the thread that is
|
||||
* about to be freed.
|
||||
*/
|
||||
while (pthread != NULL &&
|
||||
pthread->nxt != pthread_cln)
|
||||
/* Point to the next thread: */
|
||||
pthread = pthread->nxt;
|
||||
|
||||
/* Check that a previous thread was found: */
|
||||
if (pthread != NULL) {
|
||||
/*
|
||||
* Point the previous thread to
|
||||
* the one after the thread being
|
||||
* freed:
|
||||
*/
|
||||
pthread->nxt = pthread_cln->nxt;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unlock the thread list: */
|
||||
_unlock_thread_list();
|
||||
|
||||
if (pthread_cln != NULL)
|
||||
/*
|
||||
* Free the memory allocated for the thread
|
||||
* structure.
|
||||
*/
|
||||
free(pthread_cln);
|
||||
}
|
||||
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -55,6 +56,7 @@ static const struct s_thread_info thread_info[] = {
|
|||
{PS_FDR_WAIT , "Waiting for read"},
|
||||
{PS_FDW_WAIT , "Waiting for write"},
|
||||
{PS_FILE_WAIT , "Waiting for FILE lock"},
|
||||
{PS_POLL_WAIT , "Waiting on poll"},
|
||||
{PS_SELECT_WAIT , "Waiting on select"},
|
||||
{PS_SLEEP_WAIT , "Sleeping"},
|
||||
{PS_WAIT_WAIT , "Waiting process"},
|
||||
|
|
@ -108,8 +110,7 @@ _thread_dump_info(void)
|
|||
_thread_sys_write(fd, s, strlen(s));
|
||||
|
||||
/* Enter a loop to report each thread in the global list: */
|
||||
for (pthread = _thread_link_list; pthread != NULL;
|
||||
pthread = pthread->nxt) {
|
||||
TAILQ_FOREACH(pthread, &_thread_list, tle) {
|
||||
/* Find the state: */
|
||||
for (j = 0; j < (sizeof(thread_info) /
|
||||
sizeof(struct s_thread_info)) - 1; j++)
|
||||
|
|
@ -214,8 +215,29 @@ _thread_dump_info(void)
|
|||
_thread_sys_write(fd, s, strlen(s));
|
||||
}
|
||||
|
||||
/* Output a header for threads in the work queue: */
|
||||
strcpy(s, "\n\n=============\nTHREADS IN WORKQ\n\n");
|
||||
_thread_sys_write(fd, s, strlen(s));
|
||||
|
||||
/* Enter a loop to report each thread in the waiting queue: */
|
||||
TAILQ_FOREACH (pthread, &_workq, qe) {
|
||||
/* Find the state: */
|
||||
for (j = 0; j < (sizeof(thread_info) /
|
||||
sizeof(struct s_thread_info)) - 1; j++)
|
||||
if (thread_info[j].state == pthread->state)
|
||||
break;
|
||||
/* Output a record for the current thread: */
|
||||
snprintf(s, sizeof(s),
|
||||
"--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n",
|
||||
pthread, (pthread->name == NULL) ?
|
||||
"":pthread->name, pthread->base_priority,
|
||||
thread_info[j].name,
|
||||
pthread->fname,pthread->lineno);
|
||||
_thread_sys_write(fd, s, strlen(s));
|
||||
}
|
||||
|
||||
/* Check if there are no dead threads: */
|
||||
if (_thread_dead == NULL) {
|
||||
if (TAILQ_FIRST(&_dead_list) == NULL) {
|
||||
/* Output a record: */
|
||||
strcpy(s, "\n\nTHERE ARE NO DEAD THREADS\n");
|
||||
_thread_sys_write(fd, s, strlen(s));
|
||||
|
|
@ -228,8 +250,7 @@ _thread_dump_info(void)
|
|||
* Enter a loop to report each thread in the global
|
||||
* dead thread list:
|
||||
*/
|
||||
for (pthread = _thread_dead; pthread != NULL;
|
||||
pthread = pthread->nxt_dead) {
|
||||
TAILQ_FOREACH(pthread, &_dead_list, dle) {
|
||||
/* Output a record for the current thread: */
|
||||
snprintf(s, sizeof(s),
|
||||
"Thread %p prio %3d [%s:%d]\n",
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/* Allocate space for global thread variables here: */
|
||||
|
|
@ -39,7 +40,9 @@
|
|||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ttycom.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -81,6 +84,9 @@ _thread_init(void)
|
|||
int fd;
|
||||
int flags;
|
||||
int i;
|
||||
int len;
|
||||
int mib[2];
|
||||
struct clockinfo clockinfo;
|
||||
struct sigaction act;
|
||||
|
||||
/* Check if this function has already been called: */
|
||||
|
|
@ -147,8 +153,8 @@ _thread_init(void)
|
|||
/* Abort this application: */
|
||||
PANIC("Cannot get kernel write pipe flags");
|
||||
}
|
||||
/* Initialize the ready queue: */
|
||||
else if (_pq_init(&_readyq, PTHREAD_MIN_PRIORITY, PTHREAD_MAX_PRIORITY) != 0) {
|
||||
/* Allocate and initialize the ready queue: */
|
||||
else if (_pq_alloc(&_readyq, PTHREAD_MIN_PRIORITY, PTHREAD_MAX_PRIORITY) != 0) {
|
||||
/* Abort this application: */
|
||||
PANIC("Cannot allocate priority ready queue.");
|
||||
}
|
||||
|
|
@ -165,8 +171,9 @@ _thread_init(void)
|
|||
_thread_kern_thread.flags = PTHREAD_FLAGS_PRIVATE;
|
||||
memset(_thread_initial, 0, sizeof(struct pthread));
|
||||
|
||||
/* Initialize the waiting queue: */
|
||||
/* Initialize the waiting and work queues: */
|
||||
TAILQ_INIT(&_waitingq);
|
||||
TAILQ_INIT(&_workq);
|
||||
|
||||
/* Initialize the scheduling switch hook routine: */
|
||||
_sched_switch_hook = NULL;
|
||||
|
|
@ -186,23 +193,23 @@ _thread_init(void)
|
|||
_thread_initial->state = PS_RUNNING;
|
||||
|
||||
/* Initialise the queue: */
|
||||
_thread_queue_init(&(_thread_initial->join_queue));
|
||||
TAILQ_INIT(&(_thread_initial->join_queue));
|
||||
|
||||
/* Initialize the owned mutex queue and count: */
|
||||
TAILQ_INIT(&(_thread_initial->mutexq));
|
||||
_thread_initial->priority_mutex_count = 0;
|
||||
|
||||
/* Initialise the rest of the fields: */
|
||||
_thread_initial->sched_defer_count = 0;
|
||||
_thread_initial->yield_on_sched_undefer = 0;
|
||||
_thread_initial->poll_data.nfds = 0;
|
||||
_thread_initial->poll_data.fds = NULL;
|
||||
_thread_initial->sig_defer_count = 0;
|
||||
_thread_initial->yield_on_sig_undefer = 0;
|
||||
_thread_initial->specific_data = NULL;
|
||||
_thread_initial->cleanup = NULL;
|
||||
_thread_initial->queue = NULL;
|
||||
_thread_initial->qnxt = NULL;
|
||||
_thread_initial->nxt = NULL;
|
||||
_thread_initial->flags = 0;
|
||||
_thread_initial->error = 0;
|
||||
_thread_link_list = _thread_initial;
|
||||
TAILQ_INIT(&_thread_list);
|
||||
TAILQ_INSERT_HEAD(&_thread_list, _thread_initial, tle);
|
||||
_thread_run = _thread_initial;
|
||||
|
||||
/* Initialise the global signal action structure: */
|
||||
|
|
@ -210,6 +217,9 @@ _thread_init(void)
|
|||
act.sa_handler = (void (*) ()) _thread_sig_handler;
|
||||
act.sa_flags = 0;
|
||||
|
||||
/* Initialize signal handling: */
|
||||
_thread_sig_init();
|
||||
|
||||
/* Enter a loop to get the existing signal status: */
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
/* Check for signals which cannot be trapped: */
|
||||
|
|
@ -241,6 +251,13 @@ _thread_init(void)
|
|||
PANIC("Cannot initialise signal handler");
|
||||
}
|
||||
|
||||
/* Get the kernel clockrate: */
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_CLOCKRATE;
|
||||
len = sizeof (struct clockinfo);
|
||||
if (sysctl(mib, 2, &clockinfo, &len, NULL, 0) == 0)
|
||||
_clock_res_nsec = clockinfo.tick * 1000;
|
||||
|
||||
/* Get the table size: */
|
||||
if ((_thread_dtablesize = getdtablesize()) < 0) {
|
||||
/*
|
||||
|
|
@ -256,6 +273,14 @@ _thread_init(void)
|
|||
* table, so abort this process.
|
||||
*/
|
||||
PANIC("Cannot allocate memory for file descriptor table");
|
||||
}
|
||||
/* Allocate memory for the pollfd table: */
|
||||
if ((_thread_pfd_table = (struct pollfd *) malloc(sizeof(struct pollfd) * _thread_dtablesize)) == NULL) {
|
||||
/*
|
||||
* Cannot allocate memory for the file descriptor
|
||||
* table, so abort this process.
|
||||
*/
|
||||
PANIC("Cannot allocate memory for pollfd table");
|
||||
} else {
|
||||
/*
|
||||
* Enter a loop to initialise the file descriptor
|
||||
|
|
@ -265,6 +290,14 @@ _thread_init(void)
|
|||
/* Initialise the file descriptor table: */
|
||||
_thread_fd_table[i] = NULL;
|
||||
}
|
||||
|
||||
/* Initialize stdio file descriptor table entries: */
|
||||
if ((_thread_fd_table_init(0) != 0) ||
|
||||
(_thread_fd_table_init(1) != 0) ||
|
||||
(_thread_fd_table_init(2) != 0)) {
|
||||
PANIC("Cannot initialize stdio file descriptor "
|
||||
"table entries");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -71,7 +72,7 @@ pthread_join(pthread_t pthread, void **thread_return)
|
|||
/* Check if the thread is not dead: */
|
||||
else if (pthread->state != PS_DEAD) {
|
||||
/* Add the running thread to the join queue: */
|
||||
_thread_queue_enq(&(pthread->join_queue), _thread_run);
|
||||
TAILQ_INSERT_TAIL(&(pthread->join_queue), _thread_run, qe);
|
||||
|
||||
/* Schedule the next thread: */
|
||||
_thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
|
@ -46,18 +47,18 @@ pthread_kill(pthread_t pthread, int sig)
|
|||
/* Invalid signal: */
|
||||
ret = EINVAL;
|
||||
|
||||
/* Ignored signals get dropped on the floor. */
|
||||
else if (_thread_sigact[sig - 1].sa_handler == SIG_IGN)
|
||||
ret = 0;
|
||||
|
||||
/* Find the thread in the list of active threads: */
|
||||
else if ((ret = _find_thread(pthread)) == 0) {
|
||||
/*
|
||||
* Ensure the thread is in the list of active threads, and the
|
||||
* signal is valid (signal 0 specifies error checking only) and
|
||||
* not being ignored:
|
||||
*/
|
||||
else if (((ret = _find_thread(pthread)) == 0) && (sig > 0) &&
|
||||
(_thread_sigact[sig - 1].sa_handler != SIG_IGN)) {
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues.
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
switch (pthread->state) {
|
||||
case PS_SIGSUSPEND:
|
||||
|
|
@ -90,15 +91,19 @@ pthread_kill(pthread_t pthread, int sig)
|
|||
sigaddset(&pthread->sigpend,sig);
|
||||
break;
|
||||
|
||||
case PS_SELECT_WAIT:
|
||||
case PS_FDR_WAIT:
|
||||
case PS_FDW_WAIT:
|
||||
case PS_POLL_WAIT:
|
||||
case PS_SLEEP_WAIT:
|
||||
case PS_SELECT_WAIT:
|
||||
if (!sigismember(&pthread->sigmask, sig) &&
|
||||
(_thread_sigact[sig - 1].sa_handler != SIG_IGN)) {
|
||||
/* Flag the operation as interrupted: */
|
||||
pthread->interrupted = 1;
|
||||
|
||||
if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
|
||||
PTHREAD_WORKQ_REMOVE(pthread);
|
||||
|
||||
/* Change the state of the thread to run: */
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
|
||||
|
|
@ -116,11 +121,43 @@ pthread_kill(pthread_t pthread, int sig)
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling signal
|
||||
* occurred while in the critical region.
|
||||
* Check that a custom handler is installed
|
||||
* and if the signal is not blocked:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
if (_thread_sigact[sig - 1].sa_handler != SIG_DFL &&
|
||||
_thread_sigact[sig - 1].sa_handler != SIG_IGN &&
|
||||
sigismember(&pthread->sigpend, sig) &&
|
||||
!sigismember(&pthread->sigmask, sig)) {
|
||||
pthread_t pthread_saved = _thread_run;
|
||||
|
||||
/* Current thread inside critical region? */
|
||||
if (_thread_run->sig_defer_count > 0)
|
||||
pthread->sig_defer_count++;
|
||||
|
||||
_thread_run = pthread;
|
||||
|
||||
/* Clear the pending signal: */
|
||||
sigdelset(&pthread->sigpend, sig);
|
||||
|
||||
/*
|
||||
* Dispatch the signal via the custom signal
|
||||
* handler:
|
||||
*/
|
||||
(*(_thread_sigact[sig - 1].sa_handler))(sig);
|
||||
|
||||
_thread_run = pthread_saved;
|
||||
|
||||
if (_thread_run->sig_defer_count > 0)
|
||||
pthread->sig_defer_count--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -39,6 +40,25 @@
|
|||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
#define _MUTEX_INIT_LINK(m) do { \
|
||||
(m)->m_qe.tqe_prev = NULL; \
|
||||
(m)->m_qe.tqe_next = NULL; \
|
||||
} while (0)
|
||||
#define _MUTEX_ASSERT_IS_OWNED(m) do { \
|
||||
if ((m)->m_qe.tqe_prev == NULL) \
|
||||
PANIC("mutex is not on list"); \
|
||||
} while (0)
|
||||
#define _MUTEX_ASSERT_NOT_OWNED(m) do { \
|
||||
if (((m)->m_qe.tqe_prev != NULL) || \
|
||||
((m)->m_qe.tqe_next != NULL)) \
|
||||
PANIC("mutex is on list"); \
|
||||
} while (0)
|
||||
#else
|
||||
#define _MUTEX_INIT_LINK(m)
|
||||
#define _MUTEX_ASSERT_IS_OWNED(m)
|
||||
#define _MUTEX_ASSERT_NOT_OWNED(m)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
|
|
@ -55,6 +75,34 @@ static inline void mutex_queue_enq(pthread_mutex_t, pthread_t);
|
|||
|
||||
static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER;
|
||||
|
||||
/* Reinitialize a mutex to defaults. */
|
||||
int
|
||||
_mutex_reinit(pthread_mutex_t * mutex)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (mutex == NULL)
|
||||
ret = EINVAL;
|
||||
else if (*mutex == NULL)
|
||||
ret = pthread_mutex_init(mutex, NULL);
|
||||
else {
|
||||
/*
|
||||
* Initialize the mutex structure:
|
||||
*/
|
||||
(*mutex)->m_type = PTHREAD_MUTEX_DEFAULT;
|
||||
(*mutex)->m_protocol = PTHREAD_PRIO_NONE;
|
||||
TAILQ_INIT(&(*mutex)->m_queue);
|
||||
(*mutex)->m_owner = NULL;
|
||||
(*mutex)->m_data.m_count = 0;
|
||||
(*mutex)->m_flags = MUTEX_FLAGS_INITED;
|
||||
(*mutex)->m_refcount = 0;
|
||||
(*mutex)->m_prio = 0;
|
||||
(*mutex)->m_saved_prio = 0;
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
memset(&(*mutex)->lock, 0, sizeof((*mutex)->lock));
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
pthread_mutex_init(pthread_mutex_t * mutex,
|
||||
|
|
@ -138,6 +186,7 @@ pthread_mutex_init(pthread_mutex_t * mutex,
|
|||
else
|
||||
pmutex->m_prio = 0;
|
||||
pmutex->m_saved_prio = 0;
|
||||
_MUTEX_INIT_LINK(pmutex);
|
||||
memset(&pmutex->lock, 0, sizeof(pmutex->lock));
|
||||
*mutex = pmutex;
|
||||
} else {
|
||||
|
|
@ -147,7 +196,7 @@ pthread_mutex_init(pthread_mutex_t * mutex,
|
|||
}
|
||||
}
|
||||
/* Return the completion status: */
|
||||
return (ret);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -177,6 +226,7 @@ pthread_mutex_destroy(pthread_mutex_t * mutex)
|
|||
* Free the memory allocated for the mutex
|
||||
* structure:
|
||||
*/
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
free(*mutex);
|
||||
|
||||
/*
|
||||
|
|
@ -221,29 +271,25 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
|
|||
* initialization:
|
||||
*/
|
||||
else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the mutex structure: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* If the mutex was statically allocated, properly
|
||||
* initialize the tail queue.
|
||||
*/
|
||||
if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
|
||||
TAILQ_INIT(&(*mutex)->m_queue);
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
(*mutex)->m_flags |= MUTEX_FLAGS_INITED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guard against being preempted by a scheduling signal.
|
||||
* To support priority inheritence mutexes, we need to
|
||||
* maintain lists of mutex ownerships for each thread as
|
||||
* well as lists of waiting threads for each mutex. In
|
||||
* order to propagate priorities we need to atomically
|
||||
* walk these lists and cannot rely on a single mutex
|
||||
* lock to provide protection against modification.
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
|
||||
/* Lock the mutex structure: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/* Process according to mutex type: */
|
||||
switch ((*mutex)->m_protocol) {
|
||||
/* Default POSIX mutex: */
|
||||
|
|
@ -254,6 +300,7 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
|
|||
(*mutex)->m_owner = _thread_run;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
} else if ((*mutex)->m_owner == _thread_run)
|
||||
|
|
@ -282,6 +329,7 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
|
|||
_thread_run->inherited_priority;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
} else if ((*mutex)->m_owner == _thread_run)
|
||||
|
|
@ -317,6 +365,7 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
|
|||
(*mutex)->m_prio;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
} else if ((*mutex)->m_owner == _thread_run)
|
||||
|
|
@ -337,10 +386,10 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
|
|||
_SPINUNLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* Renable preemption and yield if a scheduling signal
|
||||
* arrived while in the critical region:
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
@ -360,6 +409,15 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
* initialization:
|
||||
*/
|
||||
else if (*mutex != NULL || (ret = init_static(mutex)) == 0) {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the mutex structure: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* If the mutex was statically allocated, properly
|
||||
* initialize the tail queue.
|
||||
|
|
@ -367,22 +425,9 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
|
||||
TAILQ_INIT(&(*mutex)->m_queue);
|
||||
(*mutex)->m_flags |= MUTEX_FLAGS_INITED;
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Guard against being preempted by a scheduling signal.
|
||||
* To support priority inheritence mutexes, we need to
|
||||
* maintain lists of mutex ownerships for each thread as
|
||||
* well as lists of waiting threads for each mutex. In
|
||||
* order to propagate priorities we need to atomically
|
||||
* walk these lists and cannot rely on a single mutex
|
||||
* lock to provide protection against modification.
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
|
||||
/* Lock the mutex structure: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/* Process according to mutex type: */
|
||||
switch ((*mutex)->m_protocol) {
|
||||
/* Default POSIX mutex: */
|
||||
|
|
@ -392,6 +437,7 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
(*mutex)->m_owner = _thread_run;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
|
||||
|
|
@ -419,12 +465,6 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
|
||||
/* Lock the mutex structure again: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* This thread is no longer waiting for
|
||||
* the mutex:
|
||||
*/
|
||||
_thread_run->data.mutex = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -449,6 +489,7 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
(*mutex)->m_prio;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
|
||||
|
|
@ -481,12 +522,6 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
|
||||
/* Lock the mutex structure again: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* This thread is no longer waiting for
|
||||
* the mutex:
|
||||
*/
|
||||
_thread_run->data.mutex = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -519,6 +554,7 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
(*mutex)->m_prio;
|
||||
|
||||
/* Add to the list of owned mutexes: */
|
||||
_MUTEX_ASSERT_NOT_OWNED(*mutex);
|
||||
TAILQ_INSERT_TAIL(&_thread_run->mutexq,
|
||||
(*mutex), m_qe);
|
||||
} else if ((*mutex)->m_owner == _thread_run)
|
||||
|
|
@ -556,12 +592,6 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
*/
|
||||
ret = _thread_run->error;
|
||||
_thread_run->error = 0;
|
||||
|
||||
/*
|
||||
* This thread is no longer waiting for
|
||||
* the mutex:
|
||||
*/
|
||||
_thread_run->data.mutex = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -576,10 +606,10 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
|
|||
_SPINUNLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* Renable preemption and yield if a scheduling signal
|
||||
* arrived while in the critical region:
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
@ -683,15 +713,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
ret = EINVAL;
|
||||
} else {
|
||||
/*
|
||||
* Guard against being preempted by a scheduling signal.
|
||||
* To support priority inheritence mutexes, we need to
|
||||
* maintain lists of mutex ownerships for each thread as
|
||||
* well as lists of waiting threads for each mutex. In
|
||||
* order to propagate priorities we need to atomically
|
||||
* walk these lists and cannot rely on a single mutex
|
||||
* lock to provide protection against modification.
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Lock the mutex structure: */
|
||||
_SPINLOCK(&(*mutex)->lock);
|
||||
|
|
@ -723,8 +748,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
(*mutex)->m_data.m_count = 0;
|
||||
|
||||
/* Remove the mutex from the threads queue. */
|
||||
_MUTEX_ASSERT_IS_OWNED(*mutex);
|
||||
TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
|
||||
(*mutex), m_qe);
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
|
||||
/*
|
||||
* Get the next thread from the queue of
|
||||
|
|
@ -738,6 +765,19 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
*/
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
|
||||
/*
|
||||
* Add the mutex to the threads list of
|
||||
* owned mutexes:
|
||||
*/
|
||||
TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq,
|
||||
(*mutex), m_qe);
|
||||
|
||||
/*
|
||||
* The owner is no longer waiting for
|
||||
* this mutex:
|
||||
*/
|
||||
(*mutex)->m_owner->data.mutex = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -784,8 +824,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
_thread_run->priority_mutex_count--;
|
||||
|
||||
/* Remove the mutex from the threads queue. */
|
||||
_MUTEX_ASSERT_IS_OWNED(*mutex);
|
||||
TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
|
||||
(*mutex), m_qe);
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
|
||||
/*
|
||||
* Get the next thread from the queue of threads
|
||||
|
|
@ -891,8 +933,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
_thread_run->priority_mutex_count--;
|
||||
|
||||
/* Remove the mutex from the threads queue. */
|
||||
_MUTEX_ASSERT_IS_OWNED(*mutex);
|
||||
TAILQ_REMOVE(&(*mutex)->m_owner->mutexq,
|
||||
(*mutex), m_qe);
|
||||
(*mutex), m_qe);
|
||||
_MUTEX_INIT_LINK(*mutex);
|
||||
|
||||
/*
|
||||
* Enter a loop to find a waiting thread whose
|
||||
|
|
@ -913,6 +957,11 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
(*mutex)->m_owner->error = EINVAL;
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
/*
|
||||
* The thread is no longer waiting for
|
||||
* this mutex:
|
||||
*/
|
||||
(*mutex)->m_owner->data.mutex = NULL;
|
||||
}
|
||||
|
||||
/* Check for a new owner: */
|
||||
|
|
@ -978,10 +1027,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
_SPINUNLOCK(&(*mutex)->lock);
|
||||
|
||||
/*
|
||||
* Renable preemption and yield if a scheduling signal
|
||||
* arrived while in the critical region:
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
|
||||
/* Return the completion status: */
|
||||
|
|
@ -990,11 +1039,11 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
|||
|
||||
|
||||
/*
|
||||
* This function is called when a change in base priority occurs
|
||||
* for a thread that is thread holding, or waiting for, a priority
|
||||
* protection or inheritence mutex. A change in a threads base
|
||||
* priority can effect changes to active priorities of other threads
|
||||
* and to the ordering of mutex locking by waiting threads.
|
||||
* This function is called when a change in base priority occurs for
|
||||
* a thread that is holding or waiting for a priority protection or
|
||||
* inheritence mutex. A change in a threads base priority can effect
|
||||
* changes to active priorities of other threads and to the ordering
|
||||
* of mutex locking by waiting threads.
|
||||
*
|
||||
* This must be called while thread scheduling is deferred.
|
||||
*/
|
||||
|
|
@ -1231,8 +1280,7 @@ mutex_rescan_owned (pthread_t pthread, pthread_mutex_t mutex)
|
|||
* If this thread is in the priority queue, it must be
|
||||
* removed and reinserted for its new priority.
|
||||
*/
|
||||
if ((pthread != _thread_run) &&
|
||||
(pthread->state == PS_RUNNING)) {
|
||||
if (pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) {
|
||||
/*
|
||||
* Remove the thread from the priority queue
|
||||
* before changing its priority:
|
||||
|
|
|
|||
95
lib/libpthread/thread/thr_poll.c
Normal file
95
lib/libpthread/thread/thr_poll.c
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 1999 Daniel Eischen <eischen@vigrid.com>
|
||||
* 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. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Daniel Eischen.
|
||||
* 4. 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 DANIEL EISCHEN 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.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <poll.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/fcntl.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
|
||||
|
||||
int
|
||||
poll(struct pollfd *fds, unsigned int nfds, int timeout)
|
||||
{
|
||||
struct timespec ts;
|
||||
int numfds = nfds;
|
||||
int i, ret = 0, found = 0;
|
||||
struct pthread_poll_data data;
|
||||
|
||||
if (numfds > _thread_dtablesize) {
|
||||
numfds = _thread_dtablesize;
|
||||
}
|
||||
/* Check if a timeout was specified: */
|
||||
if (timeout == INFTIM) {
|
||||
/* Wait for ever: */
|
||||
_thread_kern_set_timeout(NULL);
|
||||
} else if (timeout != 0) {
|
||||
/* Convert the timeout in msec to a timespec: */
|
||||
ts.tv_sec = timeout / 1000;
|
||||
ts.tv_nsec = (timeout % 1000) * 1000;
|
||||
|
||||
/* Set the wake up time: */
|
||||
_thread_kern_set_timeout(&ts);
|
||||
}
|
||||
|
||||
if (((ret = _thread_sys_poll(fds, numfds, 0)) == 0) && (timeout != 0)) {
|
||||
data.nfds = numfds;
|
||||
data.fds = fds;
|
||||
|
||||
/*
|
||||
* Clear revents in case of a timeout which leaves fds
|
||||
* unchanged:
|
||||
*/
|
||||
for (i = 0; i < numfds; i++) {
|
||||
fds[i].revents = 0;
|
||||
}
|
||||
|
||||
_thread_run->data.poll_data = &data;
|
||||
_thread_run->interrupted = 0;
|
||||
_thread_kern_sched_state(PS_POLL_WAIT, __FILE__, __LINE__);
|
||||
if (_thread_run->interrupted) {
|
||||
errno = EINTR;
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = data.nfds;
|
||||
}
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <sys/queue.h>
|
||||
|
|
@ -40,9 +41,51 @@
|
|||
/* Prototypes: */
|
||||
static void pq_insert_prio_list(pq_queue_t *pq, int prio);
|
||||
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
|
||||
static int _pq_active = 0;
|
||||
|
||||
#define _PQ_IN_SCHEDQ (PTHREAD_FLAGS_IN_PRIOQ | PTHREAD_FLAGS_IN_WAITQ | PTHREAD_FLAGS_IN_WORKQ)
|
||||
|
||||
#define _PQ_SET_ACTIVE() _pq_active = 1
|
||||
#define _PQ_CLEAR_ACTIVE() _pq_active = 0
|
||||
#define _PQ_ASSERT_ACTIVE(msg) do { \
|
||||
if (_pq_active == 0) \
|
||||
PANIC(msg); \
|
||||
} while (0)
|
||||
#define _PQ_ASSERT_INACTIVE(msg) do { \
|
||||
if (_pq_active != 0) \
|
||||
PANIC(msg); \
|
||||
} while (0)
|
||||
#define _PQ_ASSERT_IN_WAITQ(thrd, msg) do { \
|
||||
if (((thrd)->flags & PTHREAD_FLAGS_IN_WAITQ) == 0) \
|
||||
PANIC(msg); \
|
||||
} while (0)
|
||||
#define _PQ_ASSERT_IN_PRIOQ(thrd, msg) do { \
|
||||
if (((thrd)->flags & PTHREAD_FLAGS_IN_PRIOQ) == 0) \
|
||||
PANIC(msg); \
|
||||
} while (0)
|
||||
#define _PQ_ASSERT_NOT_QUEUED(thrd, msg) do { \
|
||||
if ((thrd)->flags & _PQ_IN_SCHEDQ) \
|
||||
PANIC(msg); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define _PQ_SET_ACTIVE()
|
||||
#define _PQ_CLEAR_ACTIVE()
|
||||
#define _PQ_ASSERT_ACTIVE(msg)
|
||||
#define _PQ_ASSERT_INACTIVE(msg)
|
||||
#define _PQ_ASSERT_IN_WAITQ(thrd, msg)
|
||||
#define _PQ_ASSERT_IN_PRIOQ(thrd, msg)
|
||||
#define _PQ_ASSERT_NOT_QUEUED(thrd, msg)
|
||||
#define _PQ_CHECK_PRIO()
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
_pq_init(pq_queue_t *pq, int minprio, int maxprio)
|
||||
_pq_alloc(pq_queue_t *pq, int minprio, int maxprio)
|
||||
{
|
||||
int i, ret = 0;
|
||||
int prioslots = maxprio - minprio + 1;
|
||||
|
|
@ -55,9 +98,27 @@ _pq_init(pq_queue_t *pq, int minprio, int maxprio)
|
|||
(pq_list_t *) malloc(sizeof(pq_list_t) * prioslots)) == NULL)
|
||||
ret = -1;
|
||||
|
||||
else {
|
||||
/* Remember the queue size: */
|
||||
pq->pq_size = prioslots;
|
||||
|
||||
ret = _pq_init(pq);
|
||||
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
_pq_init(pq_queue_t *pq)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
if ((pq == NULL) || (pq->pq_lists == NULL))
|
||||
ret = -1;
|
||||
|
||||
else {
|
||||
/* Initialize the queue for each priority slot: */
|
||||
for (i = 0; i < prioslots; i++) {
|
||||
for (i = 0; i < pq->pq_size; i++) {
|
||||
TAILQ_INIT(&pq->pq_lists[i].pl_head);
|
||||
pq->pq_lists[i].pl_prio = i;
|
||||
pq->pq_lists[i].pl_queued = 0;
|
||||
|
|
@ -65,9 +126,7 @@ _pq_init(pq_queue_t *pq, int minprio, int maxprio)
|
|||
|
||||
/* Initialize the priority queue: */
|
||||
TAILQ_INIT(&pq->pq_queue);
|
||||
|
||||
/* Remember the queue size: */
|
||||
pq->pq_size = prioslots;
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
|
@ -77,7 +136,27 @@ _pq_remove(pq_queue_t *pq, pthread_t pthread)
|
|||
{
|
||||
int prio = pthread->active_priority;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_pq_remove: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_IN_PRIOQ(pthread, "_pq_remove: Not in priority queue");
|
||||
|
||||
/*
|
||||
* Remove this thread from priority list. Note that if
|
||||
* the priority list becomes empty, it is not removed
|
||||
* from the priority queue because another thread may be
|
||||
* added to the priority list (resulting in a needless
|
||||
* removal/insertion). Priority lists are only removed
|
||||
* from the priority queue when _pq_first is called.
|
||||
*/
|
||||
TAILQ_REMOVE(&pq->pq_lists[prio].pl_head, pthread, pqe);
|
||||
|
||||
/* This thread is now longer in the priority queue. */
|
||||
pthread->flags &= ~PTHREAD_FLAGS_IN_PRIOQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -86,10 +165,23 @@ _pq_insert_head(pq_queue_t *pq, pthread_t pthread)
|
|||
{
|
||||
int prio = pthread->active_priority;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_pq_insert_head: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_NOT_QUEUED(pthread,
|
||||
"_pq_insert_head: Already in priority queue");
|
||||
|
||||
TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe);
|
||||
if (pq->pq_lists[prio].pl_queued == 0)
|
||||
/* Insert the list into the priority queue: */
|
||||
pq_insert_prio_list(pq, prio);
|
||||
|
||||
/* Mark this thread as being in the priority queue. */
|
||||
pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -98,10 +190,23 @@ _pq_insert_tail(pq_queue_t *pq, pthread_t pthread)
|
|||
{
|
||||
int prio = pthread->active_priority;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_pq_insert_tail: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_NOT_QUEUED(pthread,
|
||||
"_pq_insert_tail: Already in priority queue");
|
||||
|
||||
TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe);
|
||||
if (pq->pq_lists[prio].pl_queued == 0)
|
||||
/* Insert the list into the priority queue: */
|
||||
pq_insert_prio_list(pq, prio);
|
||||
|
||||
/* Mark this thread as being in the priority queue. */
|
||||
pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -111,6 +216,12 @@ _pq_first(pq_queue_t *pq)
|
|||
pq_list_t *pql;
|
||||
pthread_t pthread = NULL;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_pq_first: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
|
||||
while (((pql = TAILQ_FIRST(&pq->pq_queue)) != NULL) &&
|
||||
(pthread == NULL)) {
|
||||
if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) {
|
||||
|
|
@ -124,6 +235,8 @@ _pq_first(pq_queue_t *pq)
|
|||
pql->pl_queued = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
return (pthread);
|
||||
}
|
||||
|
||||
|
|
@ -133,10 +246,15 @@ pq_insert_prio_list(pq_queue_t *pq, int prio)
|
|||
{
|
||||
pq_list_t *pql;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_ACTIVE("pq_insert_prio_list: pq_active");
|
||||
|
||||
/*
|
||||
* The priority queue is in descending priority order. Start at
|
||||
* the beginning of the queue and find the list before which the
|
||||
* new list should to be inserted.
|
||||
* new list should be inserted.
|
||||
*/
|
||||
pql = TAILQ_FIRST(&pq->pq_queue);
|
||||
while ((pql != NULL) && (pql->pl_prio > prio))
|
||||
|
|
@ -152,4 +270,66 @@ pq_insert_prio_list(pq_queue_t *pq, int prio)
|
|||
pq->pq_lists[prio].pl_queued = 1;
|
||||
}
|
||||
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
void
|
||||
_waitq_insert(pthread_t pthread)
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_waitq_insert: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_NOT_QUEUED(pthread, "_waitq_insert: Already in queue");
|
||||
|
||||
if (pthread->wakeup_time.tv_sec == -1)
|
||||
TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe);
|
||||
else {
|
||||
tid = TAILQ_FIRST(&_waitingq);
|
||||
while ((tid != NULL) && (tid->wakeup_time.tv_sec != -1) &&
|
||||
((tid->wakeup_time.tv_sec < pthread->wakeup_time.tv_sec) ||
|
||||
((tid->wakeup_time.tv_sec == pthread->wakeup_time.tv_sec) &&
|
||||
(tid->wakeup_time.tv_nsec <= pthread->wakeup_time.tv_nsec))))
|
||||
tid = TAILQ_NEXT(tid, pqe);
|
||||
if (tid == NULL)
|
||||
TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe);
|
||||
else
|
||||
TAILQ_INSERT_BEFORE(tid, pthread, pqe);
|
||||
}
|
||||
pthread->flags |= PTHREAD_FLAGS_IN_WAITQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
|
||||
void
|
||||
_waitq_remove(pthread_t pthread)
|
||||
{
|
||||
/*
|
||||
* Make some assertions when debugging is enabled:
|
||||
*/
|
||||
_PQ_ASSERT_INACTIVE("_waitq_remove: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_IN_WAITQ(pthread, "_waitq_remove: Not in queue");
|
||||
|
||||
TAILQ_REMOVE(&_waitingq, pthread, pqe);
|
||||
pthread->flags &= ~PTHREAD_FLAGS_IN_WAITQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
|
||||
void
|
||||
_waitq_setactive(void)
|
||||
{
|
||||
_PQ_ASSERT_INACTIVE("_waitq_setactive: pq_active");
|
||||
_PQ_SET_ACTIVE();
|
||||
}
|
||||
|
||||
void
|
||||
_waitq_clearactive(void)
|
||||
{
|
||||
_PQ_ASSERT_ACTIVE("_waitq_clearactive: ! pq_active");
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
*
|
||||
* Private thread definitions for the uthread kernel.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#ifndef _PTHREAD_PRIVATE_H
|
||||
|
|
@ -68,33 +69,88 @@
|
|||
|
||||
|
||||
/*
|
||||
* Priority queue manipulation macros:
|
||||
* Priority queue manipulation macros (using pqe link):
|
||||
*/
|
||||
#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)
|
||||
#define PTHREAD_PRIOQ_FIRST() _pq_first(&_readyq)
|
||||
|
||||
/*
|
||||
* Waiting queue manipulation macros:
|
||||
* Waiting queue manipulation macros (using pqe link):
|
||||
*/
|
||||
#define PTHREAD_WAITQ_INSERT(thrd) TAILQ_INSERT_TAIL(&_waitingq,thrd,pqe)
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
#define PTHREAD_WAITQ_REMOVE(thrd) _waitq_remove(thrd)
|
||||
#define PTHREAD_WAITQ_INSERT(thrd) _waitq_insert(thrd)
|
||||
#define PTHREAD_WAITQ_CLEARACTIVE() _waitq_clearactive()
|
||||
#define PTHREAD_WAITQ_SETACTIVE() _waitq_setactive()
|
||||
#else
|
||||
#define PTHREAD_WAITQ_REMOVE(thrd) TAILQ_REMOVE(&_waitingq,thrd,pqe)
|
||||
#define PTHREAD_WAITQ_INSERT(thrd) do { \
|
||||
if ((thrd)->wakeup_time.tv_sec == -1) \
|
||||
TAILQ_INSERT_TAIL(&_waitingq,thrd,pqe); \
|
||||
else { \
|
||||
pthread_t tid = TAILQ_FIRST(&_waitingq); \
|
||||
while ((tid != NULL) && (tid->wakeup_time.tv_sec != -1) && \
|
||||
((tid->wakeup_time.tv_sec < (thrd)->wakeup_time.tv_sec) || \
|
||||
((tid->wakeup_time.tv_sec == (thrd)->wakeup_time.tv_sec) && \
|
||||
(tid->wakeup_time.tv_nsec <= (thrd)->wakeup_time.tv_nsec)))) \
|
||||
tid = TAILQ_NEXT(tid, pqe); \
|
||||
if (tid == NULL) \
|
||||
TAILQ_INSERT_TAIL(&_waitingq,thrd,pqe); \
|
||||
else \
|
||||
TAILQ_INSERT_BEFORE(tid,thrd,pqe); \
|
||||
} \
|
||||
} while (0)
|
||||
#define PTHREAD_WAITQ_CLEARACTIVE()
|
||||
#define PTHREAD_WAITQ_SETACTIVE()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Work queue manipulation macros (using qe link):
|
||||
*/
|
||||
#define PTHREAD_WORKQ_INSERT(thrd) do { \
|
||||
TAILQ_INSERT_TAIL(&_workq,thrd,qe); \
|
||||
(thrd)->flags |= PTHREAD_FLAGS_IN_WORKQ; \
|
||||
} while (0)
|
||||
#define PTHREAD_WORKQ_REMOVE(thrd) do { \
|
||||
TAILQ_REMOVE(&_workq,thrd,qe); \
|
||||
(thrd)->flags &= ~PTHREAD_FLAGS_IN_WORKQ; \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* State change macro without scheduling queue change:
|
||||
*/
|
||||
#define PTHREAD_SET_STATE(thrd, newstate) { \
|
||||
#define PTHREAD_SET_STATE(thrd, newstate) do { \
|
||||
(thrd)->state = newstate; \
|
||||
(thrd)->fname = __FILE__; \
|
||||
(thrd)->lineno = __LINE__; \
|
||||
}
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* 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 defined(_PTHREADS_INVARIANTS)
|
||||
#define PTHREAD_NEW_STATE(thrd, newstate) do { \
|
||||
if (_thread_kern_new_state != 0) \
|
||||
PANIC("Recursive PTHREAD_NEW_STATE"); \
|
||||
_thread_kern_new_state = 1; \
|
||||
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); \
|
||||
} \
|
||||
} \
|
||||
_thread_kern_new_state = 0; \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
} while (0)
|
||||
#else
|
||||
#define PTHREAD_NEW_STATE(thrd, newstate) do { \
|
||||
if ((thrd)->state != newstate) { \
|
||||
if ((thrd)->state == PS_RUNNING) { \
|
||||
PTHREAD_PRIOQ_REMOVE(thrd); \
|
||||
|
|
@ -105,7 +161,8 @@
|
|||
} \
|
||||
} \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
}
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define the signals to be used for scheduling.
|
||||
|
|
@ -118,15 +175,6 @@
|
|||
#define _SCHED_SIGNAL SIGPROF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Queue definitions.
|
||||
*/
|
||||
struct pthread_queue {
|
||||
struct pthread *q_next;
|
||||
struct pthread *q_last;
|
||||
void *q_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* Priority queues.
|
||||
*
|
||||
|
|
@ -146,15 +194,10 @@ typedef struct pq_queue {
|
|||
} pq_queue_t;
|
||||
|
||||
|
||||
/*
|
||||
* Static queue initialization values.
|
||||
*/
|
||||
#define PTHREAD_QUEUE_INITIALIZER { NULL, NULL, NULL }
|
||||
|
||||
/*
|
||||
* TailQ initialization values.
|
||||
*/
|
||||
#define TAILQ_INITIALIZER { NULL, NULL }
|
||||
#define TAILQ_INITIALIZER { NULL, NULL }
|
||||
|
||||
/*
|
||||
* Mutex definitions.
|
||||
|
|
@ -257,7 +300,7 @@ struct pthread_cond_attr {
|
|||
* Static cond initialization values.
|
||||
*/
|
||||
#define PTHREAD_COND_STATIC_INITIALIZER \
|
||||
{ COND_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, NULL, NULL, \
|
||||
{ COND_TYPE_FAST, TAILQ_INITIALIZER, NULL, NULL, \
|
||||
0, _SPINLOCK_INITIALIZER }
|
||||
|
||||
/*
|
||||
|
|
@ -302,12 +345,6 @@ struct pthread_attr {
|
|||
*/
|
||||
#define CLOCK_RES_NSEC 10000000
|
||||
|
||||
/*
|
||||
* Number of microseconds between incremental priority updates for
|
||||
* threads that are ready to run, but denied being run.
|
||||
*/
|
||||
#define INC_PRIO_USEC 500000
|
||||
|
||||
/*
|
||||
* Time slice period in microseconds.
|
||||
*/
|
||||
|
|
@ -345,6 +382,7 @@ enum pthread_state {
|
|||
PS_FDR_WAIT,
|
||||
PS_FDW_WAIT,
|
||||
PS_FILE_WAIT,
|
||||
PS_POLL_WAIT,
|
||||
PS_SELECT_WAIT,
|
||||
PS_SLEEP_WAIT,
|
||||
PS_WAIT_WAIT,
|
||||
|
|
@ -377,8 +415,8 @@ struct fd_table_entry {
|
|||
* state of the lock on the file descriptor.
|
||||
*/
|
||||
spinlock_t lock;
|
||||
struct pthread_queue r_queue; /* Read queue. */
|
||||
struct pthread_queue w_queue; /* Write queue. */
|
||||
TAILQ_HEAD(, pthread) r_queue; /* Read queue. */
|
||||
TAILQ_HEAD(, pthread) w_queue; /* Write queue. */
|
||||
struct pthread *r_owner; /* Ptr to thread owning read lock. */
|
||||
struct pthread *w_owner; /* Ptr to thread owning write lock. */
|
||||
char *r_fname; /* Ptr to read lock source file name */
|
||||
|
|
@ -390,11 +428,9 @@ struct fd_table_entry {
|
|||
int flags; /* Flags used in open. */
|
||||
};
|
||||
|
||||
struct pthread_select_data {
|
||||
struct pthread_poll_data {
|
||||
int nfds;
|
||||
fd_set readfds;
|
||||
fd_set writefds;
|
||||
fd_set exceptfds;
|
||||
struct pollfd *fds;
|
||||
};
|
||||
|
||||
union pthread_wait_data {
|
||||
|
|
@ -406,7 +442,7 @@ union pthread_wait_data {
|
|||
short branch; /* Line number, for debugging. */
|
||||
char *fname; /* Source file name for debugging.*/
|
||||
} fd;
|
||||
struct pthread_select_data * select_data;
|
||||
struct pthread_poll_data * poll_data;
|
||||
spinlock_t *spinlock;
|
||||
};
|
||||
|
||||
|
|
@ -427,15 +463,11 @@ struct pthread {
|
|||
*/
|
||||
spinlock_t lock;
|
||||
|
||||
/*
|
||||
* Pointer to the next thread in the thread linked list.
|
||||
*/
|
||||
struct pthread *nxt;
|
||||
/* Queue entry for list of all threads: */
|
||||
TAILQ_ENTRY(pthread) tle;
|
||||
|
||||
/*
|
||||
* Pointer to the next thread in the dead thread linked list.
|
||||
*/
|
||||
struct pthread *nxt_dead;
|
||||
/* Queue entry for list of dead threads: */
|
||||
TAILQ_ENTRY(pthread) dle;
|
||||
|
||||
/*
|
||||
* Thread start routine, argument, stack pointer and thread
|
||||
|
|
@ -514,25 +546,25 @@ struct pthread {
|
|||
*/
|
||||
int error;
|
||||
|
||||
/* Join queue for waiting threads: */
|
||||
struct pthread_queue join_queue;
|
||||
/* Join queue head and link for waiting threads: */
|
||||
TAILQ_HEAD(join_head, pthread) join_queue;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* The current thread can belong to only one scheduling queue at
|
||||
* a time (ready or waiting queue). It can also belong to (only)
|
||||
* one of:
|
||||
*
|
||||
* o A queue of threads waiting for a mutex
|
||||
* o A queue of threads waiting for a condition variable
|
||||
* o A queue of threads waiting for another thread to terminate
|
||||
* (the join queue above)
|
||||
* o A queue of threads waiting for a file descriptor lock
|
||||
* o A queue of threads needing work done by the kernel thread
|
||||
* (waiting for a spinlock or file I/O)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* XXX The queuing should be changed to use the TAILQ entry below.
|
||||
* XXX For the time being, it's hybrid.
|
||||
* and qe for other links.
|
||||
*/
|
||||
struct pthread_queue *queue;
|
||||
|
||||
/* Pointer to next element in queue. */
|
||||
struct pthread *qnxt;
|
||||
|
||||
/* Priority queue entry for this thread: */
|
||||
TAILQ_ENTRY(pthread) pqe;
|
||||
|
|
@ -543,6 +575,11 @@ struct pthread {
|
|||
/* Wait data. */
|
||||
union pthread_wait_data data;
|
||||
|
||||
/*
|
||||
* Allocated for converting select into poll.
|
||||
*/
|
||||
struct pthread_poll_data poll_data;
|
||||
|
||||
/*
|
||||
* Set to TRUE if a blocking operation was
|
||||
* interrupted by a signal:
|
||||
|
|
@ -553,23 +590,26 @@ struct pthread {
|
|||
int signo;
|
||||
|
||||
/*
|
||||
* Set to non-zero when this thread has deferred thread
|
||||
* scheduling. We allow for recursive deferral.
|
||||
* Set to non-zero when this thread has deferred signals.
|
||||
* We allow for recursive deferral.
|
||||
*/
|
||||
int sched_defer_count;
|
||||
int sig_defer_count;
|
||||
|
||||
/*
|
||||
* Set to TRUE if this thread should yield after undeferring
|
||||
* thread scheduling.
|
||||
* signals.
|
||||
*/
|
||||
int yield_on_sched_undefer;
|
||||
int yield_on_sig_undefer;
|
||||
|
||||
/* Miscellaneous data. */
|
||||
int flags;
|
||||
#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_FLAGS_IN_CONDQ 0x0004 /* in condition queue using qe link*/
|
||||
#define PTHREAD_FLAGS_IN_WORKQ 0x0008 /* in work queue using qe link */
|
||||
#define PTHREAD_FLAGS_IN_WAITQ 0x0010 /* in waiting queue using pqe link*/
|
||||
#define PTHREAD_FLAGS_IN_PRIOQ 0x0020 /* in priority queue using pqe link*/
|
||||
#define PTHREAD_FLAGS_TRACE 0x0040 /* for debugging purposes */
|
||||
|
||||
/*
|
||||
* Base priority is the user setable and retrievable priority
|
||||
|
|
@ -592,7 +632,7 @@ struct pthread {
|
|||
/*
|
||||
* 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
|
||||
* in either the base or inherited priority, the active
|
||||
* priority must be recalculated.
|
||||
*/
|
||||
char active_priority;
|
||||
|
|
@ -649,10 +689,10 @@ SCLASS struct pthread * volatile _thread_single
|
|||
;
|
||||
#endif
|
||||
|
||||
/* Ptr to the first thread in the thread linked list: */
|
||||
SCLASS struct pthread * volatile _thread_link_list
|
||||
/* List of all threads: */
|
||||
SCLASS TAILQ_HEAD(, pthread) _thread_list
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= NULL;
|
||||
= TAILQ_HEAD_INITIALIZER(_thread_list);
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
|
|
@ -661,7 +701,7 @@ SCLASS struct pthread * volatile _thread_link_list
|
|||
* Array of kernel pipe file descriptors that are used to ensure that
|
||||
* no signals are missed in calls to _select.
|
||||
*/
|
||||
SCLASS int _thread_kern_pipe[2]
|
||||
SCLASS int _thread_kern_pipe[2]
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= {
|
||||
-1,
|
||||
|
|
@ -670,7 +710,7 @@ SCLASS int _thread_kern_pipe[2]
|
|||
#else
|
||||
;
|
||||
#endif
|
||||
SCLASS int _thread_kern_in_select
|
||||
SCLASS int volatile _queue_signals
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= 0;
|
||||
#else
|
||||
|
|
@ -692,9 +732,9 @@ SCLASS struct timeval kern_inc_prio_time
|
|||
#endif
|
||||
|
||||
/* Dead threads: */
|
||||
SCLASS struct pthread * volatile _thread_dead
|
||||
SCLASS TAILQ_HEAD(, pthread) _dead_list
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= NULL;
|
||||
= TAILQ_HEAD_INITIALIZER(_dead_list);
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
|
|
@ -747,6 +787,14 @@ SCLASS struct fd_table_entry **_thread_fd_table
|
|||
;
|
||||
#endif
|
||||
|
||||
/* Table for polling file descriptors: */
|
||||
SCLASS struct pollfd *_thread_pfd_table
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= NULL;
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
|
||||
SCLASS const int dtablecount
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= 4096/sizeof(struct fd_table_entry);
|
||||
|
|
@ -760,6 +808,13 @@ SCLASS int _thread_dtablesize /* Descriptor table size. */
|
|||
;
|
||||
#endif
|
||||
|
||||
SCLASS int _clock_res_nsec /* Clock resolution in nsec. */
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= CLOCK_RES_NSEC;
|
||||
#else
|
||||
;
|
||||
#endif
|
||||
|
||||
/* Garbage collector mutex and condition variable. */
|
||||
SCLASS pthread_mutex_t _gc_mutex
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
|
|
@ -783,8 +838,20 @@ struct sigaction _thread_sigact[NSIG];
|
|||
SCLASS pq_queue_t _readyq;
|
||||
SCLASS TAILQ_HEAD(, pthread) _waitingq;
|
||||
|
||||
/* Indicates that the waitingq now has threads ready to run. */
|
||||
SCLASS volatile int _waitingq_check_reqd
|
||||
/*
|
||||
* Work queue:
|
||||
*/
|
||||
SCLASS TAILQ_HEAD(, pthread) _workq;
|
||||
|
||||
/* Tracks the number of threads blocked while waiting for a spinlock. */
|
||||
SCLASS volatile int _spinblock_count
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= 0
|
||||
#endif
|
||||
;
|
||||
|
||||
/* Indicates that the signal queue needs to be checked. */
|
||||
SCLASS volatile int _sigq_check_reqd
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= 0
|
||||
#endif
|
||||
|
|
@ -797,6 +864,13 @@ SCLASS pthread_switch_routine_t _sched_switch_hook
|
|||
#endif
|
||||
;
|
||||
|
||||
/* Used for _PTHREADS_INVARIANTS checking. */
|
||||
SCLASS int _thread_kern_new_state
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
= 0
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
/* Undefine the storage class specifier: */
|
||||
#undef SCLASS
|
||||
|
|
@ -825,18 +899,23 @@ int _thread_fd_lock(int, int, struct timespec *);
|
|||
int _thread_fd_lock_debug(int, int, struct timespec *,char *fname,int lineno);
|
||||
void _dispatch_signals(void);
|
||||
void _thread_signal(pthread_t, int);
|
||||
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 *);
|
||||
int _mutex_reinit(pthread_mutex_t *);
|
||||
void _mutex_notify_priochange(struct pthread *);
|
||||
int _pq_init(struct pq_queue *pq, int, int);
|
||||
int _cond_reinit(pthread_cond_t *);
|
||||
int _pq_alloc(struct pq_queue *, int, int);
|
||||
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);
|
||||
#if defined(_PTHREADS_INVARIANTS)
|
||||
void _waitq_insert(pthread_t pthread);
|
||||
void _waitq_remove(pthread_t pthread);
|
||||
void _waitq_setactive(void);
|
||||
void _waitq_clearactive(void);
|
||||
#endif
|
||||
void _thread_exit(char *, int, char *);
|
||||
void _thread_fd_unlock(int, int);
|
||||
void _thread_fd_unlock_debug(int, int, char *, int);
|
||||
|
|
@ -849,18 +928,15 @@ void _thread_kern_sched_state(enum pthread_state,char *fname,int lineno);
|
|||
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_kern_sig_defer(void);
|
||||
void _thread_kern_sig_undefer(void);
|
||||
void _thread_sig_handler(int, int, struct sigcontext *);
|
||||
void _thread_sig_handle(int, struct sigcontext *);
|
||||
void _thread_sig_init(void);
|
||||
void _thread_start(void);
|
||||
void _thread_start_sig_handler(void);
|
||||
void _thread_seterrno(pthread_t,int);
|
||||
void _thread_queue_init(struct pthread_queue *);
|
||||
void _thread_queue_enq(struct pthread_queue *, struct pthread *);
|
||||
int _thread_queue_remove(struct pthread_queue *, struct pthread *);
|
||||
int _thread_fd_table_init(int fd);
|
||||
struct pthread *_thread_queue_get(struct pthread_queue *);
|
||||
struct pthread *_thread_queue_deq(struct pthread_queue *);
|
||||
pthread_addr_t _thread_gc(pthread_addr_t);
|
||||
|
||||
/* #include <signal.h> */
|
||||
|
|
@ -1036,6 +1112,11 @@ pid_t _thread_sys_waitpid(pid_t, int *, int);
|
|||
pid_t _thread_sys_wait3(int *, int, struct rusage *);
|
||||
pid_t _thread_sys_wait4(pid_t, int *, int, struct rusage *);
|
||||
#endif
|
||||
|
||||
/* #include <poll.h> */
|
||||
#ifdef _SYS_POLL_H_
|
||||
int _thread_sys_poll(struct pollfd *, unsigned, int);
|
||||
#endif
|
||||
__END_DECLS
|
||||
|
||||
#endif /* !_PTHREAD_PRIVATE_H */
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -46,20 +47,19 @@ pthread_resume_np(pthread_t thread)
|
|||
/* The thread exists. Is it suspended? */
|
||||
if (thread->state != PS_SUSPENDED) {
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues.
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Allow the thread to run. */
|
||||
PTHREAD_NEW_STATE(thread,PS_RUNNING);
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling
|
||||
* signal occurred while in the critical region.
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
}
|
||||
return(ret);
|
||||
|
|
|
|||
|
|
@ -29,10 +29,13 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
|
@ -44,12 +47,10 @@ int
|
|||
select(int numfds, fd_set * readfds, fd_set * writefds,
|
||||
fd_set * exceptfds, struct timeval * timeout)
|
||||
{
|
||||
fd_set read_locks, write_locks, rdwr_locks;
|
||||
struct timespec ts;
|
||||
struct timeval zero_timeout = {0, 0};
|
||||
int i, ret = 0, got_all_locks = 1;
|
||||
int f_wait = 1;
|
||||
struct pthread_select_data data;
|
||||
int i, ret = 0, f_wait = 1;
|
||||
int pfd_index, got_one = 0, fd_count = 0;
|
||||
struct pthread_poll_data data;
|
||||
|
||||
if (numfds > _thread_dtablesize) {
|
||||
numfds = _thread_dtablesize;
|
||||
|
|
@ -68,112 +69,129 @@ select(int numfds, fd_set * readfds, fd_set * writefds,
|
|||
_thread_kern_set_timeout(NULL);
|
||||
}
|
||||
|
||||
FD_ZERO(&read_locks);
|
||||
FD_ZERO(&write_locks);
|
||||
FD_ZERO(&rdwr_locks);
|
||||
|
||||
/* lock readfds */
|
||||
/* Count the number of file descriptors to be polled: */
|
||||
if (readfds || writefds || exceptfds) {
|
||||
for (i = 0; i < numfds; i++) {
|
||||
if ((readfds && (FD_ISSET(i, readfds))) || (exceptfds && FD_ISSET(i, exceptfds))) {
|
||||
if (writefds && FD_ISSET(i, writefds)) {
|
||||
if ((ret = _FD_LOCK(i, FD_RDWR, NULL)) != 0) {
|
||||
got_all_locks = 0;
|
||||
break;
|
||||
}
|
||||
FD_SET(i, &rdwr_locks);
|
||||
} else {
|
||||
if ((ret = _FD_LOCK(i, FD_READ, NULL)) != 0) {
|
||||
got_all_locks = 0;
|
||||
break;
|
||||
}
|
||||
FD_SET(i, &read_locks);
|
||||
}
|
||||
} else {
|
||||
if (writefds && FD_ISSET(i, writefds)) {
|
||||
if ((ret = _FD_LOCK(i, FD_WRITE, NULL)) != 0) {
|
||||
got_all_locks = 0;
|
||||
break;
|
||||
}
|
||||
FD_SET(i, &write_locks);
|
||||
}
|
||||
if ((readfds && FD_ISSET(i, readfds)) ||
|
||||
(exceptfds && FD_ISSET(i, exceptfds)) ||
|
||||
(writefds && FD_ISSET(i, writefds))) {
|
||||
fd_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (got_all_locks) {
|
||||
data.nfds = numfds;
|
||||
FD_ZERO(&data.readfds);
|
||||
FD_ZERO(&data.writefds);
|
||||
FD_ZERO(&data.exceptfds);
|
||||
if (readfds != NULL) {
|
||||
memcpy(&data.readfds, readfds, sizeof(data.readfds));
|
||||
|
||||
/*
|
||||
* Allocate memory for poll data if it hasn't already been
|
||||
* allocated or if previously allocated memory is insufficient.
|
||||
*/
|
||||
if ((_thread_run->poll_data.fds == NULL) ||
|
||||
(_thread_run->poll_data.nfds < fd_count)) {
|
||||
data.fds = (struct pollfd *) realloc(_thread_run->poll_data.fds,
|
||||
sizeof(struct pollfd) * MAX(128, fd_count));
|
||||
if (data.fds == NULL) {
|
||||
errno = ENOMEM;
|
||||
ret = -1;
|
||||
}
|
||||
if (writefds != NULL) {
|
||||
memcpy(&data.writefds, writefds, sizeof(data.writefds));
|
||||
else {
|
||||
/*
|
||||
* Note that the threads poll data always
|
||||
* indicates what is allocated, not what is
|
||||
* currently being polled.
|
||||
*/
|
||||
_thread_run->poll_data.fds = data.fds;
|
||||
_thread_run->poll_data.nfds = MAX(128, fd_count);
|
||||
}
|
||||
if (exceptfds != NULL) {
|
||||
memcpy(&data.exceptfds, exceptfds, sizeof(data.exceptfds));
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* Setup the wait data. */
|
||||
data.fds = _thread_run->poll_data.fds;
|
||||
data.nfds = fd_count;
|
||||
|
||||
/*
|
||||
* Setup the array of pollfds. Optimize this by
|
||||
* running the loop in reverse and stopping when
|
||||
* the number of selected file descriptors is reached.
|
||||
*/
|
||||
for (i = numfds - 1, pfd_index = fd_count - 1;
|
||||
(i >= 0) && (pfd_index >= 0); i--) {
|
||||
data.fds[pfd_index].events = 0;
|
||||
if (readfds && FD_ISSET(i, readfds)) {
|
||||
data.fds[pfd_index].events = POLLRDNORM;
|
||||
}
|
||||
if (exceptfds && FD_ISSET(i, exceptfds)) {
|
||||
data.fds[pfd_index].events |= POLLRDBAND;
|
||||
}
|
||||
if (writefds && FD_ISSET(i, writefds)) {
|
||||
data.fds[pfd_index].events |= POLLWRNORM;
|
||||
}
|
||||
if (data.fds[pfd_index].events != 0) {
|
||||
/*
|
||||
* Set the file descriptor to be polled and
|
||||
* clear revents in case of a timeout which
|
||||
* leaves fds unchanged:
|
||||
*/
|
||||
data.fds[pfd_index].fd = i;
|
||||
data.fds[pfd_index].revents = 0;
|
||||
pfd_index--;
|
||||
}
|
||||
}
|
||||
if ((ret = _thread_sys_select(data.nfds, &data.readfds, &data.writefds, &data.exceptfds, &zero_timeout)) == 0 && f_wait) {
|
||||
data.nfds = numfds;
|
||||
FD_ZERO(&data.readfds);
|
||||
FD_ZERO(&data.writefds);
|
||||
FD_ZERO(&data.exceptfds);
|
||||
if (readfds != NULL) {
|
||||
memcpy(&data.readfds, readfds, sizeof(data.readfds));
|
||||
}
|
||||
if (writefds != NULL) {
|
||||
memcpy(&data.writefds, writefds, sizeof(data.writefds));
|
||||
}
|
||||
if (exceptfds != NULL) {
|
||||
memcpy(&data.exceptfds, exceptfds, sizeof(data.exceptfds));
|
||||
}
|
||||
_thread_run->data.select_data = &data;
|
||||
if (((ret = _thread_sys_poll(data.fds, data.nfds, 0)) == 0) &&
|
||||
(f_wait != 0)) {
|
||||
_thread_run->data.poll_data = &data;
|
||||
_thread_run->interrupted = 0;
|
||||
_thread_kern_sched_state(PS_SELECT_WAIT, __FILE__, __LINE__);
|
||||
if (_thread_run->interrupted) {
|
||||
errno = EINTR;
|
||||
data.nfds = 0;
|
||||
ret = -1;
|
||||
} else
|
||||
ret = data.nfds;
|
||||
}
|
||||
}
|
||||
/* clean up the locks */
|
||||
for (i = 0; i < numfds; i++)
|
||||
if (FD_ISSET(i, &read_locks))
|
||||
_FD_UNLOCK(i, FD_READ);
|
||||
for (i = 0; i < numfds; i++)
|
||||
if (FD_ISSET(i, &rdwr_locks))
|
||||
_FD_UNLOCK(i, FD_RDWR);
|
||||
for (i = 0; i < numfds; i++)
|
||||
if (FD_ISSET(i, &write_locks))
|
||||
_FD_UNLOCK(i, FD_WRITE);
|
||||
|
||||
if (ret >= 0) {
|
||||
if (readfds != NULL) {
|
||||
for (i = 0; i < numfds; i++) {
|
||||
if (FD_ISSET(i, readfds) &&
|
||||
!FD_ISSET(i, &data.readfds)) {
|
||||
FD_CLR(i, readfds);
|
||||
numfds = 0;
|
||||
for (i = 0; i < fd_count; i++) {
|
||||
/*
|
||||
* Check the results of the poll and clear
|
||||
* this file descriptor from the fdset if
|
||||
* the requested event wasn't ready.
|
||||
*/
|
||||
got_one = 0;
|
||||
if (readfds != NULL) {
|
||||
if (FD_ISSET(data.fds[i].fd, readfds)) {
|
||||
if (data.fds[i].revents & (POLLIN |
|
||||
POLLRDNORM))
|
||||
got_one = 1;
|
||||
else
|
||||
FD_CLR(data.fds[i].fd, readfds);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (writefds != NULL) {
|
||||
for (i = 0; i < numfds; i++) {
|
||||
if (FD_ISSET(i, writefds) &&
|
||||
!FD_ISSET(i, &data.writefds)) {
|
||||
FD_CLR(i, writefds);
|
||||
if (writefds != NULL) {
|
||||
if (FD_ISSET(data.fds[i].fd, writefds)) {
|
||||
if (data.fds[i].revents & (POLLOUT |
|
||||
POLLWRNORM | POLLWRBAND))
|
||||
got_one = 1;
|
||||
else
|
||||
FD_CLR(data.fds[i].fd,
|
||||
writefds);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exceptfds != NULL) {
|
||||
for (i = 0; i < numfds; i++) {
|
||||
if (FD_ISSET(i, exceptfds) &&
|
||||
!FD_ISSET(i, &data.exceptfds)) {
|
||||
FD_CLR(i, exceptfds);
|
||||
if (exceptfds != NULL) {
|
||||
if (FD_ISSET(data.fds[i].fd, exceptfds)) {
|
||||
if (data.fds[i].revents & (POLLRDBAND |
|
||||
POLLPRI | POLLHUP | POLLERR |
|
||||
POLLNVAL))
|
||||
got_one = 1;
|
||||
else
|
||||
FD_CLR(data.fds[i].fd,
|
||||
exceptfds);
|
||||
}
|
||||
}
|
||||
if (got_one)
|
||||
numfds++;
|
||||
}
|
||||
ret = numfds;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <sys/param.h>
|
||||
|
|
@ -50,10 +51,10 @@ pthread_setschedparam(pthread_t pthread, int policy, struct sched_param *param)
|
|||
/* Find the thread in the list of active threads: */
|
||||
else if ((ret = _find_thread(pthread)) == 0) {
|
||||
/*
|
||||
* Guard against being preempted by a scheduling
|
||||
* signal:
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
if (param->sched_priority != pthread->base_priority) {
|
||||
/*
|
||||
|
|
@ -61,8 +62,7 @@ pthread_setschedparam(pthread_t pthread, int policy, struct sched_param *param)
|
|||
* queue before any adjustments are made to its
|
||||
* active priority:
|
||||
*/
|
||||
if ((pthread != _thread_run) &&
|
||||
(pthread->state == PS_RUNNING)) {
|
||||
if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0) {
|
||||
in_readyq = 1;
|
||||
old_prio = pthread->active_priority;
|
||||
PTHREAD_PRIOQ_REMOVE(pthread);
|
||||
|
|
@ -103,10 +103,10 @@ pthread_setschedparam(pthread_t pthread, int policy, struct sched_param *param)
|
|||
pthread->attr.sched_policy = policy;
|
||||
|
||||
/*
|
||||
* Renable preemption and yield if a scheduling signal
|
||||
* arrived while in the critical region:
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
|
|
@ -38,107 +39,51 @@
|
|||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
|
||||
/*
|
||||
* State change macro for signal handler:
|
||||
*/
|
||||
#define PTHREAD_SIG_NEW_STATE(thrd, newstate) { \
|
||||
if ((_thread_run->sched_defer_count == 0) && \
|
||||
(_thread_kern_in_sched == 0)) { \
|
||||
PTHREAD_NEW_STATE(thrd, newstate); \
|
||||
} else { \
|
||||
_waitingq_check_reqd = 1; \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Static variables: */
|
||||
static int volatile yield_on_unlock_thread = 0;
|
||||
static spinlock_t thread_link_list_lock = _SPINLOCK_INITIALIZER;
|
||||
static spinlock_t signal_lock = _SPINLOCK_INITIALIZER;
|
||||
unsigned int pending_sigs[NSIG];
|
||||
unsigned int handled_sigs[NSIG];
|
||||
int volatile check_pending = 0;
|
||||
|
||||
/* Lock the thread list: */
|
||||
/* Initialize signal handling facility: */
|
||||
void
|
||||
_lock_thread_list()
|
||||
_thread_sig_init(void)
|
||||
{
|
||||
/* Lock the thread list: */
|
||||
_SPINLOCK(&thread_link_list_lock);
|
||||
}
|
||||
int i;
|
||||
|
||||
/* Lock the thread list: */
|
||||
void
|
||||
_unlock_thread_list()
|
||||
{
|
||||
/* Unlock the thread list: */
|
||||
_SPINUNLOCK(&thread_link_list_lock);
|
||||
|
||||
/*
|
||||
* Check if a scheduler interrupt occurred while the thread
|
||||
* list was locked:
|
||||
*/
|
||||
if (yield_on_unlock_thread) {
|
||||
/* Reset the interrupt flag: */
|
||||
yield_on_unlock_thread = 0;
|
||||
|
||||
/* This thread has overstayed it's welcome: */
|
||||
sched_yield();
|
||||
/* Clear pending and handled signal counts: */
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
pending_sigs[i - 1] = 0;
|
||||
handled_sigs[i - 1] = 0;
|
||||
}
|
||||
|
||||
/* Clear the lock: */
|
||||
signal_lock.access_lock = 0;
|
||||
}
|
||||
|
||||
void
|
||||
_thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
||||
{
|
||||
char c;
|
||||
int i;
|
||||
pthread_t pthread;
|
||||
|
||||
/*
|
||||
* Check if the pthread kernel has unblocked signals (or is about to)
|
||||
* and was on its way into a _select when the current
|
||||
* signal interrupted it:
|
||||
*/
|
||||
if (_thread_kern_in_select) {
|
||||
/* Cast the signal number to a character variable: */
|
||||
c = sig;
|
||||
|
||||
/*
|
||||
* Write the signal number to the kernel pipe so that it will
|
||||
* be ready to read when this signal handler returns. This
|
||||
* means that the _select call will complete
|
||||
* immediately.
|
||||
*/
|
||||
_thread_sys_write(_thread_kern_pipe[1], &c, 1);
|
||||
}
|
||||
/* Check if the signal requires a dump of thread information: */
|
||||
if (sig == SIGINFO)
|
||||
/* Dump thread information to file: */
|
||||
_thread_dump_info();
|
||||
char c;
|
||||
int i;
|
||||
|
||||
/* Check if an interval timer signal: */
|
||||
else if (sig == _SCHED_SIGNAL) {
|
||||
/* Check if the scheduler interrupt has come at an
|
||||
* unfortunate time which one of the threads is
|
||||
* modifying the thread list:
|
||||
*/
|
||||
if (thread_link_list_lock.access_lock)
|
||||
if (sig == _SCHED_SIGNAL) {
|
||||
if (_thread_kern_in_sched != 0) {
|
||||
/*
|
||||
* Set a flag so that the thread that has
|
||||
* the lock yields when it unlocks the
|
||||
* thread list:
|
||||
* The scheduler is already running; ignore this
|
||||
* signal.
|
||||
*/
|
||||
yield_on_unlock_thread = 1;
|
||||
|
||||
}
|
||||
/*
|
||||
* Check if the scheduler interrupt has come when
|
||||
* the currently running thread has deferred thread
|
||||
* scheduling.
|
||||
* signals.
|
||||
*/
|
||||
else if (_thread_run->sched_defer_count)
|
||||
_thread_run->yield_on_sched_undefer = 1;
|
||||
else if (_thread_run->sig_defer_count > 0)
|
||||
_thread_run->yield_on_sig_undefer = 1;
|
||||
|
||||
/*
|
||||
* Check if the kernel has not been interrupted while
|
||||
* executing scheduler code:
|
||||
*/
|
||||
else if (!_thread_kern_in_sched) {
|
||||
else {
|
||||
/*
|
||||
* Schedule the next thread. This function is not
|
||||
* expected to return because it will do a longjmp
|
||||
|
|
@ -152,6 +97,72 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
|||
*/
|
||||
PANIC("Returned to signal function from scheduler");
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Check if the kernel has been interrupted while the scheduler
|
||||
* is accessing the scheduling queues or if there is a currently
|
||||
* running thread that has deferred signals.
|
||||
*/
|
||||
else if ((_queue_signals != 0) || ((_thread_kern_in_sched == 0) &&
|
||||
(_thread_run->sig_defer_count > 0))) {
|
||||
/* Cast the signal number to a character variable: */
|
||||
c = sig;
|
||||
|
||||
/*
|
||||
* Write the signal number to the kernel pipe so that it will
|
||||
* be ready to read when this signal handler returns.
|
||||
*/
|
||||
_thread_sys_write(_thread_kern_pipe[1], &c, 1);
|
||||
|
||||
/* Indicate that there are queued signals in the pipe. */
|
||||
_sigq_check_reqd = 1;
|
||||
}
|
||||
else {
|
||||
if (_atomic_lock(&signal_lock.access_lock)) {
|
||||
/* There is another signal handler running: */
|
||||
pending_sigs[sig - 1]++;
|
||||
check_pending = 1;
|
||||
}
|
||||
else {
|
||||
/* It's safe to handle the signal now. */
|
||||
_thread_sig_handle(sig, scp);
|
||||
|
||||
/* Reset the pending and handled count back to 0: */
|
||||
pending_sigs[sig - 1] = 0;
|
||||
handled_sigs[sig - 1] = 0;
|
||||
|
||||
signal_lock.access_lock = 0;
|
||||
}
|
||||
|
||||
/* Enter a loop to process pending signals: */
|
||||
while ((check_pending != 0) &&
|
||||
(_atomic_lock(&signal_lock.access_lock) == 0)) {
|
||||
check_pending = 0;
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (pending_sigs[i - 1] > handled_sigs[i - 1])
|
||||
_thread_sig_handle(i, scp);
|
||||
}
|
||||
signal_lock.access_lock = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_thread_sig_handle(int sig, struct sigcontext * scp)
|
||||
{
|
||||
int i;
|
||||
pthread_t pthread, pthread_next;
|
||||
|
||||
/* Check if the signal requires a dump of thread information: */
|
||||
if (sig == SIGINFO)
|
||||
/* Dump thread information to file: */
|
||||
_thread_dump_info();
|
||||
|
||||
/* Check if an interval timer signal: */
|
||||
else if (sig == _SCHED_SIGNAL) {
|
||||
/*
|
||||
* This shouldn't ever occur (should this panic?).
|
||||
*/
|
||||
} else {
|
||||
/* Check if a child has terminated: */
|
||||
if (sig == SIGCHLD) {
|
||||
|
|
@ -183,10 +194,9 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
|||
* Enter a loop to discard pending SIGCONT
|
||||
* signals:
|
||||
*/
|
||||
for (pthread = _thread_link_list;
|
||||
pthread != NULL;
|
||||
pthread = pthread->nxt)
|
||||
TAILQ_FOREACH(pthread, &_thread_list, tle) {
|
||||
sigdelset(&pthread->sigpend,SIGCONT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -196,11 +206,18 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
|||
* if there are multiple waiters, we'll give it to the
|
||||
* first one we find.
|
||||
*/
|
||||
TAILQ_FOREACH(pthread, &_waitingq, pqe) {
|
||||
for (pthread = TAILQ_FIRST(&_waitingq);
|
||||
pthread != NULL; pthread = pthread_next) {
|
||||
/*
|
||||
* Grab the next thread before possibly destroying
|
||||
* the link entry.
|
||||
*/
|
||||
pthread_next = TAILQ_NEXT(pthread, pqe);
|
||||
|
||||
if ((pthread->state == PS_SIGWAIT) &&
|
||||
sigismember(pthread->data.sigwait, sig)) {
|
||||
/* Change the state of the thread to run: */
|
||||
PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
|
||||
/* Return the signal number: */
|
||||
pthread->signo = sig;
|
||||
|
|
@ -219,10 +236,13 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
|||
* Enter a loop to process each thread in the linked
|
||||
* list:
|
||||
*/
|
||||
for (pthread = _thread_link_list; pthread != NULL;
|
||||
pthread = pthread->nxt) {
|
||||
TAILQ_FOREACH(pthread, &_thread_list, tle) {
|
||||
pthread_t pthread_saved = _thread_run;
|
||||
|
||||
/* Current thread inside critical region? */
|
||||
if (_thread_run->sig_defer_count > 0)
|
||||
pthread->sig_defer_count++;
|
||||
|
||||
_thread_run = pthread;
|
||||
_thread_signal(pthread,sig);
|
||||
|
||||
|
|
@ -232,6 +252,10 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
|
|||
*/
|
||||
_dispatch_signals();
|
||||
_thread_run = pthread_saved;
|
||||
|
||||
/* Current thread inside critical region? */
|
||||
if (_thread_run->sig_defer_count > 0)
|
||||
pthread->sig_defer_count--;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -284,7 +308,7 @@ _thread_signal(pthread_t pthread, int sig)
|
|||
pthread->interrupted = 1;
|
||||
|
||||
/* Change the state of the thread to run: */
|
||||
PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
|
||||
/* Return the signal number: */
|
||||
pthread->signo = sig;
|
||||
|
|
@ -296,6 +320,7 @@ _thread_signal(pthread_t pthread, int sig)
|
|||
*/
|
||||
case PS_FDR_WAIT:
|
||||
case PS_FDW_WAIT:
|
||||
case PS_POLL_WAIT:
|
||||
case PS_SLEEP_WAIT:
|
||||
case PS_SELECT_WAIT:
|
||||
if (sig != SIGCHLD ||
|
||||
|
|
@ -303,8 +328,11 @@ _thread_signal(pthread_t pthread, int sig)
|
|||
/* Flag the operation as interrupted: */
|
||||
pthread->interrupted = 1;
|
||||
|
||||
if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
|
||||
PTHREAD_WORKQ_REMOVE(pthread);
|
||||
|
||||
/* Change the state of the thread to run: */
|
||||
PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
|
||||
/* Return the signal number: */
|
||||
pthread->signo = sig;
|
||||
|
|
@ -319,7 +347,7 @@ _thread_signal(pthread_t pthread, int sig)
|
|||
if (!sigismember(&pthread->sigmask, sig) &&
|
||||
_thread_sigact[sig - 1].sa_handler != SIG_DFL) {
|
||||
/* Change the state of the thread to run: */
|
||||
PTHREAD_SIG_NEW_STATE(pthread,PS_RUNNING);
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
|
||||
/* Return the signal number: */
|
||||
pthread->signo = sig;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -77,6 +78,9 @@ sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
|
|||
gact.sa_mask = act->sa_mask;
|
||||
gact.sa_flags = 0;
|
||||
|
||||
/* Ensure the scheduling signal is masked: */
|
||||
sigaddset(&gact.sa_mask, _SCHED_SIGNAL);
|
||||
|
||||
/*
|
||||
* Check if the signal handler is being set to
|
||||
* the default or ignore handlers:
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
|
@ -41,7 +42,7 @@ sigwait(const sigset_t * set, int *sig)
|
|||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
sigset_t tempset;
|
||||
sigset_t tempset, waitset;
|
||||
struct sigaction act;
|
||||
|
||||
/*
|
||||
|
|
@ -51,17 +52,23 @@ sigwait(const sigset_t * set, int *sig)
|
|||
act.sa_flags = SA_RESTART;
|
||||
act.sa_mask = *set;
|
||||
|
||||
/* Ensure the scheduling signal is masked: */
|
||||
sigaddset(&act.sa_mask, _SCHED_SIGNAL);
|
||||
|
||||
/*
|
||||
* These signals can't be waited on.
|
||||
* Initialize the set of signals that will be waited on:
|
||||
*/
|
||||
sigdelset(&act.sa_mask, SIGKILL);
|
||||
sigdelset(&act.sa_mask, SIGSTOP);
|
||||
sigdelset(&act.sa_mask, _SCHED_SIGNAL);
|
||||
sigdelset(&act.sa_mask, SIGCHLD);
|
||||
sigdelset(&act.sa_mask, SIGINFO);
|
||||
waitset = *set;
|
||||
|
||||
/* These signals can't be waited on. */
|
||||
sigdelset(&waitset, SIGKILL);
|
||||
sigdelset(&waitset, SIGSTOP);
|
||||
sigdelset(&waitset, _SCHED_SIGNAL);
|
||||
sigdelset(&waitset, SIGCHLD);
|
||||
sigdelset(&waitset, SIGINFO);
|
||||
|
||||
/* Check to see if a pending signal is in the wait mask. */
|
||||
if (tempset = (_thread_run->sigpend & act.sa_mask)) {
|
||||
if (tempset = (_thread_run->sigpend & waitset)) {
|
||||
/* Enter a loop to find a pending signal: */
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (sigismember (&tempset, i))
|
||||
|
|
@ -81,17 +88,17 @@ sigwait(const sigset_t * set, int *sig)
|
|||
* Enter a loop to find the signals that are SIG_DFL. For
|
||||
* these signals we must install a dummy signal handler in
|
||||
* order for the kernel to pass them in to us. POSIX says
|
||||
* that the application must explicitly install a dummy
|
||||
* that the _application_ must explicitly install a dummy
|
||||
* handler for signals that are SIG_IGN in order to sigwait
|
||||
* on them. Note that SIG_IGN signals are left in the
|
||||
* mask because a subsequent sigaction could enable an
|
||||
* ignored signal.
|
||||
*/
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (sigismember(&act.sa_mask, i)) {
|
||||
if (_thread_sigact[i - 1].sa_handler == SIG_DFL)
|
||||
if (_thread_sys_sigaction(i,&act,NULL) != 0)
|
||||
ret = -1;
|
||||
if (sigismember(&waitset, i) &&
|
||||
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
|
||||
if (_thread_sys_sigaction(i,&act,NULL) != 0)
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
|
|
@ -101,7 +108,7 @@ sigwait(const sigset_t * set, int *sig)
|
|||
* mask is independent of the threads signal mask
|
||||
* and requires separate storage.
|
||||
*/
|
||||
_thread_run->data.sigwait = &act.sa_mask;
|
||||
_thread_run->data.sigwait = &waitset;
|
||||
|
||||
/* Wait for a signal: */
|
||||
_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);
|
||||
|
|
@ -119,7 +126,7 @@ sigwait(const sigset_t * set, int *sig)
|
|||
/* Restore the sigactions: */
|
||||
act.sa_handler = SIG_DFL;
|
||||
for (i = 1; i < NSIG; i++) {
|
||||
if (sigismember(&act.sa_mask, i) &&
|
||||
if (sigismember(&waitset, i) &&
|
||||
(_thread_sigact[i - 1].sa_handler == SIG_DFL)) {
|
||||
if (_thread_sys_sigaction(i,&act,NULL) != 0)
|
||||
ret = -1;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <errno.h>
|
||||
#ifdef _THREAD_SAFE
|
||||
|
|
@ -52,20 +53,19 @@ pthread_suspend_np(pthread_t thread)
|
|||
}
|
||||
|
||||
/*
|
||||
* Guard against preemption by a scheduling signal.
|
||||
* A change of thread state modifies the waiting
|
||||
* and priority queues.
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sched_defer();
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Suspend the thread. */
|
||||
PTHREAD_NEW_STATE(thread,PS_SUSPENDED);
|
||||
|
||||
/*
|
||||
* Reenable preemption and yield if a scheduling signal
|
||||
* occurred while in the critical region.
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sched_undefer();
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue