From 199d96f3e3f6077235be8e0bf9482d2a46e108c2 Mon Sep 17 00:00:00 2001 From: rpj Date: Thu, 7 Sep 2000 15:41:11 +0000 Subject: 2000-09-08 Ross Johnson * cancel.c (pthread_cancel): Must get "self" through calling pthread_self() which will ensure a POSIX thread struct is built for non-POSIX threads; return an error if this fails - Ollie Leahy (pthread_setcancelstate): Likewise. (pthread_setcanceltype): Likewise. * misc.c (ptw32_cancelable_wait): Likewise. * private.c (ptw32_tkAssocCreate): Remove unused #if 0 wrapped code. * pthread.h (ptw32_get_exception_services_code): Needed to be forward declared unconditionally. 2000-09-06 Ross Johnson * cancel.c (pthread_cancel): If called from the main thread "self" would be NULL; get "self" via pthread_self() instead of directly from TLS so that an implicit pthread object is created. * misc.c (pthread_equal): Strengthen test for NULLs. --- ANNOUNCE | 4 +- ChangeLog | 26 ++++++++ cancel.c | 13 ++-- misc.c | 9 ++- private.c | 14 ----- pthread.h | 4 +- tests/ChangeLog | 10 +++ tests/GNUmakefile | 5 +- tests/Makefile | 5 +- tests/cancel5.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/eyal1.c | 4 +- 11 files changed, 240 insertions(+), 31 deletions(-) create mode 100644 tests/cancel5.c diff --git a/ANNOUNCE b/ANNOUNCE index 9607dd4..22ed166 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -1,5 +1,5 @@ - PTHREADS-WIN32 SNAPSHOT 2000-08-13 + PTHREADS-WIN32 SNAPSHOT 2000-09-08 ---------------------------------- Web Site: http://sources.redhat.com/pthreads-win32/ FTP Site: ftp://sources.redhat.com/pub/pthreads-win32 @@ -30,6 +30,8 @@ New: pthread_getw32threadhandle_np Bugs fixed: +- Calling pthread_cancel from non-POSIX threads fixed. +- Possible deadlock threat using pthread_cond_broadcast() reduced. - TSD key creation race condition; - Other potential race conditions associated with initialising various diff --git a/ChangeLog b/ChangeLog index f032072..fd623f8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2000-09-08 Ross Johnson + + * cancel.c (pthread_cancel): Must get "self" through + calling pthread_self() which will ensure a POSIX thread + struct is built for non-POSIX threads; return an error + if this fails + - Ollie Leahy + (pthread_setcancelstate): Likewise. + (pthread_setcanceltype): Likewise. + * misc.c (ptw32_cancelable_wait): Likewise. + + * private.c (ptw32_tkAssocCreate): Remove unused #if 0 + wrapped code. + + * pthread.h (ptw32_get_exception_services_code): + Needed to be forward declared unconditionally. + +2000-09-06 Ross Johnson + + * cancel.c (pthread_cancel): If called from the main + thread "self" would be NULL; get "self" via pthread_self() + instead of directly from TLS so that an implicit + pthread object is created. + + * misc.c (pthread_equal): Strengthen test for NULLs. + 2000-09-02 Ross Johnson * condvar.c (ptw32_cond_wait_cleanup): Ensure that all diff --git a/cancel.c b/cancel.c index 9e5b789..2e8aa41 100644 --- a/cancel.c +++ b/cancel.c @@ -106,7 +106,7 @@ pthread_setcancelstate (int state, int *oldstate) */ { int result = 0; - pthread_t self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey); + pthread_t self = pthread_self(); if (self == NULL || (state != PTHREAD_CANCEL_ENABLE @@ -190,7 +190,7 @@ pthread_setcanceltype (int type, int *oldtype) */ { int result = 0; - pthread_t self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey); + pthread_t self = pthread_self(); if (self == NULL || (type != PTHREAD_CANCEL_DEFERRED @@ -261,7 +261,7 @@ pthread_testcancel (void) * ------------------------------------------------------ */ { - pthread_t self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey); + pthread_t self = pthread_self(); if (self != NULL && self->cancelState == PTHREAD_CANCEL_ENABLE @@ -295,7 +295,7 @@ pthread_cancel (pthread_t thread) * RESULTS * 0 successfully requested cancellation, * ESRCH no thread found corresponding to 'thread', - * + * ENOMEM implicit self thread create failed. * ------------------------------------------------------ */ { @@ -309,7 +309,10 @@ pthread_cancel (pthread_t thread) } result = 0; - self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey); + if ((self = pthread_self()) == NULL) + { + return ENOMEM; + }; /* * FIXME!! diff --git a/misc.c b/misc.c index 724bbc2..e79819d 100644 --- a/misc.c +++ b/misc.c @@ -229,7 +229,11 @@ pthread_equal (pthread_t t1, pthread_t t2) { int result; - result = ((t1 == t2) && (t1->thread == t2->thread)); + /* + * We also accept NULL == NULL - treating NULL as a thread + * for this special case, because there is no error that we can return. + */ + result = ( ( t1 == t2 ) && ( t1 == NULL || ( t1->thread == t2->thread ) ) ); return (result); @@ -260,8 +264,7 @@ ptw32_cancelable_wait (HANDLE waitHandle, DWORD timeout) handles[0] = waitHandle; - if ((self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey)) - != NULL) + if ((self = pthread_self()) != NULL) { /* * Get cancelEvent handle diff --git a/private.c b/private.c index 37cb910..0e94d5f 100644 --- a/private.c +++ b/private.c @@ -399,22 +399,10 @@ ptw32_tkAssocCreate (ThreadKeyAssoc ** assocP, goto FAIL0; } -#if 0 - - if ((result = pthread_mutex_init (&(assoc->lock), NULL)) != 0) - { - goto FAIL1; - } - -#else - /* * Initialise only when used for the first time. */ assoc->lock = PTHREAD_MUTEX_INITIALIZER; - -#endif - assoc->thread = thread; assoc->key = key; @@ -451,8 +439,6 @@ ptw32_tkAssocCreate (ThreadKeyAssoc ** assocP, */ FAIL2: pthread_mutex_destroy (&(assoc->lock)); - -FAIL1: free (assoc); FAIL0: diff --git a/pthread.h b/pthread.h index c25b1fd..b0c9946 100644 --- a/pthread.h +++ b/pthread.h @@ -981,14 +981,14 @@ class ptw32_exception_exit : public ptw32_exception {}; #endif -#ifndef PTW32_BUILD - /* FIXME: This is only required if the library was built using SEH */ /* * Get internal SEH tag */ DWORD ptw32_get_exception_services_code(void); +#ifndef PTW32_BUILD + #if defined(_MSC_VER) && !defined(__cplusplus) /* diff --git a/tests/ChangeLog b/tests/ChangeLog index 0bccb5b..a809dca 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,13 @@ +2000-09-08 Ross Johnson + + * cancel5.c: New; tests calling pthread_cancel() + from the main thread without first creating a + POSIX thread struct for the non-POSIX main thread + - this forces pthread_cancel() to create one via + pthread_self(). + * Makefile (cancel5): Add new test. + * GNUmakefile (cancel5): Likewise. + 2000-08-17 Ross Johnson * create2.c: New; Test that pthread_t contains diff --git a/tests/GNUmakefile b/tests/GNUmakefile index e8438e2..a775e10 100644 --- a/tests/GNUmakefile +++ b/tests/GNUmakefile @@ -35,7 +35,7 @@ TESTS = loadfree \ condvar3 condvar4 condvar5 condvar6 condvar7 condvar8 condvar9 \ errno1 \ rwlock1 rwlock2 rwlock3 rwlock4 rwlock5 rwlock6 \ - context1 cancel3 cancel4 \ + context1 cancel3 cancel4 cancel5 \ cleanup0 cleanup1 cleanup2 cleanup3 \ exception1 @@ -83,7 +83,8 @@ rwlock6.pass: rwlock5.pass context1.pass: cancel2.pass cancel3.pass: context1.pass cancel4.pass: cancel3.pass -cleanup0.pass: cancel4.pass +cancel5.pass: cancel3.pass +cleanup0.pass: cancel5.pass cleanup1.pass: cleanup0.pass cleanup2.pass: cleanup1.pass cleanup3.pass: cleanup2.pass diff --git a/tests/Makefile b/tests/Makefile index 08cfcce..41e202c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -47,7 +47,7 @@ PASSES= loadfree.pass \ errno1.pass \ rwlock1.pass rwlock2.pass rwlock3.pass rwlock4.pass rwlock5.pass rwlock6.pass \ context1.pass \ - cancel3.pass cancel4.pass \ + cancel3.pass cancel4.pass cancel5.pass \ cleanup0.pass cleanup1.pass cleanup2.pass cleanup3.pass \ exception1.pass @@ -140,7 +140,8 @@ rwlock6.pass: rwlock5.pass context1.pass: cancel2.pass cancel3.pass: context1.pass cancel4.pass: cancel3.pass -cleanup0.pass: cancel4.pass +cancel5.pass: cancel3.pass +cleanup0.pass: cancel5.pass cleanup1.pass: cleanup0.pass cleanup2.pass: cleanup1.pass cleanup3.pass: cleanup2.pass diff --git a/tests/cancel5.c b/tests/cancel5.c new file mode 100644 index 0000000..7d7262a --- /dev/null +++ b/tests/cancel5.c @@ -0,0 +1,177 @@ +/* + * File: cancel5.c + * + * Test Synopsis: Test calling pthread_cancel from the main thread + * without calling pthread_self() in main. + * + * Test Method (Validation or Falsification): + * - + * + * Requirements Tested: + * - + * + * Features Tested: + * - + * + * Cases Tested: + * - + * + * Description: + * - + * + * Environment: + * - + * + * Input: + * - None. + * + * Output: + * - File name, Line number, and failed expression on failure. + * - No output on success. + * + * Assumptions: + * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock + * pthread_testcancel, pthread_cancel, pthread_join + * + * Pass Criteria: + * - Process returns zero exit status. + * + * Fail Criteria: + * - Process returns non-zero exit status. + */ + +#if defined(_MSC_VER) || defined(__cplusplus) + +#include "test.h" + +/* + * Create NUMTHREADS threads in addition to the Main thread. + */ +enum { + NUMTHREADS = 4 +}; + +typedef struct bag_t_ bag_t; +struct bag_t_ { + int threadnum; + int started; + /* Add more per-thread state variables here */ + int count; +}; + +static bag_t threadbag[NUMTHREADS + 1]; + +void * +mythread(void * arg) +{ + int result = ((int)PTHREAD_CANCELED + 1); + bag_t * bag = (bag_t *) arg; + + assert(bag == &threadbag[bag->threadnum]); + assert(bag->started == 0); + bag->started = 1; + + /* Set to known state and type */ + + assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0); + + assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0); + + /* + * We wait up to 10 seconds, waking every 0.1 seconds, + * for a cancelation to be applied to us. + */ + for (bag->count = 0; bag->count < 100; bag->count++) + Sleep(100); + + return (void *) result; +} + +int +main() +{ + int failed = 0; + int i; + pthread_t t[NUMTHREADS + 1]; + + for (i = 1; i <= NUMTHREADS; i++) + { + threadbag[i].started = 0; + threadbag[i].threadnum = i; + assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0); + } + + /* + * Code to control or munipulate child threads should probably go here. + */ + Sleep(500); + + for (i = 1; i <= NUMTHREADS; i++) + { + assert(pthread_cancel(t[i]) == 0); + } + + /* + * Give threads time to run. + */ + Sleep(NUMTHREADS * 100); + + /* + * Standard check that all threads started. + */ + for (i = 1; i <= NUMTHREADS; i++) + { + if (!threadbag[i].started) + { + failed |= !threadbag[i].started; + fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started); + } + } + + assert(!failed); + + /* + * Check any results here. Set "failed" and only print output on failure. + */ + failed = 0; + for (i = 1; i <= NUMTHREADS; i++) + { + int fail = 0; + int result = 0; + + /* + * The thread does not contain any cancelation points, so + * a return value of PTHREAD_CANCELED confirms that async + * cancelation succeeded. + */ + assert(pthread_join(t[i], (void **) &result) == 0); + + fail = (result != (int) PTHREAD_CANCELED); + + if (fail) + { + fprintf(stderr, "Thread %d: started %d: count %d\n", + i, + threadbag[i].started, + threadbag[i].count); + } + failed = (failed || fail); + } + + assert(!failed); + + /* + * Success. + */ + return 0; +} + +#else /* defined(_MSC_VER) || defined(__cplusplus) */ + +int +main() +{ + return 0; +} + +#endif /* defined(_MSC_VER) || defined(__cplusplus) */ diff --git a/tests/eyal1.c b/tests/eyal1.c index 412fbf0..843cb33 100644 --- a/tests/eyal1.c +++ b/tests/eyal1.c @@ -62,8 +62,8 @@ struct thread_control { typedef struct thread_control TC; static TC *tcs = NULL; -static int nthreads = 7; -static int nwork = 50; +static int nthreads = 14; +static int nwork = 100; static int quiet = 0; static int todo = -1; -- cgit v1.2.3