minix/lib/libmthread/condition.c
Thomas Veerman a7072a5e1c Revamp the mthread library and update test59
Before, the 'main thread' of a process was never taken into account anywhere in
the library, causing mutexes not to work properly (and consequently, neither
did the condition variables). For example, if the 'main thread' (that is, the
thread which is started at the beginning of a process; not a spawned thread by
the library) would lock a mutex, it wasn't actually locked.
2010-09-30 13:44:13 +00:00

301 lines
7.4 KiB
C

#include <minix/mthread.h>
#include "global.h"
#include "proto.h"
PRIVATE struct __mthread_cond *vc_front, *vc_rear;
FORWARD _PROTOTYPE( void mthread_cond_add, (mthread_cond_t *c) );
FORWARD _PROTOTYPE( void mthread_cond_remove, (mthread_cond_t *c) );
FORWARD _PROTOTYPE( int mthread_cond_valid, (mthread_cond_t *c) );
#define MAIN_COND mainthread.m_cond
/*===========================================================================*
* mthread_init_valid_conditions *
*===========================================================================*/
PUBLIC void mthread_init_valid_conditions(void)
{
/* Initialize condition variable list */
vc_front = vc_rear = NULL;
}
/*===========================================================================*
* mthread_cond_add *
*===========================================================================*/
PRIVATE void mthread_cond_add(c)
mthread_cond_t *c;
{
/* Add condition to list of valid, initialized conditions */
if (vc_front == NULL) { /* Empty list */
vc_front = *c;
(*c)->prev = NULL;
} else {
vc_rear->next = *c;
(*c)->prev = vc_rear;
}
(*c)->next = NULL;
vc_rear = *c;
}
/*===========================================================================*
* mthread_cond_broadcast *
*===========================================================================*/
PUBLIC int mthread_cond_broadcast(cond)
mthread_cond_t *cond;
{
/* Signal all threads waiting for condition 'cond'. */
mthread_thread_t t;
mthread_tcb_t *tcb;
mthread_init(); /* Make sure libmthread is initialized */
if(cond == NULL) {
errno = EINVAL;
return(-1);
}
if (!mthread_cond_valid(cond)) {
errno = EINVAL;
return(-1);
}
tcb = mthread_find_tcb(MAIN_THREAD);
if (tcb->m_state == MS_CONDITION && tcb->m_cond == *cond)
mthread_unsuspend(MAIN_THREAD);
for (t = (mthread_thread_t) 0; t < no_threads; t++) {
tcb = mthread_find_tcb(t);
if (tcb->m_state == MS_CONDITION && tcb->m_cond == *cond)
mthread_unsuspend(t);
}
return(0);
}
/*===========================================================================*
* mthread_cond_destroy *
*===========================================================================*/
PUBLIC int mthread_cond_destroy(cond)
mthread_cond_t *cond;
{
/* Destroy a condition variable. Make sure it's not in use */
mthread_thread_t t;
mthread_tcb_t *tcb;
mthread_init(); /* Make sure libmthread is initialized */
if (cond == NULL) {
errno = EINVAL;
return(-1);
}
if (!mthread_cond_valid(cond)) {
errno = EINVAL;
return(-1);
}
/* Is another thread currently using this condition variable? */
tcb = mthread_find_tcb(MAIN_THREAD);
if (tcb->m_state == MS_CONDITION && tcb->m_cond == *cond) {
errno = EBUSY;
return(-1);
}
for (t = (mthread_thread_t) 0; t < no_threads; t++) {
tcb = mthread_find_tcb(t);
if(tcb->m_state == MS_CONDITION && tcb->m_cond == *cond){
errno = EBUSY;
return(-1);
}
}
/* Not in use; invalidate it. */
mthread_cond_remove(cond);
free(*cond);
*cond = NULL;
return(0);
}
/*===========================================================================*
* mthread_cond_init *
*===========================================================================*/
PUBLIC int mthread_cond_init(cond, cattr)
mthread_cond_t *cond;
mthread_condattr_t *cattr;
{
/* Initialize condition variable to a known state. cattr is ignored */
struct __mthread_cond *c;
mthread_init(); /* Make sure libmthread is initialized */
if (cond == NULL) {
errno = EINVAL;
return(-1);
} else if (cattr != NULL) {
errno = ENOSYS;
return(-1);
}
if (mthread_cond_valid(cond)) {
/* Already initialized */
errno = EBUSY;
return(-1);
}
if ((c = malloc(sizeof(struct __mthread_cond))) == NULL)
return(-1);
c->mutex = NULL;
*cond = (mthread_cond_t) c;
mthread_cond_add(cond);
return(0);
}
/*===========================================================================*
* mthread_cond_remove *
*===========================================================================*/
PRIVATE void mthread_cond_remove(c)
mthread_cond_t *c;
{
/* Remove condition from list of valid, initialized conditions */
if ((*c)->prev == NULL)
vc_front = (*c)->next;
else
(*c)->prev->next = (*c)->next;
if ((*c)->next == NULL)
vc_rear = (*c)->prev;
else
(*c)->next->prev = (*c)->prev;
}
/*===========================================================================*
* mthread_cond_signal *
*===========================================================================*/
PUBLIC int mthread_cond_signal(cond)
mthread_cond_t *cond;
{
/* Signal a thread that condition 'cond' was met. Just a single thread. */
mthread_thread_t t;
mthread_tcb_t *tcb;
mthread_init(); /* Make sure libmthread is initialized */
if(cond == NULL) {
errno = EINVAL;
return(-1);
}
if (!mthread_cond_valid(cond)) {
errno = EINVAL;
return(-1);
}
tcb = mthread_find_tcb(MAIN_THREAD);
if (tcb->m_state == MS_CONDITION && tcb->m_cond == *cond)
mthread_unsuspend(MAIN_THREAD);
for (t = (mthread_thread_t) 0; t < no_threads; t++) {
tcb = mthread_find_tcb(t);
if(tcb->m_state == MS_CONDITION && tcb->m_cond == *cond){
mthread_unsuspend(t);
break;
}
}
return(0);
}
/*===========================================================================*
* mthread_cond_valid *
*===========================================================================*/
PRIVATE int mthread_cond_valid(c)
mthread_cond_t *c;
{
/* Check to see if cond is on the list of valid conditions */
struct __mthread_cond *loopitem;
loopitem = vc_front;
while (loopitem != NULL) {
if (loopitem == *c)
return(1);
loopitem = loopitem->next;
}
return(0);
}
/*===========================================================================*
* mthread_cond_verify *
*===========================================================================*/
#ifdef MDEBUG
PUBLIC int mthread_cond_verify(void)
{
/* Return true in case no condition variables are in use. */
mthread_init(); /* Make sure libmthread is initialized */
return(vc_front == NULL);
}
#endif
/*===========================================================================*
* mthread_cond_wait *
*===========================================================================*/
PUBLIC int mthread_cond_wait(cond, mutex)
mthread_cond_t *cond;
mthread_mutex_t *mutex;
{
/* Wait for a condition to be signaled */
mthread_tcb_t *tcb;
struct __mthread_cond *c;
struct __mthread_mutex *m;
mthread_init(); /* Make sure libmthread is initialized */
if (cond == NULL || mutex == NULL) {
errno = EINVAL;
return(-1);
}
c = (struct __mthread_cond *) *cond;
m = (struct __mthread_mutex *) *mutex;
if (!mthread_cond_valid(cond) || !mthread_mutex_valid(mutex)) {
errno = EINVAL;
return(-1);
}
c->mutex = m; /* Remember we're using this mutex in a cond_wait */
if (mthread_mutex_unlock(mutex) != 0) /* Fails when we're not the owner */
return(-1);
tcb = mthread_find_tcb(current_thread);
tcb->m_cond = c; /* Register condition variable. */
mthread_suspend(MS_CONDITION);
/* When execution returns here, the condition was met. Lock mutex again. */
c->mutex = NULL; /* Forget about this mutex */
tcb->m_cond = NULL; /* ... and condition var */
if (mthread_mutex_lock(mutex) != 0)
return(-1);
return(0);
}