Revamp suspend and resume. While I'm here add pthread_suspend_all_np()

and pthread_resume_all_np().  These suspend and resume all threads except
the current thread, respectively.  The existing functions pthread_single_np()
and pthread_multi_np(), which formerly had no effect, now exhibit the same
behaviour and pthread_suspend_all_np() and pthread_resume_all_np().  These
functions have been added mostly for the native java port.

Don't allow the uthread kernel pipe to use the same descriptors as
stdio.  Mostily submitted by Oswald Buddenhagen <ossi@kde.org>.

Correct some minor style nits.
This commit is contained in:
deischen 2002-05-24 04:32:28 +00:00
parent abd4f3d6cc
commit 9ba1f9fa38
39 changed files with 684 additions and 912 deletions

View File

@ -189,14 +189,15 @@
if ((thrd)->state != newstate) { \ if ((thrd)->state != newstate) { \
if ((thrd)->state == PS_RUNNING) { \ if ((thrd)->state == PS_RUNNING) { \
PTHREAD_PRIOQ_REMOVE(thrd); \ PTHREAD_PRIOQ_REMOVE(thrd); \
PTHREAD_SET_STATE(thrd, newstate); \
PTHREAD_WAITQ_INSERT(thrd); \ PTHREAD_WAITQ_INSERT(thrd); \
} else if (newstate == PS_RUNNING) { \ } else if (newstate == PS_RUNNING) { \
PTHREAD_WAITQ_REMOVE(thrd); \ PTHREAD_WAITQ_REMOVE(thrd); \
PTHREAD_SET_STATE(thrd, newstate); \
PTHREAD_PRIOQ_INSERT_TAIL(thrd); \ PTHREAD_PRIOQ_INSERT_TAIL(thrd); \
} \ } \
} \ } \
_thread_kern_new_state = 0; \ _thread_kern_new_state = 0; \
PTHREAD_SET_STATE(thrd, newstate); \
} while (0) } while (0)
#else #else
#define PTHREAD_ASSERT(cond, msg) #define PTHREAD_ASSERT(cond, msg)
@ -399,18 +400,6 @@ struct pthread_attr {
#define PTHREAD_CREATE_RUNNING 0 #define PTHREAD_CREATE_RUNNING 0
#define PTHREAD_CREATE_SUSPENDED 1 #define PTHREAD_CREATE_SUSPENDED 1
/*
* Additional state for a thread suspended with pthread_suspend_np().
*/
enum pthread_susp {
SUSP_NO, /* Not suspended. */
SUSP_YES, /* Suspended. */
SUSP_JOIN, /* Suspended, joining. */
SUSP_NOWAIT, /* Suspended, was in a mutex or condition queue. */
SUSP_MUTEX_WAIT,/* Suspended, still in a mutex queue. */
SUSP_COND_WAIT /* Suspended, still in a condition queue. */
};
/* /*
* Miscellaneous definitions. * Miscellaneous definitions.
*/ */
@ -684,8 +673,6 @@ struct pthread {
#define PTHREAD_CANCEL_NEEDED 0x0010 #define PTHREAD_CANCEL_NEEDED 0x0010
int cancelflags; int cancelflags;
enum pthread_susp suspended;
thread_continuation_t continuation; thread_continuation_t continuation;
/* /*
@ -802,7 +789,8 @@ struct pthread {
#define PTHREAD_FLAGS_IN_FDQ 0x0040 /* in fd lock queue using qe link */ #define PTHREAD_FLAGS_IN_FDQ 0x0040 /* in fd lock queue using qe link */
#define PTHREAD_FLAGS_IN_CONDQ 0x0080 /* in condition queue using sqe link*/ #define PTHREAD_FLAGS_IN_CONDQ 0x0080 /* in condition queue using sqe link*/
#define PTHREAD_FLAGS_IN_MUTEXQ 0x0100 /* in mutex queue using sqe link */ #define PTHREAD_FLAGS_IN_MUTEXQ 0x0100 /* in mutex queue using sqe link */
#define PTHREAD_FLAGS_TRACE 0x0200 /* for debugging purposes */ #define PTHREAD_FLAGS_SUSPENDED 0x0200 /* thread is suspended */
#define PTHREAD_FLAGS_TRACE 0x0400 /* for debugging purposes */
#define PTHREAD_FLAGS_IN_SYNCQ \ #define PTHREAD_FLAGS_IN_SYNCQ \
(PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ) (PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ)
@ -880,17 +868,6 @@ SCLASS struct pthread * volatile _last_user_thread
; ;
#endif #endif
/*
* Ptr to the thread running in single-threaded mode or NULL if
* running multi-threaded (default POSIX behaviour).
*/
SCLASS struct pthread * volatile _thread_single
#ifdef GLOBAL_PTHREAD_PRIVATE
= NULL;
#else
;
#endif
/* List of all threads: */ /* List of all threads: */
SCLASS TAILQ_HEAD(, pthread) _thread_list SCLASS TAILQ_HEAD(, pthread) _thread_list
#ifdef GLOBAL_PTHREAD_PRIVATE #ifdef GLOBAL_PTHREAD_PRIVATE

View File

@ -78,20 +78,6 @@ _pthread_cancel(pthread_t pthread)
break; break;
case PS_SUSPENDED: case PS_SUSPENDED:
if (pthread->suspended == SUSP_NO ||
pthread->suspended == SUSP_YES ||
pthread->suspended == SUSP_JOIN ||
pthread->suspended == SUSP_NOWAIT) {
/*
* This thread isn't in any scheduling
* queues; just change it's state:
*/
pthread->cancelflags |=
PTHREAD_CANCELLING;
PTHREAD_SET_STATE(pthread, PS_RUNNING);
break;
}
/* FALLTHROUGH */
case PS_MUTEX_WAIT: case PS_MUTEX_WAIT:
case PS_COND_WAIT: case PS_COND_WAIT:
case PS_FDLR_WAIT: case PS_FDLR_WAIT:
@ -109,7 +95,7 @@ _pthread_cancel(pthread_t pthread)
*/ */
pthread->interrupted = 1; pthread->interrupted = 1;
pthread->cancelflags |= PTHREAD_CANCEL_NEEDED; pthread->cancelflags |= PTHREAD_CANCEL_NEEDED;
PTHREAD_NEW_STATE(pthread,PS_RUNNING); PTHREAD_NEW_STATE(pthread, PS_RUNNING);
pthread->continuation = finish_cancellation; pthread->continuation = finish_cancellation;
break; break;

View File

@ -524,15 +524,9 @@ _pthread_cond_signal(pthread_cond_t * cond)
if ((pthread = cond_queue_deq(*cond)) != NULL) { if ((pthread = cond_queue_deq(*cond)) != NULL) {
/* /*
* Unless the thread is currently suspended, * Wake up the signaled thread:
* allow it to run. If the thread is suspended,
* make a note that the thread isn't in a wait
* queue any more.
*/ */
if (pthread->state != PS_SUSPENDED) PTHREAD_NEW_STATE(pthread, PS_RUNNING);
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
else
pthread->suspended = SUSP_NOWAIT;
} }
/* Check for no more waiters: */ /* Check for no more waiters: */
@ -596,15 +590,9 @@ _pthread_cond_broadcast(pthread_cond_t * cond)
*/ */
while ((pthread = cond_queue_deq(*cond)) != NULL) { while ((pthread = cond_queue_deq(*cond)) != NULL) {
/* /*
* Unless the thread is currently suspended, * Wake up the signaled thread:
* allow it to run. If the thread is suspended,
* make a note that the thread isn't in a wait
* queue any more.
*/ */
if (pthread->state != PS_SUSPENDED) PTHREAD_NEW_STATE(pthread, PS_RUNNING);
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
else
pthread->suspended = SUSP_NOWAIT;
} }
/* There are no more waiting threads: */ /* There are no more waiting threads: */

View File

@ -202,22 +202,8 @@ _pthread_exit(void *status)
pthread = curthread->joiner; pthread = curthread->joiner;
curthread->joiner = NULL; curthread->joiner = NULL;
switch (pthread->suspended) { /* Make the joining thread runnable: */
case SUSP_JOIN: PTHREAD_NEW_STATE(pthread, PS_RUNNING);
/*
* The joining thread is suspended. Change the
* suspension state to make the thread runnable when it
* is resumed:
*/
pthread->suspended = SUSP_NO;
break;
case SUSP_NO:
/* Make the joining thread runnable: */
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
break;
default:
PANIC("Unreachable code reached");
}
/* Set the return value for the joining thread: */ /* Set the return value for the joining thread: */
pthread->join_status.ret = curthread->ret; pthread->join_status.ret = curthread->ret;

View File

@ -201,20 +201,21 @@ _thread_init(void)
PANIC("Can't open console"); PANIC("Can't open console");
if (setlogin("root") == -1) if (setlogin("root") == -1)
PANIC("Can't set login to root"); PANIC("Can't set login to root");
if (__sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1) if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1)
PANIC("Can't set controlling terminal"); PANIC("Can't set controlling terminal");
if (__sys_dup2(fd,0) == -1 || if (__sys_dup2(fd, 0) == -1 ||
__sys_dup2(fd,1) == -1 || __sys_dup2(fd, 1) == -1 ||
__sys_dup2(fd,2) == -1) __sys_dup2(fd, 2) == -1)
PANIC("Can't dup2"); PANIC("Can't dup2");
} }
/* Get the standard I/O flags before messing with them : */ /* Get the standard I/O flags before messing with them : */
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++) {
if (((_pthread_stdio_flags[i] = if (((_pthread_stdio_flags[i] =
__sys_fcntl(i,F_GETFL, NULL)) == -1) && __sys_fcntl(i, F_GETFL, NULL)) == -1) &&
(errno != EBADF)) (errno != EBADF))
PANIC("Cannot get stdio flags"); PANIC("Cannot get stdio flags");
}
/* /*
* Create a pipe that is written to by the signal handler to prevent * Create a pipe that is written to by the signal handler to prevent
@ -224,8 +225,21 @@ _thread_init(void)
/* Cannot create pipe, so abort: */ /* Cannot create pipe, so abort: */
PANIC("Cannot create kernel pipe"); PANIC("Cannot create kernel pipe");
} }
/*
* Make sure the pipe does not get in the way of stdio:
*/
for (i = 0; i < 2; i++) {
if (_thread_kern_pipe[i] < 3) {
fd = __sys_fcntl(_thread_kern_pipe[i], F_DUPFD, 3);
if (fd == -1)
PANIC("Cannot create kernel pipe");
__sys_close(_thread_kern_pipe[i]);
_thread_kern_pipe[i] = fd;
}
}
/* Get the flags for the read pipe: */ /* Get the flags for the read pipe: */
else if ((flags = __sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) { if ((flags = __sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) {
/* Abort this application: */ /* Abort this application: */
PANIC("Cannot get kernel read pipe flags"); PANIC("Cannot get kernel read pipe flags");
} }

View File

@ -31,16 +31,20 @@
* *
* $FreeBSD$ * $FreeBSD$
*/ */
#include <string.h>
#include <pthread.h> #include <pthread.h>
#include "pthread_private.h" #include <pthread_np.h>
__weak_reference(_pthread_multi_np, pthread_multi_np); __weak_reference(_pthread_multi_np, pthread_multi_np);
int int
_pthread_multi_np() _pthread_multi_np()
{ {
/* Return to multi-threaded scheduling mode: */ /* Return to multi-threaded scheduling mode: */
_thread_single = NULL; /*
return(0); * XXX - Do we want to do this?
* __is_threaded = 1;
*/
pthread_resume_all_np();
return (0);
} }

View File

@ -887,21 +887,9 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
*/ */
if (((*mutex)->m_owner = if (((*mutex)->m_owner =
mutex_queue_deq(*mutex)) != NULL) { mutex_queue_deq(*mutex)) != NULL) {
/* /* Make the new owner runnable: */
* Unless the new owner of the mutex is PTHREAD_NEW_STATE((*mutex)->m_owner,
* currently suspended, allow the owner PS_RUNNING);
* to run. If the thread is suspended,
* make a note that the thread isn't in
* a wait queue any more.
*/
if (((*mutex)->m_owner->state !=
PS_SUSPENDED)) {
PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_RUNNING);
} else {
(*mutex)->m_owner->suspended =
SUSP_NOWAIT;
}
/* /*
* Add the mutex to the threads list of * Add the mutex to the threads list of
@ -1019,20 +1007,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
(*mutex)->m_prio; (*mutex)->m_prio;
/* /*
* Unless the new owner of the mutex is * Make the new owner runnable:
* currently suspended, allow the owner
* to run. If the thread is suspended,
* make a note that the thread isn't in
* a wait queue any more.
*/ */
if (((*mutex)->m_owner->state != PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_SUSPENDED)) { PS_RUNNING);
PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_RUNNING);
} else {
(*mutex)->m_owner->suspended =
SUSP_NOWAIT;
}
} }
} }
break; break;
@ -1148,20 +1126,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
(*mutex)->m_prio; (*mutex)->m_prio;
/* /*
* Unless the new owner of the mutex is * Make the new owner runnable:
* currently suspended, allow the owner
* to run. If the thread is suspended,
* make a note that the thread isn't in
* a wait queue any more.
*/ */
if (((*mutex)->m_owner->state != PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_SUSPENDED)) { PS_RUNNING);
PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_RUNNING);
} else {
(*mutex)->m_owner->suspended =
SUSP_NOWAIT;
}
} }
} }
break; break;

