diff options
author | rpj <rpj> | 2000-12-29 07:08:44 +0000 |
---|---|---|
committer | rpj <rpj> | 2000-12-29 07:08:44 +0000 |
commit | 0c2cb3fb140fb0d12586587001cb1ca238cf8c25 (patch) | |
tree | 72caf359f0e3d2aea2c833c8061b65f971f91381 | |
parent | bab1896412f2d292ebd8d44bc9d6ddb58a8702b0 (diff) |
./ChangeLog:
2000-12-29 Ross Johnson <rpj@special.ise.canberra.edu.au>
* Makefile: Back-out "for" loops which don't work.
* GNUmakefile: Remove the fake.a target; add the "realclean"
target; don't remove built libs under the "clean" target.
* config.h: Add a guard against multiple inclusion.
* semaphore.h: Add some defines from config.h to make
semaphore.h independent of config.h when building apps.
* pthread.h (_errno): Back-out previous fix until we know how to
fix it properly.
* implement.h (lockCount): Add missing element to pthread_mutex_t_.
* sync.c (pthread_join): Spelling fix in comment.
* private.c (ptw32_threadStart): Reset original termination
function (C++).
(ptw32_threadStart): Cleanup detached threads early in case
the library is statically linked.
(ptw32_callUserDestroyRoutines): Remove [SEH] __try block from
destructor call so that unhandled exceptions will be passed through
to the system; call terminate() from [C++] try block for the same
reason.
* tsd.c (pthread_getspecific): Add comment.
* mutex.c (pthread_mutex_init): Initialise new elements in
pthread_mutex_t.
(pthread_mutex_unlock): Invert "pthread_equal()" test.
2000-12-28 Ross Johnson <rpj@special.ise.canberra.edu.au>
* semaphore.c (mode_t): Use ifndef HAVE_MODE_T to include definition.
* config.h.in (HAVE_MODE_T): Added.
(_UWIN): Start adding defines for the UWIN package.
./tests/ChangeLog:
2000-12-29 Ross Johnson <rpj@special.ise.canberra.edu.au>
* GNUmakefile: Add mutex4 test; ensure libpthreadw32.a is
removed for "clean" target.
* Makefile: Add mutex4 test.
* exception3.c: Remove SEH code; automatically pass the test
under SEH (which is an N/A environment).
* mutex4.c: New test.
* eyal1.c (do_work_unit): Add a dummy "if" to force the
optimiser to retain code; reduce thread work loads.
* condvar8.c (main): Add an additional "assert" for debugging;
increase pthread_cond_signal timeout.
-rw-r--r-- | ChangeLog | 39 | ||||
-rw-r--r-- | GNUmakefile | 13 | ||||
-rw-r--r-- | Makefile | 20 | ||||
-rw-r--r-- | config.h | 20 | ||||
-rw-r--r-- | config.h.in | 20 | ||||
-rw-r--r-- | implement.h | 1 | ||||
-rw-r--r-- | mutex.c | 4 | ||||
-rw-r--r-- | private.c | 57 | ||||
-rw-r--r-- | pthread.h | 6 | ||||
-rw-r--r-- | semaphore.h | 23 | ||||
-rw-r--r-- | sync.c | 4 | ||||
-rw-r--r-- | tests/ChangeLog | 17 | ||||
-rw-r--r-- | tests/GNUmakefile | 5 | ||||
-rw-r--r-- | tests/Makefile | 3 | ||||
-rw-r--r-- | tests/condvar8.c | 8 | ||||
-rw-r--r-- | tests/exception3.c | 72 | ||||
-rw-r--r-- | tests/eyal1.c | 12 | ||||
-rw-r--r-- | tests/mutex4.c | 34 | ||||
-rw-r--r-- | tsd.c | 2 |
19 files changed, 228 insertions, 132 deletions
@@ -1,5 +1,44 @@ +2000-12-29 Ross Johnson <rpj@special.ise.canberra.edu.au> + + * Makefile: Back-out "for" loops which don't work. + + * GNUmakefile: Remove the fake.a target; add the "realclean" + target; don't remove built libs under the "clean" target. + + * config.h: Add a guard against multiple inclusion. + + * semaphore.h: Add some defines from config.h to make + semaphore.h independent of config.h when building apps. + + * pthread.h (_errno): Back-out previous fix until we know how to + fix it properly. + + * implement.h (lockCount): Add missing element to pthread_mutex_t_. + + * sync.c (pthread_join): Spelling fix in comment. + + * private.c (ptw32_threadStart): Reset original termination + function (C++). + (ptw32_threadStart): Cleanup detached threads early in case + the library is statically linked. + (ptw32_callUserDestroyRoutines): Remove [SEH] __try block from + destructor call so that unhandled exceptions will be passed through + to the system; call terminate() from [C++] try block for the same + reason. + + * tsd.c (pthread_getspecific): Add comment. + + * mutex.c (pthread_mutex_init): Initialise new elements in + pthread_mutex_t. + (pthread_mutex_unlock): Invert "pthread_equal()" test. + 2000-12-28 Ross Johnson <rpj@special.ise.canberra.edu.au> + * semaphore.c (mode_t): Use ifndef HAVE_MODE_T to include definition. + + * config.h.in (HAVE_MODE_T): Added. + (_UWIN): Start adding defines for the UWIN package. + * private.c (ptw32_threadStart): Unhandled exceptions are now passed through to the system to deal with. This is consistent with normal Windows behaviour. C++ applications may use diff --git a/GNUmakefile b/GNUmakefile index 9ad6119..a7d13b3 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -52,12 +52,6 @@ LIBS = libpthreadw32.a all: $(LIBS) -fake.a: - @ $(CP) pthreadVCE.dll $(DLL) - dlltool --def pthread.def --output-lib $@ --dllname $(DLL) - @-$(RM) $(LIBS) - $(MV) fake.a $(LIBS) - $(LIBS): $(DLL) dlltool --def pthread.def --output-lib $@ --dllname $(DLL) @@ -78,10 +72,11 @@ $(DLL): $(OBJS) clean: -$(RM) *~ - -$(RM) $(LIBS) -$(RM) *.o -$(RM) *.exe - -$(RM) $(DLL) -$(RM) $(DLL:.dll=.base) -$(RM) $(DLL:.dll=.exp) - -$(RM) fake.a + +realclean: + -$(RM) $(LIBS) + -$(RM) $(DLL) @@ -53,21 +53,15 @@ VSE: @ nmake /nologo EHFLAGS="$(VSEFLAGS)" pthreadVSE.dll
realclean: clean
- @ for %%ext in (dll lib) do \
- if exist *.%%ext del *.%%ext
-
-# del *.dll
-# del *.lib
+ if exist *.dll del *.dll
+ if exit *.lib del *.lib
clean:
- @ for %%ext in (obj ilk pdb exp o) do \
- if exist *.%%ext del *.%%ext
-
-# if exist *.obj del *.obj
-# if exist *.ilk del *.ilk
-# if exist *.pdb del *.pdb
-# if exist *.exp del *.exp
-# if exist *.o del *.o
+ if exist *.obj del *.obj
+ if exist *.ilk del *.ilk
+ if exist *.pdb del *.pdb
+ if exist *.exp del *.exp
+ if exist *.o del *.o
install: $(DLLS)
@@ -1,5 +1,8 @@ /* config.h.in. Generated automatically from configure.in by autoheader. */ +#ifndef PTW32_CONFIG_H +#define PTW32_CONFIG_H + /* Do we know about the C type sigset_t? */ #undef HAVE_SIGSET_T @@ -27,6 +30,12 @@ /* Define if you need to convert string parameters to unicode. (eg. WinCE) */ #undef NEED_UNICODE_CONSTS +/* Do we know about type mode_t? */ +#undef HAVE_MODE_T + +/* Define if you have the timespec struct */ +#undef HAVE_STRUCT_TIMESPEC + /* * Target specific groups */ @@ -39,3 +48,14 @@ #define NEED_SEM #define NEED_UNICODE_CONSTS #endif + +#ifdef _UWIN +#define HAVE_MODE_T +#define HAVE_STRUCT_TIMESPEC +#endif + +#ifdef __MINGW32__ +#define HAVE_MODE_T +#endif + +#endif
\ No newline at end of file diff --git a/config.h.in b/config.h.in index acea758..75e0338 100644 --- a/config.h.in +++ b/config.h.in @@ -1,5 +1,8 @@ /* config.h.in. Generated automatically from configure.in by autoheader. */ +#ifndef PTW32_CONFIG_H +#define PTW32_CONFIG_H + /* Do we know about the C type sigset_t? */ #undef HAVE_SIGSET_T @@ -27,6 +30,12 @@ /* Define if you need to convert string parameters to unicode. (eg. WinCE) */ #undef NEED_UNICODE_CONSTS +/* Do we know about type mode_t? */ +#undef HAVE_MODE_T + +/* Define if you have the timespec struct */ +#undef HAVE_STRUCT_TIMESPEC + /* * Target specific groups */ @@ -39,3 +48,14 @@ #define NEED_SEM #define NEED_UNICODE_CONSTS #endif + +#ifdef _UWIN +#define HAVE_MODE_T +#define HAVE_STRUCT_TIMESPEC +#endif + +#ifdef __MINGW32__ +#define HAVE_MODE_T +#endif + +#endif
\ No newline at end of file diff --git a/implement.h b/implement.h index 9c74bb4..c6f535e 100644 --- a/implement.h +++ b/implement.h @@ -124,6 +124,7 @@ struct pthread_attr_t_ { struct pthread_mutex_t_ { HANDLE mutex; CRITICAL_SECTION cs; + int lockCount; pthread_t ownerThread; }; @@ -105,6 +105,8 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) } mx->mutex = 0; + mx->lockCount = 0; + mx->ownerThread = NULL; if (attr != NULL && *attr != NULL @@ -586,7 +588,7 @@ pthread_mutex_unlock(pthread_mutex_t *mutex) { pthread_t self = pthread_self(); - if (pthread_equal(mx->ownerThread, self) == 0) + if (pthread_equal(mx->ownerThread, self)) { int oldCount = mx->lockCount; pthread_t oldOwner = mx->ownerThread; @@ -240,7 +240,7 @@ ptw32_threadStart (ThreadParms * threadParms) void *(*start) (void *); void *arg; -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__cplusplus) DWORD ei[] = {0,0,0}; #endif @@ -354,6 +354,7 @@ ptw32_threadStart (ThreadParms * threadParms) */ status = self->exitStatus = PTHREAD_CANCELED; (void) pthread_mutex_destroy(&self->cancelLock); + (void) set_terminate(ptw32_oldTerminate); ptw32_callUserDestroyRoutines(self); throw; @@ -362,6 +363,8 @@ ptw32_threadStart (ThreadParms * threadParms) */ } + (void) set_terminate(ptw32_oldTerminate); + #else /* __cplusplus */ /* @@ -375,7 +378,32 @@ ptw32_threadStart (ThreadParms * threadParms) #endif /* _MSC_VER */ (void) pthread_mutex_destroy(&self->cancelLock); - ptw32_callUserDestroyRoutines(self); + +#if 1 + if (self->detachState == PTHREAD_CREATE_DETACHED) + { + /* + * We need to cleanup the pthread now in case we have + * been statically linked, in which case the cleanup + * in dllMain won't get done. Joinable threads will + * be cleaned up by pthread_join(). + * + * Note that implicitly created pthreads (those created + * for Win32 threads which have called pthreads routines) + * must be cleaned up explicitly by the application + * (by calling pthread_win32_thread_detach_np()) if + * this library has been statically linked. For the dll, + * dllMain will do the cleanup automatically. + */ + (void) pthread_win32_thread_detach_np (); + } + else + { + ptw32_callUserDestroyRoutines (self); + } +#else + ptw32_callUserDestroyRoutines (self); +#endif #if ! defined (__MINGW32__) || defined (__MSVCRT__) _endthreadex ((unsigned) status); @@ -611,21 +639,15 @@ ptw32_callUserDestroyRoutines (pthread_t thread) #if defined(_MSC_VER) && !defined(__cplusplus) - __try - { /* * Run the caller's cleanup routine. + * + * If an exception occurs we let the system handle it + * as an unhandled exception. Since we are leaving the + * thread we should not get any internal pthreads + * exceptions. */ (*(k->destructor)) (value); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - /* - * A system unexpected exception had occurred - * running the user's destructor. - * We get control back within this block. - */ - } #else /* _MSC_VER && !__cplusplus */ #ifdef __cplusplus @@ -640,10 +662,15 @@ ptw32_callUserDestroyRoutines (pthread_t thread) catch (...) { /* - * A system unexpected exception had occurred + * A system unexpected exception has occurred * running the user's destructor. - * We get control back within this block. + * We get control back within this block in case + * the application has set up it's own terminate + * handler. Since we are leaving the thread we + * should not get any internal pthreads + * exceptions. */ + terminate(); } #else /* __cplusplus */ @@ -941,6 +941,11 @@ int pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout); /* * Thread-Safe C Runtime Library Mappings. */ +#if 1 +#if (! defined(NEED_ERRNO)) || (! defined( _REENTRANT ) && (! defined( _MT ) || ! defined( _MD ))) +int * _errno( void ); +#endif +#else #if (! defined(NEED_ERRNO)) || (! defined( _REENTRANT ) && (! defined( _MT ) || ! defined( _MD ))) #if defined(PTW32_BUILD) __declspec( dllexport ) int * _errno( void ); @@ -948,6 +953,7 @@ __declspec( dllexport ) int * _errno( void ); int * _errno( void ); #endif #endif +#endif /* * WIN32 C runtime library had been made thread-safe diff --git a/semaphore.h b/semaphore.h index 8af8be8..bc66e35 100644 --- a/semaphore.h +++ b/semaphore.h @@ -28,7 +28,26 @@ #if !defined( SEMAPHORE_H ) #define SEMAPHORE_H -#ifdef NEED_ERRNO +/* + * This is a duplicate of what is in the autoconf config.h, + * which is only used when building the pthread-win32 libraries. + */ + +#ifndef PTW32_CONFIG_H +# if defined(WINCE) +# define NEED_ERRNO +# define NEED_SEM +# endif +# if defined(_UWIN) || defined(__MINGW32__) +# define HAVE_MODE_T +# endif +#endif + +/* + * + */ + +#ifdef NEED_SEM #include "need_errno.h" #else #include <errno.h> @@ -41,7 +60,7 @@ extern "C" { #endif /* __cplusplus */ -#if defined(_MSC_VER) +#ifndef HAVE_MODE_T typedef unsigned int mode_t; #endif @@ -131,10 +131,10 @@ pthread_join (pthread_t thread, void **value_ptr) { /* * Pthread_join is a cancelation point. - * If we are cancelled then our target thread must not be + * If we are canceled then our target thread must not be * detached (destroyed). This is guarranteed because * pthreadCancelableWait will not return if we - * are cancelled. + * are canceled. */ result = pthreadCancelableWait(thread->threadH); diff --git a/tests/ChangeLog b/tests/ChangeLog index db66602..92fca1b 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,20 @@ +2000-12-29 Ross Johnson <rpj@special.ise.canberra.edu.au> + + * GNUmakefile: Add mutex4 test; ensure libpthreadw32.a is + removed for "clean" target. + * Makefile: Add mutex4 test. + + * exception3.c: Remove SEH code; automatically pass the test + under SEH (which is an N/A environment). + + * mutex4.c: New test. + + * eyal1.c (do_work_unit): Add a dummy "if" to force the + optimiser to retain code; reduce thread work loads. + + * condvar8.c (main): Add an additional "assert" for debugging; + increase pthread_cond_signal timeout. + 2000-12-28 Ross Johnson <rpj@special.ise.canberra.edu.au> * eyal1.c: Increase thread work loads. diff --git a/tests/GNUmakefile b/tests/GNUmakefile index 7b4fd64..33de3ac 100644 --- a/tests/GNUmakefile +++ b/tests/GNUmakefile @@ -32,7 +32,7 @@ COPYFILES = $(HDR) $(LIB) $(DLL) TESTS = loadfree \ mutex1 condvar1 condvar2 exit1 create1 equal1 \ exit2 exit3 \ - join0 join1 join2 mutex2 mutex3 \ + join0 join1 join2 mutex2 mutex3 mutex4 \ count1 once1 tsd1 self1 self2 cancel1 cancel2 eyal1 \ condvar3 condvar4 condvar5 condvar6 condvar7 condvar8 condvar9 \ errno1 \ @@ -57,6 +57,7 @@ create1.pass: mutex2.pass cancel1.pass: create1.pass cancel2.pass: cancel1.pass mutex3.pass: create1.pass +mutex4.pass: mutex3.pass equal1.pass: create1.pass exit2.pass: create1.pass exit3.pass: create1.pass @@ -122,7 +123,7 @@ clean: - $(RM) pthread.h - $(RM) semaphore.h - $(RM) sched.h - - $(RM) *.a + - $(RM) libpthreadw32.a - $(RM) *.e - $(RM) *.obj - $(RM) *.pdb diff --git a/tests/Makefile b/tests/Makefile index 208b438..281cd50 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -33,7 +33,7 @@ EHFLAGS = # stop.
PASSES= loadfree.pass \
- mutex1.pass mutex2.pass mutex3.pass \
+ mutex1.pass mutex2.pass mutex3.pass mutex4.pass \
condvar1.pass condvar2.pass \
exit1.pass create1.pass equal1.pass \
exit2.pass exit3.pass \
@@ -112,6 +112,7 @@ create1.pass: mutex2.pass cancel1.pass: create1.pass
cancel2.pass: cancel1.pass
mutex3.pass: create1.pass
+mutex4.pass: mutex3.pass
equal1.pass: create1.pass
exit2.pass: create1.pass
exit3.pass: create1.pass
diff --git a/tests/condvar8.c b/tests/condvar8.c index 9e63b79..ff893c7 100644 --- a/tests/condvar8.c +++ b/tests/condvar8.c @@ -93,10 +93,6 @@ mythread(void * arg) assert(pthread_mutex_lock(&cvthing.lock) == 0); - /* - * pthread_cond_timedwait is a cancelation point and we - * going to cancel one deliberately. - */ pthread_cleanup_push(pthread_mutex_unlock, (void *) &cvthing.lock); while (! (cvthing.shared > 0)) @@ -135,7 +131,7 @@ main() abstime.tv_sec = currSysTime.time; abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm; - abstime.tv_sec += 5; + abstime.tv_sec += 10; assert((t[0] = pthread_self()) != NULL); @@ -179,6 +175,8 @@ main() * Give threads time to complete. */ Sleep(1000); + + assert(awoken == (i - 1)); } diff --git a/tests/exception3.c b/tests/exception3.c index b820b4b..66f4173 100644 --- a/tests/exception3.c +++ b/tests/exception3.c @@ -39,17 +39,16 @@ * - Process returns non-zero exit status. */ +#include "test.h" + +#if defined(__cplusplus) -#if defined(_MSC_VER) && defined(__cplusplus) +#if defined(_MSC_VER) #include <eh.h> #else #include <new.h> #endif -#if defined(_MSC_VER) || defined(__cplusplus) - -#include "test.h" - /* * Create NUMTHREADS threads in addition to the Main thread. */ @@ -60,28 +59,12 @@ enum { int caught = 0; pthread_mutex_t caughtLock = PTHREAD_MUTEX_INITIALIZER; -#if defined(_MSC_VER) && !defined(__cplusplus) - -LONG unhandledExceptionFilter (EXCEPTION_POINTERS *ep) -{ - if (ep->ExceptionRecord->ExceptionCode == 0x1) - { - pthread_mutex_lock(&caughtLock); - caught++; - pthread_mutex_unlock(&caughtLock); - } - - return EXCEPTION_CONTINUE_EXECUTION; -} - -#elif defined(__cplusplus) - void terminateFunction () { pthread_mutex_lock(&caughtLock); caught++; -#if 1 +#if 0 { FILE * fp = fopen("pthread.log", "a"); fprintf(fp, "Caught = %d\n", caught); @@ -92,28 +75,15 @@ terminateFunction () pthread_exit((void *) 0); } -#endif - void * exceptionedThread(void * arg) { int dummy = 0x1; - { -#if defined(_MSC_VER) && !defined(__cplusplus) + (void) set_terminate(&terminateFunction); + throw dummy; - RaiseException(dummy, 0, 0, NULL); - -#elif defined(__cplusplus) - - (void) set_terminate(&terminateFunction); - - throw dummy; - -#endif - } - - return (void *) 100; + return (void *) 0; } int @@ -125,25 +95,13 @@ main() assert((mt = pthread_self()) != NULL); - { -#if defined(_MSC_VER) && !defined(__cplusplus) - LPTOP_LEVEL_EXCEPTION_FILTER oldHandler; - oldHandler = SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER) unhandledExceptionFilter); -#endif - - for (i = 0; i < NUMTHREADS; i++) - { - assert(pthread_create(&et[i], NULL, exceptionedThread, NULL) == 0); - } - -#if defined(_MSC_VER) && !defined(__cplusplus) - (void) SetUnhandledExceptionFilter(oldHandler); -#endif + for (i = 0; i < NUMTHREADS; i++) + { + assert(pthread_create(&et[i], NULL, exceptionedThread, NULL) == 0); + } - Sleep(30000); - } + Sleep(10000); - printf("Caught = %d\n", caught); assert(caught == NUMTHREADS); /* @@ -152,7 +110,7 @@ main() return 0; } -#else /* defined(_MSC_VER) || defined(__cplusplus) */ +#else /* defined(__cplusplus) */ int main() @@ -161,4 +119,4 @@ main() return 0; } -#endif /* defined(_MSC_VER) || defined(__cplusplus) */ +#endif /* defined(__cplusplus) */ diff --git a/tests/eyal1.c b/tests/eyal1.c index a9ba909..6954c3b 100644 --- a/tests/eyal1.c +++ b/tests/eyal1.c @@ -63,7 +63,7 @@ typedef struct thread_control TC; static TC *tcs = NULL; static int nthreads = 10; -static int nwork = 1000; +static int nwork = 100; static int quiet = 0; static int todo = -1; @@ -86,7 +86,7 @@ die (int ret) } -static void +static double waste_time (int n) { int i; @@ -98,6 +98,7 @@ waste_time (int n) { f = 2 * f * f / (f * f); } + return f; } static int @@ -105,6 +106,7 @@ do_work_unit (int who, int n) { int i; static int nchars = 0; + double f = 0.0; if (quiet) i = 0; @@ -131,7 +133,11 @@ do_work_unit (int who, int n) } n = rand () % 10000; /* ignore incoming 'n' */ - waste_time (n); + f = waste_time (n); + + /* This prevents the statement above from being optimised out */ + if (f > 0.0) + return(n); return (n); } diff --git a/tests/mutex4.c b/tests/mutex4.c index 5290f2a..7b989d0 100644 --- a/tests/mutex4.c +++ b/tests/mutex4.c @@ -10,35 +10,32 @@ */ #include "test.h" - -pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; -pthread_mutex_t locker_done = PTHREAD_MUTEX_INITIALIZER; -pthread_mutex_t unlocker_done = PTHREAD_MUTEX_INITIALIZER; -static int washere = 0; +static int wasHere = 0; + +static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; void * locker(void * arg) { - assert(pthread_mutex_lock(&locker_start) == 0); + wasHere++; assert(pthread_mutex_lock(&mutex1) == 0); - assert(pthread_mutex_unlock(&locker_start) == 0); - - /* Wait for unlocker to finish */ - assert(pthread_mutex_lock(&unlocker_end) == 0); + Sleep(1000); assert(pthread_mutex_unlock(&mutex1) == 0); + wasHere++; return 0; } void * unlocker(void * arg) { + wasHere++; + /* Wait for locker to lock mutex1 */ - assert(pthread_mutex_lock(&unlocker_start) == 0); + Sleep(500); assert(pthread_mutex_unlock(&mutex1) == EPERM); - assert(pthread_mutex_unlock(&unlocker_start) == 0); - + wasHere++; return 0; } @@ -47,16 +44,11 @@ main() { pthread_t t; - assert(pthread_mutex_lock(&locker_start) == 0); - assert(pthread_mutex_lock(&unlocker_start) == 0); - assert(pthread_create(&t, NULL, locker, NULL) == 0); - assert(pthread_mutex_unlock(&locker_start) == 0); - Sleep(0); - assert(pthread_create(&t, NULL, unlocker, NULL) == 0); - assert(pthread_mutex_unlock(&unlocker_start) == 0); - Sleep(0); + Sleep(2000); + + assert(wasHere == 4); return 0; } @@ -317,7 +317,7 @@ pthread_getspecific (pthread_key_t key) * the thread, NULL is returned. * * RESULTS - * key value + * key value or NULL on failure * * ------------------------------------------------------ */ |