2010-09-21 14:22:38 +02:00
|
|
|
#include <minix/mthread.h>
|
|
|
|
#include "global.h"
|
2010-09-30 15:44:13 +02:00
|
|
|
#include "proto.h"
|
2010-09-21 14:22:38 +02:00
|
|
|
|
|
|
|
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. */
|
|
|
|
|
2010-09-30 15:44:13 +02:00
|
|
|
mthread_thread_t t;
|
|
|
|
mthread_tcb_t *tcb;
|
2010-09-21 14:22:38 +02:00
|
|
|
|
|
|
|
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) {
|
2010-09-30 15:44:13 +02:00
|
|
|
printf("mutex owner is %d, so not destroying\n", (*mutex)->owner);
|
2010-09-21 14:22:38 +02:00
|
|
|
errno = EBUSY;
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if this mutex is not associated with a condition */
|
2010-09-30 15:44:13 +02:00
|
|
|
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) {
|
2010-09-21 14:22:38 +02:00
|
|
|
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 *
|
|
|
|
*===========================================================================*/
|
2010-09-30 15:44:13 +02:00
|
|
|
PUBLIC int mthread_mutex_lock_f(mutex, file, line)
|
2010-09-21 14:22:38 +02:00
|
|
|
mthread_mutex_t *mutex; /* Mutex that is to be locked */
|
2010-09-30 15:44:13 +02:00
|
|
|
char file[NAME_MAX + 1];
|
|
|
|
int line;
|
2010-09-21 14:22:38 +02:00
|
|
|
{
|
|
|
|
/* 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;
|
2010-09-30 15:44:13 +02:00
|
|
|
if (current_thread == MAIN_THREAD)
|
|
|
|
mthread_debug("MAIN_THREAD now mutex owner\n");
|
2010-09-21 14:22:38 +02:00
|
|
|
} else if (m->owner == current_thread) {
|
|
|
|
errno = EDEADLK;
|
|
|
|
return(-1);
|
|
|
|
} else {
|
|
|
|
mthread_queue_add( &(m->queue), current_thread);
|
2010-09-30 15:44:13 +02:00
|
|
|
if (m->owner == MAIN_THREAD)
|
|
|
|
mthread_dump_queue(&(m->queue));
|
|
|
|
mthread_suspend(MS_MUTEX);
|
2010-09-21 14:22:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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) {
|
2010-09-30 15:44:13 +02:00
|
|
|
printf("mutex corruption: owner: %d\n", loopitem->owner);
|
2010-09-21 14:22:38 +02:00
|
|
|
loopitem = loopitem->next;
|
|
|
|
r = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return(r);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|