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
abd4f3d6cc
commit
9ba1f9fa38
@ -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
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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: */
|
||||||
|
@ -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;
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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: */
|
||||||
|
@ -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;
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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: */
|
||||||
|
@ -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;
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user