Clean up mthread
This commit is contained in:
parent
b67a7fca8c
commit
9b43de2cb3
10 changed files with 111 additions and 132 deletions
|
@ -9,9 +9,6 @@
|
|||
#include <ucontext.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef __NBSD_LIBC
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#ifdef __NBSD_LIBC
|
||||
#include <sys/signal.h>
|
||||
|
@ -32,16 +29,20 @@ typedef struct {
|
|||
struct __mthread_mutex {
|
||||
mthread_queue_t mm_queue; /* Queue of threads blocked on this mutex */
|
||||
mthread_thread_t mm_owner; /* Thread ID that currently owns mutex */
|
||||
#ifdef MTHREAD_STRICT
|
||||
struct __mthread_mutex *mm_prev;
|
||||
struct __mthread_mutex *mm_next;
|
||||
#endif
|
||||
unsigned int mm_magic;
|
||||
};
|
||||
typedef struct __mthread_mutex *mthread_mutex_t;
|
||||
|
||||
struct __mthread_cond {
|
||||
struct __mthread_mutex *mc_mutex; /* Associate mutex with condition */
|
||||
#ifdef MTHREAD_STRICT
|
||||
struct __mthread_cond *mc_prev;
|
||||
struct __mthread_cond *mc_next;
|
||||
#endif
|
||||
unsigned int mc_magic;
|
||||
};
|
||||
typedef struct __mthread_cond *mthread_cond_t;
|
||||
|
@ -64,7 +65,7 @@ typedef struct __mthread_attr *mthread_attr_t;
|
|||
/* allocate.c */
|
||||
_PROTOTYPE( int mthread_create, (mthread_thread_t *thread,
|
||||
mthread_attr_t *tattr,
|
||||
void (*proc)(void *), void *arg) );
|
||||
void *(*proc)(void *), void *arg) );
|
||||
_PROTOTYPE( int mthread_detach, (mthread_thread_t thread) );
|
||||
_PROTOTYPE( int mthread_equal, (mthread_thread_t l, mthread_thread_t r) );
|
||||
_PROTOTYPE( void mthread_exit, (void *value) );
|
||||
|
|
|
@ -5,13 +5,10 @@
|
|||
#include "global.h"
|
||||
#include "proto.h"
|
||||
|
||||
#define FALLBACK_CTX (&(fallback.m_context))
|
||||
|
||||
FORWARD _PROTOTYPE( void mthread_fallback, (void) );
|
||||
FORWARD _PROTOTYPE( int mthread_increase_thread_pool, (void) );
|
||||
FORWARD _PROTOTYPE( void mthread_thread_init, (mthread_thread_t thread,
|
||||
mthread_attr_t *tattr,
|
||||
void (*proc)(void *),
|
||||
void *(*proc)(void *),
|
||||
void *arg) );
|
||||
|
||||
FORWARD _PROTOTYPE( void mthread_thread_reset, (mthread_thread_t thread));
|
||||
|
@ -45,7 +42,7 @@ mthread_thread_t r;
|
|||
PUBLIC int mthread_create(threadid, tattr, proc, arg)
|
||||
mthread_thread_t *threadid;
|
||||
mthread_attr_t *tattr;
|
||||
void (*proc)(void *);
|
||||
void *(*proc)(void *);
|
||||
void *arg;
|
||||
{
|
||||
/* Register procedure proc for execution in a thread. */
|
||||
|
@ -111,7 +108,6 @@ PUBLIC void mthread_exit(value)
|
|||
void *value;
|
||||
{
|
||||
/* Make a thread stop running and store the result value. */
|
||||
int fallback_exit = 0;
|
||||
mthread_tcb_t *tcb;
|
||||
|
||||
mthread_init(); /* Make sure libmthread is initialized */
|
||||
|
@ -123,13 +119,6 @@ void *value;
|
|||
|
||||
mthread_cleanup_values();
|
||||
|
||||
/* When we're called from the fallback thread, the fallback thread
|
||||
* will invoke the scheduler. However, if the thread itself called
|
||||
* mthread_exit, _we_ will have to wake up the scheduler.
|
||||
*/
|
||||
if (tcb->m_state == MS_FALLBACK_EXITING)
|
||||
fallback_exit = 1;
|
||||
|
||||
tcb->m_result = value;
|
||||
tcb->m_state = MS_EXITING;
|
||||
|
||||
|
@ -145,42 +134,9 @@ void *value;
|
|||
*/
|
||||
}
|
||||
|
||||
/* The fallback thread does a mthread_schedule. If we're not running from
|
||||
* that thread, we have to do it ourselves.
|
||||
*/
|
||||
if (!fallback_exit)
|
||||
mthread_schedule();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* mthread_fallback *
|
||||
*===========================================================================*/
|
||||
PRIVATE void mthread_fallback(void)
|
||||
{
|
||||
/* The libmthread fallback thread. The idea is that every thread calls
|
||||
* mthread_exit(...) to stop running when it has nothing to do anymore.
|
||||
* However, in case a thread forgets to do that, the whole process exit()s and
|
||||
* that might be a bit problematic. Therefore, all threads will run this
|
||||
* fallback thread when they exit, giving the scheduler a chance to fix the
|
||||
* situation.
|
||||
*/
|
||||
mthread_tcb_t *tcb;
|
||||
|
||||
tcb = mthread_find_tcb(current_thread);
|
||||
|
||||
tcb->m_state = MS_FALLBACK_EXITING;
|
||||
mthread_exit(NULL);
|
||||
|
||||
/* Reconstruct fallback context for next invocation */
|
||||
makecontext(FALLBACK_CTX, (void (*) (void)) mthread_fallback, 0);
|
||||
|
||||
/* Let another thread run */
|
||||
mthread_schedule();
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* mthread_find_tcb *
|
||||
*===========================================================================*/
|
||||
|
@ -288,15 +244,6 @@ PUBLIC void mthread_init(void)
|
|||
mthread_init_keys();
|
||||
mthread_init_scheduler();
|
||||
|
||||
/* Initialize the fallback thread */
|
||||
if (mthread_getcontext(FALLBACK_CTX) == -1)
|
||||
mthread_panic("Could not initialize fallback thread");
|
||||
FALLBACK_CTX->uc_link = &(mainthread.m_context);
|
||||
FALLBACK_CTX->uc_stack.ss_sp = fallback_stack;
|
||||
FALLBACK_CTX->uc_stack.ss_size = STACKSZ;
|
||||
memset(fallback_stack, '\0', STACKSZ);
|
||||
makecontext(FALLBACK_CTX, (void (*) (void)) mthread_fallback, 0);
|
||||
|
||||
initialized = 1;
|
||||
}
|
||||
}
|
||||
|
@ -399,7 +346,7 @@ PUBLIC mthread_thread_t mthread_self(void)
|
|||
PRIVATE void mthread_thread_init(thread, tattr, proc, arg)
|
||||
mthread_thread_t thread;
|
||||
mthread_attr_t *tattr;
|
||||
void (*proc)(void *);
|
||||
void *(*proc)(void *);
|
||||
void *arg;
|
||||
{
|
||||
/* Initialize a thread so that it, when unsuspended, will run the given
|
||||
|
@ -414,7 +361,7 @@ void *arg;
|
|||
tcb = mthread_find_tcb(thread);
|
||||
tcb->m_next = NULL;
|
||||
tcb->m_state = MS_DEAD;
|
||||
tcb->m_proc = (void *(*)(void *)) proc; /* Yikes */
|
||||
tcb->m_proc = proc;
|
||||
tcb->m_arg = arg;
|
||||
/* Threads use a copy of the provided attributes. This way, if another
|
||||
* thread modifies the attributes (such as detach state), already running
|
||||
|
@ -429,10 +376,9 @@ void *arg;
|
|||
if (mthread_cond_init(&(tcb->m_exited), NULL) != 0)
|
||||
mthread_panic("Could not initialize thread");
|
||||
|
||||
/* First set the fallback thread, */
|
||||
tcb->m_context.uc_link = FALLBACK_CTX;
|
||||
tcb->m_context.uc_link = NULL;
|
||||
|
||||
/* then construct this thread's context to run procedure proc. */
|
||||
/* Construct this thread's context to run procedure proc. */
|
||||
if (mthread_getcontext(&(tcb->m_context)) == -1)
|
||||
mthread_panic("Failed to initialize context state");
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
#include "global.h"
|
||||
#include "proto.h"
|
||||
|
||||
PRIVATE struct __mthread_cond *vc_front, *vc_rear;
|
||||
#ifdef MTHREAD_STRICT
|
||||
PRIVATE struct __mthread_cond *vc_front, *vc_rear;
|
||||
FORWARD _PROTOTYPE( void mthread_cond_add, (mthread_cond_t *c) );
|
||||
FORWARD _PROTOTYPE( void mthread_cond_remove, (mthread_cond_t *c) );
|
||||
FORWARD _PROTOTYPE( int mthread_cond_valid, (mthread_cond_t *c) );
|
||||
|
@ -19,8 +19,10 @@ FORWARD _PROTOTYPE( int mthread_cond_valid, (mthread_cond_t *c) );
|
|||
*===========================================================================*/
|
||||
PUBLIC void mthread_init_valid_conditions(void)
|
||||
{
|
||||
#ifdef MTHREAD_STRICT
|
||||
/* Initialize condition variable list */
|
||||
vc_front = vc_rear = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#define MTHREAD_NOT_INUSE 0xdefec7
|
||||
|
||||
typedef enum {
|
||||
MS_CONDITION, MS_DEAD, MS_EXITING, MS_FALLBACK_EXITING, MS_MUTEX, MS_RUNNABLE
|
||||
MS_CONDITION, MS_DEAD, MS_EXITING, MS_MUTEX, MS_RUNNABLE
|
||||
} mthread_state_t;
|
||||
|
||||
struct __mthread_tcb {
|
||||
|
@ -40,10 +40,8 @@ EXTERN mthread_thread_t current_thread;
|
|||
EXTERN mthread_queue_t free_threads;
|
||||
EXTERN mthread_queue_t run_queue; /* FIFO of runnable threads */
|
||||
EXTERN mthread_tcb_t **threads;
|
||||
EXTERN mthread_tcb_t fallback;
|
||||
EXTERN mthread_tcb_t mainthread;
|
||||
EXTERN int no_threads;
|
||||
EXTERN int used_threads;
|
||||
EXTERN int running_main_thread;
|
||||
EXTERN char fallback_stack[STACKSZ];
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "global.h"
|
||||
#include "proto.h"
|
||||
|
||||
PRIVATE int keys_used = 0;
|
||||
PRIVATE struct {
|
||||
int used;
|
||||
int nvalues;
|
||||
|
@ -34,6 +35,7 @@ PUBLIC int mthread_key_create(mthread_key_t *key, void (*destructor)(void *))
|
|||
mthread_key_t k;
|
||||
|
||||
mthread_init(); /* Make sure libmthread is initialized */
|
||||
keys_used = 1;
|
||||
|
||||
/* We do not yet allocate storage space for the values here, because we can
|
||||
* not estimate how many threads will be created in the common case that the
|
||||
|
@ -150,6 +152,8 @@ PUBLIC void mthread_cleanup_values(void)
|
|||
void *value;
|
||||
int found;
|
||||
|
||||
if (!keys_used) return; /* Only clean up if we used any keys at all */
|
||||
|
||||
/* Any of the destructors may set a new value on any key, so we may have to
|
||||
* loop over the table of keys multiple times. This implementation has no
|
||||
* protection against infinite loops in this case.
|
||||
|
|
|
@ -6,18 +6,18 @@
|
|||
/*===========================================================================*
|
||||
* mthread_debug_f *
|
||||
*===========================================================================*/
|
||||
#ifdef MDEBUG
|
||||
PUBLIC void mthread_debug_f(const char *file, int line, const char *msg)
|
||||
{
|
||||
/* Print debug message */
|
||||
#ifdef MDEBUG
|
||||
printf("MTH (%s:%d): %s\n", file, line, msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*===========================================================================*
|
||||
* mthread_panic_f *
|
||||
*===========================================================================*/
|
||||
#ifdef MDEBUG
|
||||
PUBLIC void mthread_panic_f(const char *file, int line, const char *msg)
|
||||
{
|
||||
/* Print panic message to stdout and exit */
|
||||
|
@ -32,6 +32,17 @@ PUBLIC void mthread_panic_f(const char *file, int line, const char *msg)
|
|||
*((int *) sf ) = 1; /* Cause segfault to generate trace */
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
PUBLIC void mthread_panic_s(void)
|
||||
{
|
||||
/* Silent panic */
|
||||
volatile int *sf;
|
||||
|
||||
sf = NULL;
|
||||
*((int *) sf ) = 1; /* Cause segfault to generate trace */
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
|
@ -68,9 +79,6 @@ PUBLIC void mthread_verify_f(char *file, int line)
|
|||
if(!threads_ok || !conditions_ok || !mutexes_ok)
|
||||
mthread_panic("Library state corrupt\n");
|
||||
}
|
||||
#else
|
||||
PUBLIC void mthread_verify_f(char *f, int l) { ; }
|
||||
#endif
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
|
@ -80,8 +88,8 @@ PUBLIC void mthread_stats(void)
|
|||
{
|
||||
mthread_thread_t t;
|
||||
mthread_tcb_t *tcb;
|
||||
int st_run, st_dead, st_cond, st_mutex, st_exit, st_fbexit;
|
||||
st_run = st_dead = st_cond = st_mutex = st_exit = st_fbexit = 0;
|
||||
int st_run, st_dead, st_cond, st_mutex, st_exit;
|
||||
st_run = st_dead = st_cond = st_mutex = st_exit = 0;
|
||||
|
||||
for (t = (mthread_thread_t) 0; t < no_threads; t++) {
|
||||
tcb = mthread_find_tcb(t);
|
||||
|
@ -91,13 +99,13 @@ PUBLIC void mthread_stats(void)
|
|||
case MS_MUTEX: st_mutex++; break;
|
||||
case MS_CONDITION: st_cond++; break;
|
||||
case MS_EXITING: st_exit++; break;
|
||||
case MS_FALLBACK_EXITING: st_fbexit++; break;
|
||||
default: mthread_panic("Unknown state");
|
||||
}
|
||||
}
|
||||
|
||||
printf("Pool: %-5d In use: %-5d R: %-5d D: %-5d M: %-5d C: %-5d E: %-5d"
|
||||
"F: %-5d\n",
|
||||
printf("Pool: %-5d In use: %-5d R: %-5d D: %-5d M: %-5d C: %-5d E: %-5d\n",
|
||||
no_threads, used_threads, st_run, st_dead, st_mutex, st_cond,
|
||||
st_exit, st_fbexit);
|
||||
st_exit);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
#include "global.h"
|
||||
#include "proto.h"
|
||||
|
||||
PRIVATE struct __mthread_mutex *vm_front, *vm_rear;
|
||||
#ifdef MTHREAD_STRICT
|
||||
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) );
|
||||
#else
|
||||
|
@ -16,8 +16,10 @@ FORWARD _PROTOTYPE( void mthread_mutex_remove, (mthread_mutex_t *m) );
|
|||
*===========================================================================*/
|
||||
PUBLIC void mthread_init_valid_mutexes(void)
|
||||
{
|
||||
#ifdef MTHREAD_STRICT
|
||||
/* Initialize list of valid mutexes */
|
||||
vm_front = vm_rear = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -135,14 +137,10 @@ mthread_mutex_t *mutex; /* Mutex that is to be locked */
|
|||
return(EINVAL);
|
||||
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) {
|
||||
return(EDEADLK);
|
||||
} 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);
|
||||
}
|
||||
|
||||
|
@ -244,10 +242,10 @@ mthread_mutex_t *m;
|
|||
loopitem = vm_front;
|
||||
|
||||
while (loopitem != NULL) {
|
||||
if (loopitem == *m)
|
||||
return(1);
|
||||
if (loopitem == *m)
|
||||
return(1);
|
||||
|
||||
loopitem = loopitem->mm_next;
|
||||
loopitem = loopitem->mm_next;
|
||||
}
|
||||
|
||||
return(0);
|
||||
|
@ -266,13 +264,15 @@ PUBLIC int mthread_mutex_verify(void)
|
|||
|
||||
mthread_init(); /* Make sure mthreads is initialized */
|
||||
|
||||
#ifdef MTHREAD_STRICT
|
||||
loopitem = vm_front;
|
||||
|
||||
while (loopitem != NULL) {
|
||||
printf("mutex corruption: owner: %d\n", loopitem->mm_owner);
|
||||
loopitem = loopitem->next;
|
||||
loopitem = loopitem->mm_next;
|
||||
r = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return(r);
|
||||
}
|
||||
|
|
|
@ -21,12 +21,18 @@ _PROTOTYPE( void mthread_init_keys, (void) );
|
|||
_PROTOTYPE( void mthread_cleanup_values, (void) );
|
||||
|
||||
/* misc.c */
|
||||
#ifdef MDEBUG
|
||||
#define mthread_panic(m) mthread_panic_f(__FILE__, __LINE__, (m))
|
||||
_PROTOTYPE( void mthread_panic_f, (const char *file, int line,
|
||||
const char *msg) );
|
||||
#define mthread_debug(m) mthread_debug_f(__FILE__, __LINE__, (m))
|
||||
_PROTOTYPE( void mthread_debug_f, (const char *file, int line,
|
||||
const char *msg) );
|
||||
#else
|
||||
_PROTOTYPE( void mthread_panic_s, (void) );
|
||||
# define mthread_panic(m) mthread_panic_s()
|
||||
# define mthread_debug(m)
|
||||
#endif
|
||||
|
||||
/* mutex.c */
|
||||
_PROTOTYPE( void mthread_init_valid_mutexes, (void) );
|
||||
|
@ -49,7 +55,9 @@ _PROTOTYPE( void mthread_suspend, (mthread_state_t state) );
|
|||
_PROTOTYPE( void mthread_unsuspend, (mthread_thread_t thread) );
|
||||
|
||||
/* queue.c */
|
||||
#ifdef MDEBUG
|
||||
_PROTOTYPE( void mthread_dump_queue, (mthread_queue_t *queue) );
|
||||
#endif
|
||||
_PROTOTYPE( void mthread_queue_init, (mthread_queue_t *queue) );
|
||||
_PROTOTYPE( void mthread_queue_add, (mthread_queue_t *queue,
|
||||
mthread_thread_t thread) );
|
||||
|
|
|
@ -54,6 +54,7 @@ mthread_queue_t *queue;
|
|||
/*===========================================================================*
|
||||
* mthread_dump_queue *
|
||||
*===========================================================================*/
|
||||
#ifdef MDEBUG
|
||||
PUBLIC void mthread_dump_queue(queue)
|
||||
mthread_queue_t *queue;
|
||||
{
|
||||
|
@ -61,39 +62,30 @@ mthread_queue_t *queue;
|
|||
mthread_tcb_t *t;
|
||||
mthread_thread_t tid;
|
||||
threshold = no_threads;
|
||||
#ifdef MDEBUG
|
||||
printf("Dumping queue: ");
|
||||
#endif
|
||||
|
||||
if(queue->mq_head != NULL) {
|
||||
t = queue->mq_head;
|
||||
if (t == &mainthread) tid = MAIN_THREAD;
|
||||
else tid = t->m_tid;
|
||||
#ifdef MDEBUG
|
||||
printf("%d ", tid);
|
||||
#endif
|
||||
count++;
|
||||
t = t->m_next;
|
||||
while (t != NULL) {
|
||||
if (t == &mainthread) tid = MAIN_THREAD;
|
||||
else tid = t->m_tid;
|
||||
#ifdef MDEBUG
|
||||
printf("%d ", tid);
|
||||
#endif
|
||||
t = t->m_next;
|
||||
count++;
|
||||
if (count > threshold) break;
|
||||
}
|
||||
} else {
|
||||
#ifdef MDEBUG
|
||||
printf("[empty]");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MDEBUG
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*===========================================================================*
|
||||
* mthread_queue_remove *
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* lets you check the internal integrity of the library. */
|
||||
#include <stdio.h>
|
||||
#include <minix/mthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define thread_t mthread_thread_t
|
||||
#define mutex_t mthread_mutex_t
|
||||
|
@ -38,16 +39,18 @@ PRIVATE int first;
|
|||
#define THRESH1 3
|
||||
#define THRESH2 8
|
||||
#define MEG 1024*1024
|
||||
#define MAGIC 0xb4a3f1c2
|
||||
#define MAGIC ((signed) 0xb4a3f1c2)
|
||||
|
||||
FORWARD _PROTOTYPE( void thread_a, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void thread_b, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void thread_c, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void thread_d, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void destr_a, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void destr_b, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void *thread_a, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void *thread_b, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void *thread_c, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void *thread_d, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void thread_e, (void) );
|
||||
FORWARD _PROTOTYPE( void thread_f, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void thread_g, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void thread_h, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void *thread_f, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void *thread_g, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void *thread_h, (void *arg) );
|
||||
FORWARD _PROTOTYPE( void test_scheduling, (void) );
|
||||
FORWARD _PROTOTYPE( void test_mutex, (void) );
|
||||
FORWARD _PROTOTYPE( void test_condition, (void) );
|
||||
|
@ -58,34 +61,38 @@ FORWARD _PROTOTYPE( void err, (int subtest, int error) );
|
|||
/*===========================================================================*
|
||||
* thread_a *
|
||||
*===========================================================================*/
|
||||
PRIVATE void thread_a(void *arg) {
|
||||
PRIVATE void *thread_a(void *arg) {
|
||||
th_a++;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* thread_b *
|
||||
*===========================================================================*/
|
||||
PRIVATE void thread_b(void *arg) {
|
||||
PRIVATE void *thread_b(void *arg) {
|
||||
th_b++;
|
||||
if (mthread_once(&once, thread_e) != 0) err(10, 1);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* thread_c *
|
||||
*===========================================================================*/
|
||||
PRIVATE void thread_c(void *arg) {
|
||||
PRIVATE void *thread_c(void *arg) {
|
||||
th_c++;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* thread_d *
|
||||
*===========================================================================*/
|
||||
PRIVATE void thread_d(void *arg) {
|
||||
PRIVATE void *thread_d(void *arg) {
|
||||
th_d++;
|
||||
mthread_exit(NULL); /* Thread wants to stop running */
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -100,31 +107,33 @@ PRIVATE void thread_e(void) {
|
|||
/*===========================================================================*
|
||||
* thread_f *
|
||||
*===========================================================================*/
|
||||
PRIVATE void thread_f(void *arg) {
|
||||
PRIVATE void *thread_f(void *arg) {
|
||||
if (mthread_mutex_lock(condition_mutex) != 0) err(12, 1);
|
||||
th_f++;
|
||||
if (mthread_cond_signal(&condition) != 0) err(12, 2);
|
||||
if (mthread_mutex_unlock(condition_mutex) != 0) err(12, 3);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* thread_g *
|
||||
*===========================================================================*/
|
||||
PRIVATE void thread_g(void *arg) {
|
||||
PRIVATE void *thread_g(void *arg) {
|
||||
char bigarray[MTHREAD_STACK_MIN + 1];
|
||||
if (mthread_mutex_lock(condition_mutex) != 0) err(13, 1);
|
||||
memset(bigarray, '\0', MTHREAD_STACK_MIN + 1); /* Actually allocate it */
|
||||
th_g++;
|
||||
if (mthread_cond_signal(&condition) != 0) err(13, 2);
|
||||
if (mthread_mutex_unlock(condition_mutex) != 0) err(13, 3);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* thread_h *
|
||||
*===========================================================================*/
|
||||
PRIVATE void thread_h(void *arg) {
|
||||
PRIVATE void *thread_h(void *arg) {
|
||||
char bigarray[2 * MEG];
|
||||
int reply;
|
||||
if (mthread_mutex_lock(condition_mutex) != 0) err(14, 1);
|
||||
|
@ -134,6 +143,7 @@ PRIVATE void thread_h(void *arg) {
|
|||
if (mthread_mutex_unlock(condition_mutex) != 0) err(14, 3);
|
||||
reply = *((int *) arg);
|
||||
mthread_exit((void *) reply);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -154,7 +164,7 @@ PRIVATE void err(int sub, int error) {
|
|||
*===========================================================================*/
|
||||
PRIVATE void test_scheduling(void)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
thread_t t[7];
|
||||
|
||||
#ifdef MDEBUG
|
||||
|
@ -217,10 +227,9 @@ PRIVATE void test_scheduling(void)
|
|||
/*===========================================================================*
|
||||
* mutex_a *
|
||||
*===========================================================================*/
|
||||
PRIVATE void mutex_a(void *arg)
|
||||
PRIVATE void *mutex_a(void *arg)
|
||||
{
|
||||
mutex_t *mu = (mutex_t *) arg;
|
||||
mutex_t mu2;
|
||||
|
||||
VERIFY_MUTEX(0, 0, 0, 3, 1);
|
||||
if (mthread_mutex_lock(&mu[0]) != 0) err(3, 2);
|
||||
|
@ -267,13 +276,14 @@ PRIVATE void mutex_a(void *arg)
|
|||
if (mthread_mutex_unlock(NULL) == 0) err(3, 19);
|
||||
|
||||
if (mthread_mutex_unlock(&mu[2]) != 0) err(3, 20);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* mutex_b *
|
||||
*===========================================================================*/
|
||||
PRIVATE void mutex_b(void *arg)
|
||||
PRIVATE void *mutex_b(void *arg)
|
||||
{
|
||||
mutex_t *mu = (mutex_t *) arg;
|
||||
|
||||
|
@ -302,13 +312,14 @@ PRIVATE void mutex_b(void *arg)
|
|||
|
||||
if (mthread_mutex_unlock(&mu[1]) != 0) err(4, 8);
|
||||
mutex_b_step = 4;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* mutex_c *
|
||||
*===========================================================================*/
|
||||
PRIVATE void mutex_c(void *arg)
|
||||
PRIVATE void *mutex_c(void *arg)
|
||||
{
|
||||
mutex_t *mu = (mutex_t *) arg;
|
||||
|
||||
|
@ -329,6 +340,7 @@ PRIVATE void mutex_c(void *arg)
|
|||
|
||||
if (mthread_mutex_unlock(&mu[0]) != 0) err(5, 9);
|
||||
mutex_c_step = 4;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -337,7 +349,7 @@ PRIVATE void mutex_c(void *arg)
|
|||
*===========================================================================*/
|
||||
PRIVATE void test_mutex(void)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
thread_t t[3];
|
||||
#ifdef MDEBUG
|
||||
mthread_verify();
|
||||
|
@ -381,7 +393,7 @@ PRIVATE void test_mutex(void)
|
|||
/*===========================================================================*
|
||||
* cond_a *
|
||||
*===========================================================================*/
|
||||
PRIVATE void cond_a(void *arg)
|
||||
PRIVATE void *cond_a(void *arg)
|
||||
{
|
||||
cond_t c;
|
||||
int did_count = 0;
|
||||
|
@ -406,6 +418,7 @@ PRIVATE void cond_a(void *arg)
|
|||
|
||||
/* Try faulty addresses */
|
||||
if (mthread_mutex_lock(condition_mutex) != 0) err(6, 7);
|
||||
#ifdef MTHREAD_STRICT
|
||||
/* Condition c is not initialized, so whatever we do with it should fail. */
|
||||
if (mthread_cond_wait(&c, condition_mutex) == 0) err(6, 8);
|
||||
if (mthread_cond_wait(NULL, condition_mutex) == 0) err(6, 9);
|
||||
|
@ -415,19 +428,21 @@ PRIVATE void cond_a(void *arg)
|
|||
/* Try again with an unlocked mutex */
|
||||
if (mthread_cond_wait(&c, condition_mutex) == 0) err(6, 12);
|
||||
if (mthread_cond_signal(&c) == 0) err(6, 13);
|
||||
#endif
|
||||
|
||||
/* And again with an unlocked mutex, but initialized c */
|
||||
if (mthread_cond_init(&c, NULL) != 0) err(6, 14);
|
||||
if (mthread_cond_wait(&c, condition_mutex) == 0) err(6, 15);
|
||||
if (mthread_cond_signal(&c) != 0) err(6, 16);/*c.f., 6.10 this should work!*/
|
||||
if (mthread_cond_destroy(&c) != 0) err(6, 17);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* cond_b *
|
||||
*===========================================================================*/
|
||||
PRIVATE void cond_b(void *arg)
|
||||
PRIVATE void *cond_b(void *arg)
|
||||
{
|
||||
int did_count = 0;
|
||||
while(1) {
|
||||
|
@ -448,14 +463,14 @@ PRIVATE void cond_b(void *arg)
|
|||
|
||||
if (!(did_count >= count - (THRESH2 - THRESH1 + 1))) err(7, 6);
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* cond_broadcast *
|
||||
*===========================================================================*/
|
||||
PRIVATE void cond_broadcast(void *arg)
|
||||
PRIVATE void *cond_broadcast(void *arg)
|
||||
{
|
||||
int rounds = 0;
|
||||
if (mthread_mutex_lock(condition_mutex) != 0) err(9, 1);
|
||||
|
||||
while(!condition_met)
|
||||
|
@ -466,6 +481,7 @@ PRIVATE void cond_broadcast(void *arg)
|
|||
if (mthread_mutex_lock(count_mutex) != 0) err(9, 4);
|
||||
count++;
|
||||
if (mthread_mutex_unlock(count_mutex) != 0) err(9, 5);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
@ -474,7 +490,7 @@ PRIVATE void cond_broadcast(void *arg)
|
|||
PRIVATE void test_condition(void)
|
||||
{
|
||||
#define NTHREADS 10
|
||||
int i, r;
|
||||
int i;
|
||||
thread_t t[2], s[NTHREADS];
|
||||
count_mutex = &mu[0];
|
||||
condition_mutex = &mu[1];
|
||||
|
@ -498,7 +514,7 @@ PRIVATE void test_condition(void)
|
|||
if (mthread_create(&t[0], NULL, cond_a, NULL) != 0) err(8, 4);
|
||||
if (mthread_create(&t[1], NULL, cond_b, NULL) != 0) err(8, 5);
|
||||
|
||||
for (i = 0; i < (sizeof(t) / sizeof(thread_t)); i++)
|
||||
for (i = 0; i < (sizeof(t) / sizeof(thread_t)); i++)
|
||||
if (mthread_join(t[i], NULL) != 0) err(8, 6);
|
||||
|
||||
if (mthread_mutex_destroy(count_mutex) != 0) err(8, 7);
|
||||
|
@ -564,7 +580,7 @@ PRIVATE void test_attributes(void)
|
|||
attr_t tattr;
|
||||
thread_t tid;
|
||||
int detachstate = -1, status = 0;
|
||||
int i, no_ints, stack_untouched = 1;
|
||||
unsigned int i, no_ints, stack_untouched = 1;
|
||||
void *stackaddr, *newstackaddr;
|
||||
int *stackp;
|
||||
size_t stacksize, newstacksize;
|
||||
|
@ -720,7 +736,7 @@ PRIVATE void test_attributes(void)
|
|||
#endif
|
||||
|
||||
if (mthread_join(tid, (void *) &status) != 0) err(11, 69);
|
||||
if (status != stacksize) err(11, 70);
|
||||
if ((size_t) status != stacksize) err(11, 70);
|
||||
if (mthread_attr_destroy(&tattr) != 0) err(11, 71);
|
||||
if (mthread_mutex_destroy(condition_mutex) != 0) err(11, 72);
|
||||
if (mthread_cond_destroy(&condition) != 0) err(11, 73);
|
||||
|
@ -759,7 +775,7 @@ PRIVATE void destr_b(void *value)
|
|||
/*===========================================================================*
|
||||
* key_a *
|
||||
*===========================================================================*/
|
||||
PRIVATE void key_a(void *arg)
|
||||
PRIVATE void *key_a(void *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -785,12 +801,13 @@ PRIVATE void key_a(void *arg)
|
|||
|
||||
/* If a key's value is set to NULL, its destructor must not be called. */
|
||||
if (mthread_setspecific(key[4], NULL) != 0) err(17, 5);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* key_b *
|
||||
*===========================================================================*/
|
||||
PRIVATE void key_b(void *arg)
|
||||
PRIVATE void *key_b(void *arg)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -810,12 +827,13 @@ PRIVATE void key_b(void *arg)
|
|||
if (mthread_key_delete(key[3]) != 0) err(18, 3);
|
||||
|
||||
mthread_exit(NULL);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* key_c *
|
||||
*===========================================================================*/
|
||||
PRIVATE void key_c(void *arg)
|
||||
PRIVATE void *key_c(void *arg)
|
||||
{
|
||||
/* The only thing that this thread should do, is set a value. */
|
||||
if (mthread_setspecific(key[0], (void *) mthread_self()) != 0) err(19, 1);
|
||||
|
@ -824,6 +842,7 @@ PRIVATE void key_c(void *arg)
|
|||
|
||||
if (!mthread_equal((thread_t) mthread_getspecific(key[0]), mthread_self()))
|
||||
err(19, 2);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
@ -919,5 +938,6 @@ int main(void)
|
|||
test_attributes();
|
||||
test_keys();
|
||||
quit();
|
||||
return(0); /* Not reachable */
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue