a7072a5e1c
Before, the 'main thread' of a process was never taken into account anywhere in the library, causing mutexes not to work properly (and consequently, neither did the condition variables). For example, if the 'main thread' (that is, the thread which is started at the beginning of a process; not a spawned thread by the library) would lock a mutex, it wasn't actually locked.
297 lines
7.5 KiB
C
297 lines
7.5 KiB
C
#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
|
|
|
|
|