View File

@ -164,52 +164,74 @@ _pq_remove(pq_queue_t *pq, pthread_t pthread)
void void
_pq_insert_head(pq_queue_t *pq, pthread_t pthread) _pq_insert_head(pq_queue_t *pq, pthread_t pthread)
{ {
int prio = pthread->active_priority; int prio;
/* /*
* Make some assertions when debugging is enabled: * Don't insert suspended threads into the priority queue.
* The caller is responsible for setting the threads state.
*/ */
_PQ_ASSERT_INACTIVE("_pq_insert_head: pq_active"); if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
_PQ_SET_ACTIVE(); /* Make sure the threads state is suspended. */
_PQ_ASSERT_NOT_QUEUED(pthread, if (pthread->state != PS_SUSPENDED)
"_pq_insert_head: Already in priority queue"); PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
_PQ_ASSERT_PROTECTED("_pq_insert_head: prioq not protected!"); } else {
/*
* 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");
_PQ_ASSERT_PROTECTED("_pq_insert_head: prioq not protected!");
TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe); prio = pthread->active_priority;
if (pq->pq_lists[prio].pl_queued == 0) TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe);
/* Insert the list into the priority queue: */ if (pq->pq_lists[prio].pl_queued == 0)
pq_insert_prio_list(pq, prio); /* Insert the list into the priority queue: */
pq_insert_prio_list(pq, prio);
/* Mark this thread as being in the priority queue. */ /* Mark this thread as being in the priority queue. */
pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
_PQ_CLEAR_ACTIVE(); _PQ_CLEAR_ACTIVE();
}
} }
void void
_pq_insert_tail(pq_queue_t *pq, pthread_t pthread) _pq_insert_tail(pq_queue_t *pq, pthread_t pthread)
{ {
int prio = pthread->active_priority; int prio;
/* /*
* Make some assertions when debugging is enabled: * Don't insert suspended threads into the priority queue.
* The caller is responsible for setting the threads state.
*/ */
_PQ_ASSERT_INACTIVE("_pq_insert_tail: pq_active"); if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
_PQ_SET_ACTIVE(); /* Make sure the threads state is suspended. */
_PQ_ASSERT_NOT_QUEUED(pthread, if (pthread->state != PS_SUSPENDED)
"_pq_insert_tail: Already in priority queue"); PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
_PQ_ASSERT_PROTECTED("_pq_insert_tail: prioq not protected!"); } else {
/*
* 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");
_PQ_ASSERT_PROTECTED("_pq_insert_tail: prioq not protected!");
TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe); prio = pthread->active_priority;
if (pq->pq_lists[prio].pl_queued == 0) TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe);
/* Insert the list into the priority queue: */ if (pq->pq_lists[prio].pl_queued == 0)
pq_insert_prio_list(pq, prio); /* Insert the list into the priority queue: */
pq_insert_prio_list(pq, prio);
/* Mark this thread as being in the priority queue. */ /* Mark this thread as being in the priority queue. */
pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
_PQ_CLEAR_ACTIVE(); _PQ_CLEAR_ACTIVE();
}
} }
@ -237,6 +259,17 @@ _pq_first(pq_queue_t *pq)
/* Mark the list as not being in the queue: */ /* Mark the list as not being in the queue: */
pql->pl_queued = 0; pql->pl_queued = 0;
} else if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
/*
* This thread is suspended; remove it from the
* list and ensure its state is suspended.
*/
TAILQ_REMOVE(&pql->pl_head, pthread, pqe);
PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
/* This thread is now longer in the priority queue. */
pthread->flags &= ~PTHREAD_FLAGS_IN_PRIOQ;
pthread = NULL;
} }
} }

View File

@ -35,62 +35,77 @@
#include <pthread.h> #include <pthread.h>
#include "pthread_private.h" #include "pthread_private.h"
static void resume_common(struct pthread *);
__weak_reference(_pthread_resume_np, pthread_resume_np); __weak_reference(_pthread_resume_np, pthread_resume_np);
__weak_reference(_pthread_resume_all_np, pthread_resume_all_np);
/* Resume a thread: */ /* Resume a thread: */
int int
_pthread_resume_np(pthread_t thread) _pthread_resume_np(pthread_t thread)
{ {
int ret; int ret;
enum pthread_susp old_suspended;
/* Find the thread in the list of active threads: */ /* Find the thread in the list of active threads: */
if ((ret = _find_thread(thread)) == 0) { if ((ret = _find_thread(thread)) == 0) {
/* Cancel any pending suspensions: */ /*
old_suspended = thread->suspended; * Defer signals to protect the scheduling queues
thread->suspended = SUSP_NO; * from access by the signal handler:
*/
_thread_kern_sig_defer();
/* Is it currently suspended? */ if ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0)
if (thread->state == PS_SUSPENDED) { resume_common(thread);
/*
* Defer signals to protect the scheduling queues
* from access by the signal handler:
*/
_thread_kern_sig_defer();
switch (old_suspended) { /*
case SUSP_MUTEX_WAIT: * Undefer and handle pending signals, yielding if
/* Set the thread's state back. */ * necessary:
PTHREAD_SET_STATE(thread,PS_MUTEX_WAIT); */
break; _thread_kern_sig_undefer();
case SUSP_COND_WAIT: }
/* Set the thread's state back. */ return (ret);
PTHREAD_SET_STATE(thread,PS_COND_WAIT); }
break;
case SUSP_JOIN: void
/* Set the thread's state back. */ _pthread_resume_all_np(void)
PTHREAD_SET_STATE(thread,PS_JOIN); {
break; struct pthread *curthread = _get_curthread();
case SUSP_NOWAIT: struct pthread *thread;
/* Allow the thread to run. */
PTHREAD_SET_STATE(thread,PS_RUNNING); /*
PTHREAD_WAITQ_REMOVE(thread); * Defer signals to protect the scheduling queues from access
PTHREAD_PRIOQ_INSERT_TAIL(thread); * by the signal handler:
break; */
case SUSP_NO: _thread_kern_sig_defer();
case SUSP_YES:
/* Allow the thread to run. */ TAILQ_FOREACH(thread, &_thread_list, tle) {
PTHREAD_SET_STATE(thread,PS_RUNNING); if ((thread != curthread) &&
PTHREAD_PRIOQ_INSERT_TAIL(thread); ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0))
break; resume_common(thread);
} }
/* /*
* Undefer and handle pending signals, yielding if * Undefer and handle pending signals, yielding if necessary:
* necessary: */
*/ _thread_kern_sig_undefer();
_thread_kern_sig_undefer(); }
}
static void
resume_common(struct pthread *thread)
{
/* Clear the suspend flag: */
thread->flags &= ~PTHREAD_FLAGS_SUSPENDED;
/*
* If the thread's state is suspended, that means it is
* now runnable but not in any scheduling queue. Set the
* state to running and insert it into the run queue.
*/
if (thread->state == PS_SUSPENDED) {
PTHREAD_SET_STATE(thread, PS_RUNNING);
if (thread->priority_mutex_count > 0)
PTHREAD_PRIOQ_INSERT_HEAD(thread);
else
PTHREAD_PRIOQ_INSERT_TAIL(thread);
} }
return(ret);
} }

View File

@ -54,7 +54,7 @@ static void thread_sigframe_save(struct pthread *thread,
static void thread_sig_invoke_handler(int sig, siginfo_t *info, static void thread_sig_invoke_handler(int sig, siginfo_t *info,
ucontext_t *ucp); ucontext_t *ucp);
/* #define DEBUG_SIGNAL */ /*#define DEBUG_SIGNAL*/
#ifdef DEBUG_SIGNAL #ifdef DEBUG_SIGNAL
#define DBG_MSG stdout_debug #define DBG_MSG stdout_debug
#else #else
@ -375,7 +375,8 @@ thread_sig_find(int sig)
return (NULL); return (NULL);
} }
else if ((handler_installed != 0) && else if ((handler_installed != 0) &&
!sigismember(&pthread->sigmask, sig)) { !sigismember(&pthread->sigmask, sig) &&
((pthread->flags & PTHREAD_FLAGS_SUSPENDED) == 0)) {
if (pthread->state == PS_SIGSUSPEND) { if (pthread->state == PS_SIGSUSPEND) {
if (suspended_thread == NULL) if (suspended_thread == NULL)
suspended_thread = pthread; suspended_thread = pthread;
@ -791,10 +792,17 @@ thread_sig_add(struct pthread *pthread, int sig, int has_args)
/* /*
* The thread should be removed from all scheduling * The thread should be removed from all scheduling
* queues at this point. Raise the priority and place * queues at this point. Raise the priority and place
* the thread in the run queue. * the thread in the run queue. It is also possible
* for a signal to be sent to a suspended thread,
* mostly via pthread_kill(). If a thread is suspended,
* don't insert it into the priority queue; just set
* its state to suspended and it will run the signal
* handler when it is resumed.
*/ */
pthread->active_priority |= PTHREAD_SIGNAL_PRIORITY; pthread->active_priority |= PTHREAD_SIGNAL_PRIORITY;
if (thread_is_active == 0) if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0)
PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
else if (thread_is_active == 0)
PTHREAD_PRIOQ_INSERT_TAIL(pthread); PTHREAD_PRIOQ_INSERT_TAIL(pthread);
} }
} }

