- Refactor mthread structure fields to prevent name clashes

- 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
This commit is contained in:
Thomas Veerman 2011-03-18 10:29:54 +00:00
parent 03a7d0e8ae
commit c8d0edc06a
10 changed files with 178 additions and 146 deletions

View File

@ -24,31 +24,33 @@ typedef void * mthread_mutexattr_t;
struct __mthread_tcb; struct __mthread_tcb;
typedef struct { typedef struct {
struct __mthread_tcb *head; struct __mthread_tcb *mq_head;
struct __mthread_tcb *tail; struct __mthread_tcb *mq_tail;
} mthread_queue_t; } mthread_queue_t;
struct __mthread_mutex { struct __mthread_mutex {
mthread_queue_t queue; /* Queue of threads blocked on this mutex */ mthread_queue_t mm_queue; /* Queue of threads blocked on this mutex */
mthread_thread_t owner; /* Thread ID that currently owns mutex */ mthread_thread_t mm_owner; /* Thread ID that currently owns mutex */
struct __mthread_mutex *prev; struct __mthread_mutex *mm_prev;
struct __mthread_mutex *next; struct __mthread_mutex *mm_next;
unsigned int mm_magic;
}; };
typedef struct __mthread_mutex *mthread_mutex_t; typedef struct __mthread_mutex *mthread_mutex_t;
struct __mthread_cond { struct __mthread_cond {
struct __mthread_mutex *mutex; /* Associate mutex with condition */ struct __mthread_mutex *mc_mutex; /* Associate mutex with condition */
struct __mthread_cond *prev; struct __mthread_cond *mc_prev;
struct __mthread_cond *next; struct __mthread_cond *mc_next;
unsigned int mc_magic;
}; };
typedef struct __mthread_cond *mthread_cond_t; typedef struct __mthread_cond *mthread_cond_t;
struct __mthread_attr { struct __mthread_attr {
size_t a_stacksize; size_t ma_stacksize;
char *a_stackaddr; char *ma_stackaddr;
int a_detachstate; int ma_detachstate;
struct __mthread_attr *prev; struct __mthread_attr *ma_prev;
struct __mthread_attr *next; struct __mthread_attr *ma_next;
}; };
typedef struct __mthread_attr *mthread_attr_t; typedef struct __mthread_attr *mthread_attr_t;
@ -106,12 +108,7 @@ _PROTOTYPE( void mthread_verify_f, (char *f, int l) );
_PROTOTYPE( int mthread_mutex_destroy, (mthread_mutex_t *mutex) ); _PROTOTYPE( int mthread_mutex_destroy, (mthread_mutex_t *mutex) );
_PROTOTYPE( int mthread_mutex_init, (mthread_mutex_t *mutex, _PROTOTYPE( int mthread_mutex_init, (mthread_mutex_t *mutex,
mthread_mutexattr_t *mattr) ); mthread_mutexattr_t *mattr) );
#if 0
_PROTOTYPE( int mthread_mutex_lock, (mthread_mutex_t *mutex) ); _PROTOTYPE( int mthread_mutex_lock, (mthread_mutex_t *mutex) );
#endif
_PROTOTYPE( int mthread_mutex_lock_f, (mthread_mutex_t *mutex,
char *file, int line) );
#define mthread_mutex_lock(x) mthread_mutex_lock_f(x, __FILE__, __LINE__)
_PROTOTYPE( int mthread_mutex_trylock, (mthread_mutex_t *mutex) ); _PROTOTYPE( int mthread_mutex_trylock, (mthread_mutex_t *mutex) );
_PROTOTYPE( int mthread_mutex_unlock, (mthread_mutex_t *mutex) ); _PROTOTYPE( int mthread_mutex_unlock, (mthread_mutex_t *mutex) );

View File

