This can be turned back on when the library is compiled with -DMTHREAD_STRICT (which enables more sanity checks). However, always performing this check shows up in system profiling results.
		
			
				
	
	
		
			288 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			288 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include <minix/mthread.h>
 | 
						|
#include "global.h"
 | 
						|
#include "proto.h"
 | 
						|
 | 
						|
#ifdef MTHREAD_STRICT
 | 
						|
static struct __mthread_cond *vc_front, *vc_rear;
 | 
						|
static void mthread_cond_add(mthread_cond_t *c);
 | 
						|
static void mthread_cond_remove(mthread_cond_t *c);
 | 
						|
static 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		     *
 | 
						|
 *===========================================================================*/
 | 
						|
void mthread_init_valid_conditions(void)
 | 
						|
{
 | 
						|
#ifdef MTHREAD_STRICT
 | 
						|
/* Initialize condition variable list */
 | 
						|
  vc_front = vc_rear = NULL;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				mthread_cond_add			     *
 | 
						|
 *===========================================================================*/
 | 
						|
#ifdef MTHREAD_STRICT
 | 
						|
static 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			     *
 | 
						|
 *===========================================================================*/
 | 
						|
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_CHECK_INIT();	/* Make sure libmthread is initialized */
 | 
						|
 | 
						|
  if (cond == NULL) 
 | 
						|
  	return(EINVAL);
 | 
						|
  else if (!mthread_cond_valid(cond))
 | 
						|
  	return(EINVAL);
 | 
						|
 | 
						|
  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			     *
 | 
						|
 *===========================================================================*/
 | 
						|
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_CHECK_INIT();	/* Make sure libmthread is initialized */
 | 
						|
 | 
						|
  if (cond == NULL)
 | 
						|
  	return(EINVAL);
 | 
						|
  else if (!mthread_cond_valid(cond))
 | 
						|
  	return(EINVAL);
 | 
						|
 | 
						|
  /* Is another thread currently using this condition variable? */
 | 
						|
  tcb = mthread_find_tcb(MAIN_THREAD);
 | 
						|
  if (tcb->m_state == MS_CONDITION && tcb->m_cond == *cond)
 | 
						|
  	return(EBUSY);
 | 
						|
 | 
						|
  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)
 | 
						|
		return(EBUSY);
 | 
						|
  }
 | 
						|
 | 
						|
  /* Not in use; invalidate it. */
 | 
						|
  mthread_cond_remove(cond);
 | 
						|
  free(*cond);
 | 
						|
  *cond = NULL;
 | 
						|
 | 
						|
  return(0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				mthread_cond_init			     *
 | 
						|
 *===========================================================================*/
 | 
						|
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_CHECK_INIT();	/* Make sure libmthread is initialized */
 | 
						|
 | 
						|
  if (cond == NULL) 
 | 
						|
	return(EINVAL);
 | 
						|
  else if (cattr != NULL) 
 | 
						|
  	return(ENOSYS);
 | 
						|
 | 
						|
#ifdef MTHREAD_STRICT
 | 
						|
  else if (mthread_cond_valid(cond)) 
 | 
						|
	/* Already initialized */
 | 
						|
  	return(EBUSY);
 | 
						|
#endif
 | 
						|
  else if ((c = malloc(sizeof(struct __mthread_cond))) == NULL) 
 | 
						|
  	return(ENOMEM);
 | 
						|
 | 
						|
  c->mc_mutex = NULL;
 | 
						|
  *cond = (mthread_cond_t) c;
 | 
						|
  mthread_cond_add(cond);
 | 
						|
 | 
						|
  return(0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				mthread_cond_remove			     *
 | 
						|
 *===========================================================================*/
 | 
						|
#ifdef MTHREAD_STRICT
 | 
						|
static 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			     *
 | 
						|
 *===========================================================================*/
 | 
						|
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_CHECK_INIT();	/* Make sure libmthread is initialized */
 | 
						|
 | 
						|
  if (cond == NULL)
 | 
						|
	return(EINVAL);
 | 
						|
  else if (!mthread_cond_valid(cond))
 | 
						|
	return(EINVAL);
 | 
						|
 | 
						|
  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
 | 
						|
static 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_CHECK_INIT();
 | 
						|
 | 
						|
  loopitem = vc_front;
 | 
						|
 | 
						|
  while (loopitem != NULL) {
 | 
						|
  	if (loopitem == *c)
 | 
						|
  		return(1);
 | 
						|
 | 
						|
  	loopitem = loopitem->mc_next;
 | 
						|
  }
 | 
						|
 | 
						|
  return(0);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				mthread_cond_verify			     *
 | 
						|
 *===========================================================================*/
 | 
						|
#ifdef MDEBUG
 | 
						|
int mthread_cond_verify(void)
 | 
						|
{
 | 
						|
/* Return true in case no condition variables are in use. */
 | 
						|
 | 
						|
  MTHREAD_CHECK_INIT();	/* Make sure libmthread is initialized */
 | 
						|
 | 
						|
  return(vc_front == NULL);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
/*===========================================================================*
 | 
						|
 *				mthread_cond_wait			     *
 | 
						|
 *===========================================================================*/
 | 
						|
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_CHECK_INIT();	/* Make sure libmthread is initialized */
 | 
						|
 | 
						|
  if (cond == NULL || mutex == NULL)
 | 
						|
	return(EINVAL);
 | 
						|
  
 | 
						|
  c = (struct __mthread_cond *) *cond;
 | 
						|
  m = (struct __mthread_mutex *) *mutex;
 | 
						|
 | 
						|
  if (!mthread_cond_valid(cond) || !mthread_mutex_valid(mutex)) 
 | 
						|
	return(EINVAL);
 | 
						|
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
 |