View File

@ -31,17 +31,19 @@
* *
* $FreeBSD$ * $FreeBSD$
*/ */
#include <string.h>
#include <pthread.h> #include <pthread.h>
#include "pthread_private.h" #include <pthread_np.h>
__weak_reference(_pthread_single_np, pthread_single_np); __weak_reference(_pthread_single_np, pthread_single_np);
int _pthread_single_np() int _pthread_single_np()
{ {
struct pthread *curthread = _get_curthread();
/* Enter single-threaded (non-POSIX) scheduling mode: */ /* Enter single-threaded (non-POSIX) scheduling mode: */
_thread_single = curthread; pthread_suspend_all_np();
return(0); /*
* XXX - Do we want to do this?
* __is_threaded = 0;
*/
return (0);
} }

View File

@ -93,7 +93,7 @@ _spinlock_debug(spinlock_t *lck, char *fname, int lineno)
cnt++; cnt++;
if (cnt > 100) { if (cnt > 100) {
char str[256]; char str[256];
snprintf(str, sizeof(str), "%s - Warning: Thread %p attempted to lock %p from %s (%d) was left locked from %s (%d)\n", _getprogname(), curthread, lck, fname, lineno, lck->fname, lck->lineno); snprintf(str, sizeof(str), "%s - Warning: Thread %p attempted to lock %p from %s (%d) was left locked from %s (%d)\n", getprogname(), curthread, lck, fname, lineno, lck->fname, lck->lineno);
__sys_write(2,str,strlen(str)); __sys_write(2,str,strlen(str));
__sleep(1); __sleep(1);
cnt = 0; cnt = 0;

View File

@ -35,9 +35,10 @@
#include <pthread.h> #include <pthread.h>
#include "pthread_private.h" #include "pthread_private.h"
static void finish_suspension(void *arg); static void suspend_common(struct pthread *thread);
__weak_reference(_pthread_suspend_np, pthread_suspend_np); __weak_reference(_pthread_suspend_np, pthread_suspend_np);
__weak_reference(_pthread_suspend_all_np, pthread_suspend_all_np);
/* Suspend a thread: */ /* Suspend a thread: */
int int
@ -45,100 +46,19 @@ _pthread_suspend_np(pthread_t thread)
{ {
int ret; int ret;
/* Suspending the current thread doesn't make sense. */
if (thread == _get_curthread())
ret = EDEADLK;
/* Find the thread in the list of active threads: */ /* Find the thread in the list of active threads: */
if ((ret = _find_thread(thread)) == 0) { else if ((ret = _find_thread(thread)) == 0) {
/* /*
* Defer signals to protect the scheduling queues from * Defer signals to protect the scheduling queues from
* access by the signal handler: * access by the signal handler:
*/ */
_thread_kern_sig_defer(); _thread_kern_sig_defer();
switch (thread->state) { suspend_common(thread);
case PS_RUNNING:
/*
* Remove the thread from the priority queue and
* set the state to suspended:
*/
PTHREAD_PRIOQ_REMOVE(thread);
PTHREAD_SET_STATE(thread, PS_SUSPENDED);
break;
case PS_SPINBLOCK:
case PS_FDR_WAIT:
case PS_FDW_WAIT:
case PS_POLL_WAIT:
case PS_SELECT_WAIT:
/*
* Remove these threads from the work queue
* and mark the operation as interrupted:
*/
if ((thread->flags & PTHREAD_FLAGS_IN_WORKQ) != 0)
PTHREAD_WORKQ_REMOVE(thread);
_thread_seterrno(thread,EINTR);
/* FALLTHROUGH */
case PS_SLEEP_WAIT:
thread->interrupted = 1;
/* FALLTHROUGH */
case PS_SIGTHREAD:
case PS_WAIT_WAIT:
case PS_SIGSUSPEND:
case PS_SIGWAIT:
/*
* Remove these threads from the waiting queue and
* set their state to suspended:
*/
PTHREAD_WAITQ_REMOVE(thread);
PTHREAD_SET_STATE(thread, PS_SUSPENDED);
break;
case PS_MUTEX_WAIT:
/* Mark the thread as suspended and still in a queue. */
thread->suspended = SUSP_MUTEX_WAIT;
PTHREAD_SET_STATE(thread, PS_SUSPENDED);
break;
case PS_COND_WAIT:
/* Mark the thread as suspended and still in a queue. */
thread->suspended = SUSP_COND_WAIT;
PTHREAD_SET_STATE(thread, PS_SUSPENDED);
break;
case PS_JOIN:
/* Mark the thread as suspended and joining: */
thread->suspended = SUSP_JOIN;
PTHREAD_NEW_STATE(thread, PS_SUSPENDED);
break;
case PS_FDLR_WAIT:
case PS_FDLW_WAIT:
case PS_FILE_WAIT:
/* Mark the thread as suspended: */
thread->suspended = SUSP_YES;
/*
* Threads in these states may be in queues.
* In order to preserve queue integrity, the
* cancelled thread must remove itself from the
* queue. Mark the thread as interrupted and
* set the state to running. When the thread
* resumes, it will remove itself from the queue
* and call the suspension completion routine.
*/
thread->interrupted = 1;
_thread_seterrno(thread, EINTR);
PTHREAD_NEW_STATE(thread, PS_RUNNING);
thread->continuation = finish_suspension;
break;
case PS_DEAD:
case PS_DEADLOCK:
case PS_STATE_MAX:
case PS_SUSPENDED:
/* Nothing needs to be done: */
break;
}
/* /*
* Undefer and handle pending signals, yielding if * Undefer and handle pending signals, yielding if
@ -146,16 +66,39 @@ _pthread_suspend_np(pthread_t thread)
*/ */
_thread_kern_sig_undefer(); _thread_kern_sig_undefer();
} }
return(ret); return (ret);
} }
static void void
finish_suspension(void *arg) _pthread_suspend_all_np(void)
{ {
struct pthread *curthread = _get_curthread(); struct pthread *curthread = _get_curthread();
struct pthread *thread;
if (curthread->suspended != SUSP_NO) /*
_thread_kern_sched_state(PS_SUSPENDED, __FILE__, __LINE__); * Defer signals to protect the scheduling queues from
* access by the signal handler:
*/
_thread_kern_sig_defer();
TAILQ_FOREACH(thread, &_thread_list, tle) {
if (thread != curthread)
suspend_common(thread);
}
/*
* Undefer and handle pending signals, yielding if
* necessary:
*/
_thread_kern_sig_undefer();
} }
void
suspend_common(struct pthread *thread)
{
thread->flags |= PTHREAD_FLAGS_SUSPENDED;
if (thread->flags & PTHREAD_FLAGS_IN_PRIOQ) {
PTHREAD_PRIOQ_REMOVE(thread);
PTHREAD_SET_STATE(thread, PS_SUSPENDED);
}
}

View File

@ -78,20 +78,6 @@ _pthread_cancel(pthread_t pthread)
break; break;
case PS_SUSPENDED: case PS_SUSPENDED:
if (pthread->suspended == SUSP_NO ||
pthread->suspended == SUSP_YES ||
pthread->suspended == SUSP_JOIN ||
pthread->suspended == SUSP_NOWAIT) {
/*
* This thread isn't in any scheduling
* queues; just change it's state:
*/
pthread->cancelflags |=
PTHREAD_CANCELLING;
PTHREAD_SET_STATE(pthread, PS_RUNNING);
break;
}
/* FALLTHROUGH */
case PS_MUTEX_WAIT: case PS_MUTEX_WAIT:
case PS_COND_WAIT: case PS_COND_WAIT:
case PS_FDLR_WAIT: case PS_FDLR_WAIT:
@ -109,7 +95,7 @@ _pthread_cancel(pthread_t pthread)
*/ */
pthread->interrupted = 1; pthread->interrupted = 1;
pthread->cancelflags |= PTHREAD_CANCEL_NEEDED; pthread->cancelflags |= PTHREAD_CANCEL_NEEDED;
PTHREAD_NEW_STATE(pthread,PS_RUNNING); PTHREAD_NEW_STATE(pthread, PS_RUNNING);
pthread->continuation = finish_cancellation; pthread->continuation = finish_cancellation;
break; break;

View File

@ -524,15 +524,9 @@ _pthread_cond_signal(pthread_cond_t * cond)
if ((pthread = cond_queue_deq(*cond)) != NULL) { if ((pthread = cond_queue_deq(*cond)) != NULL) {
/* /*
* Unless the thread is currently suspended, * Wake up the signaled thread:
* allow it to run. If the thread is suspended,
* make a note that the thread isn't in a wait
* queue any more.
*/ */
if (pthread->state != PS_SUSPENDED) PTHREAD_NEW_STATE(pthread, PS_RUNNING);
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
else
pthread->suspended = SUSP_NOWAIT;
} }
/* Check for no more waiters: */ /* Check for no more waiters: */
@ -596,15 +590,9 @@ _pthread_cond_broadcast(pthread_cond_t * cond)
*/ */
while ((pthread = cond_queue_deq(*cond)) != NULL) { while ((pthread = cond_queue_deq(*cond)) != NULL) {
/* /*
* Unless the thread is currently suspended, * Wake up the signaled thread:
* allow it to run. If the thread is suspended,
* make a note that the thread isn't in a wait
* queue any more.
*/ */
if (pthread->state != PS_SUSPENDED) PTHREAD_NEW_STATE(pthread, PS_RUNNING);
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
else
pthread->suspended = SUSP_NOWAIT;
} }
/* There are no more waiting threads: */ /* There are no more waiting threads: */

View File

@ -202,22 +202,8 @@ _pthread_exit(void *status)
pthread = curthread->joiner; pthread = curthread->joiner;
curthread->joiner = NULL; curthread->joiner = NULL;
switch (pthread->suspended) { /* Make the joining thread runnable: */
case SUSP_JOIN: PTHREAD_NEW_STATE(pthread, PS_RUNNING);
/*
* The joining thread is suspended. Change the
* suspension state to make the thread runnable when it
* is resumed:
*/
pthread->suspended = SUSP_NO;
break;
case SUSP_NO:
/* Make the joining thread runnable: */
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
break;
default:
PANIC("Unreachable code reached");
}
/* Set the return value for the joining thread: */ /* Set the return value for the joining thread: */
pthread->join_status.ret = curthread->ret; pthread->join_status.ret = curthread->ret;

View File

@ -201,20 +201,21 @@ _thread_init(void)
PANIC("Can't open console"); PANIC("Can't open console");
if (setlogin("root") == -1) if (setlogin("root") == -1)
PANIC("Can't set login to root"); PANIC("Can't set login to root");
if (__sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1) if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1)
PANIC("Can't set controlling terminal"); PANIC("Can't set controlling terminal");
if (__sys_dup2(fd,0) == -1 || if (__sys_dup2(fd, 0) == -1 ||
__sys_dup2(fd,1) == -1 || __sys_dup2(fd, 1) == -1 ||
__sys_dup2(fd,2) == -1) __sys_dup2(fd, 2) == -1)
PANIC("Can't dup2"); PANIC("Can't dup2");
} }
/* Get the standard I/O flags before messing with them : */ /* Get the standard I/O flags before messing with them : */
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++) {
if (((_pthread_stdio_flags[i] = if (((_pthread_stdio_flags[i] =
__sys_fcntl(i,F_GETFL, NULL)) == -1) && __sys_fcntl(i, F_GETFL, NULL)) == -1) &&
(errno != EBADF)) (errno != EBADF))
PANIC("Cannot get stdio flags"); PANIC("Cannot get stdio flags");
}
/* /*
* Create a pipe that is written to by the signal handler to prevent * Create a pipe that is written to by the signal handler to prevent
@ -224,8 +225,21 @@ _thread_init(void)
/* Cannot create pipe, so abort: */ /* Cannot create pipe, so abort: */
PANIC("Cannot create kernel pipe"); PANIC("Cannot create kernel pipe");
} }
/*
* Make sure the pipe does not get in the way of stdio:
*/
for (i = 0; i < 2; i++) {
if (_thread_kern_pipe[i] < 3) {
fd = __sys_fcntl(_thread_kern_pipe[i], F_DUPFD, 3);
if (fd == -1)
PANIC("Cannot create kernel pipe");
__sys_close(_thread_kern_pipe[i]);
_thread_kern_pipe[i] = fd;
}
}
/* Get the flags for the read pipe: */ /* Get the flags for the read pipe: */
else if ((flags = __sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) { if ((flags = __sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) {
/* Abort this application: */ /* Abort this application: */
PANIC("Cannot get kernel read pipe flags"); PANIC("Cannot get kernel read pipe flags");
} }

View File

@ -31,16 +31,20 @@
* *
* $FreeBSD$ * $FreeBSD$
*/ */
#include <string.h>
#include <pthread.h> #include <pthread.h>
#include "pthread_private.h" #include <pthread_np.h>
__weak_reference(_pthread_multi_np, pthread_multi_np); __weak_reference(_pthread_multi_np, pthread_multi_np);
int int
_pthread_multi_np() _pthread_multi_np()
{ {
/* Return to multi-threaded scheduling mode: */ /* Return to multi-threaded scheduling mode: */
_thread_single = NULL; /*
return(0); * XXX - Do we want to do this?
* __is_threaded = 1;
*/
pthread_resume_all_np();
return (0);
} }

View File

@ -887,21 +887,9 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
*/ */
if (((*mutex)->m_owner = if (((*mutex)->m_owner =
mutex_queue_deq(*mutex)) != NULL) { mutex_queue_deq(*mutex)) != NULL) {
/* /* Make the new owner runnable: */
* Unless the new owner of the mutex is PTHREAD_NEW_STATE((*mutex)->m_owner,
* currently suspended, allow the owner PS_RUNNING);
* to run. If the thread is suspended,
* make a note that the thread isn't in
* a wait queue any more.
*/
if (((*mutex)->m_owner->state !=
PS_SUSPENDED)) {
PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_RUNNING);
} else {
(*mutex)->m_owner->suspended =
SUSP_NOWAIT;
}
/* /*
* Add the mutex to the threads list of * Add the mutex to the threads list of
@ -1019,20 +1007,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
(*mutex)->m_prio; (*mutex)->m_prio;
/* /*
* Unless the new owner of the mutex is * Make the new owner runnable:
* currently suspended, allow the owner
* to run. If the thread is suspended,
* make a note that the thread isn't in
* a wait queue any more.
*/ */
if (((*mutex)->m_owner->state != PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_SUSPENDED)) { PS_RUNNING);
PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_RUNNING);
} else {
(*mutex)->m_owner->suspended =
SUSP_NOWAIT;
}
} }
} }
break; break;
@ -1148,20 +1126,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
(*mutex)->m_prio; (*mutex)->m_prio;
/* /*
* Unless the new owner of the mutex is * Make the new owner runnable:
* currently suspended, allow the owner
* to run. If the thread is suspended,
* make a note that the thread isn't in
* a wait queue any more.
*/ */
if (((*mutex)->m_owner->state != PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_SUSPENDED)) { PS_RUNNING);
PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_RUNNING);
} else {
(*mutex)->m_owner->suspended =
SUSP_NOWAIT;
}
} }
} }
break; break;