@ -100,11 +100,11 @@ mthread_thread_t detach;
if (tcb->m_state == MS_DEAD) { if (tcb->m_state == MS_DEAD) {
errno = ESRCH; errno = ESRCH;
return(-1); return(-1);
} else if (tcb->m_attr.a_detachstate != MTHREAD_CREATE_DETACHED) { } else if (tcb->m_attr.ma_detachstate != MTHREAD_CREATE_DETACHED) {
if (tcb->m_state == MS_EXITING) if (tcb->m_state == MS_EXITING)
mthread_thread_stop(detach); mthread_thread_stop(detach);
else else
tcb->m_attr.a_detachstate = MTHREAD_CREATE_DETACHED; tcb->m_attr.ma_detachstate = MTHREAD_CREATE_DETACHED;
} }
return(0); return(0);
@ -138,7 +138,7 @@ void *value;
tcb->m_result = value; tcb->m_result = value;
tcb->m_state = MS_EXITING; tcb->m_state = MS_EXITING;
if (tcb->m_attr.a_detachstate == MTHREAD_CREATE_DETACHED) { if (tcb->m_attr.ma_detachstate == MTHREAD_CREATE_DETACHED) {
mthread_thread_stop(current_thread); mthread_thread_stop(current_thread);
} else { } else {
/* Joinable thread; notify possibly waiting thread */ /* Joinable thread; notify possibly waiting thread */
@ -283,7 +283,7 @@ PUBLIC void mthread_init(void)
* not enter this clause. * not enter this clause.
*/ */
if (getcontext(&(mainthread.m_context)) == -1) if (mthread_getcontext(&(mainthread.m_context)) == -1)
mthread_panic("Couldn't save state for main thread"); mthread_panic("Couldn't save state for main thread");
current_thread = MAIN_THREAD; current_thread = MAIN_THREAD;
@ -293,7 +293,7 @@ PUBLIC void mthread_init(void)
mthread_init_scheduler(); mthread_init_scheduler();
/* Initialize the fallback thread */ /* Initialize the fallback thread */
if (getcontext(FALLBACK_CTX) == -1) if (mthread_getcontext(FALLBACK_CTX) == -1)
mthread_panic("Could not initialize fallback thread"); mthread_panic("Could not initialize fallback thread");
FALLBACK_CTX->uc_link = &(mainthread.m_context); FALLBACK_CTX->uc_link = &(mainthread.m_context);
FALLBACK_CTX->uc_stack.ss_sp = fallback_stack; FALLBACK_CTX->uc_stack.ss_sp = fallback_stack;
@ -331,7 +331,7 @@ void **value;
if (tcb->m_state == MS_DEAD) { if (tcb->m_state == MS_DEAD) {
errno = ESRCH; errno = ESRCH;
return(-1); return(-1);
} else if (tcb->m_attr.a_detachstate == MTHREAD_CREATE_DETACHED) { } else if (tcb->m_attr.ma_detachstate == MTHREAD_CREATE_DETACHED) {
errno = EINVAL; errno = EINVAL;
return(-1); return(-1);
} }
@ -445,11 +445,11 @@ void *arg;
tcb->m_context.uc_link = FALLBACK_CTX; tcb->m_context.uc_link = FALLBACK_CTX;
/* then construct this thread's context to run procedure proc. */ /* then construct this thread's context to run procedure proc. */
if (getcontext(&(tcb->m_context)) == -1) if (mthread_getcontext(&(tcb->m_context)) == -1)
mthread_panic("Failed to initialize context state"); mthread_panic("Failed to initialize context state");
stacksize = tcb->m_attr.a_stacksize; stacksize = tcb->m_attr.ma_stacksize;
stackaddr = tcb->m_attr.a_stackaddr; stackaddr = tcb->m_attr.ma_stackaddr;
if (stacksize == (size_t) 0) if (stacksize == (size_t) 0)
stacksize = (size_t) MTHREAD_STACK_MIN; stacksize = (size_t) MTHREAD_STACK_MIN;
@ -488,9 +488,10 @@ mthread_thread_t thread;
rt->m_arg = NULL; rt->m_arg = NULL;
rt->m_result = NULL; rt->m_result = NULL;
rt->m_cond = NULL; rt->m_cond = NULL;
if (rt->m_context.uc_stack.ss_sp) if (rt->m_context.uc_stack.ss_sp) {
free(rt->m_context.uc_stack.ss_sp); /* Free allocated stack */ free(rt->m_context.uc_stack.ss_sp); /* Free allocated stack */
rt->m_context.uc_stack.ss_sp = NULL; rt->m_context.uc_stack.ss_sp = NULL;
}
rt->m_context.uc_stack.ss_size = 0; rt->m_context.uc_stack.ss_size = 0;
rt->m_context.uc_link = NULL; rt->m_context.uc_link = NULL;
} }

View File

