minix/lib/libmthread/condition.c
Thomas Veerman c8d0edc06a - Refactor mthread structure fields to prevent name clashes
- Remove sanity checks for initialized mutexes and condition variables. This
  significantly boosts performance. The checks can be turned back on by
  compiling libmthread with MTHREAD_STRICT. According to POSIX operations on
  uninitialized variables are a MAY fail if, therefore allowing this
  optimization.
- Test59 has to be accommodated to the lack of sanity checks on uninitialized
  variables in the library. It specifically tests for them and will run into
  segfaults when the checks are absent in the library.
- Fix a few bugs related to the scheduler
- Do some general code cleanups
2011-03-18 10:29:54 +00:00

309 lines
7.8 KiB
C

#include <minix/mthread.h>
#include "global.h"
#include "proto.h"
PRIVATE struct __mthread_cond *vc_front, *vc_rear;
#ifdef MTHREAD_STRICT
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) );
#else
# define mthread_cond_add(c) ((*c)->mc_magic = MTHREAD_INIT_MAGIC)
# define mthread_cond_remove(c) ((*c)->mc_magic = MTHREAD_NOT_INUSE)
# define mthread_cond_valid(c) ((*c)->mc_magic == MTHREAD_INIT_MAGIC)
#endif
#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 *
*===========================================================================*/
#ifdef MTHREAD_STRICT
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)->mc_prev = NULL;
} else {
vc_rear->mc_next = *c;
(*c)->mc_prev = vc_rear;
}
(*c)->mc_next = NULL;
vc_rear = *c;
}
#endif
/*===========================================================================*
* 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);
} else 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);
} else 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);
}
#ifdef MTHREAD_STRICT
else if (mthread_cond_valid(cond)) {
/* Already initialized */
errno = EBUSY;
return(-1);
}
#endif
else if ((c = malloc(sizeof(struct __mthread_cond))) == NULL) {
errno = ENOMEM;
return(-1);
}
c->mc_mutex = NULL;
*cond = (mthread_cond_t) c;
mthread_cond_add(cond);
return(0);
}
/*===========================================================================*
* mthread_cond_remove *
*===========================================================================*/
#ifdef MTHREAD_STRICT
PRIVATE void mthread_cond_remove(c)
mthread_cond_t *c;
{
/* Remove condition from list of valid, initialized conditions */
if ((*c)->mc_prev == NULL)
vc_front = (*c)->mc_next;
else
(*c)->mc_prev->mc_next = (*c)->mc_next;
if ((*c)->mc_next == NULL)
vc_rear = (*c)->mc_prev;
else
(*c)->mc_next->mc_prev = (*c)->mc_prev;
}
#endif
/*===========================================================================*
* 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);
} else 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 *
*===========================================================================*/
#ifdef MTHREAD_STRICT
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;
mthread_init();
loopitem = vc_front;
while (loopitem != NULL) {
if (loopitem == *c)
return(1);
loopitem = loopitem->mc_next;
}
return(0);
}
#endif
/*===========================================================================*
* 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->mc_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->mc_mutex = NULL; /* Forget about this mutex */
tcb->m_cond = NULL; /* ... and condition var */
if (mthread_mutex_lock(mutex) != 0)
return(-1);
return(0);
}