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:
parent
a119f25995
commit
5eb8d1f0b0
@ -189,14 +189,15 @@
|
||||
if ((thrd)->state != newstate) { \
|
||||
if ((thrd)->state == PS_RUNNING) { \
|
||||
PTHREAD_PRIOQ_REMOVE(thrd); \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
PTHREAD_WAITQ_INSERT(thrd); \
|
||||
} else if (newstate == PS_RUNNING) { \
|
||||
PTHREAD_WAITQ_REMOVE(thrd); \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
PTHREAD_PRIOQ_INSERT_TAIL(thrd); \
|
||||
} \
|
||||
} \
|
||||
_thread_kern_new_state = 0; \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
} while (0)
|
||||
#else
|
||||
#define PTHREAD_ASSERT(cond, msg)
|
||||
@ -399,18 +400,6 @@ struct pthread_attr {
|
||||
#define PTHREAD_CREATE_RUNNING 0
|
||||
#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.
|
||||
*/
|
||||
@ -684,8 +673,6 @@ struct pthread {
|
||||
#define PTHREAD_CANCEL_NEEDED 0x0010
|
||||
int cancelflags;
|
||||
|
||||
enum pthread_susp suspended;
|
||||
|
||||
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_CONDQ 0x0080 /* in condition 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 \
|
||||
(PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ)
|
||||
|
||||
@ -880,17 +868,6 @@ SCLASS struct pthread * volatile _last_user_thread
|
||||
;
|
||||
#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: */
|
||||
SCLASS TAILQ_HEAD(, pthread) _thread_list
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
|
@ -78,20 +78,6 @@ _pthread_cancel(pthread_t pthread)
|
||||
break;
|
||||
|
||||
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_COND_WAIT:
|
||||
case PS_FDLR_WAIT:
|
||||
@ -109,7 +95,7 @@ _pthread_cancel(pthread_t pthread)
|
||||
*/
|
||||
pthread->interrupted = 1;
|
||||
pthread->cancelflags |= PTHREAD_CANCEL_NEEDED;
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
|
||||
pthread->continuation = finish_cancellation;
|
||||
break;
|
||||
|
||||
|
@ -524,15 +524,9 @@ _pthread_cond_signal(pthread_cond_t * cond)
|
||||
|
||||
if ((pthread = cond_queue_deq(*cond)) != NULL) {
|
||||
/*
|
||||
* Unless the thread is currently suspended,
|
||||
* allow it to run. If the thread is suspended,
|
||||
* make a note that the thread isn't in a wait
|
||||
* queue any more.
|
||||
* Wake up the signaled thread:
|
||||
*/
|
||||
if (pthread->state != PS_SUSPENDED)
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
else
|
||||
pthread->suspended = SUSP_NOWAIT;
|
||||
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
|
||||
}
|
||||
|
||||
/* Check for no more waiters: */
|
||||
@ -596,15 +590,9 @@ _pthread_cond_broadcast(pthread_cond_t * cond)
|
||||
*/
|
||||
while ((pthread = cond_queue_deq(*cond)) != NULL) {
|
||||
/*
|
||||
* Unless the thread is currently suspended,
|
||||
* allow it to run. If the thread is suspended,
|
||||
* make a note that the thread isn't in a wait
|
||||
* queue any more.
|
||||
* Wake up the signaled thread:
|
||||
*/
|
||||
if (pthread->state != PS_SUSPENDED)
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
else
|
||||
pthread->suspended = SUSP_NOWAIT;
|
||||
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
|
||||
}
|
||||
|
||||
/* There are no more waiting threads: */
|
||||
|
@ -202,22 +202,8 @@ _pthread_exit(void *status)
|
||||
pthread = curthread->joiner;
|
||||
curthread->joiner = NULL;
|
||||
|
||||
switch (pthread->suspended) {
|
||||
case SUSP_JOIN:
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
/* Make the joining thread runnable: */
|
||||
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
|
||||
|
||||
/* Set the return value for the joining thread: */
|
||||
pthread->join_status.ret = curthread->ret;
|
||||
|
@ -201,20 +201,21 @@ _thread_init(void)
|
||||
PANIC("Can't open console");
|
||||
if (setlogin("root") == -1)
|
||||
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");
|
||||
if (__sys_dup2(fd,0) == -1 ||
|
||||
__sys_dup2(fd,1) == -1 ||
|
||||
__sys_dup2(fd,2) == -1)
|
||||
if (__sys_dup2(fd, 0) == -1 ||
|
||||
__sys_dup2(fd, 1) == -1 ||
|
||||
__sys_dup2(fd, 2) == -1)
|
||||
PANIC("Can't dup2");
|
||||
}
|
||||
|
||||
/* 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] =
|
||||
__sys_fcntl(i,F_GETFL, NULL)) == -1) &&
|
||||
__sys_fcntl(i, F_GETFL, NULL)) == -1) &&
|
||||
(errno != EBADF))
|
||||
PANIC("Cannot get stdio flags");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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: */
|
||||
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: */
|
||||
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: */
|
||||
PANIC("Cannot get kernel read pipe flags");
|
||||
}
|
||||
|
@ -31,16 +31,20 @@
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
#include <pthread_np.h>
|
||||
|
||||
__weak_reference(_pthread_multi_np, pthread_multi_np);
|
||||
|
||||
int
|
||||
_pthread_multi_np()
|
||||
{
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
@ -887,21 +887,9 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
||||
*/
|
||||
if (((*mutex)->m_owner =
|
||||
mutex_queue_deq(*mutex)) != NULL) {
|
||||
/*
|
||||
* Unless the new owner of the mutex is
|
||||
* 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 !=
|
||||
PS_SUSPENDED)) {
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
} else {
|
||||
(*mutex)->m_owner->suspended =
|
||||
SUSP_NOWAIT;
|
||||
}
|
||||
/* Make the new owner runnable: */
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/*
|
||||
* Unless the new owner of the mutex is
|
||||
* 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.
|
||||
* Make the new owner runnable:
|
||||
*/
|
||||
if (((*mutex)->m_owner->state !=
|
||||
PS_SUSPENDED)) {
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
} else {
|
||||
(*mutex)->m_owner->suspended =
|
||||
SUSP_NOWAIT;
|
||||
}
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1148,20 +1126,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
||||
(*mutex)->m_prio;
|
||||
|
||||
/*
|
||||
* Unless the new owner of the mutex is
|
||||
* 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.
|
||||
* Make the new owner runnable:
|
||||
*/
|
||||
if (((*mutex)->m_owner->state !=
|
||||
PS_SUSPENDED)) {
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
} else {
|
||||
(*mutex)->m_owner->suspended =
|
||||
SUSP_NOWAIT;
|
||||
}
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -164,52 +164,74 @@ _pq_remove(pq_queue_t *pq, pthread_t pthread)
|
||||
void
|
||||
_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");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_NOT_QUEUED(pthread,
|
||||
"_pq_insert_head: Already in priority queue");
|
||||
_PQ_ASSERT_PROTECTED("_pq_insert_head: prioq not protected!");
|
||||
if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
|
||||
/* Make sure the threads state is suspended. */
|
||||
if (pthread->state != PS_SUSPENDED)
|
||||
PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
|
||||
} 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);
|
||||
if (pq->pq_lists[prio].pl_queued == 0)
|
||||
/* Insert the list into the priority queue: */
|
||||
pq_insert_prio_list(pq, prio);
|
||||
prio = pthread->active_priority;
|
||||
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;
|
||||
/* Mark this thread as being in the priority queue. */
|
||||
pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_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");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_NOT_QUEUED(pthread,
|
||||
"_pq_insert_tail: Already in priority queue");
|
||||
_PQ_ASSERT_PROTECTED("_pq_insert_tail: prioq not protected!");
|
||||
if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
|
||||
/* Make sure the threads state is suspended. */
|
||||
if (pthread->state != PS_SUSPENDED)
|
||||
PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
|
||||
} 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);
|
||||
if (pq->pq_lists[prio].pl_queued == 0)
|
||||
/* Insert the list into the priority queue: */
|
||||
pq_insert_prio_list(pq, prio);
|
||||
prio = pthread->active_priority;
|
||||
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;
|
||||
/* Mark this thread as being in the priority queue. */
|
||||
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: */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,62 +35,77 @@
|
||||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
|
||||
static void resume_common(struct pthread *);
|
||||
|
||||
__weak_reference(_pthread_resume_np, pthread_resume_np);
|
||||
__weak_reference(_pthread_resume_all_np, pthread_resume_all_np);
|
||||
|
||||
/* Resume a thread: */
|
||||
int
|
||||
_pthread_resume_np(pthread_t thread)
|
||||
{
|
||||
int ret;
|
||||
enum pthread_susp old_suspended;
|
||||
int ret;
|
||||
|
||||
/* Find the thread in the list of active threads: */
|
||||
if ((ret = _find_thread(thread)) == 0) {
|
||||
/* Cancel any pending suspensions: */
|
||||
old_suspended = thread->suspended;
|
||||
thread->suspended = SUSP_NO;
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Is it currently suspended? */
|
||||
if (thread->state == PS_SUSPENDED) {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
if ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0)
|
||||
resume_common(thread);
|
||||
|
||||
switch (old_suspended) {
|
||||
case SUSP_MUTEX_WAIT:
|
||||
/* Set the thread's state back. */
|
||||
PTHREAD_SET_STATE(thread,PS_MUTEX_WAIT);
|
||||
break;
|
||||
case SUSP_COND_WAIT:
|
||||
/* Set the thread's state back. */
|
||||
PTHREAD_SET_STATE(thread,PS_COND_WAIT);
|
||||
break;
|
||||
case SUSP_JOIN:
|
||||
/* Set the thread's state back. */
|
||||
PTHREAD_SET_STATE(thread,PS_JOIN);
|
||||
break;
|
||||
case SUSP_NOWAIT:
|
||||
/* Allow the thread to run. */
|
||||
PTHREAD_SET_STATE(thread,PS_RUNNING);
|
||||
PTHREAD_WAITQ_REMOVE(thread);
|
||||
PTHREAD_PRIOQ_INSERT_TAIL(thread);
|
||||
break;
|
||||
case SUSP_NO:
|
||||
case SUSP_YES:
|
||||
/* Allow the thread to run. */
|
||||
PTHREAD_SET_STATE(thread,PS_RUNNING);
|
||||
PTHREAD_PRIOQ_INSERT_TAIL(thread);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
void
|
||||
_pthread_resume_all_np(void)
|
||||
{
|
||||
struct pthread *curthread = _get_curthread();
|
||||
struct pthread *thread;
|
||||
|
||||
/*
|
||||
* 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) &&
|
||||
((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0))
|
||||
resume_common(thread);
|
||||
}
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if necessary:
|
||||
*/
|
||||
_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);
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ static void thread_sigframe_save(struct pthread *thread,
|
||||
static void thread_sig_invoke_handler(int sig, siginfo_t *info,
|
||||
ucontext_t *ucp);
|
||||
|
||||
/* #define DEBUG_SIGNAL */
|
||||
/*#define DEBUG_SIGNAL*/
|
||||
#ifdef DEBUG_SIGNAL
|
||||
#define DBG_MSG stdout_debug
|
||||
#else
|
||||
@ -375,7 +375,8 @@ thread_sig_find(int sig)
|
||||
return (NULL);
|
||||
}
|
||||
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 (suspended_thread == NULL)
|
||||
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
|
||||
* 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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -31,17 +31,19 @@
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
#include <pthread_np.h>
|
||||
|
||||
__weak_reference(_pthread_single_np, pthread_single_np);
|
||||
|
||||
int _pthread_single_np()
|
||||
{
|
||||
struct pthread *curthread = _get_curthread();
|
||||
|
||||
/* Enter single-threaded (non-POSIX) scheduling mode: */
|
||||
_thread_single = curthread;
|
||||
return(0);
|
||||
pthread_suspend_all_np();
|
||||
/*
|
||||
* XXX - Do we want to do this?
|
||||
* __is_threaded = 0;
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ _spinlock_debug(spinlock_t *lck, char *fname, int lineno)
|
||||
cnt++;
|
||||
if (cnt > 100) {
|
||||
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));
|
||||
__sleep(1);
|
||||
cnt = 0;
|
||||
|
@ -35,9 +35,10 @@
|
||||
#include <pthread.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_all_np, pthread_suspend_all_np);
|
||||
|
||||
/* Suspend a thread: */
|
||||
int
|
||||
@ -45,100 +46,19 @@ _pthread_suspend_np(pthread_t thread)
|
||||
{
|
||||
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: */
|
||||
if ((ret = _find_thread(thread)) == 0) {
|
||||
else if ((ret = _find_thread(thread)) == 0) {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
switch (thread->state) {
|
||||
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;
|
||||
}
|
||||
suspend_common(thread);
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
@ -146,16 +66,39 @@ _pthread_suspend_np(pthread_t thread)
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
return(ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
finish_suspension(void *arg)
|
||||
void
|
||||
_pthread_suspend_all_np(void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -78,20 +78,6 @@ _pthread_cancel(pthread_t pthread)
|
||||
break;
|
||||
|
||||
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_COND_WAIT:
|
||||
case PS_FDLR_WAIT:
|
||||
@ -109,7 +95,7 @@ _pthread_cancel(pthread_t pthread)
|
||||
*/
|
||||
pthread->interrupted = 1;
|
||||
pthread->cancelflags |= PTHREAD_CANCEL_NEEDED;
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
|
||||
pthread->continuation = finish_cancellation;
|
||||
break;
|
||||
|
||||
|
@ -524,15 +524,9 @@ _pthread_cond_signal(pthread_cond_t * cond)
|
||||
|
||||
if ((pthread = cond_queue_deq(*cond)) != NULL) {
|
||||
/*
|
||||
* Unless the thread is currently suspended,
|
||||
* allow it to run. If the thread is suspended,
|
||||
* make a note that the thread isn't in a wait
|
||||
* queue any more.
|
||||
* Wake up the signaled thread:
|
||||
*/
|
||||
if (pthread->state != PS_SUSPENDED)
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
else
|
||||
pthread->suspended = SUSP_NOWAIT;
|
||||
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
|
||||
}
|
||||
|
||||
/* Check for no more waiters: */
|
||||
@ -596,15 +590,9 @@ _pthread_cond_broadcast(pthread_cond_t * cond)
|
||||
*/
|
||||
while ((pthread = cond_queue_deq(*cond)) != NULL) {
|
||||
/*
|
||||
* Unless the thread is currently suspended,
|
||||
* allow it to run. If the thread is suspended,
|
||||
* make a note that the thread isn't in a wait
|
||||
* queue any more.
|
||||
* Wake up the signaled thread:
|
||||
*/
|
||||
if (pthread->state != PS_SUSPENDED)
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
else
|
||||
pthread->suspended = SUSP_NOWAIT;
|
||||
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
|
||||
}
|
||||
|
||||
/* There are no more waiting threads: */
|
||||
|
@ -202,22 +202,8 @@ _pthread_exit(void *status)
|
||||
pthread = curthread->joiner;
|
||||
curthread->joiner = NULL;
|
||||
|
||||
switch (pthread->suspended) {
|
||||
case SUSP_JOIN:
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
/* Make the joining thread runnable: */
|
||||
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
|
||||
|
||||
/* Set the return value for the joining thread: */
|
||||
pthread->join_status.ret = curthread->ret;
|
||||
|
@ -201,20 +201,21 @@ _thread_init(void)
|
||||
PANIC("Can't open console");
|
||||
if (setlogin("root") == -1)
|
||||
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");
|
||||
if (__sys_dup2(fd,0) == -1 ||
|
||||
__sys_dup2(fd,1) == -1 ||
|
||||
__sys_dup2(fd,2) == -1)
|
||||
if (__sys_dup2(fd, 0) == -1 ||
|
||||
__sys_dup2(fd, 1) == -1 ||
|
||||
__sys_dup2(fd, 2) == -1)
|
||||
PANIC("Can't dup2");
|
||||
}
|
||||
|
||||
/* 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] =
|
||||
__sys_fcntl(i,F_GETFL, NULL)) == -1) &&
|
||||
__sys_fcntl(i, F_GETFL, NULL)) == -1) &&
|
||||
(errno != EBADF))
|
||||
PANIC("Cannot get stdio flags");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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: */
|
||||
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: */
|
||||
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: */
|
||||
PANIC("Cannot get kernel read pipe flags");
|
||||
}
|
||||
|
@ -31,16 +31,20 @@
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
#include <pthread_np.h>
|
||||
|
||||
__weak_reference(_pthread_multi_np, pthread_multi_np);
|
||||
|
||||
int
|
||||
_pthread_multi_np()
|
||||
{
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
@ -887,21 +887,9 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
||||
*/
|
||||
if (((*mutex)->m_owner =
|
||||
mutex_queue_deq(*mutex)) != NULL) {
|
||||
/*
|
||||
* Unless the new owner of the mutex is
|
||||
* 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 !=
|
||||
PS_SUSPENDED)) {
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
} else {
|
||||
(*mutex)->m_owner->suspended =
|
||||
SUSP_NOWAIT;
|
||||
}
|
||||
/* Make the new owner runnable: */
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/*
|
||||
* Unless the new owner of the mutex is
|
||||
* 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.
|
||||
* Make the new owner runnable:
|
||||
*/
|
||||
if (((*mutex)->m_owner->state !=
|
||||
PS_SUSPENDED)) {
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
} else {
|
||||
(*mutex)->m_owner->suspended =
|
||||
SUSP_NOWAIT;
|
||||
}
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1148,20 +1126,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
||||
(*mutex)->m_prio;
|
||||
|
||||
/*
|
||||
* Unless the new owner of the mutex is
|
||||
* 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.
|
||||
* Make the new owner runnable:
|
||||
*/
|
||||
if (((*mutex)->m_owner->state !=
|
||||
PS_SUSPENDED)) {
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
} else {
|
||||
(*mutex)->m_owner->suspended =
|
||||
SUSP_NOWAIT;
|
||||
}
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -164,52 +164,74 @@ _pq_remove(pq_queue_t *pq, pthread_t pthread)
|
||||
void
|
||||
_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");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_NOT_QUEUED(pthread,
|
||||
"_pq_insert_head: Already in priority queue");
|
||||
_PQ_ASSERT_PROTECTED("_pq_insert_head: prioq not protected!");
|
||||
if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
|
||||
/* Make sure the threads state is suspended. */
|
||||
if (pthread->state != PS_SUSPENDED)
|
||||
PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
|
||||
} 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);
|
||||
if (pq->pq_lists[prio].pl_queued == 0)
|
||||
/* Insert the list into the priority queue: */
|
||||
pq_insert_prio_list(pq, prio);
|
||||
prio = pthread->active_priority;
|
||||
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;
|
||||
/* Mark this thread as being in the priority queue. */
|
||||
pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_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");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_NOT_QUEUED(pthread,
|
||||
"_pq_insert_tail: Already in priority queue");
|
||||
_PQ_ASSERT_PROTECTED("_pq_insert_tail: prioq not protected!");
|
||||
if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
|
||||
/* Make sure the threads state is suspended. */
|
||||
if (pthread->state != PS_SUSPENDED)
|
||||
PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
|
||||
} 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);
|
||||
if (pq->pq_lists[prio].pl_queued == 0)
|
||||
/* Insert the list into the priority queue: */
|
||||
pq_insert_prio_list(pq, prio);
|
||||
prio = pthread->active_priority;
|
||||
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;
|
||||
/* Mark this thread as being in the priority queue. */
|
||||
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: */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,14 +189,15 @@
|
||||
if ((thrd)->state != newstate) { \
|
||||
if ((thrd)->state == PS_RUNNING) { \
|
||||
PTHREAD_PRIOQ_REMOVE(thrd); \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
PTHREAD_WAITQ_INSERT(thrd); \
|
||||
} else if (newstate == PS_RUNNING) { \
|
||||
PTHREAD_WAITQ_REMOVE(thrd); \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
PTHREAD_PRIOQ_INSERT_TAIL(thrd); \
|
||||
} \
|
||||
} \
|
||||
_thread_kern_new_state = 0; \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
} while (0)
|
||||
#else
|
||||
#define PTHREAD_ASSERT(cond, msg)
|
||||
@ -399,18 +400,6 @@ struct pthread_attr {
|
||||
#define PTHREAD_CREATE_RUNNING 0
|
||||
#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.
|
||||
*/
|
||||
@ -684,8 +673,6 @@ struct pthread {
|
||||
#define PTHREAD_CANCEL_NEEDED 0x0010
|
||||
int cancelflags;
|
||||
|
||||
enum pthread_susp suspended;
|
||||
|
||||
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_CONDQ 0x0080 /* in condition 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 \
|
||||
(PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ)
|
||||
|
||||
@ -880,17 +868,6 @@ SCLASS struct pthread * volatile _last_user_thread
|
||||
;
|
||||
#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: */
|
||||
SCLASS TAILQ_HEAD(, pthread) _thread_list
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
|
@ -35,62 +35,77 @@
|
||||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
|
||||
static void resume_common(struct pthread *);
|
||||
|
||||
__weak_reference(_pthread_resume_np, pthread_resume_np);
|
||||
__weak_reference(_pthread_resume_all_np, pthread_resume_all_np);
|
||||
|
||||
/* Resume a thread: */
|
||||
int
|
||||
_pthread_resume_np(pthread_t thread)
|
||||
{
|
||||
int ret;
|
||||
enum pthread_susp old_suspended;
|
||||
int ret;
|
||||
|
||||
/* Find the thread in the list of active threads: */
|
||||
if ((ret = _find_thread(thread)) == 0) {
|
||||
/* Cancel any pending suspensions: */
|
||||
old_suspended = thread->suspended;
|
||||
thread->suspended = SUSP_NO;
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Is it currently suspended? */
|
||||
if (thread->state == PS_SUSPENDED) {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
if ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0)
|
||||
resume_common(thread);
|
||||
|
||||
switch (old_suspended) {
|
||||
case SUSP_MUTEX_WAIT:
|
||||
/* Set the thread's state back. */
|
||||
PTHREAD_SET_STATE(thread,PS_MUTEX_WAIT);
|
||||
break;
|
||||
case SUSP_COND_WAIT:
|
||||
/* Set the thread's state back. */
|
||||
PTHREAD_SET_STATE(thread,PS_COND_WAIT);
|
||||
break;
|
||||
case SUSP_JOIN:
|
||||
/* Set the thread's state back. */
|
||||
PTHREAD_SET_STATE(thread,PS_JOIN);
|
||||
break;
|
||||
case SUSP_NOWAIT:
|
||||
/* Allow the thread to run. */
|
||||
PTHREAD_SET_STATE(thread,PS_RUNNING);
|
||||
PTHREAD_WAITQ_REMOVE(thread);
|
||||
PTHREAD_PRIOQ_INSERT_TAIL(thread);
|
||||
break;
|
||||
case SUSP_NO:
|
||||
case SUSP_YES:
|
||||
/* Allow the thread to run. */
|
||||
PTHREAD_SET_STATE(thread,PS_RUNNING);
|
||||
PTHREAD_PRIOQ_INSERT_TAIL(thread);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
void
|
||||
_pthread_resume_all_np(void)
|
||||
{
|
||||
struct pthread *curthread = _get_curthread();
|
||||
struct pthread *thread;
|
||||
|
||||
/*
|
||||
* 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) &&
|
||||
((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0))
|
||||
resume_common(thread);
|
||||
}
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if necessary:
|
||||
*/
|
||||
_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);
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ static void thread_sigframe_save(struct pthread *thread,
|
||||
static void thread_sig_invoke_handler(int sig, siginfo_t *info,
|
||||
ucontext_t *ucp);
|
||||
|
||||
/* #define DEBUG_SIGNAL */
|
||||
/*#define DEBUG_SIGNAL*/
|
||||
#ifdef DEBUG_SIGNAL
|
||||
#define DBG_MSG stdout_debug
|
||||
#else
|
||||
@ -375,7 +375,8 @@ thread_sig_find(int sig)
|
||||
return (NULL);
|
||||
}
|
||||
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 (suspended_thread == NULL)
|
||||
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
|
||||
* 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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -31,17 +31,19 @@
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
#include <pthread_np.h>
|
||||
|
||||
__weak_reference(_pthread_single_np, pthread_single_np);
|
||||
|
||||
int _pthread_single_np()
|
||||
{
|
||||
struct pthread *curthread = _get_curthread();
|
||||
|
||||
/* Enter single-threaded (non-POSIX) scheduling mode: */
|
||||
_thread_single = curthread;
|
||||
return(0);
|
||||
pthread_suspend_all_np();
|
||||
/*
|
||||
* XXX - Do we want to do this?
|
||||
* __is_threaded = 0;
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ _spinlock_debug(spinlock_t *lck, char *fname, int lineno)
|
||||
cnt++;
|
||||
if (cnt > 100) {
|
||||
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));
|
||||
__sleep(1);
|
||||
cnt = 0;
|
||||
|
@ -35,9 +35,10 @@
|
||||
#include <pthread.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_all_np, pthread_suspend_all_np);
|
||||
|
||||
/* Suspend a thread: */
|
||||
int
|
||||
@ -45,100 +46,19 @@ _pthread_suspend_np(pthread_t thread)
|
||||
{
|
||||
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: */
|
||||
if ((ret = _find_thread(thread)) == 0) {
|
||||
else if ((ret = _find_thread(thread)) == 0) {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
switch (thread->state) {
|
||||
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;
|
||||
}
|
||||
suspend_common(thread);
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
@ -146,16 +66,39 @@ _pthread_suspend_np(pthread_t thread)
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
return(ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
finish_suspension(void *arg)
|
||||
void
|
||||
_pthread_suspend_all_np(void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -78,20 +78,6 @@ _pthread_cancel(pthread_t pthread)
|
||||
break;
|
||||
|
||||
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_COND_WAIT:
|
||||
case PS_FDLR_WAIT:
|
||||
@ -109,7 +95,7 @@ _pthread_cancel(pthread_t pthread)
|
||||
*/
|
||||
pthread->interrupted = 1;
|
||||
pthread->cancelflags |= PTHREAD_CANCEL_NEEDED;
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
|
||||
pthread->continuation = finish_cancellation;
|
||||
break;
|
||||
|
||||
|
@ -524,15 +524,9 @@ _pthread_cond_signal(pthread_cond_t * cond)
|
||||
|
||||
if ((pthread = cond_queue_deq(*cond)) != NULL) {
|
||||
/*
|
||||
* Unless the thread is currently suspended,
|
||||
* allow it to run. If the thread is suspended,
|
||||
* make a note that the thread isn't in a wait
|
||||
* queue any more.
|
||||
* Wake up the signaled thread:
|
||||
*/
|
||||
if (pthread->state != PS_SUSPENDED)
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
else
|
||||
pthread->suspended = SUSP_NOWAIT;
|
||||
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
|
||||
}
|
||||
|
||||
/* Check for no more waiters: */
|
||||
@ -596,15 +590,9 @@ _pthread_cond_broadcast(pthread_cond_t * cond)
|
||||
*/
|
||||
while ((pthread = cond_queue_deq(*cond)) != NULL) {
|
||||
/*
|
||||
* Unless the thread is currently suspended,
|
||||
* allow it to run. If the thread is suspended,
|
||||
* make a note that the thread isn't in a wait
|
||||
* queue any more.
|
||||
* Wake up the signaled thread:
|
||||
*/
|
||||
if (pthread->state != PS_SUSPENDED)
|
||||
PTHREAD_NEW_STATE(pthread,PS_RUNNING);
|
||||
else
|
||||
pthread->suspended = SUSP_NOWAIT;
|
||||
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
|
||||
}
|
||||
|
||||
/* There are no more waiting threads: */
|
||||
|
@ -202,22 +202,8 @@ _pthread_exit(void *status)
|
||||
pthread = curthread->joiner;
|
||||
curthread->joiner = NULL;
|
||||
|
||||
switch (pthread->suspended) {
|
||||
case SUSP_JOIN:
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
/* Make the joining thread runnable: */
|
||||
PTHREAD_NEW_STATE(pthread, PS_RUNNING);
|
||||
|
||||
/* Set the return value for the joining thread: */
|
||||
pthread->join_status.ret = curthread->ret;
|
||||
|
@ -201,20 +201,21 @@ _thread_init(void)
|
||||
PANIC("Can't open console");
|
||||
if (setlogin("root") == -1)
|
||||
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");
|
||||
if (__sys_dup2(fd,0) == -1 ||
|
||||
__sys_dup2(fd,1) == -1 ||
|
||||
__sys_dup2(fd,2) == -1)
|
||||
if (__sys_dup2(fd, 0) == -1 ||
|
||||
__sys_dup2(fd, 1) == -1 ||
|
||||
__sys_dup2(fd, 2) == -1)
|
||||
PANIC("Can't dup2");
|
||||
}
|
||||
|
||||
/* 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] =
|
||||
__sys_fcntl(i,F_GETFL, NULL)) == -1) &&
|
||||
__sys_fcntl(i, F_GETFL, NULL)) == -1) &&
|
||||
(errno != EBADF))
|
||||
PANIC("Cannot get stdio flags");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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: */
|
||||
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: */
|
||||
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: */
|
||||
PANIC("Cannot get kernel read pipe flags");
|
||||
}
|
||||
|
@ -31,16 +31,20 @@
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
#include <pthread_np.h>
|
||||
|
||||
__weak_reference(_pthread_multi_np, pthread_multi_np);
|
||||
|
||||
int
|
||||
_pthread_multi_np()
|
||||
{
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
@ -887,21 +887,9 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
||||
*/
|
||||
if (((*mutex)->m_owner =
|
||||
mutex_queue_deq(*mutex)) != NULL) {
|
||||
/*
|
||||
* Unless the new owner of the mutex is
|
||||
* 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 !=
|
||||
PS_SUSPENDED)) {
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
} else {
|
||||
(*mutex)->m_owner->suspended =
|
||||
SUSP_NOWAIT;
|
||||
}
|
||||
/* Make the new owner runnable: */
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/*
|
||||
* Unless the new owner of the mutex is
|
||||
* 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.
|
||||
* Make the new owner runnable:
|
||||
*/
|
||||
if (((*mutex)->m_owner->state !=
|
||||
PS_SUSPENDED)) {
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
} else {
|
||||
(*mutex)->m_owner->suspended =
|
||||
SUSP_NOWAIT;
|
||||
}
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1148,20 +1126,10 @@ mutex_unlock_common(pthread_mutex_t * mutex, int add_reference)
|
||||
(*mutex)->m_prio;
|
||||
|
||||
/*
|
||||
* Unless the new owner of the mutex is
|
||||
* 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.
|
||||
* Make the new owner runnable:
|
||||
*/
|
||||
if (((*mutex)->m_owner->state !=
|
||||
PS_SUSPENDED)) {
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
} else {
|
||||
(*mutex)->m_owner->suspended =
|
||||
SUSP_NOWAIT;
|
||||
}
|
||||
PTHREAD_NEW_STATE((*mutex)->m_owner,
|
||||
PS_RUNNING);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -164,52 +164,74 @@ _pq_remove(pq_queue_t *pq, pthread_t pthread)
|
||||
void
|
||||
_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");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_NOT_QUEUED(pthread,
|
||||
"_pq_insert_head: Already in priority queue");
|
||||
_PQ_ASSERT_PROTECTED("_pq_insert_head: prioq not protected!");
|
||||
if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
|
||||
/* Make sure the threads state is suspended. */
|
||||
if (pthread->state != PS_SUSPENDED)
|
||||
PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
|
||||
} 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);
|
||||
if (pq->pq_lists[prio].pl_queued == 0)
|
||||
/* Insert the list into the priority queue: */
|
||||
pq_insert_prio_list(pq, prio);
|
||||
prio = pthread->active_priority;
|
||||
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;
|
||||
/* Mark this thread as being in the priority queue. */
|
||||
pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ;
|
||||
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
_PQ_CLEAR_ACTIVE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_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");
|
||||
_PQ_SET_ACTIVE();
|
||||
_PQ_ASSERT_NOT_QUEUED(pthread,
|
||||
"_pq_insert_tail: Already in priority queue");
|
||||
_PQ_ASSERT_PROTECTED("_pq_insert_tail: prioq not protected!");
|
||||
if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) {
|
||||
/* Make sure the threads state is suspended. */
|
||||
if (pthread->state != PS_SUSPENDED)
|
||||
PTHREAD_SET_STATE(pthread, PS_SUSPENDED);
|
||||
} 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);
|
||||
if (pq->pq_lists[prio].pl_queued == 0)
|
||||
/* Insert the list into the priority queue: */
|
||||
pq_insert_prio_list(pq, prio);
|
||||
prio = pthread->active_priority;
|
||||
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;
|
||||
/* Mark this thread as being in the priority queue. */
|
||||
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: */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,14 +189,15 @@
|
||||
if ((thrd)->state != newstate) { \
|
||||
if ((thrd)->state == PS_RUNNING) { \
|
||||
PTHREAD_PRIOQ_REMOVE(thrd); \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
PTHREAD_WAITQ_INSERT(thrd); \
|
||||
} else if (newstate == PS_RUNNING) { \
|
||||
PTHREAD_WAITQ_REMOVE(thrd); \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
PTHREAD_PRIOQ_INSERT_TAIL(thrd); \
|
||||
} \
|
||||
} \
|
||||
_thread_kern_new_state = 0; \
|
||||
PTHREAD_SET_STATE(thrd, newstate); \
|
||||
} while (0)
|
||||
#else
|
||||
#define PTHREAD_ASSERT(cond, msg)
|
||||
@ -399,18 +400,6 @@ struct pthread_attr {
|
||||
#define PTHREAD_CREATE_RUNNING 0
|
||||
#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.
|
||||
*/
|
||||
@ -684,8 +673,6 @@ struct pthread {
|
||||
#define PTHREAD_CANCEL_NEEDED 0x0010
|
||||
int cancelflags;
|
||||
|
||||
enum pthread_susp suspended;
|
||||
|
||||
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_CONDQ 0x0080 /* in condition 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 \
|
||||
(PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ)
|
||||
|
||||
@ -880,17 +868,6 @@ SCLASS struct pthread * volatile _last_user_thread
|
||||
;
|
||||
#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: */
|
||||
SCLASS TAILQ_HEAD(, pthread) _thread_list
|
||||
#ifdef GLOBAL_PTHREAD_PRIVATE
|
||||
|
@ -35,62 +35,77 @@
|
||||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
|
||||
static void resume_common(struct pthread *);
|
||||
|
||||
__weak_reference(_pthread_resume_np, pthread_resume_np);
|
||||
__weak_reference(_pthread_resume_all_np, pthread_resume_all_np);
|
||||
|
||||
/* Resume a thread: */
|
||||
int
|
||||
_pthread_resume_np(pthread_t thread)
|
||||
{
|
||||
int ret;
|
||||
enum pthread_susp old_suspended;
|
||||
int ret;
|
||||
|
||||
/* Find the thread in the list of active threads: */
|
||||
if ((ret = _find_thread(thread)) == 0) {
|
||||
/* Cancel any pending suspensions: */
|
||||
old_suspended = thread->suspended;
|
||||
thread->suspended = SUSP_NO;
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
/* Is it currently suspended? */
|
||||
if (thread->state == PS_SUSPENDED) {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues
|
||||
* from access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
if ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0)
|
||||
resume_common(thread);
|
||||
|
||||
switch (old_suspended) {
|
||||
case SUSP_MUTEX_WAIT:
|
||||
/* Set the thread's state back. */
|
||||
PTHREAD_SET_STATE(thread,PS_MUTEX_WAIT);
|
||||
break;
|
||||
case SUSP_COND_WAIT:
|
||||
/* Set the thread's state back. */
|
||||
PTHREAD_SET_STATE(thread,PS_COND_WAIT);
|
||||
break;
|
||||
case SUSP_JOIN:
|
||||
/* Set the thread's state back. */
|
||||
PTHREAD_SET_STATE(thread,PS_JOIN);
|
||||
break;
|
||||
case SUSP_NOWAIT:
|
||||
/* Allow the thread to run. */
|
||||
PTHREAD_SET_STATE(thread,PS_RUNNING);
|
||||
PTHREAD_WAITQ_REMOVE(thread);
|
||||
PTHREAD_PRIOQ_INSERT_TAIL(thread);
|
||||
break;
|
||||
case SUSP_NO:
|
||||
case SUSP_YES:
|
||||
/* Allow the thread to run. */
|
||||
PTHREAD_SET_STATE(thread,PS_RUNNING);
|
||||
PTHREAD_PRIOQ_INSERT_TAIL(thread);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
* necessary:
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
void
|
||||
_pthread_resume_all_np(void)
|
||||
{
|
||||
struct pthread *curthread = _get_curthread();
|
||||
struct pthread *thread;
|
||||
|
||||
/*
|
||||
* 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) &&
|
||||
((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0))
|
||||
resume_common(thread);
|
||||
}
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if necessary:
|
||||
*/
|
||||
_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);
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ static void thread_sigframe_save(struct pthread *thread,
|
||||
static void thread_sig_invoke_handler(int sig, siginfo_t *info,
|
||||
ucontext_t *ucp);
|
||||
|
||||
/* #define DEBUG_SIGNAL */
|
||||
/*#define DEBUG_SIGNAL*/
|
||||
#ifdef DEBUG_SIGNAL
|
||||
#define DBG_MSG stdout_debug
|
||||
#else
|
||||
@ -375,7 +375,8 @@ thread_sig_find(int sig)
|
||||
return (NULL);
|
||||
}
|
||||
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 (suspended_thread == NULL)
|
||||
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
|
||||
* 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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -31,17 +31,19 @@
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include "pthread_private.h"
|
||||
#include <pthread_np.h>
|
||||
|
||||
__weak_reference(_pthread_single_np, pthread_single_np);
|
||||
|
||||
int _pthread_single_np()
|
||||
{
|
||||
struct pthread *curthread = _get_curthread();
|
||||
|
||||
/* Enter single-threaded (non-POSIX) scheduling mode: */
|
||||
_thread_single = curthread;
|
||||
return(0);
|
||||
pthread_suspend_all_np();
|
||||
/*
|
||||
* XXX - Do we want to do this?
|
||||
* __is_threaded = 0;
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ _spinlock_debug(spinlock_t *lck, char *fname, int lineno)
|
||||
cnt++;
|
||||
if (cnt > 100) {
|
||||
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));
|
||||
__sleep(1);
|
||||
cnt = 0;
|
||||
|
@ -35,9 +35,10 @@
|
||||
#include <pthread.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_all_np, pthread_suspend_all_np);
|
||||
|
||||
/* Suspend a thread: */
|
||||
int
|
||||
@ -45,100 +46,19 @@ _pthread_suspend_np(pthread_t thread)
|
||||
{
|
||||
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: */
|
||||
if ((ret = _find_thread(thread)) == 0) {
|
||||
else if ((ret = _find_thread(thread)) == 0) {
|
||||
/*
|
||||
* Defer signals to protect the scheduling queues from
|
||||
* access by the signal handler:
|
||||
*/
|
||||
_thread_kern_sig_defer();
|
||||
|
||||
switch (thread->state) {
|
||||
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;
|
||||
}
|
||||
suspend_common(thread);
|
||||
|
||||
/*
|
||||
* Undefer and handle pending signals, yielding if
|
||||
@ -146,16 +66,39 @@ _pthread_suspend_np(pthread_t thread)
|
||||
*/
|
||||
_thread_kern_sig_undefer();
|
||||
}
|
||||
return(ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
finish_suspension(void *arg)
|
||||
void
|
||||
_pthread_suspend_all_np(void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user