@ -27,13 +27,13 @@ mthread_attr_t *a;
if (va_front == NULL) { /* Empty list */ if (va_front == NULL) { /* Empty list */
va_front = *a; va_front = *a;
(*a)->prev = NULL; (*a)->ma_prev = NULL;
} else { } else {
va_rear->next = *a; va_rear->ma_next = *a;
(*a)->prev = va_rear; (*a)->ma_prev = va_rear;
} }
(*a)->next = NULL; (*a)->ma_next = NULL;
va_rear = *a; va_rear = *a;
} }
@ -89,9 +89,9 @@ mthread_attr_t *attr; /* Attribute */
if ((a = malloc(sizeof(struct __mthread_attr))) == NULL) if ((a = malloc(sizeof(struct __mthread_attr))) == NULL)
return(-1); return(-1);
a->a_detachstate = MTHREAD_CREATE_JOINABLE; a->ma_detachstate = MTHREAD_CREATE_JOINABLE;
a->a_stackaddr = NULL; a->ma_stackaddr = NULL;
a->a_stacksize = (size_t) 0; a->ma_stacksize = (size_t) 0;
*attr = (mthread_attr_t) a; *attr = (mthread_attr_t) a;
mthread_attr_add(attr); /* Validate attribute: attribute now in use */ mthread_attr_add(attr); /* Validate attribute: attribute now in use */
@ -122,7 +122,7 @@ int *detachstate;
return(-1); return(-1);
} }
*detachstate = a->a_detachstate; *detachstate = a->ma_detachstate;
return(0); return(0);
} }
@ -155,7 +155,7 @@ int detachstate;
return(-1); return(-1);
} }
a->a_detachstate = detachstate; a->ma_detachstate = detachstate;
return(0); return(0);
} }
@ -185,8 +185,8 @@ size_t *stacksize;
return(-1); return(-1);
} }
*stackaddr = a->a_stackaddr; *stackaddr = a->ma_stackaddr;
*stacksize = a->a_stacksize; *stacksize = a->ma_stacksize;
return(0); return(0);
} }
@ -215,7 +215,7 @@ size_t *stacksize;
return(-1); return(-1);
} }
*stacksize = a->a_stacksize; *stacksize = a->ma_stacksize;
return(0); return(0);
} }
@ -249,8 +249,8 @@ size_t stacksize;
* the cost of some memory if needed). * the cost of some memory if needed).
*/ */
a->a_stackaddr = stackaddr; a->ma_stackaddr = stackaddr;
a->a_stacksize = stacksize; a->ma_stacksize = stacksize;
return(0); return(0);
} }
@ -279,7 +279,7 @@ size_t stacksize;
return(-1); return(-1);
} }
a->a_stacksize = stacksize; a->ma_stacksize = stacksize;
return(0); return(0);
} }
@ -293,15 +293,15 @@ mthread_attr_t *a;
{ {
/* Remove attribute from list of valid, initialized attributes */ /* Remove attribute from list of valid, initialized attributes */
if ((*a)->prev == NULL) if ((*a)->ma_prev == NULL)
va_front = (*a)->next; va_front = (*a)->ma_next;
else else
(*a)->prev->next = (*a)->next; (*a)->ma_prev->ma_next = (*a)->ma_next;
if ((*a)->next == NULL) if ((*a)->ma_next == NULL)
va_rear = (*a)->prev; va_rear = (*a)->ma_prev;
else else
(*a)->next->prev = (*a)->prev; (*a)->ma_next->ma_prev = (*a)->ma_prev;
} }
@ -322,7 +322,7 @@ mthread_attr_t *a;
if (loopitem == *a) if (loopitem == *a)
return(1); return(1);
loopitem = loopitem->next; loopitem = loopitem->ma_next;
} }
return(0); return(0);
@ -343,7 +343,7 @@ PUBLIC int mthread_attr_verify(void)
loopitem = va_front; loopitem = va_front;
while (loopitem != NULL) { while (loopitem != NULL) {
loopitem = loopitem->next; loopitem = loopitem->ma_next;
return(0); return(0);
} }

View File

