 76092ddf33
			
		
	
	
		76092ddf33
		
	
	
	
	
		
			
			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.
		
			
				
	
	
		
			282 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			282 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <minix/mthread.h>
 | |
| #include "global.h"
 | |
| #include "proto.h"
 | |
| 
 | |
| #ifdef MTHREAD_STRICT
 | |
| static struct __mthread_mutex *vm_front, *vm_rear;
 | |
| static void mthread_mutex_add(mthread_mutex_t *m);
 | |
| static void mthread_mutex_remove(mthread_mutex_t *m);
 | |
| #else
 | |
| # define mthread_mutex_add(m)		((*m)->mm_magic = MTHREAD_INIT_MAGIC)
 | |
| # define mthread_mutex_remove(m)	((*m)->mm_magic = MTHREAD_NOT_INUSE)
 | |
| #endif
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_init_valid_mutexes		     *
 | |
|  *===========================================================================*/
 | |
| void mthread_init_valid_mutexes(void)
 | |
| {
 | |
| #ifdef MTHREAD_STRICT
 | |
| /* Initialize list of valid mutexes */
 | |
|   vm_front = vm_rear = NULL;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_mutex_add			     *
 | |
|  *===========================================================================*/
 | |
| #ifdef MTHREAD_STRICT
 | |
| static void mthread_mutex_add(m) 
 | |
| mthread_mutex_t *m;
 | |
| {
 | |
| /* Add mutex to list of valid, initialized mutexes */
 | |
| 
 | |
|   if (vm_front == NULL) {	/* Empty list */
 | |
|   	vm_front = *m;
 | |
|   	(*m)->mm_prev = NULL;
 | |
|   } else {
 | |
|   	vm_rear->mm_next = *m;
 | |
|   	(*m)->mm_prev = vm_rear;
 | |
|   }
 | |
| 
 | |
|   (*m)->mm_next = NULL;
 | |
|   vm_rear = *m;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_mutex_destroy			     *
 | |
|  *===========================================================================*/
 | |
| int mthread_mutex_destroy(mutex)
 | |
| mthread_mutex_t *mutex;
 | |
| {
 | |
| /* Invalidate mutex and deallocate resources. */
 | |
| 
 | |
|   mthread_thread_t t;
 | |
|   mthread_tcb_t *tcb;
 | |
| 
 | |
|   MTHREAD_CHECK_INIT();	/* Make sure mthreads is initialized */
 | |
| 
 | |
|   if (mutex == NULL)
 | |
|   	return(EINVAL);
 | |
| 
 | |
|   if (!mthread_mutex_valid(mutex)) 
 | |
|   	return(EINVAL);
 | |
|   else if ((*mutex)->mm_owner != NO_THREAD)
 | |
|   	return(EBUSY);
 | |
| 
 | |
|   /* Check if this mutex is not associated with a condition */
 | |
|   for (t = (mthread_thread_t) 0; t < no_threads; t++) {
 | |
|   	tcb = mthread_find_tcb(t);
 | |
| 	if (tcb->m_state == MS_CONDITION) {
 | |
| 		if (tcb->m_cond != NULL && tcb->m_cond->mc_mutex == *mutex) 
 | |
| 			return(EBUSY);
 | |
| 	}
 | |
|   }
 | |
| 
 | |
|   /* Not in use; invalidate it */
 | |
|   mthread_mutex_remove(mutex);	
 | |
|   free(*mutex);
 | |
|   *mutex = NULL;
 | |
| 
 | |
|   return(0);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_mutex_init			     *
 | |
|  *===========================================================================*/
 | |
| int mthread_mutex_init(mutex, mattr)
 | |
| mthread_mutex_t *mutex;	/* Mutex that is to be initialized */
 | |
| mthread_mutexattr_t *mattr;	/* Mutex attribute */
 | |
| {
 | |
| /* Initialize the mutex to a known state. Attributes are not supported */
 | |
| 
 | |
|   struct __mthread_mutex *m;
 | |
| 
 | |
|   MTHREAD_CHECK_INIT();	/* Make sure mthreads is initialized */
 | |
| 
 | |
|   if (mutex == NULL)
 | |
|   	return(EAGAIN);
 | |
|   else if (mattr != NULL)
 | |
|   	return(ENOSYS);
 | |
| #ifdef MTHREAD_STRICT
 | |
|   else if (mthread_mutex_valid(mutex))
 | |
|   	return(EBUSY);
 | |
| #endif
 | |
|   else if ((m = malloc(sizeof(struct __mthread_mutex))) == NULL) 
 | |
|   	return(ENOMEM);
 | |
| 
 | |
|   mthread_queue_init(&m->mm_queue);
 | |
|   m->mm_owner = NO_THREAD;
 | |
|   *mutex = (mthread_mutex_t) m;
 | |
|   mthread_mutex_add(mutex); /* Validate mutex; mutex now in use */
 | |
| 
 | |
|   return(0);
 | |
| }
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_mutex_lock			     *
 | |
|  *===========================================================================*/
 | |
| int mthread_mutex_lock(mutex)
 | |
| mthread_mutex_t *mutex;	/* Mutex that is to be locked */
 | |
| {
 | |
| /* Try to lock this mutex. If already locked, append the current thread to
 | |
|  * FIFO queue associated with this mutex and suspend the thread. */
 | |
| 
 | |
|   struct __mthread_mutex *m;
 | |
| 
 | |
|   MTHREAD_CHECK_INIT();	/* Make sure mthreads is initialized */
 | |
| 
 | |
|   if (mutex == NULL)
 | |
|   	return(EINVAL);
 | |
| 
 | |
|   m = (struct __mthread_mutex *) *mutex;
 | |
|   if (!mthread_mutex_valid(&m)) 
 | |
|   	return(EINVAL);
 | |
|   else if (m->mm_owner == NO_THREAD) { /* Not locked */
 | |
| 	m->mm_owner = current_thread;
 | |
|   } else if (m->mm_owner == current_thread) {
 | |
|   	return(EDEADLK);
 | |
|   } else {
 | |
| 	mthread_queue_add(&m->mm_queue, current_thread);
 | |
| 	mthread_suspend(MS_MUTEX);
 | |
|   }
 | |
| 
 | |
|   /* When we get here we acquired the lock. */
 | |
|   return(0);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_mutex_remove			     *
 | |
|  *===========================================================================*/
 | |
| #ifdef MTHREAD_STRICT
 | |
| static void mthread_mutex_remove(m)
 | |
| mthread_mutex_t *m;
 | |
| {
 | |
| /* Remove mutex from list of valid, initialized mutexes */
 | |
| 
 | |
|   if ((*m)->mm_prev == NULL)
 | |
|   	vm_front = (*m)->mm_next;
 | |
|   else
 | |
|   	(*m)->mm_prev->mm_next = (*m)->mm_next;
 | |
| 
 | |
|   if ((*m)->mm_next == NULL)
 | |
|   	vm_rear = (*m)->mm_prev;
 | |
|   else
 | |
|   	(*m)->mm_next->mm_prev = (*m)->mm_prev;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_mutex_trylock			     *
 | |
|  *===========================================================================*/
 | |
| int mthread_mutex_trylock(mutex)
 | |
| mthread_mutex_t *mutex;	/* Mutex that is to be locked */
 | |
| {
 | |
| /* Try to lock this mutex and return OK. If already locked, return error. */
 | |
| 
 | |
|   struct __mthread_mutex *m;
 | |
| 
 | |
|   MTHREAD_CHECK_INIT();	/* Make sure mthreads is initialized */
 | |
| 
 | |
|   if (mutex == NULL) 
 | |
|   	return(EINVAL);
 | |
| 
 | |
|   m = (struct __mthread_mutex *) *mutex;
 | |
|   if (!mthread_mutex_valid(&m))
 | |
|   	return(EINVAL);
 | |
|   else if (m->mm_owner == current_thread)
 | |
| 	return(EDEADLK);
 | |
|   else if (m->mm_owner == NO_THREAD) {
 | |
| 	m->mm_owner = current_thread;
 | |
| 	return(0);
 | |
|   } 
 | |
| 
 | |
|   return(EBUSY);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_mutex_unlock			     *
 | |
|  *===========================================================================*/
 | |
| int mthread_mutex_unlock(mutex)
 | |
| mthread_mutex_t *mutex;	/* Mutex that is to be unlocked */
 | |
| {
 | |
| /* Unlock a previously locked mutex. If there is a pending lock for this mutex 
 | |
|  * by another thread, mark that thread runnable. */
 | |
| 
 | |
|   struct __mthread_mutex *m;
 | |
| 
 | |
|   MTHREAD_CHECK_INIT();	/* Make sure mthreads is initialized */
 | |
| 
 | |
|   if (mutex == NULL) 
 | |
| 	return(EINVAL);
 | |
| 
 | |
|   m = (struct __mthread_mutex *) *mutex;
 | |
|   if (!mthread_mutex_valid(&m))
 | |
| 	return(EINVAL);
 | |
|   else if (m->mm_owner != current_thread) 
 | |
|   	return(EPERM);	/* Can't unlock a mutex locked by another thread. */
 | |
| 
 | |
|   m->mm_owner = mthread_queue_remove(&m->mm_queue);
 | |
|   if (m->mm_owner != NO_THREAD) mthread_unsuspend(m->mm_owner);
 | |
|   return(0);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_mutex_valid			     *
 | |
|  *===========================================================================*/
 | |
| #ifdef MTHREAD_STRICT
 | |
| int mthread_mutex_valid(m)
 | |
| mthread_mutex_t *m;
 | |
| {
 | |
| /* Check to see if mutex is on the list of valid mutexes */
 | |
|   struct __mthread_mutex *loopitem;
 | |
| 
 | |
|   MTHREAD_CHECK_INIT();	/* Make sure mthreads is initialized */
 | |
| 
 | |
|   loopitem = vm_front;
 | |
| 
 | |
|   while (loopitem != NULL) {
 | |
| 	if (loopitem == *m)
 | |
| 		return(1);
 | |
| 
 | |
| 	loopitem = loopitem->mm_next;
 | |
|   }
 | |
| 
 | |
|   return(0);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*===========================================================================*
 | |
|  *				mthread_mutex_verify			     *
 | |
|  *===========================================================================*/
 | |
| #ifdef MDEBUG
 | |
| int mthread_mutex_verify(void)
 | |
| {
 | |
|   /* Return true when no mutexes are in use */
 | |
|   int r = 1;
 | |
|   struct __mthread_mutex *loopitem;
 | |
| 
 | |
|   MTHREAD_CHECK_INIT();	/* Make sure mthreads is initialized */
 | |
| 
 | |
| #ifdef MTHREAD_STRICT
 | |
|   loopitem = vm_front;
 | |
| 
 | |
|   while (loopitem != NULL) {
 | |
|   	printf("mutex corruption: owner: %d\n", loopitem->mm_owner);
 | |
| 	loopitem = loopitem->mm_next;
 | |
|   	r = 0;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   return(r);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| 
 |