minix/lib/libmthread/mutex.c

298 lines
7.5 KiB
C
Raw Normal View History

#include <minix/mthread.h>
#include "global.h"
#include "proto.h"
PRIVATE struct __mthread_mutex *vm_front, *vm_rear;
FORWARD _PROTOTYPE( void mthread_mutex_add, (mthread_mutex_t *m) );
FORWARD _PROTOTYPE( void mthread_mutex_remove, (mthread_mutex_t *m) );
/*===========================================================================*
* mthread_init_valid_mutexes *
*===========================================================================*/
PUBLIC void mthread_init_valid_mutexes(void)
{
/* Initialize list of valid mutexes */
vm_front = vm_rear = NULL;
}
/*===========================================================================*
* mthread_mutex_add *
*===========================================================================*/
PRIVATE 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)->prev = NULL;
} else {
vm_rear->next = *m;
(*m)->prev = vm_rear;
}
(*m)->next = NULL;
vm_rear = *m;
}
/*===========================================================================*
* mthread_mutex_destroy *
*===========================================================================*/
PUBLIC int mthread_mutex_destroy(mutex)
mthread_mutex_t *mutex;
{
/* Invalidate mutex and deallocate resources. */
mthread_thread_t t;
mthread_tcb_t *tcb;
mthread_init(); /* Make sure mthreads is initialized */
if (mutex == NULL) {
errno = EINVAL;
return(-1);
}
if (!mthread_mutex_valid(mutex)) {
errno = EINVAL;
return(-1);
} else if ((*mutex)->owner != NO_THREAD) {
printf("mutex owner is %d, so not destroying\n", (*mutex)->owner);
errno = EBUSY;
return(-1);
}
/* 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->mutex == *mutex) {
errno = EBUSY;
return(-1);
}
}
}
/* Not in use; invalidate it */
mthread_mutex_remove(mutex);
free(*mutex);
*mutex = NULL;
return(0);
}
/*===========================================================================*
* mthread_mutex_init *
*===========================================================================*/
PUBLIC 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_init(); /* Make sure mthreads is initialized */
if (mutex == NULL) {
errno = EAGAIN;
return(-1);
} else if (mattr != NULL) {
errno = ENOSYS;
return(-1);
} else if (mthread_mutex_valid(mutex)) {
errno = EBUSY;
return(-1);
}
if ((m = malloc(sizeof(struct __mthread_mutex))) == NULL)
return(-1);
mthread_queue_init( &(m->queue) );
m->owner = NO_THREAD;
*mutex = (mthread_mutex_t) m;
mthread_mutex_add(mutex); /* Validate mutex; mutex now in use */
return(0);
}
/*===========================================================================*
* mthread_mutex_lock *
*===========================================================================*/
PUBLIC int mthread_mutex_lock_f(mutex, file, line)
mthread_mutex_t *mutex; /* Mutex that is to be locked */
char file[NAME_MAX + 1];
int line;
{
/* 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_init(); /* Make sure mthreads is initialized */
if (mutex == NULL) {
errno = EINVAL;
return(-1);
}
m = (struct __mthread_mutex *) *mutex;
if (!mthread_mutex_valid(&m)) {
errno = EINVAL;
return(-1);
} else if (m->owner == NO_THREAD) { /* Not locked */
m->owner = current_thread;
if (current_thread == MAIN_THREAD)
mthread_debug("MAIN_THREAD now mutex owner\n");
} else if (m->owner == current_thread) {
errno = EDEADLK;
return(-1);
} else {
mthread_queue_add( &(m->queue), current_thread);
if (m->owner == MAIN_THREAD)
mthread_dump_queue(&(m->queue));
mthread_suspend(MS_MUTEX);
}
/* When we get here we acquired the lock. */
return(0);
}
/*===========================================================================*
* mthread_mutex_remove *
*===========================================================================*/
PRIVATE void mthread_mutex_remove(m)
mthread_mutex_t *m;
{
/* Remove mutex from list of valid, initialized mutexes */
if ((*m)->prev == NULL)
vm_front = (*m)->next;
else
(*m)->prev->next = (*m)->next;
if ((*m)->next == NULL)
vm_rear = (*m)->prev;
else
(*m)->next->prev = (*m)->prev;
}
/*===========================================================================*
* mthread_mutex_trylock *
*===========================================================================*/
PUBLIC 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_init(); /* Make sure mthreads is initialized */
if (mutex == NULL) {
errno = EINVAL;
return(-1);
}
m = (struct __mthread_mutex *) *mutex;
if (!mthread_mutex_valid(&m)) {
errno = EINVAL;
return(-1);
} else if (m->owner == NO_THREAD) {
m->owner = current_thread;
return(0);
}
errno = EBUSY;
return(-1);
}
/*===========================================================================*
* mthread_mutex_unlock *
*===========================================================================*/
PUBLIC 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_init(); /* Make sure mthreads is initialized */
if (mutex == NULL) {
errno = EINVAL;
return(-1);
}
m = (struct __mthread_mutex *) *mutex;
if (!mthread_mutex_valid(&m)) {
errno = EINVAL;
return(-1);
} else if (m->owner != current_thread) {
errno = EPERM;
return(-1); /* Can't unlock a mutex locked by another thread. */
}
m->owner = mthread_queue_remove( &(m->queue) );
if (m->owner != NO_THREAD) mthread_unsuspend(m->owner);
return(0);
}
/*===========================================================================*
* mthread_mutex_valid *
*===========================================================================*/
PUBLIC 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_init(); /* Make sure mthreads is initialized */
loopitem = vm_front;
while (loopitem != NULL) {
if (loopitem == *m)
return(1);
loopitem = loopitem->next;
}
return(0);
}
/*===========================================================================*
* mthread_mutex_verify *
*===========================================================================*/
#ifdef MDEBUG
PUBLIC int mthread_mutex_verify(void)
{
/* Return true when no mutexes are in use */
int r = 1;
struct __mthread_mutex *loopitem;
mthread_init(); /* Make sure mthreads is initialized */
loopitem = vm_front;
while (loopitem != NULL) {
printf("mutex corruption: owner: %d\n", loopitem->owner);
loopitem = loopitem->next;
r = 0;
}
return(r);
}
#endif