@ -3,9 +3,15 @@
#include "proto.h" #include "proto.h"
PRIVATE struct __mthread_cond *vc_front, *vc_rear; PRIVATE struct __mthread_cond *vc_front, *vc_rear;
#ifdef MTHREAD_STRICT
FORWARD _PROTOTYPE( void mthread_cond_add, (mthread_cond_t *c) ); FORWARD _PROTOTYPE( void mthread_cond_add, (mthread_cond_t *c) );
FORWARD _PROTOTYPE( void mthread_cond_remove, (mthread_cond_t *c) ); FORWARD _PROTOTYPE( void mthread_cond_remove, (mthread_cond_t *c) );
FORWARD _PROTOTYPE( int mthread_cond_valid, (mthread_cond_t *c) ); FORWARD _PROTOTYPE( int mthread_cond_valid, (mthread_cond_t *c) );
#else
# define mthread_cond_add(c) ((*c)->mc_magic = MTHREAD_INIT_MAGIC)
# define mthread_cond_remove(c) ((*c)->mc_magic = MTHREAD_NOT_INUSE)
# define mthread_cond_valid(c) ((*c)->mc_magic == MTHREAD_INIT_MAGIC)
#endif
#define MAIN_COND mainthread.m_cond #define MAIN_COND mainthread.m_cond
/*===========================================================================* /*===========================================================================*
@ -21,6 +27,7 @@ PUBLIC void mthread_init_valid_conditions(void)
/*===========================================================================* /*===========================================================================*
* mthread_cond_add * * mthread_cond_add *
*===========================================================================*/ *===========================================================================*/
#ifdef MTHREAD_STRICT
PRIVATE void mthread_cond_add(c) PRIVATE void mthread_cond_add(c)
mthread_cond_t *c; mthread_cond_t *c;
{ {
@ -28,16 +35,16 @@ mthread_cond_t *c;
if (vc_front == NULL) { /* Empty list */ if (vc_front == NULL) { /* Empty list */
vc_front = *c; vc_front = *c;
(*c)->prev = NULL; (*c)->mc_prev = NULL;
} else { } else {
vc_rear->next = *c; vc_rear->mc_next = *c;
(*c)->prev = vc_rear; (*c)->mc_prev = vc_rear;
} }
(*c)->next = NULL; (*c)->mc_next = NULL;
vc_rear = *c; vc_rear = *c;
} }
#endif
/*===========================================================================* /*===========================================================================*
* mthread_cond_broadcast * * mthread_cond_broadcast *
@ -51,12 +58,10 @@ mthread_cond_t *cond;
mthread_init(); /* Make sure libmthread is initialized */ mthread_init(); /* Make sure libmthread is initialized */
if(cond == NULL) { if (cond == NULL) {
errno = EINVAL; errno = EINVAL;
return(-1); return(-1);
} } else if (!mthread_cond_valid(cond)) {
if (!mthread_cond_valid(cond)) {
errno = EINVAL; errno = EINVAL;
return(-1); return(-1);
} }
@ -90,9 +95,7 @@ mthread_cond_t *cond;
if (cond == NULL) { if (cond == NULL) {
errno = EINVAL; errno = EINVAL;
return(-1); return(-1);
} } else if (!mthread_cond_valid(cond)) {
if (!mthread_cond_valid(cond)) {
errno = EINVAL; errno = EINVAL;
return(-1); return(-1);
} }
@ -106,7 +109,7 @@ mthread_cond_t *cond;
for (t = (mthread_thread_t) 0; t < no_threads; t++) { for (t = (mthread_thread_t) 0; t < no_threads; t++) {
tcb = mthread_find_tcb(t); tcb = mthread_find_tcb(t);
if(tcb->m_state == MS_CONDITION && tcb->m_cond == *cond){ if (tcb->m_state == MS_CONDITION && tcb->m_cond == *cond){
errno = EBUSY; errno = EBUSY;
return(-1); return(-1);
} }
@ -140,17 +143,19 @@ mthread_condattr_t *cattr;
errno = ENOSYS; errno = ENOSYS;
return(-1); return(-1);
} }
#ifdef MTHREAD_STRICT
if (mthread_cond_valid(cond)) { else if (mthread_cond_valid(cond)) {
/* Already initialized */ /* Already initialized */
errno = EBUSY; errno = EBUSY;
return(-1); return(-1);
} }
#endif
if ((c = malloc(sizeof(struct __mthread_cond))) == NULL) else if ((c = malloc(sizeof(struct __mthread_cond))) == NULL) {
errno = ENOMEM;
return(-1); return(-1);
}
c->mutex = NULL; c->mc_mutex = NULL;
*cond = (mthread_cond_t) c; *cond = (mthread_cond_t) c;
mthread_cond_add(cond); mthread_cond_add(cond);
@ -161,23 +166,24 @@ mthread_condattr_t *cattr;
/*===========================================================================* /*===========================================================================*
* mthread_cond_remove * * mthread_cond_remove *
*===========================================================================*/ *===========================================================================*/
#ifdef MTHREAD_STRICT
PRIVATE void mthread_cond_remove(c) PRIVATE void mthread_cond_remove(c)
mthread_cond_t *c; mthread_cond_t *c;
{ {
/* Remove condition from list of valid, initialized conditions */ /* Remove condition from list of valid, initialized conditions */
if ((*c)->prev == NULL) if ((*c)->mc_prev == NULL)
vc_front = (*c)->next; vc_front = (*c)->mc_next;
else else
(*c)->prev->next = (*c)->next; (*c)->mc_prev->mc_next = (*c)->mc_next;
if ((*c)->next == NULL) if ((*c)->mc_next == NULL)
vc_rear = (*c)->prev; vc_rear = (*c)->mc_prev;
else else
(*c)->next->prev = (*c)->prev; (*c)->mc_next->mc_prev = (*c)->mc_prev;
} }
#endif
/*===========================================================================* /*===========================================================================*
* mthread_cond_signal * * mthread_cond_signal *
@ -191,12 +197,10 @@ mthread_cond_t *cond;
mthread_init(); /* Make sure libmthread is initialized */ mthread_init(); /* Make sure libmthread is initialized */
if(cond == NULL) { if (cond == NULL) {
errno = EINVAL; errno = EINVAL;
return(-1); return(-1);
} } else if (!mthread_cond_valid(cond)) {
if (!mthread_cond_valid(cond)) {
errno = EINVAL; errno = EINVAL;
return(-1); return(-1);
} }
@ -207,7 +211,7 @@ mthread_cond_t *cond;
for (t = (mthread_thread_t) 0; t < no_threads; t++) { for (t = (mthread_thread_t) 0; t < no_threads; t++) {
tcb = mthread_find_tcb(t); tcb = mthread_find_tcb(t);
if(tcb->m_state == MS_CONDITION && tcb->m_cond == *cond){ if (tcb->m_state == MS_CONDITION && tcb->m_cond == *cond){
mthread_unsuspend(t); mthread_unsuspend(t);
break; break;
} }
@ -220,24 +224,27 @@ mthread_cond_t *cond;
/*===========================================================================* /*===========================================================================*
* mthread_cond_valid * * mthread_cond_valid *
*===========================================================================*/ *===========================================================================*/
#ifdef MTHREAD_STRICT
PRIVATE int mthread_cond_valid(c) PRIVATE int mthread_cond_valid(c)
mthread_cond_t *c; mthread_cond_t *c;
{ {
/* Check to see if cond is on the list of valid conditions */ /* Check to see if cond is on the list of valid conditions */
struct __mthread_cond *loopitem; struct __mthread_cond *loopitem;
mthread_init();
loopitem = vc_front; loopitem = vc_front;
while (loopitem != NULL) { while (loopitem != NULL) {
if (loopitem == *c) if (loopitem == *c)
return(1); return(1);
loopitem = loopitem->next; loopitem = loopitem->mc_next;
} }
return(0); return(0);
} }
#endif
/*===========================================================================* /*===========================================================================*
* mthread_cond_verify * * mthread_cond_verify *
@ -281,7 +288,7 @@ mthread_mutex_t *mutex;
return(-1); return(-1);
} }
c->mutex = m; /* Remember we're using this mutex in a cond_wait */ c->mc_mutex = m; /* Remember we're using this mutex in a cond_wait */
if (mthread_mutex_unlock(mutex) != 0) /* Fails when we're not the owner */ if (mthread_mutex_unlock(mutex) != 0) /* Fails when we're not the owner */
return(-1); return(-1);
@ -290,7 +297,7 @@ mthread_mutex_t *mutex;
mthread_suspend(MS_CONDITION); mthread_suspend(MS_CONDITION);
/* When execution returns here, the condition was met. Lock mutex again. */ /* When execution returns here, the condition was met. Lock mutex again. */
c->mutex = NULL; /* Forget about this mutex */ c->mc_mutex = NULL; /* Forget about this mutex */
tcb->m_cond = NULL; /* ... and condition var */ tcb->m_cond = NULL; /* ... and condition var */
if (mthread_mutex_lock(mutex) != 0) if (mthread_mutex_lock(mutex) != 0)
return(-1); return(-1);

View File

@ -12,6 +12,8 @@
#define MAIN_THREAD -1 #define MAIN_THREAD -1
#define NO_THREAD -2 #define NO_THREAD -2
#define isokthreadid(i) (i == MAIN_THREAD || (i >= 0 && i < no_threads)) #define isokthreadid(i) (i == MAIN_THREAD || (i >= 0 && i < no_threads))
#define MTHREAD_INIT_MAGIC 0xca11ab1e
#define MTHREAD_NOT_INUSE 0xdefec7
typedef enum { typedef enum {
MS_CONDITION, MS_DEAD, MS_EXITING, MS_FALLBACK_EXITING, MS_MUTEX, MS_RUNNABLE MS_CONDITION, MS_DEAD, MS_EXITING, MS_FALLBACK_EXITING, MS_MUTEX, MS_RUNNABLE

View File

@ -3,8 +3,13 @@
#include "proto.h" #include "proto.h"
PRIVATE struct __mthread_mutex *vm_front, *vm_rear; 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_add, (mthread_mutex_t *m) );
FORWARD _PROTOTYPE( void mthread_mutex_remove, (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 * * mthread_init_valid_mutexes *
@ -19,6 +24,7 @@ PUBLIC void mthread_init_valid_mutexes(void)
/*===========================================================================* /*===========================================================================*
* mthread_mutex_add * * mthread_mutex_add *
*===========================================================================*/ *===========================================================================*/
#ifdef MTHREAD_STRICT
PRIVATE void mthread_mutex_add(m) PRIVATE void mthread_mutex_add(m)
mthread_mutex_t *m; mthread_mutex_t *m;
{ {
@ -26,16 +32,16 @@ mthread_mutex_t *m;
if (vm_front == NULL) { /* Empty list */ if (vm_front == NULL) { /* Empty list */
vm_front = *m; vm_front = *m;
(*m)->prev = NULL; (*m)->mm_prev = NULL;
} else { } else {
vm_rear->next = *m; vm_rear->mm_next = *m;
(*m)->prev = vm_rear; (*m)->mm_prev = vm_rear;
} }
(*m)->next = NULL; (*m)->mm_next = NULL;
vm_rear = *m; vm_rear = *m;
} }
#endif
/*===========================================================================* /*===========================================================================*
* mthread_mutex_destroy * * mthread_mutex_destroy *
@ -58,8 +64,7 @@ mthread_mutex_t *mutex;
if (!mthread_mutex_valid(mutex)) { if (!mthread_mutex_valid(mutex)) {
errno = EINVAL; errno = EINVAL;
return(-1); return(-1);
} else if ((*mutex)->owner != NO_THREAD) { } else if ((*mutex)->mm_owner != NO_THREAD) {
printf("mutex owner is %d, so not destroying\n", (*mutex)->owner);
errno = EBUSY; errno = EBUSY;
return(-1); return(-1);
} }
@ -68,7 +73,7 @@ mthread_mutex_t *mutex;
for (t = (mthread_thread_t) 0; t < no_threads; t++) { for (t = (mthread_thread_t) 0; t < no_threads; t++) {
tcb = mthread_find_tcb(t); tcb = mthread_find_tcb(t);
if (tcb->m_state == MS_CONDITION) { if (tcb->m_state == MS_CONDITION) {
if (tcb->m_cond != NULL && tcb->m_cond->mutex == *mutex) { if (tcb->m_cond != NULL && tcb->m_cond->mc_mutex == *mutex) {
errno = EBUSY; errno = EBUSY;
return(-1); return(-1);
} }
@ -103,16 +108,20 @@ mthread_mutexattr_t *mattr; /* Mutex attribute */
} else if (mattr != NULL) { } else if (mattr != NULL) {
errno = ENOSYS; errno = ENOSYS;
return(-1); return(-1);
} else if (mthread_mutex_valid(mutex)) { }
#ifdef MTHREAD_STRICT
else if (mthread_mutex_valid(mutex)) {
errno = EBUSY; errno = EBUSY;
return(-1); return(-1);
} }
#endif
if ((m = malloc(sizeof(struct __mthread_mutex))) == NULL) else if ((m = malloc(sizeof(struct __mthread_mutex))) == NULL) {
errno = ENOMEM;
return(-1); return(-1);
}
mthread_queue_init( &(m->queue) ); mthread_queue_init(&m->mm_queue);
m->owner = NO_THREAD; m->mm_owner = NO_THREAD;
*mutex = (mthread_mutex_t) m; *mutex = (mthread_mutex_t) m;
mthread_mutex_add(mutex); /* Validate mutex; mutex now in use */ mthread_mutex_add(mutex); /* Validate mutex; mutex now in use */
@ -122,10 +131,8 @@ mthread_mutexattr_t *mattr; /* Mutex attribute */
/*===========================================================================* /*===========================================================================*
* mthread_mutex_lock * * mthread_mutex_lock *
*===========================================================================*/ *===========================================================================*/
PUBLIC int mthread_mutex_lock_f(mutex, file, line) PUBLIC int mthread_mutex_lock(mutex)
mthread_mutex_t *mutex; /* Mutex that is to be locked */ 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 /* Try to lock this mutex. If already locked, append the current thread to
* FIFO queue associated with this mutex and suspend the thread. */ * FIFO queue associated with this mutex and suspend the thread. */
@ -143,17 +150,17 @@ int line;
if (!mthread_mutex_valid(&m)) { if (!mthread_mutex_valid(&m)) {
errno = EINVAL; errno = EINVAL;
return(-1); return(-1);
} else if (m->owner == NO_THREAD) { /* Not locked */ } else if (m->mm_owner == NO_THREAD) { /* Not locked */
m->owner = current_thread; m->mm_owner = current_thread;
if (current_thread == MAIN_THREAD) if (current_thread == MAIN_THREAD)
mthread_debug("MAIN_THREAD now mutex owner\n"); mthread_debug("MAIN_THREAD now mutex owner\n");
} else if (m->owner == current_thread) { } else if (m->mm_owner == current_thread) {
errno = EDEADLK; errno = EDEADLK;
return(-1); return(-1);
} else { } else {
mthread_queue_add( &(m->queue), current_thread); mthread_queue_add(&m->mm_queue, current_thread);
if (m->owner == MAIN_THREAD) if (m->mm_owner == MAIN_THREAD)
mthread_dump_queue(&(m->queue)); mthread_dump_queue(&m->mm_queue);
mthread_suspend(MS_MUTEX); mthread_suspend(MS_MUTEX);
} }
@ -165,22 +172,23 @@ int line;
/*===========================================================================* /*===========================================================================*
* mthread_mutex_remove * * mthread_mutex_remove *
*===========================================================================*/ *===========================================================================*/
#ifdef MTHREAD_STRICT
PRIVATE void mthread_mutex_remove(m) PRIVATE void mthread_mutex_remove(m)
mthread_mutex_t *m; mthread_mutex_t *m;
{ {
/* Remove mutex from list of valid, initialized mutexes */ /* Remove mutex from list of valid, initialized mutexes */
if ((*m)->prev == NULL) if ((*m)->mm_prev == NULL)
vm_front = (*m)->next; vm_front = (*m)->mm_next;
else else
(*m)->prev->next = (*m)->next; (*m)->mm_prev->mm_next = (*m)->mm_next;
if ((*m)->next == NULL) if ((*m)->mm_next == NULL)
vm_rear = (*m)->prev; vm_rear = (*m)->mm_prev;
else else
(*m)->next->prev = (*m)->prev; (*m)->mm_next->mm_prev = (*m)->mm_prev;
} }
#endif
/*===========================================================================* /*===========================================================================*
* mthread_mutex_trylock * * mthread_mutex_trylock *
@ -203,8 +211,8 @@ mthread_mutex_t *mutex; /* Mutex that is to be locked */
if (!mthread_mutex_valid(&m)) { if (!mthread_mutex_valid(&m)) {
errno = EINVAL; errno = EINVAL;
return(-1); return(-1);
} else if (m->owner == NO_THREAD) { } else if (m->mm_owner == NO_THREAD) {
m->owner = current_thread; m->mm_owner = current_thread;
return(0); return(0);
} }
@ -235,13 +243,13 @@ mthread_mutex_t *mutex; /* Mutex that is to be unlocked */
if (!mthread_mutex_valid(&m)) { if (!mthread_mutex_valid(&m)) {
errno = EINVAL; errno = EINVAL;
return(-1); return(-1);
} else if (m->owner != current_thread) { } else if (m->mm_owner != current_thread) {
errno = EPERM; errno = EPERM;
return(-1); /* Can't unlock a mutex locked by another thread. */ return(-1); /* Can't unlock a mutex locked by another thread. */
} }
m->owner = mthread_queue_remove( &(m->queue) ); m->mm_owner = mthread_queue_remove(&m->mm_queue);
if (m->owner != NO_THREAD) mthread_unsuspend(m->owner); if (m->mm_owner != NO_THREAD) mthread_unsuspend(m->mm_owner);
return(0); return(0);
} }
@ -249,6 +257,7 @@ mthread_mutex_t *mutex; /* Mutex that is to be unlocked */
/*===========================================================================* /*===========================================================================*
* mthread_mutex_valid * * mthread_mutex_valid *
*===========================================================================*/ *===========================================================================*/
#ifdef MTHREAD_STRICT
PUBLIC int mthread_mutex_valid(m) PUBLIC int mthread_mutex_valid(m)
mthread_mutex_t *m; mthread_mutex_t *m;
{ {
@ -263,12 +272,12 @@ mthread_mutex_t *m;
if (loopitem == *m) if (loopitem == *m)
return(1); return(1);
loopitem = loopitem->next; loopitem = loopitem->mm_next;
} }
return(0); return(0);
} }
#endif
/*===========================================================================* /*===========================================================================*
* mthread_mutex_verify * * mthread_mutex_verify *
@ -285,7 +294,7 @@ PUBLIC int mthread_mutex_verify(void)
loopitem = vm_front; loopitem = vm_front;
while (loopitem != NULL) { while (loopitem != NULL) {
printf("mutex corruption: owner: %d\n", loopitem->owner); printf("mutex corruption: owner: %d\n", loopitem->mm_owner);
loopitem = loopitem->next; loopitem = loopitem->next;
r = 0; r = 0;
} }

View File

@ -26,7 +26,13 @@ _PROTOTYPE( void mthread_debug_f, (const char *file, int line,
/* mutex.c */ /* mutex.c */
_PROTOTYPE( void mthread_init_valid_mutexes, (void) ); _PROTOTYPE( void mthread_init_valid_mutexes, (void) );
#ifdef MTHREAD_STRICT
_PROTOTYPE( int mthread_mutex_valid, (mthread_mutex_t *mutex) ); _PROTOTYPE( int mthread_mutex_valid, (mthread_mutex_t *mutex) );
#else
# define mthread_mutex_valid(x) ((*x)->mm_magic == MTHREAD_INIT_MAGIC)
#endif
#ifdef MDEBUG #ifdef MDEBUG
_PROTOTYPE( int mthread_mutex_verify, (void) ); _PROTOTYPE( int mthread_mutex_verify, (void) );
#endif #endif