View File

@ -164,52 +164,74 @@ _pq_remove(pq_queue_t *pq, pthread_t pthread)
void void
_pq_insert_head(pq_queue_t *pq, pthread_t pthread) _pq_insert_head(pq_queue_t *pq, pthread_t pthread)
{ {
int prio = pthread->active_priority; int prio;
/* /*
* Make some assertions when debugging is enabled: * Don't insert suspended threads into the priority queue.
* The caller is responsible for setting the threads state.
*/ */
_PQ_ASSERT_INACTIVE("_pq_insert_head: pq_active"); if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
_PQ_SET_ACTIVE(); /* Make sure the threads state is suspended. */
_PQ_ASSERT_NOT_QUEUED(pthread, if (pthread->state != PS_SUSPENDED)
"_pq_insert_head: Already in priority queue"); PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
_PQ_ASSERT_PROTECTED("_pq_insert_head: prioq not protected!"); } else {
/*
* 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");
_PQ_ASSERT_PROTECTED("_pq_insert_head: prioq not protected!");
TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe); prio = pthread->active_priority;
if (pq->pq_lists[prio].pl_queued == 0) TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe);
/* Insert the list into the priority queue: */ if (pq->pq_lists[prio].pl_queued == 0)
pq_insert_prio_list(pq, prio); /* Insert the list into the priority queue: */
pq_insert_prio_list(pq, prio);
/* Mark this thread as being in the priority queue. */ /* Mark this thread as being in the priority queue. */
pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
_PQ_CLEAR_ACTIVE(); _PQ_CLEAR_ACTIVE();
}
} }
void void
_pq_insert_tail(pq_queue_t *pq, pthread_t pthread) _pq_insert_tail(pq_queue_t *pq, pthread_t pthread)
{ {
int prio = pthread->active_priority; int prio;
/* /*
* Make some assertions when debugging is enabled: * Don't insert suspended threads into the priority queue.
* The caller is responsible for setting the threads state.
*/ */
_PQ_ASSERT_INACTIVE("_pq_insert_tail: pq_active"); if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
_PQ_SET_ACTIVE(); /* Make sure the threads state is suspended. */
_PQ_ASSERT_NOT_QUEUED(pthread, if (pthread->state != PS_SUSPENDED)
"_pq_insert_tail: Already in priority queue"); PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
_PQ_ASSERT_PROTECTED("_pq_insert_tail: prioq not protected!"); } else {
/*
* 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");
_PQ_ASSERT_PROTECTED("_pq_insert_tail: prioq not protected!");
TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe); prio = pthread->active_priority;
if (pq->pq_lists[prio].pl_queued == 0) TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe);
/* Insert the list into the priority queue: */ if (pq->pq_lists[prio].pl_queued == 0)
pq_insert_prio_list(pq, prio); /* Insert the list into the priority queue: */
pq_insert_prio_list(pq, prio);
/* Mark this thread as being in the priority queue. */ /* Mark this thread as being in the priority queue. */
pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
_PQ_CLEAR_ACTIVE(); _PQ_CLEAR_ACTIVE();
}
} }
@ -237,6 +259,17 @@ _pq_first(pq_queue_t *pq)
/* Mark the list as not being in the queue: */ /* Mark the list as not being in the queue: */
pql->pl_queued = 0; pql->pl_queued = 0;
} else if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
/*
* This thread is suspended; remove it from the
* list and ensure its state is suspended.
*/
TAILQ_REMOVE(&pql->pl_head, pthread, pqe);
PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
/* This thread is now longer in the priority queue. */
pthread->flags &= ~PTHREAD_FLAGS_IN_PRIOQ;
pthread = NULL;
} }
} }

View File

