c8d0edc06a
- Remove sanity checks for initialized mutexes and condition variables. This significantly boosts performance. The checks can be turned back on by compiling libmthread with MTHREAD_STRICT. According to POSIX operations on uninitialized variables are a MAY fail if, therefore allowing this optimization. - Test59 has to be accommodated to the lack of sanity checks on uninitialized variables in the library. It specifically tests for them and will run into segfaults when the checks are absent in the library. - Fix a few bugs related to the scheduler - Do some general code cleanups
306 lines
7.8 KiB
C
306 lines
7.8 KiB
C
#include <minix/mthread.h>
|
|
#include "global.h"
|
|
#include "proto.h"
|
|
|
|
PRIVATE struct __mthread_mutex *vm_front, *vm_rear;
|
|
#ifdef MTHREAD_STRICT
|
|
FORWARD _PROTOTYPE( void mthread_mutex_add, (mthread_mutex_t *m) );
|
|
FORWARD _PROTOTYPE( 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 *
|
|
*===========================================================================*/
|
|
PUBLIC void mthread_init_valid_mutexes(void)
|
|
{
|
|
/* Initialize list of valid mutexes */
|
|
vm_front = vm_rear = NULL;
|
|
}
|
|
|
|
|
|
/*===========================================================================*
|
|
* mthread_mutex_add *
|
|
*===========================================================================*/
|
|
#ifdef MTHREAD_STRICT
|
|
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)->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 *
|
|
*===========================================================================*/
|
|
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)->mm_owner != NO_THREAD) {
|
|
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->mc_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);
|
|
}
|
|
#ifdef MTHREAD_STRICT
|
|
else if (mthread_mutex_valid(mutex)) {
|
|
errno = EBUSY;
|
|
return(-1);
|
|
}
|
|
#endif
|
|
else if ((m = malloc(sizeof(struct __mthread_mutex))) == NULL) {
|
|
errno = ENOMEM;
|
|
return(-1);
|
|
}
|
|
|
|
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 *
|
|
*===========================================================================*/
|
|
PUBLIC 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_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->mm_owner == NO_THREAD) { /* Not locked */
|
|
m->mm_owner = current_thread;
|
|
if (current_thread == MAIN_THREAD)
|
|
mthread_debug("MAIN_THREAD now mutex owner\n");
|
|
} else if (m->mm_owner == current_thread) {
|
|
errno = EDEADLK;
|
|
return(-1);
|
|
} else {
|
|
mthread_queue_add(&m->mm_queue, current_thread);
|
|
if (m->mm_owner == MAIN_THREAD)
|
|
mthread_dump_queue(&m->mm_queue);
|
|
mthread_suspend(MS_MUTEX);
|
|
}
|
|
|
|
/* When we get here we acquired the lock. */
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*===========================================================================*
|
|
* mthread_mutex_remove *
|
|
*===========================================================================*/
|
|
#ifdef MTHREAD_STRICT
|
|
PRIVATE 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 *
|
|
*===========================================================================*/
|
|
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->mm_owner == NO_THREAD) {
|
|
m->mm_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->mm_owner != current_thread) {
|
|
errno = EPERM;
|
|
return(-1); /* 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
|
|
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->mm_next;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
#endif
|
|
|
|
/*===========================================================================*
|
|
* 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->mm_owner);
|
|
loopitem = loopitem->next;
|
|
r = 0;
|
|
}
|
|
|
|
return(r);
|
|
}
|
|
#endif
|
|
|
|
|