View File

@ -21,10 +21,10 @@ mthread_thread_t thread;
last = mthread_find_tcb(thread); last = mthread_find_tcb(thread);
if (mthread_queue_isempty(queue)) { if (mthread_queue_isempty(queue)) {
queue->head = queue->tail = last; queue->mq_head = queue->mq_tail = last;
} else { } else {
queue->tail->m_next = last; queue->mq_tail->m_next = last;
queue->tail = last; /* 'last' is the new last in line */ queue->mq_tail = last; /* 'last' is the new last in line */
} }
} }
@ -37,7 +37,7 @@ mthread_queue_t *queue; /* Queue that has to be initialized */
{ {
/* Initialize queue to a known state */ /* Initialize queue to a known state */
queue->head = queue->tail = NULL; queue->mq_head = queue->mq_tail = NULL;
} }
@ -47,7 +47,7 @@ mthread_queue_t *queue; /* Queue that has to be initialized */
PUBLIC int mthread_queue_isempty(queue) PUBLIC int mthread_queue_isempty(queue)
mthread_queue_t *queue; mthread_queue_t *queue;
{ {
return(queue->head == NULL); return(queue->mq_head == NULL);
} }
@ -64,8 +64,8 @@ mthread_queue_t *queue;
#ifdef MDEBUG #ifdef MDEBUG
printf("Dumping queue: "); printf("Dumping queue: ");
#endif #endif
if(queue->head != NULL) { if(queue->mq_head != NULL) {
t = queue->head; t = queue->mq_head;
if (t == &mainthread) tid = MAIN_THREAD; if (t == &mainthread) tid = MAIN_THREAD;
else tid = t->m_tid; else tid = t->m_tid;
#ifdef MDEBUG #ifdef MDEBUG
@ -106,18 +106,18 @@ mthread_queue_t *queue; /* Queue we want a thread from */
mthread_tcb_t *tcb; mthread_tcb_t *tcb;
/* Calculate thread id from queue head */ /* Calculate thread id from queue head */
if (queue->head == NULL) thread = NO_THREAD; if (queue->mq_head == NULL) thread = NO_THREAD;
else if (queue->head == &mainthread) thread = MAIN_THREAD; else if (queue->mq_head == &mainthread) thread = MAIN_THREAD;
else thread = (queue->head->m_tid); else thread = (queue->mq_head->m_tid);
if (thread != NO_THREAD) { /* i.e., this queue is not empty */ if (thread != NO_THREAD) { /* i.e., this queue is not empty */
tcb = queue->head; tcb = queue->mq_head;
if (queue->head == queue->tail) { if (queue->mq_head == queue->mq_tail) {
/* Queue holds only one thread */ /* Queue holds only one thread */
queue->head = queue->tail = NULL; /* So mark thread empty */ queue->mq_head = queue->mq_tail = NULL; /* So mark thread empty */
} else { } else {
/* Second thread in line is the new first */ /* Second thread in line is the new first */
queue->head = queue->head->m_next; queue->mq_head = queue->mq_head->m_next;
} }
tcb->m_next = NULL; /* This thread is no longer part of a queue */ tcb->m_next = NULL; /* This thread is no longer part of a queue */

View File

@ -55,11 +55,9 @@ PUBLIC void mthread_schedule(void)
/* We're running the last runnable spawned thread. Return to main /* We're running the last runnable spawned thread. Return to main
* thread as there is no work left. * thread as there is no work left.
*/ */
running_main_thread = 1;
current_thread = MAIN_THREAD; current_thread = MAIN_THREAD;
} else { } else {
current_thread = mthread_queue_remove(&run_queue); current_thread = mthread_queue_remove(&run_queue);
running_main_thread = 0; /* Running thread after swap */
} }
/* Find thread entries in tcb... */ /* Find thread entries in tcb... */
@ -70,6 +68,9 @@ PUBLIC void mthread_schedule(void)
new_ctx = &(new_tcb->m_context); new_ctx = &(new_tcb->m_context);
old_ctx = &(old_tcb->m_context); old_ctx = &(old_tcb->m_context);
/* Are we running the 'main' thread after swap? */
running_main_thread = (current_thread == MAIN_THREAD);
if (swapcontext(old_ctx, new_ctx) == -1) if (swapcontext(old_ctx, new_ctx) == -1)
mthread_panic("Could not swap context"); mthread_panic("Could not swap context");
@ -156,10 +157,7 @@ PUBLIC int mthread_yield(void)
if (mthread_queue_isempty(&run_queue)) { /* No point in yielding. */ if (mthread_queue_isempty(&run_queue)) { /* No point in yielding. */
return(-1); return(-1);
} else if (current_thread == NO_THREAD) { } else if (current_thread == NO_THREAD) {
/* Can't yield this thread, but still give other threads a chance to /* Can't yield this thread */
* run.
*/
mthread_schedule();
return(-1); return(-1);
} }

View File

@ -222,12 +222,16 @@ PRIVATE void mutex_a(void *arg)
/* Trying to acquire lock again should fail with EDEADLK */ /* Trying to acquire lock again should fail with EDEADLK */
if (mthread_mutex_lock(&mu[0]) != -1) err(3, 2); if (mthread_mutex_lock(&mu[0]) != -1) err(3, 2);
if (errno != EDEADLK) err(3, 3); if (errno != EDEADLK) err(3, 3);
#ifdef MTHREAD_STRICT
/* Try to acquire lock on uninitialized mutex; should fail with EINVAL */ /* Try to acquire lock on uninitialized mutex; should fail with EINVAL */
/* Note: this check only works when libmthread is compiled with
* MTHREAD_STRICT turned on. In POSIX this situation is a MAY fail if... */
if (mthread_mutex_lock(&mu2) != -1) { if (mthread_mutex_lock(&mu2) != -1) {
err(3, 4); err(3, 4);
mthread_mutex_unlock(&mu2); mthread_mutex_unlock(&mu2);
} }
if (errno != EINVAL) err(3, 5); if (errno != EINVAL) err(3, 5);
errno = 0; errno = 0;
if (mthread_mutex_trylock(&mu2) != -1) { if (mthread_mutex_trylock(&mu2) != -1) {
@ -235,6 +239,7 @@ PRIVATE void mutex_a(void *arg)
mthread_mutex_unlock(&mu2); mthread_mutex_unlock(&mu2);
} }
if (errno != EINVAL) err(3, 7); if (errno != EINVAL) err(3, 7);
#endif
if (mthread_mutex_trylock(&mu[1]) != 0) err(3, 8); if (mthread_mutex_trylock(&mu[1]) != 0) err(3, 8);
mutex_a_step = 1; mutex_a_step = 1;
@ -502,8 +507,12 @@ PRIVATE void test_condition(void)
if (mthread_mutex_destroy(condition_mutex) != 0) err(8, 8); if (mthread_mutex_destroy(condition_mutex) != 0) err(8, 8);
if (mthread_cond_destroy(&condition) != 0) err(8, 9); if (mthread_cond_destroy(&condition) != 0) err(8, 9);
#ifdef MTHREAD_STRICT
/* Let's try to destroy it again. Should fails as it's uninitialized. */ /* Let's try to destroy it again. Should fails as it's uninitialized. */
/* Note: this only works when libmthread is compiled with MTHREAD_STRICT. In
* POSIX this situation is a MAY fail if... */
if (mthread_cond_destroy(&condition) == 0) err(8, 10); if (mthread_cond_destroy(&condition) == 0) err(8, 10);
#endif
#ifdef MDEBUG #ifdef MDEBUG
mthread_verify(); mthread_verify();
@ -538,8 +547,11 @@ PRIVATE void test_condition(void)
if (mthread_mutex_destroy(condition_mutex) != 0) err(8, 21); if (mthread_mutex_destroy(condition_mutex) != 0) err(8, 21);
if (mthread_cond_destroy(&condition) != 0) err(8, 22); if (mthread_cond_destroy(&condition) != 0) err(8, 22);
#ifdef MTHREAD_STRICT
/* Again, destroying the condition variable twice shouldn't work */ /* Again, destroying the condition variable twice shouldn't work */
/* See previous note about MTHREAD_STRICT */
if (mthread_cond_destroy(&condition) == 0) err(8, 23); if (mthread_cond_destroy(&condition) == 0) err(8, 23);
#endif
#ifdef MDEBUG #ifdef MDEBUG
mthread_verify(); mthread_verify();