@ -189,14 +189,15 @@
if ((thrd)->state != newstate) { \ if ((thrd)->state != newstate) { \
if ((thrd)->state == PS_RUNNING) { \ if ((thrd)->state == PS_RUNNING) { \
PTHREAD_PRIOQ_REMOVE(thrd); \ PTHREAD_PRIOQ_REMOVE(thrd); \
PTHREAD_SET_STATE(thrd, newstate); \
PTHREAD_WAITQ_INSERT(thrd); \ PTHREAD_WAITQ_INSERT(thrd); \
} else if (newstate == PS_RUNNING) { \ } else if (newstate == PS_RUNNING) { \
PTHREAD_WAITQ_REMOVE(thrd); \ PTHREAD_WAITQ_REMOVE(thrd); \
PTHREAD_SET_STATE(thrd, newstate); \
PTHREAD_PRIOQ_INSERT_TAIL(thrd); \ PTHREAD_PRIOQ_INSERT_TAIL(thrd); \
} \ } \
} \ } \
_thread_kern_new_state = 0; \ _thread_kern_new_state = 0; \
PTHREAD_SET_STATE(thrd, newstate); \
} while (0) } while (0)
#else #else
#define PTHREAD_ASSERT(cond, msg) #define PTHREAD_ASSERT(cond, msg)
@ -399,18 +400,6 @@ struct pthread_attr {
#define PTHREAD_CREATE_RUNNING 0 #define PTHREAD_CREATE_RUNNING 0
#define PTHREAD_CREATE_SUSPENDED 1 #define PTHREAD_CREATE_SUSPENDED 1
/*
* Additional state for a thread suspended with pthread_suspend_np().
*/
enum pthread_susp {
SUSP_NO, /* Not suspended. */
SUSP_YES, /* Suspended. */
SUSP_JOIN, /* Suspended, joining. */
SUSP_NOWAIT, /* Suspended, was in a mutex or condition queue. */
SUSP_MUTEX_WAIT,/* Suspended, still in a mutex queue. */
SUSP_COND_WAIT /* Suspended, still in a condition queue. */
};
/* /*
* Miscellaneous definitions. * Miscellaneous definitions.
*/ */
@ -684,8 +673,6 @@ struct pthread {
#define PTHREAD_CANCEL_NEEDED 0x0010 #define PTHREAD_CANCEL_NEEDED 0x0010
int cancelflags; int cancelflags;
enum pthread_susp suspended;
thread_continuation_t continuation; thread_continuation_t continuation;
/* /*
@ -802,7 +789,8 @@ struct pthread {
#define PTHREAD_FLAGS_IN_FDQ 0x0040 /* in fd lock queue using qe link */ #define PTHREAD_FLAGS_IN_FDQ 0x0040 /* in fd lock queue using qe link */
#define PTHREAD_FLAGS_IN_CONDQ 0x0080 /* in condition queue using sqe link*/ #define PTHREAD_FLAGS_IN_CONDQ 0x0080 /* in condition queue using sqe link*/
#define PTHREAD_FLAGS_IN_MUTEXQ 0x0100 /* in mutex queue using sqe link */ #define PTHREAD_FLAGS_IN_MUTEXQ 0x0100 /* in mutex queue using sqe link */
#define PTHREAD_FLAGS_TRACE 0x0200 /* for debugging purposes */ #define PTHREAD_FLAGS_SUSPENDED 0x0200 /* thread is suspended */
#define PTHREAD_FLAGS_TRACE 0x0400 /* for debugging purposes */
#define PTHREAD_FLAGS_IN_SYNCQ \ #define PTHREAD_FLAGS_IN_SYNCQ \
(PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ) (PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ)
@ -880,17 +868,6 @@ SCLASS struct pthread * volatile _last_user_thread
; ;
#endif #endif
/*
* Ptr to the thread running in single-threaded mode or NULL if
* running multi-threaded (default POSIX behaviour).
*/
SCLASS struct pthread * volatile _thread_single
#ifdef GLOBAL_PTHREAD_PRIVATE
= NULL;
#else
;
#endif
/* List of all threads: */ /* List of all threads: */
SCLASS TAILQ_HEAD(, pthread) _thread_list SCLASS TAILQ_HEAD(, pthread) _thread_list
#ifdef GLOBAL_PTHREAD_PRIVATE #ifdef GLOBAL_PTHREAD_PRIVATE

View File

@ -35,62 +35,77 @@
#include <pthread.h> #include <pthread.h>
#include "pthread_private.h" #include "pthread_private.h"
static void resume_common(struct pthread *);
__weak_reference(_pthread_resume_np, pthread_resume_np); __weak_reference(_pthread_resume_np, pthread_resume_np);
__weak_reference(_pthread_resume_all_np, pthread_resume_all_np);
/* Resume a thread: */ /* Resume a thread: */
int int
_pthread_resume_np(pthread_t thread) _pthread_resume_np(pthread_t thread)
{ {
int ret; int ret;
enum pthread_susp old_suspended;
/* Find the thread in the list of active threads: */ /* Find the thread in the list of active threads: */
if ((ret = _find_thread(thread)) == 0) { if ((ret = _find_thread(thread)) == 0) {
/* Cancel any pending suspensions: */ /*
old_suspended = thread->suspended; * Defer signals to protect the scheduling queues
thread->suspended = SUSP_NO; * from access by the signal handler:
*/
_thread_kern_sig_defer();
/* Is it currently suspended? */ if ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0)
if (thread->state == PS_SUSPENDED) { resume_common(thread);
/*
* Defer signals to protect the scheduling queues
* from access by the signal handler:
*/
_thread_kern_sig_defer();
switch (old_suspended) { /*
case SUSP_MUTEX_WAIT: * Undefer and handle pending signals, yielding if
/* Set the thread's state back. */ * necessary:
PTHREAD_SET_STATE(thread,PS_MUTEX_WAIT); */
break; _thread_kern_sig_undefer();
case SUSP_COND_WAIT: }
/* Set the thread's state back. */ return (ret);
PTHREAD_SET_STATE(thread,PS_COND_WAIT); }
break;
case SUSP_JOIN: void
/* Set the thread's state back. */ _pthread_resume_all_np(void)
PTHREAD_SET_STATE(thread,PS_JOIN); {
break; struct pthread *curthread = _get_curthread();
case SUSP_NOWAIT: struct pthread *thread;
/* Allow the thread to run. */
PTHREAD_SET_STATE(thread,PS_RUNNING); /*
PTHREAD_WAITQ_REMOVE(thread); * Defer signals to protect the scheduling queues from access
PTHREAD_PRIOQ_INSERT_TAIL(thread); * by the signal handler:
break; */
case SUSP_NO: _thread_kern_sig_defer();
case SUSP_YES:
/* Allow the thread to run. */ TAILQ_FOREACH(thread, &_thread_list, tle) {
PTHREAD_SET_STATE(thread,PS_RUNNING); if ((thread != curthread) &&
PTHREAD_PRIOQ_INSERT_TAIL(thread); ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0))
break; resume_common(thread);
} }
/* /*
* Undefer and handle pending signals, yielding if * Undefer and handle pending signals, yielding if necessary:
* necessary: */
*/ _thread_kern_sig_undefer();
_thread_kern_sig_undefer(); }
}
static void
resume_common(struct pthread *thread)
{
/* Clear the suspend flag: */
thread->flags &= ~PTHREAD_FLAGS_SUSPENDED;
/*
* If the thread's state is suspended, that means it is
* now runnable but not in any scheduling queue. Set the
* state to running and insert it into the run queue.
*/
if (thread->state == PS_SUSPENDED) {
PTHREAD_SET_STATE(thread, PS_RUNNING);
if (thread->priority_mutex_count > 0)
PTHREAD_PRIOQ_INSERT_HEAD(thread);
else
PTHREAD_PRIOQ_INSERT_TAIL(thread);
} }
return(ret);
} }

View File

@ -54,7 +54,7 @@ static void thread_sigframe_save(struct pthread *thread,
static void thread_sig_invoke_handler(int sig, siginfo_t *info, static void thread_sig_invoke_handler(int sig, siginfo_t *info,
ucontext_t *ucp); ucontext_t *ucp);
/* #define DEBUG_SIGNAL */ /*#define DEBUG_SIGNAL*/
#ifdef DEBUG_SIGNAL #ifdef DEBUG_SIGNAL
#define DBG_MSG stdout_debug #define DBG_MSG stdout_debug
#else #else
@ -375,7 +375,8 @@ thread_sig_find(int sig)
return (NULL); return (NULL);
} }
else if ((handler_installed != 0) && else if ((handler_installed != 0) &&
!sigismember(&pthread->sigmask, sig)) { !sigismember(&pthread->sigmask, sig) &&
((pthread->flags & PTHREAD_FLAGS_SUSPENDED) == 0)) {
if (pthread->state == PS_SIGSUSPEND) { if (pthread->state == PS_SIGSUSPEND) {
if (suspended_thread == NULL) if (suspended_thread == NULL)
suspended_thread = pthread; suspended_thread = pthread;
@ -791,10 +792,17 @@ thread_sig_add(struct pthread *pthread, int sig, int has_args)
/* /*
* The thread should be removed from all scheduling * The thread should be removed from all scheduling
* queues at this point. Raise the priority and place * queues at this point. Raise the priority and place
* the thread in the run queue. * the thread in the run queue. It is also possible
* for a signal to be sent to a suspended thread,
* mostly via pthread_kill(). If a thread is suspended,
* don't insert it into the priority queue; just set
* its state to suspended and it will run the signal
* handler when it is resumed.
*/ */
pthread->active_priority |= PTHREAD_SIGNAL_PRIORITY; pthread->active_priority |= PTHREAD_SIGNAL_PRIORITY;
if (thread_is_active == 0) if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0)
PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
else if (thread_is_active == 0)
PTHREAD_PRIOQ_INSERT_TAIL(pthread); PTHREAD_PRIOQ_INSERT_TAIL(pthread);
} }
} }

View File

@ -31,17 +31,19 @@
* *
* $FreeBSD$ * $FreeBSD$
*/ */
#include <string.h>
#include <pthread.h> #include <pthread.h>
#include "pthread_private.h" #include <pthread_np.h>
__weak_reference(_pthread_single_np, pthread_single_np); __weak_reference(_pthread_single_np, pthread_single_np);
int _pthread_single_np() int _pthread_single_np()
{ {
struct pthread *curthread = _get_curthread();
/* Enter single-threaded (non-POSIX) scheduling mode: */ /* Enter single-threaded (non-POSIX) scheduling mode: */
_thread_single = curthread; pthread_suspend_all_np();
return(0); /*
* XXX - Do we want to do this?
* __is_threaded = 0;
*/
return (0);
} }

View File

