From 860f5268e2d230e4fc04ab588f74ea5e05bab44a Mon Sep 17 00:00:00 2001 From: rpj Date: Sat, 25 Jul 1998 12:27:18 +0000 Subject: Sat Jul 25 00:00:13 1998 Ross Johnson * create.c (_pthread_start_call): Set thread priority. Ensure our thread entry is removed from the thread table but only if pthread_detach() was called and there are no waiting joins. (pthread_create): Set detach flag in thread entry if the thread is created PTHREAD_CREATE_DETACHED. * pthread.h (pthread_attr_t): Rename member "detachedstate". * attr.c (pthread_attr_init): Rename attr members. * exit.c (pthread_exit): Fix indirection mistake. * implement.h (_PTHREAD_THREADS_TABLE_INDEX): Add. * exit.c (_pthread_vacuum): Fix incorrect args to _pthread_handler_pop_all() calls. Make thread entry removal conditional. * sync.c (pthread_join): Add multiple join and async detach handling. * implement.h (_PTHREAD_THREADS_TABLE_INDEX): Add. * global.c (_pthread_threads_mutex_table): Add. * implement.h (_pthread_once_flag): Remove. (_pthread_once_lock): Ditto. (_pthread_threads_mutex_table): Add. * global.c (_pthread_once_flag): Remove. (_pthread_once_lock): Ditto. * sync.c (pthread_join): Fix tests involving new return value from _pthread_find_thread_entry(). (pthread_detach): Ditto. * private.c (_pthread_find_thread_entry): Failure return code changed from -1 to NULL. --- sync.c | 165 +++++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 124 insertions(+), 41 deletions(-) (limited to 'sync.c') diff --git a/sync.c b/sync.c index c4e4327..84d9bd9 100644 --- a/sync.c +++ b/sync.c @@ -6,63 +6,147 @@ * synchronisation. */ +/* POSIX STANDARD: A thread may pass a value pointer to some data via + pthread_exit(). That pointer will be stored in a location supplied + as an argument to pthread_join(). + + IMPLEMENTATION: The value_ptr is stored in the thread entry. When + pthread_join() wakes up after waiting, or immediately if the target + thread has already terminated but is not detached, the value + pointer from pthread_exit() will be copied to *value_ptr. + + If the target thread does not become detached in the mean time, all + waiting joins on that thread will get the value pointer. The last + waiting join will delete the target thread entry. + + ---- + + POSIX STANDARD: The results of multiple simultaneous calls to + pthread_join() specifying the same target thread are undefined. + + IMPLEMENTATION: Any such join that occurs before the first such + join wakes up, or the thread is otherwise detached (by a call to + pthread_detach), will return successfully with the value that was + passed to pthread_exit(). After the last such join returns, the + target thread will have be detached and it's entry removed from the + thread table. + + Until the target thread entry is deleted it will be counted against + {PTHREAD_COUNT_MAX}. + + ---- + + ---- + + POSIX STANDARD: It is unspecified whether a thread that has exited + but remains unjoined counts against {PTHREAD_COUNT_MAX}. + + IMPLEMENTATION: A thread that has exited but remains unjoined will + be counted against {PTHREAD_COUNT_MAX}. The first call to + pthread_join() or pthread_detach() will remove the target thread's + table entry and decrement the count. + + ---- */ + +#include #include "pthread.h" +#include "implement.h" int pthread_join(pthread_t thread, void ** valueptr) { LPDWORD exitcode; int detachstate; - pthread_t us = pthread_self(); + _pthread_threads_thread_t * target; /* First check if we are trying to join to ourselves. */ - if (pthread_equal(thread, us) == 0) + if (thread == pthread_self()) { return EDEADLK; } /* Find the thread. */ - this = _pthread_find_thread_entry(thread); + target = _pthread_find_thread_entry(thread); - if (this == -1) + if (target != NULL) { - return ESRCH; - } + pthread_mutex_t * target_thread_mutex; + int ret; - /* If the thread is detached, then join will return immediately. */ + target_thread_mutex = _PTHREAD_THREAD_MUTEX(target); - if (pthread_attr_getdetachedstate(&(this->attr), &detachstate) != 0 - || detachstate == PTHREAD_CREATE_DETACHED) - { - return EINVAL; - } + /* CRITICAL SECTION */ + pthread_mutex_lock(target_thread_mutex); - this->joinvalueptr = valueptr; + /* If the thread is in DETACHED state, then join will return + immediately. */ - /* Wait on the kernel thread object. */ - switch (WaitForSingleObject(thread, INFINITE)) - { - case WAIT_FAILED: - /* The thread does not exist. */ - return ESRCH; - case WAIT_OBJECT_0: - /* The thread has finished. */ - break; - default: - /* This should never happen. */ - break; - } - - /* We don't get the exit code as a result of the last operation, - so we do it now. */ + if (target->detach == TRUE) + { + return EINVAL; + } - if (GetExitCodeThread(thread, exitcode) != TRUE) - { - return ESRCH; + target->join_count++; + + pthread_mutex_lock(target_thread_mutex); + /* END CRITICAL SECTION */ + + /* Wait on the kernel thread object. */ + switch (WaitForSingleObject(thread, INFINITE)) + { + case WAIT_FAILED: + /* The thread does not exist. */ + return ESRCH; + case WAIT_OBJECT_0: + /* The thread has finished. */ + break; + default: + /* This should never happen. */ + break; + } + + /* We know the target thread entry still exists at this point + because we incremented join_count above after checking. The + thread entry will not be removed until join_count == 0 again, + ie. when the last waiting join has passed through the + following critical section. */ + + /* CRITICAL SECTION */ + pthread_mutex_lock(target_thread_mutex); + + /* Collect the value pointer passed to pthread_exit(). If + another thread detaches our target thread while we're + waiting, then we report a deadlock as it likely that storage + pointed to by target->joinvalueptr has been freed or + otherwise no longer valid. */ + + if (target->detach == TRUE) + { + ret = EDEADLK; + } + else + { + *value_ptr = target->joinvalueptr; + ret = 0; + } + + target->join_count--; + + /* If we're the last join to return then we are responsible for + removing the target thread's table entry. */ + if (target->join_count == 0) + { + _pthread_delete_thread_entry(target); + } + + pthread_mutex_lock(target_thread_mutex); + /* END CRITICAL SECTION */ + + return ret; } - /* FIXME: this is wrong. */ - return &exitcode; + /* Thread not found. */ + return ESRCH; } int @@ -73,7 +157,7 @@ pthread_detach(pthread_t thread) this = _pthread_find_thread_entry(thread); - if (this == -1) + if (this == NULL) { return ESRCH; } @@ -84,11 +168,10 @@ pthread_detach(pthread_t thread) { return EINVAL; } - - this->attr.detached = PTHREAD_CREATE_DETACHED; - if (CloseHandle(thread) != TRUE) - { - return ESRCH; - } + + /* This is all we do here - the rest is done either when the thread + exits or when pthread_join() exits. */ + this->detach = TRUE; + return 0; } -- cgit v1.2.3