diff options
-rw-r--r-- | ChangeLog | 20 | ||||
-rw-r--r-- | create.c | 34 | ||||
-rw-r--r-- | exit.c | 15 | ||||
-rw-r--r-- | implement.h | 2 | ||||
-rw-r--r-- | private.c | 1 | ||||
-rw-r--r-- | sync.c | 2 |
6 files changed, 61 insertions, 13 deletions
@@ -1,5 +1,25 @@ Fri Jul 24 03:00:25 1998 Ross Johnson <rpj@ixobrychus.canberra.edu.au> + * sync.c (pthread_join): Save valueptr arg in joinvalueptr for + pthread_exit() to use. + + * private.c (_pthread_new_thread_entry): Initialise joinvalueptr to + NULL. + + * create.c (_pthread_start_call): Rewrite to facilitate joins. + pthread_exit() will do a longjmp() back to here. Does appropriate + cleanup and exit/return from the thread. + (pthread_create): _beginthreadex() now passes a pointer to our + thread table entry instead of just the call member of that entry. + + * implement.h (_pthread_threads_thread): New member + void ** joinvalueptr. + (_pthread_call_t): New member jmpbuf env. + + * exit.c (pthread_exit): Major rewrite to handle joins and handing + value pointer to joining thread. Uses longjmp() back to + _pthread_start_call(). + * create.c (pthread_create): Ensure values of new attribute members are copied to the thread attribute object. @@ -12,26 +12,38 @@ #include "implement.h" unsigned -_pthread_start_call(void * call) +_pthread_start_call(void * thisarg) { /* We're now in a running thread. Any local variables here are on this threads private stack so we're safe to leave data in them until we leave. */ - _pthread_call_t * this; + _pthread_threads_thread__t * this = thisarg; + _pthread_call_t * call; unsigned (*func)(void *); void * arg; unsigned ret; + int from; - this = (_pthread_call_t *) call; - func = call->routine; - arg = call->arg; + func = this->call.routine; + arg = this->call.arg; - ret = (*func)(arg); + /* FIXME: Should we be using sigsetjmp() here instead. */ + from = setjmp(this->call.env); - /* If we get to here then we're returning naturally and haven't - been cancelled. We need to cleanup and remove the thread - from the threads table. */ - _pthread_vacuum(); + if (from == 0) + { + ret = (*func)(arg); + + _pthread_vacuum(); + } + else + { + /* func() called pthread_exit() which called longjmp(). */ + _pthread_vacuum(); + + /* Never returns. */ + _endthreadex(0); + } return ret; } @@ -75,7 +87,7 @@ pthread_create(pthread_t *thread, handle = (HANDLE) _beginthreadex(security, attr_copy->stacksize, _pthread_start_call, - (void *) &(this->call), + (void *) this, flags, &threadID); @@ -36,6 +36,17 @@ _pthread_vacuum(void) void pthread_exit(void * value) { - _pthread_vacuum(); - _endthreadex((DWORD) value); + _pthread_threads_thread_t * this; + + this = _PTHREAD_THIS; + + if (this->joinvalueptr != NULL) + { + *(this->joinvalueptr) = value; + } + + /* FIXME: More to do here. IE, if pthread_detach() was called + and value != NULL, do we free(value)? */ + + longjmp(this->call.env, 1); } diff --git a/implement.h b/implement.h index 14fbdbb..b72e273 100644 --- a/implement.h +++ b/implement.h @@ -37,6 +37,7 @@ struct _pthread_handler_node { typedef struct { unsigned (*routine)(void *); void * arg; + jmpbuf env; } _pthread_call_t; #define _PTHREAD_THIS (_pthread_find_thread_entry(pthread_this())) @@ -51,6 +52,7 @@ struct _pthread_threads_thread { pthread_t thread; pthread_attr_t attr; _pthread_call_t call; + void ** joinvalueptr; _pthread_handler_node_t * cleanupstack; _pthread_handler_node_t * destructorstack; _pthread_handler_node_t * forkpreparestack; @@ -59,6 +59,7 @@ _pthread_new_thread_entry(pthread_t thread, _pthread_threads_thread_t * entry) { this->thread = thread; pthread_attr_init(&(this->attr)); + this->joinvalueptr = NULL; this->cleanupstack = NULL; this->destructorstack = NULL; this->forkpreparestack = NULL; @@ -37,6 +37,8 @@ pthread_join(pthread_t thread, void ** valueptr) return EINVAL; } + this->joinvalueptr = valueptr; + /* Wait on the kernel thread object. */ switch (WaitForSingleObject(thread, INFINITE)) { |