@ -93,7 +93,7 @@ _spinlock_debug(spinlock_t *lck, char *fname, int lineno)
cnt++; cnt++;
if (cnt > 100) { if (cnt > 100) {
char str[256]; char str[256];
snprintf(str, sizeof(str), "%s - Warning: Thread %p attempted to lock %p from %s (%d) was left locked from %s (%d)\n", _getprogname(), curthread, lck, fname, lineno, lck->fname, lck->lineno); snprintf(str, sizeof(str), "%s - Warning: Thread %p attempted to lock %p from %s (%d) was left locked from %s (%d)\n", getprogname(), curthread, lck, fname, lineno, lck->fname, lck->lineno);
__sys_write(2,str,strlen(str)); __sys_write(2,str,strlen(str));
__sleep(1); __sleep(1);
cnt = 0; cnt = 0;

View File

@ -35,9 +35,10 @@
#include <pthread.h> #include <pthread.h>
#include "pthread_private.h" #include "pthread_private.h"
static void finish_suspension(void *arg); static void suspend_common(struct pthread *thread);
__weak_reference(_pthread_suspend_np, pthread_suspend_np); __weak_reference(_pthread_suspend_np, pthread_suspend_np);
__weak_reference(_pthread_suspend_all_np, pthread_suspend_all_np);
/* Suspend a thread: */ /* Suspend a thread: */
int int
@ -45,100 +46,19 @@ _pthread_suspend_np(pthread_t thread)
{ {
int ret; int ret;
/* Suspending the current thread doesn't make sense. */
if (thread == _get_curthread())
ret = EDEADLK;
/* Find the thread in the list of active threads: */ /* Find the thread in the list of active threads: */
if ((ret = _find_thread(thread)) == 0) { else if ((ret = _find_thread(thread)) == 0) {
/* /*
* Defer signals to protect the scheduling queues from * Defer signals to protect the scheduling queues from
* access by the signal handler: * access by the signal handler:
*/ */
_thread_kern_sig_defer(); _thread_kern_sig_defer();
switch (thread->state) { suspend_common(thread);
case PS_RUNNING:
/*
* Remove the thread from the priority queue and
* set the state to suspended:
*/
PTHREAD_PRIOQ_REMOVE(thread);
PTHREAD_SET_STATE(thread, PS_SUSPENDED);
break;
case PS_SPINBLOCK:
case PS_FDR_WAIT:
case PS_FDW_WAIT:
case PS_POLL_WAIT:
case PS_SELECT_WAIT:
/*
* Remove these threads from the work queue
* and mark the operation as interrupted:
*/
if ((thread->flags & PTHREAD_FLAGS_IN_WORKQ) != 0)
PTHREAD_WORKQ_REMOVE(thread);
_thread_seterrno(thread,EINTR);
/* FALLTHROUGH */
case PS_SLEEP_WAIT:
thread->interrupted = 1;
/* FALLTHROUGH */
case PS_SIGTHREAD:
case PS_WAIT_WAIT:
case PS_SIGSUSPEND:
case PS_SIGWAIT:
/*
* Remove these threads from the waiting queue and
* set their state to suspended:
*/
PTHREAD_WAITQ_REMOVE(thread);
PTHREAD_SET_STATE(thread, PS_SUSPENDED);
break;
case PS_MUTEX_WAIT:
/* Mark the thread as suspended and still in a queue. */
thread->suspended = SUSP_MUTEX_WAIT;
PTHREAD_SET_STATE(thread, PS_SUSPENDED);
break;
case PS_COND_WAIT:
/* Mark the thread as suspended and still in a queue. */
thread->suspended = SUSP_COND_WAIT;
PTHREAD_SET_STATE(thread, PS_SUSPENDED);
break;
case PS_JOIN:
/* Mark the thread as suspended and joining: */
thread->suspended = SUSP_JOIN;
PTHREAD_NEW_STATE(thread, PS_SUSPENDED);
break;
case PS_FDLR_WAIT:
case PS_FDLW_WAIT:
case PS_FILE_WAIT:
/* Mark the thread as suspended: */
thread->suspended = SUSP_YES;
/*
* Threads in these states may be in queues.
* In order to preserve queue integrity, the
* cancelled thread must remove itself from the
* queue. Mark the thread as interrupted and
* set the state to running. When the thread
* resumes, it will remove itself from the queue
* and call the suspension completion routine.
*/
thread->interrupted = 1;
_thread_seterrno(thread, EINTR);
PTHREAD_NEW_STATE(thread, PS_RUNNING);
thread->continuation = finish_suspension;
break;
case PS_DEAD:
case PS_DEADLOCK:
case PS_STATE_MAX:
case PS_SUSPENDED:
/* Nothing needs to be done: */
break;
}
/* /*
* Undefer and handle pending signals, yielding if * Undefer and handle pending signals, yielding if
@ -146,16 +66,39 @@ _pthread_suspend_np(pthread_t thread)
*/ */
_thread_kern_sig_undefer(); _thread_kern_sig_undefer();
} }
return(ret); return (ret);
} }
static void void
finish_suspension(void *arg) _pthread_suspend_all_np(void)
{ {
struct pthread *curthread = _get_curthread(); struct pthread *curthread = _get_curthread();
struct pthread *thread;
if (curthread->suspended != SUSP_NO) /*
_thread_kern_sched_state(PS_SUSPENDED, __FILE__, __LINE__); * Defer signals to protect the scheduling queues from
* access by the signal handler:
*/
_thread_kern_sig_defer();
TAILQ_FOREACH(thread, &_thread_list, tle) {
if (thread != curthread)
suspend_common(thread);
}
/*
* Undefer and handle pending signals, yielding if
* necessary:
*/
_thread_kern_sig_undefer();
} }
void
suspend_common(struct pthread *thread)
{
thread->flags |= PTHREAD_FLAGS_SUSPENDED;
if (thread->flags & PTHREAD_FLAGS_IN_PRIOQ) {
PTHREAD_PRIOQ_REMOVE(thread);
PTHREAD_SET_STATE(thread, PS_SUSPENDED);
}
}

View File

@ -78,20 +78,6 @@ _pthread_cancel(pthread_t pthread)
break; break;
case PS_SUSPENDED: case PS_SUSPENDED:
if (pthread->suspended == SUSP_NO ||
pthread->suspended == SUSP_YES ||
pthread->suspended == SUSP_JOIN ||
pthread->suspended == SUSP_NOWAIT) {
/*
* This thread isn't in any scheduling
* queues; just change it's state:
*/
pthread->cancelflags |=
PTHREAD_CANCELLING;
PTHREAD_SET_STATE(pthread, PS_RUNNING);
break;
}
/* FALLTHROUGH */
case PS_MUTEX_WAIT: case PS_MUTEX_WAIT:
case PS_COND_WAIT: case PS_COND_WAIT:
case PS_FDLR_WAIT: case PS_FDLR_WAIT:
@ -109,7 +95,7 @@ _pthread_cancel(pthread_t pthread)
*/ */
pthread->interrupted = 1; pthread->interrupted = 1;
pthread->cancelflags |= PTHREAD_CANCEL_NEEDED; pthread->cancelflags |= PTHREAD_CANCEL_NEEDED;
PTHREAD_NEW_STATE(pthread,PS_RUNNING); PTHREAD_NEW_STATE(pthread, PS_RUNNING);
pthread->continuation = finish_cancellation; pthread->continuation = finish_cancellation;
break; break;

View File

@ -524,15 +524,9 @@ _pthread_cond_signal(pthread_cond_t * cond)
if ((pthread = cond_queue_deq(*cond)) != NULL) { if ((pthread = cond_queue_deq(*cond)) != NULL) {
/* /*
* Unless the thread is currently suspended, * Wake up the signaled thread:
* allow it to run. If the thread is suspended,
* make a note that the thread isn't in a wait
* queue any more.
*/ */
if (pthread->state != PS_SUSPENDED) PTHREAD_NEW_STATE(pthread, PS_RUNNING);
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
else
pthread->suspended = SUSP_NOWAIT;
} }
/* Check for no more waiters: */ /* Check for no more waiters: */
@ -596,15 +590,9 @@ _pthread_cond_broadcast(pthread_cond_t * cond)
*/ */
while ((pthread = cond_queue_deq(*cond)) != NULL) { while ((pthread = cond_queue_deq(*cond)) != NULL) {
/* /*
* Unless the thread is currently suspended, * Wake up the signaled thread:
* allow it to run. If the thread is suspended,
* make a note that the thread isn't in a wait
* queue any more.
*/ */
if (pthread->state != PS_SUSPENDED) PTHREAD_NEW_STATE(pthread, PS_RUNNING);
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
else
pthread->suspended = SUSP_NOWAIT;
} }
/* There are no more waiting threads: */ /* There are no more waiting threads: */

View File

@ -202,22 +202,8 @@ _pthread_exit(void *status)
pthread = curthread->joiner; pthread = curthread->joiner;
curthread->joiner = NULL; curthread->joiner = NULL;
switch (pthread->suspended) { /* Make the joining thread runnable: */
case SUSP_JOIN: PTHREAD_NEW_STATE(pthread, PS_RUNNING);
/*
* The joining thread is suspended. Change the
* suspension state to make the thread runnable when it
* is resumed:
*/
pthread->suspended = SUSP_NO;
break;
case SUSP_NO:
/* Make the joining thread runnable: */
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
break;
default:
PANIC("Unreachable code reached");
}
/* Set the return value for the joining thread: */ /* Set the return value for the joining thread: */
pthread->join_status.ret = curthread->ret; pthread->join_status.ret = curthread->ret;

View File

@ -201,20 +201,21 @@ _thread_init(void)
PANIC("Can't open console"); PANIC("Can't open console");
if (setlogin("root") == -1) if (setlogin("root") == -1)
PANIC("Can't set login to root"); PANIC("Can't set login to root");
if (__sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1) if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1)
PANIC("Can't set controlling terminal"); PANIC("Can't set controlling terminal");
if (__sys_dup2(fd,0) == -1 || if (__sys_dup2(fd, 0) == -1 ||
__sys_dup2(fd,1) == -1 || __sys_dup2(fd, 1) == -1 ||
__sys_dup2(fd,2) == -1) __sys_dup2(fd, 2) == -1)
PANIC("Can't dup2"); PANIC("Can't dup2");
} }
/* Get the standard I/O flags before messing with them : */ /* Get the standard I/O flags before messing with them : */
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++) {
if (((_pthread_stdio_flags[i] = if (((_pthread_stdio_flags[i] =
__sys_fcntl(i,F_GETFL, NULL)) == -1) && __sys_fcntl(i, F_GETFL, NULL)) == -1) &&
(errno != EBADF)) (errno != EBADF))
PANIC("Cannot get stdio flags"); PANIC("Cannot get stdio flags");
}
/* /*
* Create a pipe that is written to by the signal handler to prevent * Create a pipe that is written to by the signal handler to prevent
@ -224,8 +225,21 @@ _thread_init(void)
/* Cannot create pipe, so abort: */ /* Cannot create pipe, so abort: */
PANIC("Cannot create kernel pipe"); PANIC("Cannot create kernel pipe");
} }
/*
* Make sure the pipe does not get in the way of stdio:
*/
for (i = 0; i < 2; i++) {
if (_thread_kern_pipe[i] < 3) {
fd = __sys_fcntl(_thread_kern_pipe[i], F_DUPFD, 3);
if (fd == -1)
PANIC("Cannot create kernel pipe");
__sys_close(_thread_kern_pipe[i]);
_thread_kern_pipe[i] = fd;
}
}
/* Get the flags for the read pipe: */ /* Get the flags for the read pipe: */
else if ((flags = __sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) { if ((flags = __sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) {
/* Abort this application: */ /* Abort this application: */
PANIC("Cannot get kernel read pipe flags"); PANIC("Cannot get kernel read pipe flags");
} }

View File

@ -31,16 +31,20 @@
* *
* $FreeBSD$ * $FreeBSD$
*/ */
#include <string.h>
#include <pthread.h> #include <pthread.h>
#include "pthread_private.h" #include <pthread_np.h>
__weak_reference(_pthread_multi_np, pthread_multi_np); __weak_reference(_pthread_multi_np, pthread_multi_np);
int int
_pthread_multi_np() _pthread_multi_np()
{ {
/* Return to multi-threaded scheduling mode: */ /* Return to multi-threaded scheduling mode: */
_thread_single = NULL; /*
return(0); * XXX - Do we want to do this?
* __is_threaded = 1;
*/
pthread_resume_all_np();
return (0);
} }

View File

@ -887,21 +887,9 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
*/ */
if (((*mutex)->m_owner = if (((*mutex)->m_owner =
mutex_queue_deq(*mutex)) != NULL) { mutex_queue_deq(*mutex)) != NULL) {
/* /* Make the new owner runnable: */
* Unless the new owner of the mutex is PTHREAD_NEW_STATE((*mutex)->m_owner,
* currently suspended, allow the owner PS_RUNNING);
* to run. If the thread is suspended,
* make a note that the thread isn't in
* a wait queue any more.
*/
if (((*mutex)->m_owner->state !=
PS_SUSPENDED)) {
PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_RUNNING);
} else {
(*mutex)->m_owner->suspended =
SUSP_NOWAIT;
}
/* /*
* Add the mutex to the threads list of * Add the mutex to the threads list of
@ -1019,20 +1007,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
(*mutex)->m_prio; (*mutex)->m_prio;
/* /*
* Unless the new owner of the mutex is * Make the new owner runnable:
* currently suspended, allow the owner
* to run. If the thread is suspended,
* make a note that the thread isn't in
* a wait queue any more.
*/ */
if (((*mutex)->m_owner->state != PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_SUSPENDED)) { PS_RUNNING);
PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_RUNNING);
} else {
(*mutex)->m_owner->suspended =
SUSP_NOWAIT;
}
} }
} }
break; break;
@ -1148,20 +1126,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
(*mutex)->m_prio; (*mutex)->m_prio;
/* /*
* Unless the new owner of the mutex is * Make the new owner runnable:
* currently suspended, allow the owner
* to run. If the thread is suspended,
* make a note that the thread isn't in
* a wait queue any more.
*/ */
if (((*mutex)->m_owner->state != PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_SUSPENDED)) { PS_RUNNING);
PTHREAD_NEW_STATE((*mutex)->m_owner,
PS_RUNNING);
} else {
(*mutex)->m_owner->suspended =
SUSP_NOWAIT;
}
} }
} }
break; break;

View File

@ -164,52 +164,74 @@ _pq_remove(pq_queue_t *pq, pthread_t pthread)
void void
_pq_insert_head(pq_queue_t *pq, pthread_t pthread) _pq_insert_head(pq_queue_t *pq, pthread_t pthread)
{ {
int prio = pthread->active_priority; int prio;
/* /*
* Make some assertions when debugging is enabled: * Don't insert suspended threads into the priority queue.
* The caller is responsible for setting the threads state.
*/ */
_PQ_ASSERT_INACTIVE("_pq_insert_head: pq_active"); if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
_PQ_SET_ACTIVE(); /* Make sure the threads state is suspended. */
_PQ_ASSERT_NOT_QUEUED(pthread, if (pthread->state != PS_SUSPENDED)
"_pq_insert_head: Already in priority queue"); PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
_PQ_ASSERT_PROTECTED("_pq_insert_head: prioq not protected!"); } else {
/*
* 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");
_PQ_ASSERT_PROTECTED("_pq_insert_head: prioq not protected!");
TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe); prio = pthread->active_priority;
if (pq->pq_lists[prio].pl_queued == 0) TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe);
/* Insert the list into the priority queue: */ if (pq->pq_lists[prio].pl_queued == 0)
pq_insert_prio_list(pq, prio); /* Insert the list into the priority queue: */
pq_insert_prio_list(pq, prio);
/* Mark this thread as being in the priority queue. */ /* Mark this thread as being in the priority queue. */
pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
_PQ_CLEAR_ACTIVE(); _PQ_CLEAR_ACTIVE();
}
} }
void void
_pq_insert_tail(pq_queue_t *pq, pthread_t pthread) _pq_insert_tail(pq_queue_t *pq, pthread_t pthread)
{ {
int prio = pthread->active_priority; int prio;
/* /*
* Make some assertions when debugging is enabled: * Don't insert suspended threads into the priority queue.
* The caller is responsible for setting the threads state.
*/ */
_PQ_ASSERT_INACTIVE("_pq_insert_tail: pq_active"); if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
_PQ_SET_ACTIVE(); /* Make sure the threads state is suspended. */
_PQ_ASSERT_NOT_QUEUED(pthread, if (pthread->state != PS_SUSPENDED)
"_pq_insert_tail: Already in priority queue"); PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
_PQ_ASSERT_PROTECTED("_pq_insert_tail: prioq not protected!"); } else {
/*
* 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");
_PQ_ASSERT_PROTECTED("_pq_insert_tail: prioq not protected!");
TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe); prio = pthread->active_priority;
if (pq->pq_lists[prio].pl_queued == 0) TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe);
/* Insert the list into the priority queue: */ if (pq->pq_lists[prio].pl_queued == 0)
pq_insert_prio_list(pq, prio); /* Insert the list into the priority queue: */
pq_insert_prio_list(pq, prio);
/* Mark this thread as being in the priority queue. */ /* Mark this thread as being in the priority queue. */
pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
_PQ_CLEAR_ACTIVE(); _PQ_CLEAR_ACTIVE();
}
} }
@ -237,6 +259,17 @@ _pq_first(pq_queue_t *pq)
/* Mark the list as not being in the queue: */ /* Mark the list as not being in the queue: */
pql->pl_queued = 0; pql->pl_queued = 0;
} else if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
/*
* This thread is suspended; remove it from the
* list and ensure its state is suspended.
*/
TAILQ_REMOVE(&pql->pl_head, pthread, pqe);
PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
/* This thread is now longer in the priority queue. */
pthread->flags &= ~PTHREAD_FLAGS_IN_PRIOQ;
pthread = NULL;
} }
} }

View File

@ -189,14 +189,15 @@
if ((thrd)->state != newstate) { \ if ((thrd)->state != newstate) { \
if ((thrd)->state == PS_RUNNING) { \ if ((thrd)->state == PS_RUNNING) { \
PTHREAD_PRIOQ_REMOVE(thrd); \ PTHREAD_PRIOQ_REMOVE(thrd); \
PTHREAD_SET_STATE(thrd, newstate); \
PTHREAD_WAITQ_INSERT(thrd); \ PTHREAD_WAITQ_INSERT(thrd); \
} else if (newstate == PS_RUNNING) { \ } else if (newstate == PS_RUNNING) { \
PTHREAD_WAITQ_REMOVE(thrd); \ PTHREAD_WAITQ_REMOVE(thrd); \
PTHREAD_SET_STATE(thrd, newstate); \
PTHREAD_PRIOQ_INSERT_TAIL(thrd); \ PTHREAD_PRIOQ_INSERT_TAIL(thrd); \
} \ } \
} \ } \
_thread_kern_new_state = 0; \ _thread_kern_new_state = 0; \
PTHREAD_SET_STATE(thrd, newstate); \
} while (0) } while (0)
#else #else
#define PTHREAD_ASSERT(cond, msg) #define PTHREAD_ASSERT(cond, msg)
@ -399,18 +400,6 @@ struct pthread_attr {
#define PTHREAD_CREATE_RUNNING 0 #define PTHREAD_CREATE_RUNNING 0
#define PTHREAD_CREATE_SUSPENDED 1 #define PTHREAD_CREATE_SUSPENDED 1
/*
* Additional state for a thread suspended with pthread_suspend_np().
*/
enum pthread_susp {
SUSP_NO, /* Not suspended. */
SUSP_YES, /* Suspended. */
SUSP_JOIN, /* Suspended, joining. */
SUSP_NOWAIT, /* Suspended, was in a mutex or condition queue. */
SUSP_MUTEX_WAIT,/* Suspended, still in a mutex queue. */
SUSP_COND_WAIT /* Suspended, still in a condition queue. */
};
/* /*
* Miscellaneous definitions. * Miscellaneous definitions.
*/ */
@ -684,8 +673,6 @@ struct pthread {
#define PTHREAD_CANCEL_NEEDED 0x0010 #define PTHREAD_CANCEL_NEEDED 0x0010
int cancelflags; int cancelflags;
enum pthread_susp suspended;
thread_continuation_t continuation; thread_continuation_t continuation;
/* /*
@ -802,7 +789,8 @@ struct pthread {
#define PTHREAD_FLAGS_IN_FDQ 0x0040 /* in fd lock queue using qe link */ #define PTHREAD_FLAGS_IN_FDQ 0x0040 /* in fd lock queue using qe link */
#define PTHREAD_FLAGS_IN_CONDQ 0x0080 /* in condition queue using sqe link*/ #define PTHREAD_FLAGS_IN_CONDQ 0x0080 /* in condition queue using sqe link*/
#define PTHREAD_FLAGS_IN_MUTEXQ 0x0100 /* in mutex queue using sqe link */ #define PTHREAD_FLAGS_IN_MUTEXQ 0x0100 /* in mutex queue using sqe link */
#define PTHREAD_FLAGS_TRACE 0x0200 /* for debugging purposes */ #define PTHREAD_FLAGS_SUSPENDED 0x0200 /* thread is suspended */
#define PTHREAD_FLAGS_TRACE 0x0400 /* for debugging purposes */
#define PTHREAD_FLAGS_IN_SYNCQ \ #define PTHREAD_FLAGS_IN_SYNCQ \
(PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ) (PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ)
@ -880,17 +868,6 @@ SCLASS struct pthread * volatile _last_user_thread
; ;
#endif #endif
/*
* Ptr to the thread running in single-threaded mode or NULL if
* running multi-threaded (default POSIX behaviour).
*/
SCLASS struct pthread * volatile _thread_single
#ifdef GLOBAL_PTHREAD_PRIVATE
= NULL;
#else
;
#endif
/* List of all threads: */ /* List of all threads: */
SCLASS TAILQ_HEAD(, pthread) _thread_list SCLASS TAILQ_HEAD(, pthread) _thread_list
#ifdef GLOBAL_PTHREAD_PRIVATE #ifdef GLOBAL_PTHREAD_PRIVATE

View File

@ -35,62 +35,77 @@
#include <pthread.h> #include <pthread.h>
#include "pthread_private.h" #include "pthread_private.h"
static void resume_common(struct pthread *);
__weak_reference(_pthread_resume_np, pthread_resume_np); __weak_reference(_pthread_resume_np, pthread_resume_np);
__weak_reference(_pthread_resume_all_np, pthread_resume_all_np);
/* Resume a thread: */ /* Resume a thread: */
int int
_pthread_resume_np(pthread_t thread) _pthread_resume_np(pthread_t thread)
{ {
int ret; int ret;
enum pthread_susp old_suspended;
/* Find the thread in the list of active threads: */ /* Find the thread in the list of active threads: */
if ((ret = _find_thread(thread)) == 0) { if ((ret = _find_thread(thread)) == 0) {
/* Cancel any pending suspensions: */ /*
old_suspended = thread->suspended; * Defer signals to protect the scheduling queues
thread->suspended = SUSP_NO; * from access by the signal handler:
*/
_thread_kern_sig_defer();
/* Is it currently suspended? */ if ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0)
if (thread->state == PS_SUSPENDED) { resume_common(thread);
/*
* Defer signals to protect the scheduling queues
* from access by the signal handler:
*/
_thread_kern_sig_defer();
switch (old_suspended) { /*
case SUSP_MUTEX_WAIT: * Undefer and handle pending signals, yielding if
/* Set the thread's state back. */ * necessary:
PTHREAD_SET_STATE(thread,PS_MUTEX_WAIT); */
break; _thread_kern_sig_undefer();
case SUSP_COND_WAIT: }
/* Set the thread's state back. */ return (ret);
PTHREAD_SET_STATE(thread,PS_COND_WAIT); }
break;
case SUSP_JOIN: void
/* Set the thread's state back. */ _pthread_resume_all_np(void)
PTHREAD_SET_STATE(thread,PS_JOIN); {
break; struct pthread *curthread = _get_curthread();
case SUSP_NOWAIT: struct pthread *thread;
/* Allow the thread to run. */
PTHREAD_SET_STATE(thread,PS_RUNNING); /*
PTHREAD_WAITQ_REMOVE(thread); * Defer signals to protect the scheduling queues from access
PTHREAD_PRIOQ_INSERT_TAIL(thread); * by the signal handler:
break; */
case SUSP_NO: _thread_kern_sig_defer();
case SUSP_YES:
/* Allow the thread to run. */ TAILQ_FOREACH(thread, &_thread_list, tle) {
PTHREAD_SET_STATE(thread,PS_RUNNING); if ((thread != curthread) &&
PTHREAD_PRIOQ_INSERT_TAIL(thread); ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0))
break; resume_common(thread);
} }
/* /*
* Undefer and handle pending signals, yielding if * Undefer and handle pending signals, yielding if necessary:
* necessary: */
*/ _thread_kern_sig_undefer();
_thread_kern_sig_undefer(); }
}
static void
resume_common(struct pthread *thread)
{
/* Clear the suspend flag: */
thread->flags &= ~PTHREAD_FLAGS_SUSPENDED;
/*
* If the thread's state is suspended, that means it is
* now runnable but not in any scheduling queue. Set the
* state to running and insert it into the run queue.
*/
if (thread->state == PS_SUSPENDED) {
PTHREAD_SET_STATE(thread, PS_RUNNING);
if (thread->priority_mutex_count > 0)
PTHREAD_PRIOQ_INSERT_HEAD(thread);
else
PTHREAD_PRIOQ_INSERT_TAIL(thread);
} }
return(ret);
} }

View File

@ -54,7 +54,7 @@ static void thread_sigframe_save(struct pthread *thread,
static void thread_sig_invoke_handler(int sig, siginfo_t *info, static void thread_sig_invoke_handler(int sig, siginfo_t *info,
ucontext_t *ucp); ucontext_t *ucp);
/* #define DEBUG_SIGNAL */ /*#define DEBUG_SIGNAL*/
#ifdef DEBUG_SIGNAL #ifdef DEBUG_SIGNAL
#define DBG_MSG stdout_debug #define DBG_MSG stdout_debug
#else #else
@ -375,7 +375,8 @@ thread_sig_find(int sig)
return (NULL); return (NULL);
} }
else if ((handler_installed != 0) && else if ((handler_installed != 0) &&
!sigismember(&pthread->sigmask, sig)) { !sigismember(&pthread->sigmask, sig) &&
((pthread->flags & PTHREAD_FLAGS_SUSPENDED) == 0)) {
if (pthread->state == PS_SIGSUSPEND) { if (pthread->state == PS_SIGSUSPEND) {
if (suspended_thread == NULL) if (suspended_thread == NULL)
suspended_thread = pthread; suspended_thread = pthread;
@ -791,10 +792,17 @@ thread_sig_add(struct pthread *pthread, int sig, int has_args)
/* /*
* The thread should be removed from all scheduling * The thread should be removed from all scheduling
* queues at this point. Raise the priority and place * queues at this point. Raise the priority and place
* the thread in the run queue. * the thread in the run queue. It is also possible
* for a signal to be sent to a suspended thread,
* mostly via pthread_kill(). If a thread is suspended,
* don't insert it into the priority queue; just set
* its state to suspended and it will run the signal
* handler when it is resumed.
*/ */
pthread->active_priority |= PTHREAD_SIGNAL_PRIORITY; pthread->active_priority |= PTHREAD_SIGNAL_PRIORITY;
if (thread_is_active == 0) if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0)
PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
else if (thread_is_active == 0)
PTHREAD_PRIOQ_INSERT_TAIL(pthread); PTHREAD_PRIOQ_INSERT_TAIL(pthread);
} }
} }

View File

@ -31,17 +31,19 @@
* *
* $FreeBSD$ * $FreeBSD$
*/ */
#include <string.h>
#include <pthread.h> #include <pthread.h>
#include "pthread_private.h" #include <pthread_np.h>
__weak_reference(_pthread_single_np, pthread_single_np); __weak_reference(_pthread_single_np, pthread_single_np);
int _pthread_single_np() int _pthread_single_np()
{ {
struct pthread *curthread = _get_curthread();
/* Enter single-threaded (non-POSIX) scheduling mode: */ /* Enter single-threaded (non-POSIX) scheduling mode: */
_thread_single = curthread; pthread_suspend_all_np();
return(0); /*
* XXX - Do we want to do this?
* __is_threaded = 0;
*/
return (0);
} }

View File

@ -93,7 +93,7 @@ _spinlock_debug(spinlock_t *lck, char *fname, int lineno)
cnt++; cnt++;
if (cnt > 100) { if (cnt > 100) {
char str[256]; char str[256];
snprintf(str, sizeof(str), "%s - Warning: Thread %p attempted to lock %p from %s (%d) was left locked from %s (%d)\n", _getprogname(), curthread, lck, fname, lineno, lck->fname, lck->lineno); snprintf(str, sizeof(str), "%s - Warning: Thread %p attempted to lock %p from %s (%d) was left locked from %s (%d)\n", getprogname(), curthread, lck, fname, lineno, lck->fname, lck->lineno);
__sys_write(2,str,strlen(str)); __sys_write(2,str,strlen(str));
__sleep(1); __sleep(1);
cnt = 0; cnt = 0;

View File

@ -35,9 +35,10 @@
#include <pthread.h> #include <pthread.h>
#include "pthread_private.h" #include "pthread_private.h"
static void finish_suspension(void *arg); static void suspend_common(struct pthread *thread);
__weak_reference(_pthread_suspend_np, pthread_suspend_np); __weak_reference(_pthread_suspend_np, pthread_suspend_np);
__weak_reference(_pthread_suspend_all_np, pthread_suspend_all_np);
/* Suspend a thread: */ /* Suspend a thread: */
int int
@ -45,100 +46,19 @@ _pthread_suspend_np(pthread_t thread)
{ {
int ret; int ret;
/* Suspending the current thread doesn't make sense. */
if (thread == _get_curthread())
ret = EDEADLK;
/* Find the thread in the list of active threads: */ /* Find the thread in the list of active threads: */
if ((ret = _find_thread(thread)) == 0) { else if ((ret = _find_thread(thread)) == 0) {
/* /*
* Defer signals to protect the scheduling queues from * Defer signals to protect the scheduling queues from
* access by the signal handler: * access by the signal handler:
*/ */
_thread_kern_sig_defer(); _thread_kern_sig_defer();
switch (thread->state) { suspend_common(thread);
case PS_RUNNING:
/*
* Remove the thread from the priority queue and
* set the state to suspended:
*/
PTHREAD_PRIOQ_REMOVE(thread);
PTHREAD_SET_STATE(thread, PS_SUSPENDED);
break;
case PS_SPINBLOCK:
case PS_FDR_WAIT:
case PS_FDW_WAIT:
case PS_POLL_WAIT:
case PS_SELECT_WAIT:
/*
* Remove these threads from the work queue
* and mark the operation as interrupted:
*/
if ((thread->flags & PTHREAD_FLAGS_IN_WORKQ) != 0)
PTHREAD_WORKQ_REMOVE(thread);
_thread_seterrno(thread,EINTR);
/* FALLTHROUGH */
case PS_SLEEP_WAIT:
thread->interrupted = 1;
/* FALLTHROUGH */
case PS_SIGTHREAD:
case PS_WAIT_WAIT:
case PS_SIGSUSPEND:
case PS_SIGWAIT:
/*
* Remove these threads from the waiting queue and
* set their state to suspended:
*/
PTHREAD_WAITQ_REMOVE(thread);
PTHREAD_SET_STATE(thread, PS_SUSPENDED);
break;
case PS_MUTEX_WAIT:
/* Mark the thread as suspended and still in a queue. */
thread->suspended = SUSP_MUTEX_WAIT;
PTHREAD_SET_STATE(thread, PS_SUSPENDED);
break;
case PS_COND_WAIT:
/* Mark the thread as suspended and still in a queue. */
thread->suspended = SUSP_COND_WAIT;
PTHREAD_SET_STATE(thread, PS_SUSPENDED);
break;
case PS_JOIN:
/* Mark the thread as suspended and joining: */
thread->suspended = SUSP_JOIN;
PTHREAD_NEW_STATE(thread, PS_SUSPENDED);
break;
case PS_FDLR_WAIT:
case PS_FDLW_WAIT:
case PS_FILE_WAIT:
/* Mark the thread as suspended: */
thread->suspended = SUSP_YES;
/*
* Threads in these states may be in queues.
* In order to preserve queue integrity, the
* cancelled thread must remove itself from the
* queue. Mark the thread as interrupted and
* set the state to running. When the thread
* resumes, it will remove itself from the queue
* and call the suspension completion routine.
*/
thread->interrupted = 1;
_thread_seterrno(thread, EINTR);
PTHREAD_NEW_STATE(thread, PS_RUNNING);
thread->continuation = finish_suspension;
break;
case PS_DEAD:
case PS_DEADLOCK:
case PS_STATE_MAX:
case PS_SUSPENDED:
/* Nothing needs to be done: */
break;
}
/* /*
* Undefer and handle pending signals, yielding if * Undefer and handle pending signals, yielding if
@ -146,16 +66,39 @@ _pthread_suspend_np(pthread_t thread)
*/ */
_thread_kern_sig_undefer(); _thread_kern_sig_undefer();
} }
return(ret); return (ret);
} }
static void void
finish_suspension(void *arg) _pthread_suspend_all_np(void)
{ {
struct pthread *curthread = _get_curthread(); struct pthread *curthread = _get_curthread();
struct pthread *thread;
if (curthread->suspended != SUSP_NO) /*
_thread_kern_sched_state(PS_SUSPENDED, __FILE__, __LINE__); * Defer signals to protect the scheduling queues from
* access by the signal handler:
*/
_thread_kern_sig_defer();
TAILQ_FOREACH(thread, &_thread_list, tle) {
if (thread != curthread)
suspend_common(thread);
}
/*
* Undefer and handle pending signals, yielding if
* necessary:
*/
_thread_kern_sig_undefer();
} }
void
suspend_common(struct pthread *thread)
{
thread->flags |= PTHREAD_FLAGS_SUSPENDED;
if (thread->flags & PTHREAD_FLAGS_IN_PRIOQ) {
PTHREAD_PRIOQ_REMOVE(thread);
PTHREAD_SET_STATE(thread, PS_SUSPENDED);
}
}