summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrpj <rpj>2005-05-16 15:42:44 +0000
committerrpj <rpj>2005-05-16 15:42:44 +0000
commita824c43d3f20fc5722c5fd8f0f942f632b961723 (patch)
treee33174f1e54bcb5dffa3fb16be69713f4cc497c0
parent08e2916eb07fb75b2907032e2418316bf980d945 (diff)
''
-rw-r--r--ChangeLog32
-rw-r--r--NEWS18
-rw-r--r--pthread.h47
-rw-r--r--pthread_detach.c64
-rw-r--r--pthread_join.c103
-rw-r--r--pthread_win32_attach_detach_np.c20
-rw-r--r--ptw32_threadDestroy.c19
-rw-r--r--ptw32_threadStart.c55
-rw-r--r--ptw32_throw.c4
-rw-r--r--sem_init.c4
-rw-r--r--sem_post.c2
-rw-r--r--sem_post_multiple.c2
-rw-r--r--tests/Bmakefile5
-rw-r--r--tests/ChangeLog10
-rw-r--r--tests/GNUmakefile8
-rw-r--r--tests/Makefile10
-rw-r--r--tests/Wmakefile9
-rw-r--r--tests/create3.c2
-rw-r--r--tests/detach1.c88
-rw-r--r--tests/join0.c5
-rw-r--r--tests/join1.c9
-rw-r--r--tests/join2.c4
-rw-r--r--tests/join3.c4
-rw-r--r--tests/reuse2.c14
24 files changed, 325 insertions, 213 deletions
diff --git a/ChangeLog b/ChangeLog
index 074b340..400c996 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+2005-05-13 Ross Johnson <ross at callisto.canberra.edu.au>
+
+ * pthread_win32_attach_detach_np.c (pthread_win32_thread_detach_np):
+ Move on-exit-only stuff from ptw32_threadDestroy() to here.
+ * ptw32_threadDestroy.c: It's purpose is now only to reclaim thread
+ resources for detached threads, or via pthread_join() or
+ pthread_detach() on joinable threads.
+ * ptw32_threadStart.c: Calling user destruct routines has moved to
+ pthread_win32_thread_detach_np(); call pthread_win32_thread_detach_np()
+ directly if statically linking, otherwise do so via dllMain; store
+ thread return value in thread struct for all cases, including
+ cancellation and exception exits; thread abnormal exits go via
+ pthread_win32_thread_detach_np.
+ * pthread_join.c (pthread_join): Don't try to get return code from
+ Win32 thread - always get it from he thread struct.
+ * pthread_detach.c (pthread_detach): reduce extent of the thread
+ existence check since we now don't care if the Win32 thread HANDLE has
+ been closed; reclaim thread resources if the thread has exited already.
+ * ptw32_throw.c (ptw32_throw): For Win32 threads that are not implicit,
+ only Call thread cleanup if statically linking, otherwise leave it to
+ dllMain.
+ * sem_post.c (_POSIX_SEM_VALUE_MAX): Change to SEM_VALUE_MAX.
+ * sem_post_multiple.c: Likewise.
+ * sem_init.c: Likewise.
+
+2005-05-10 Ross Johnson <ross at callisto.canberra.edu.au>
+
+ * pthread_join.c (pthread_join): Add missing check for thread ID
+ reference count in thread existence test; reduce extent of the
+ existence test since we don't care if the Win32 thread HANDLE has
+ been closed.
+
2005-05-09 Ross Johnson <ross at callisto.canberra.edu.au>^M
* ptw32_callUserDestroyRoutines.c: Run destructor process (i.e.
diff --git a/NEWS b/NEWS
index 2190454..c2c549a 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,21 @@
+RELEASE 1.10.0
+-------------
+(Not released yet)
+
+Bugs fixed
+----------
+
+* pthread_detach() now reclaims remaining thread resources when called after
+the target thread has terminated. Previously, this thread did nothing in
+this case.
+
+New tests
+---------
+
+* detach1.c - tests that pthread_detach properly invalidates the target
+thread, which indicates that the thread resources have been reclaimed.
+
+
RELEASE 1.9.0
-------------
(2005-05-09)
diff --git a/pthread.h b/pthread.h
index 293c03b..600695a 100644
--- a/pthread.h
+++ b/pthread.h
@@ -510,40 +510,49 @@ extern "C"
* Maximum number of threads supported per
* process (must be at least 64).
*
- * _POSIX_SEM_NSEMS_MAX
- * The maximum number of semaphores a process can have.
- * (only defined if not already defined)
+ * SEM_NSEMS_MAX
+ * The maximum number of semaphores a process can have.
+ * (must be at least 256)
*
- * _POSIX_SEM_VALUE_MAX
- * The maximum value a semaphore can have.
- * (only defined if not already defined)
+ * SEM_VALUE_MAX
+ * The maximum value a semaphore can have.
+ * (must be at least 32767)
*
*/
+#undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS
+#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4
+
#undef PTHREAD_DESTRUCTOR_ITERATIONS
-#define PTHREAD_DESTRUCTOR_ITERATIONS 4
+#define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS
+
+#undef _POSIX_THREAD_KEYS_MAX
+#define _POSIX_THREAD_KEYS_MAX 128
#undef PTHREAD_KEYS_MAX
-#define PTHREAD_KEYS_MAX 64
+#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX
#undef PTHREAD_STACK_MIN
-#define PTHREAD_STACK_MIN 0
-
-#if PTW32_LEVEL < 2
- /* Arbitrary value */
-# undef PTHREAD_THREADS_MAX
-# define PTHREAD_THREADS_MAX 2019
-#endif
+#define PTHREAD_STACK_MIN 0
- /* Arbitrary value */
#undef _POSIX_THREAD_THREADS_MAX
-#define _POSIX_THREAD_THREADS_MAX 2019
+#define _POSIX_THREAD_THREADS_MAX 64
/* Arbitrary value */
+#undef PTHREAD_THREADS_MAX
+#define PTHREAD_THREADS_MAX 2019
+
#undef _POSIX_SEM_NSEMS_MAX
-#define _POSIX_SEM_NSEMS_MAX 1024
+#define _POSIX_SEM_NSEMS_MAX 256
+
+ /* Arbitrary value */
+#undef SEM_NSEMS_MAX
+#define SEM_NSEMS_MAX 1024
#undef _POSIX_SEM_VALUE_MAX
-#define _POSIX_SEM_VALUE_MAX (INT_MAX/2)
+#define _POSIX_SEM_VALUE_MAX 32767
+
+#undef SEM_VALUE_MAX
+#define SEM_VALUE_MAX INT_MAX
#if __GNUC__ && ! defined (__declspec)
diff --git a/pthread_detach.c b/pthread_detach.c
index d8a7650..00fb6ad 100644
--- a/pthread_detach.c
+++ b/pthread_detach.c
@@ -58,12 +58,10 @@ pthread_detach (pthread_t thread)
*
*
* DESCRIPTION
- * This function detaches the given thread. You may
- * detach the main thread or to detach a joinable thread
- * (You should have used pthread_attr_t to create the
- * thread as detached!)
- * NOTE: detached threads cannot be joined nor canceled;
- * storage is freed immediately on termination.
+ * This function detaches the given thread. You may use it to
+ * detach the main thread or to detach a joinable thread.
+ * NOTE: detached threads cannot be joined;
+ * storage is freed immediately on termination.
*
* RESULTS
* 0 successfully detached the thread,
@@ -75,23 +73,65 @@ pthread_detach (pthread_t thread)
*/
{
int result;
+ BOOL destroyIt = PTW32_FALSE;
ptw32_thread_t * tp = (ptw32_thread_t *) thread.p;
- result = pthread_kill (thread, 0);
+ EnterCriticalSection (&ptw32_thread_reuse_lock);
- if (0 != result)
+ if (NULL == tp
+ || thread.x != tp->ptHandle.x)
{
- return result;
+ result = ESRCH;
}
-
- if (tp->detachState == PTHREAD_CREATE_DETACHED)
+ else if (PTHREAD_CREATE_DETACHED == tp->detachState)
{
result = EINVAL;
}
else
{
+ /*
+ * Joinable ptw32_thread_t structs are not scavenged until
+ * a join or detach is done. The thread may have exited already,
+ * but all of the state and locks etc are still there.
+ */
result = 0;
- tp->detachState = PTHREAD_CREATE_DETACHED;
+
+ if (pthread_mutex_lock (&tp->cancelLock) == 0)
+ {
+ if (tp->state != PThreadStateLast)
+ {
+ tp->detachState = PTHREAD_CREATE_DETACHED;
+ }
+ else if (tp->detachState != PTHREAD_CREATE_DETACHED)
+ {
+ /*
+ * Thread is joinable and has exited or is exiting.
+ */
+ destroyIt = PTW32_TRUE;
+ }
+ (void) pthread_mutex_unlock (&tp->cancelLock);
+ }
+ else
+ {
+ /* cancelLock shouldn't fail, but if it does ... */
+ result = ESRCH;
+ }
+ }
+
+ LeaveCriticalSection (&ptw32_thread_reuse_lock);
+
+ if (result == 0)
+ {
+ /* Thread is joinable */
+
+ if (destroyIt)
+ {
+ /* The thread has exited or is exiting but has not been joined or
+ * detached. Need to wait in case it's still exiting.
+ */
+ (void) WaitForSingleObject(tp->threadH, INFINITE);
+ ptw32_threadDestroy (thread);
+ }
}
return (result);
diff --git a/pthread_join.c b/pthread_join.c
index 56ed0ba..8237b6c 100644
--- a/pthread_join.c
+++ b/pthread_join.c
@@ -84,60 +84,10 @@ pthread_join (pthread_t thread, void **value_ptr)
pthread_t self;
ptw32_thread_t * tp = (ptw32_thread_t *) thread.p;
- /*
- * Possibilities for the target thread on entry to pthread_join():
- *
- * 1) the target thread is detached, in which case it could be destroyed and
- * it's thread id (struct) reused before we get the reuse lock;
- * 2) the target thread is joinable, in which case it will not be destroyed
- * until it has been joined, and it's thread id cannot be reused before we
- * get access to it.
- *
- * Only (1) is a potential race condition.
- * While (1) is possibly an application programming error, pthread_join is
- * required to handle it with an error.
- * If an application attempts to join a detached thread that exits before we
- * get the reuse lock, it's thread struct could be reused for a new joinable
- * thread before we get the reuse_lock and we will then be joining the wrong
- * thread.
- *
- * To fix this properly would require a reuse count as part of the thread id
- * so that we could confirm that we are working with the same thread. This
- * option will require a major change to the API, forcing recompilation of
- * applications that use the library.
- *
- * Cheaper alternatives that do not change the API are:
- * - separate reuse stacks could be used for detached and joinable
- * threads. Threads which detach themselves will not present a race condition
- * because they will be placed on a different stack to that which provides
- * reusable structs to new joinable threads.
- * The problem with this solution is that, an application that creates
- * joinable threads which then detach themselves can cause the detach reuse
- * stack to grow indefinitely.
- *
- * - maintain a sufficiently large reuse pool and manage it as a FIFO
- * queue. This would prevent the immediate reuse of thread structs, but this
- * only provides a statistical safeguard, not a deterministic one.
- *
- * - include an entry point array at the start of each thread struct so that
- * each reuse (modulo N) returns a different thread id (pointer to the thread
- * struct). Offset 0 from this pointer will contain a validity field and an
- * offset value field (subtracted from the pointer to obtain the address of
- * thread struct). This option is similar to including a reuse counter with
- * the thread id but maintains the thread id as a simple pointer.
- *
- * As at 03/11/2004, the reuse count option has been implemented.
- */
-
EnterCriticalSection (&ptw32_thread_reuse_lock);
- /*
- * The first test is the same as pthread_kill(thread, 0), duplicated here
- * so that we can use the reuse_lock to ensure the thread isn't destroyed
- * and reused before we've finished with the POSIX thread struct.
- */
- if (tp == NULL
- || NULL == tp->threadH
- || THREAD_PRIORITY_ERROR_RETURN == GetThreadPriority (tp->threadH))
+
+ if (NULL == tp
+ || thread.x != tp->ptHandle.x)
{
result = ESRCH;
}
@@ -147,19 +97,23 @@ pthread_join (pthread_t thread, void **value_ptr)
}
else
{
+ result = 0;
+ }
+
+ LeaveCriticalSection (&ptw32_thread_reuse_lock);
+
+ if (result == 0)
+ {
/*
* The target thread is joinable and can't be reused before we join it.
*/
-
- LeaveCriticalSection (&ptw32_thread_reuse_lock);
-
self = pthread_self();
if (NULL == self.p)
{
result = ENOENT;
}
- else if (0 != pthread_equal (self, thread))
+ else if (pthread_equal (self, thread))
{
result = EDEADLK;
}
@@ -176,29 +130,6 @@ pthread_join (pthread_t thread, void **value_ptr)
if (0 == result)
{
-
-#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__)
-
- if (value_ptr != NULL
- && !GetExitCodeThread (tp->threadH, (LPDWORD) value_ptr))
- {
- result = ESRCH;
- }
- else
- {
- /*
- * The result of making multiple simultaneous calls to
- * pthread_join() specifying the same target is undefined.
- */
- ptw32_threadDestroy (thread);
- }
-
-#else /* __MINGW32__ && ! __MSVCRT__ */
-
- /*
- * If using CRTDLL, the thread may have exited, and endthread
- * will have closed the handle.
- */
if (value_ptr != NULL)
{
*value_ptr = tp->exitStatus;
@@ -206,24 +137,18 @@ pthread_join (pthread_t thread, void **value_ptr)
/*
* The result of making multiple simultaneous calls to
- * pthread_join() specifying the same target is undefined.
+ * pthread_join() or pthread_detach() specifying the same
+ * target is undefined.
*/
- ptw32_threadDestroy (thread);
-
-#endif /* __MINGW32__ && ! __MSVCRT__ */
-
+ result = pthread_detach (thread);
}
else
{
result = ESRCH;
}
}
-
- goto FAIL0;
}
- LeaveCriticalSection (&ptw32_thread_reuse_lock);
-FAIL0:
return (result);
} /* pthread_join */
diff --git a/pthread_win32_attach_detach_np.c b/pthread_win32_attach_detach_np.c
index 6947080..d839c70 100644
--- a/pthread_win32_attach_detach_np.c
+++ b/pthread_win32_attach_detach_np.c
@@ -261,15 +261,29 @@ pthread_win32_thread_detach_np ()
*/
ptw32_thread_t * sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey);
- if (sp != NULL)
+ if (sp != NULL) // otherwise Win32 thread with no implicit POSIX handle.
{
+ HANDLE threadH = sp->threadH;
+
+ ptw32_callUserDestroyRoutines (sp->ptHandle);
+
+ (void) pthread_mutex_lock (&sp->cancelLock);
+ sp->state = PThreadStateLast;
/*
- * Detached threads have their resources automatically
- * cleaned up upon exit (others must be 'joined').
+ * If the thread is joinable at this point then it MUST be joined
+ * or detached explicitly by the application.
*/
+ (void) pthread_mutex_unlock (&sp->cancelLock);
+
if (sp->detachState == PTHREAD_CREATE_DETACHED)
{
ptw32_threadDestroy (sp->ptHandle);
+
+ if (threadH != 0)
+ {
+ CloseHandle (threadH);
+ }
+
TlsSetValue (ptw32_selfThreadKey->key, NULL);
}
}
diff --git a/ptw32_threadDestroy.c b/ptw32_threadDestroy.c
index b88e5d9..aa95e2c 100644
--- a/ptw32_threadDestroy.c
+++ b/ptw32_threadDestroy.c
@@ -47,12 +47,6 @@ ptw32_threadDestroy (pthread_t thread)
if (tp != NULL)
{
- (void) pthread_mutex_lock (&tp->cancelLock);
- tp->state = PThreadStateLast;
- (void) pthread_mutex_unlock (&tp->cancelLock);
-
- ptw32_callUserDestroyRoutines (thread);
-
/*
* Copy thread state so that the thread can be atomically NULLed.
*/
@@ -72,17 +66,6 @@ ptw32_threadDestroy (pthread_t thread)
(void) pthread_mutex_destroy(&threadCopy.cancelLock);
(void) pthread_mutex_destroy(&threadCopy.threadLock);
-
-#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__)
- /*
- * See documentation for endthread vs endthreadex.
- */
- if (threadCopy.threadH != 0)
- {
- CloseHandle (threadCopy.threadH);
- }
-#endif
-
}
-
} /* ptw32_threadDestroy */
+
diff --git a/ptw32_threadStart.c b/ptw32_threadStart.c
index b7c5748..5c0fe0e 100644
--- a/ptw32_threadStart.c
+++ b/ptw32_threadStart.c
@@ -109,12 +109,8 @@ static terminate_function
void
ptw32_terminate ()
{
- pthread_t self = pthread_self ();
- ptw32_thread_t * sp = (ptw32_thread_t *) self.p;
-
set_terminate (ptw32_oldTerminate);
- (void) pthread_mutex_destroy (&sp->cancelLock);
- ptw32_callUserDestroyRoutines (self);
+ (void) pthread_win32_thread_detach_np ();
terminate ();
}
@@ -193,7 +189,7 @@ ptw32_threadStart (void *vthreadParms)
switch (ei[0])
{
case PTW32_EPS_CANCEL:
- status = PTHREAD_CANCELED;
+ status = sp->exitStatus = PTHREAD_CANCELED;
#ifdef _UWIN
if (--pthread_count <= 0)
exit (0);
@@ -203,7 +199,7 @@ ptw32_threadStart (void *vthreadParms)
status = sp->exitStatus;
break;
default:
- status = PTHREAD_CANCELED;
+ status = sp->exitStatus = PTHREAD_CANCELED;
break;
}
}
@@ -227,13 +223,13 @@ ptw32_threadStart (void *vthreadParms)
switch (setjmp_rc)
{
case PTW32_EPS_CANCEL:
- status = PTHREAD_CANCELED;
+ status = sp->exitStatus = PTHREAD_CANCELED;
break;
case PTW32_EPS_EXIT:
status = sp->exitStatus;
break;
default:
- status = PTHREAD_CANCELED;
+ status = sp->exitStatus = PTHREAD_CANCELED;
break;
}
}
@@ -310,9 +306,8 @@ ptw32_threadStart (void *vthreadParms)
(void) pthread_mutex_lock (&sp->cancelLock);
sp->state = PThreadStateException;
(void) pthread_mutex_unlock (&sp->cancelLock);
- (void) pthread_mutex_destroy (&sp->cancelLock);
+ (void) pthread_win32_thread_detach_np ();
(void) set_terminate (ptw32_oldTerminate);
- ptw32_callUserDestroyRoutines (self);
throw;
/*
@@ -330,27 +325,23 @@ ptw32_threadStart (void *vthreadParms)
#endif /* __CLEANUP_C */
#endif /* __CLEANUP_SEH */
- if (sp->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);
- }
+#if defined(PTW32_STATIC_LIB)
+ /*
+ * We need to cleanup the pthread now if we have
+ * been statically linked, in which case the cleanup
+ * in dllMain won't get done. Joinable threads will
+ * only be partially cleaned up and must be fully cleaned
+ * up by pthread_join() or pthread_detach().
+ *
+ * Note: if this library has been statically linked,
+ * 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()).
+ * For the dll, dllMain will do the cleanup automatically.
+ */
+ (void) pthread_win32_thread_detach_np ();
+#endif
#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__)
_endthreadex ((unsigned) status);
diff --git a/ptw32_throw.c b/ptw32_throw.c
index 57814e9..493f4e4 100644
--- a/ptw32_throw.c
+++ b/ptw32_throw.c
@@ -85,8 +85,12 @@ ptw32_throw (DWORD exception)
break;
}
+#if defined(PTW32_STATIC_LIB)
+
pthread_win32_thread_detach_np ();
+#endif
+
#if ! defined (__MINGW32__) || defined (__MSVCRT__) || defined (__DMC__)
_endthreadex (exitCode);
#else
diff --git a/sem_init.c b/sem_init.c
index 647ba18..27d8cbb 100644
--- a/sem_init.c
+++ b/sem_init.c
@@ -73,7 +73,7 @@ sem_init (sem_t * sem, int pshared, unsigned int value)
* -1 failed, error in errno
* ERRNO
* EINVAL 'sem' is not a valid semaphore, or
- * 'value' >= _POSIX_SEM_VALUE_MAX
+ * 'value' >= SEM_VALUE_MAX
* ENOMEM out of memory,
* ENOSPC a required resource has been exhausted,
* ENOSYS semaphores are not supported,
@@ -93,7 +93,7 @@ sem_init (sem_t * sem, int pshared, unsigned int value)
*/
result = EPERM;
}
- else if (value > (unsigned int)_POSIX_SEM_VALUE_MAX)
+ else if (value > (unsigned int)SEM_VALUE_MAX)
{
result = EINVAL;
}
diff --git a/sem_post.c b/sem_post.c
index 2edaecf..91f9755 100644
--- a/sem_post.c
+++ b/sem_post.c
@@ -82,7 +82,7 @@ sem_post (sem_t * sem)
}
else if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
- if (s->value < _POSIX_SEM_VALUE_MAX)
+ if (s->value < SEM_VALUE_MAX)
{
#ifdef NEED_SEM
if (++s->value <= 0
diff --git a/sem_post_multiple.c b/sem_post_multiple.c
index 42ea2f4..fa950bd 100644
--- a/sem_post_multiple.c
+++ b/sem_post_multiple.c
@@ -86,7 +86,7 @@ sem_post_multiple (sem_t * sem, int count)
}
else if ((result = pthread_mutex_lock (&s->lock)) == 0)
{
- if (s->value <= (_POSIX_SEM_VALUE_MAX - count))
+ if (s->value <= (SEM_VALUE_MAX - count))
{
waiters = -s->value;
s->value += count;
diff --git a/tests/Bmakefile b/tests/Bmakefile
index 6141ffe..34ec8a6 100644
--- a/tests/Bmakefile
+++ b/tests/Bmakefile
@@ -86,7 +86,7 @@ PASSES= loadfree.pass \
exit1.pass create1.pass create2.pass reuse1.pass reuse2.pass equal1.pass \
kill1.pass valid1.pass valid2.pass \
exit2.pass exit3.pass exit4.pass exit5.pass \
- join0.pass join1.pass join2.pass join3.pass \
+ join0.pass join1.pass detach1.pass join2.pass join3.pass \
mutex4.pass mutex6.pass mutex6n.pass mutex6e.pass mutex6r.pass \
mutex6s.pass mutex6es.pass mutex6rs.pass \
mutex7.pass mutex7n.pass mutex7e.pass mutex7r.pass \
@@ -261,6 +261,7 @@ create2.pass: create1.pass
create3.pass:
delay1.pass:
delay2.pass: delay1.pass
+detach1.pass: join0.pass
equal1.pass: create1.pass
errno1.pass: mutex3.pass
exception1.pass: cancel4.pass
@@ -340,7 +341,7 @@ spin1.pass:
spin2.pass: spin1.pass
spin3.pass: spin2.pass
spin4.pass: spin3.pass
-stress1.pass: barrier5.pass
+stress1.pass:
tsd1.pass: barrier5.pass join1.pass
tsd2.pass: tsd1.pass
valid1.pass: join1.pass
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 1800c99..2677631 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,13 @@
+2005-05-15 Ross Johnson <rpj@callisto.canberra.edu.au>
+
+ * detach1.c: New test.
+ * join1.c: Reduce sleep times.
+ * join0.c: Remove MSVCRT conditional compile - join should always
+ return the thread exit code.
+ * join1.c: Likewise.
+ * join2.c: Likewise.
+ * join3.c: Likewise.
+
2005-04-12 Ross Johnson <rpj@callisto.canberra.edu.au>
* once4.c: New test; tries to test priority adjustments
diff --git a/tests/GNUmakefile b/tests/GNUmakefile
index e9df21a..9b16114 100644
--- a/tests/GNUmakefile
+++ b/tests/GNUmakefile
@@ -81,7 +81,7 @@ TESTS = sizes loadfree \
create1 create2 reuse1 reuse2 equal1 \
kill1 valid1 valid2 \
exit2 exit3 exit4 exit5 \
- join0 join1 join2 join3 \
+ join0 join1 detach1 join2 join3 \
mutex2 mutex2r mutex2e mutex3 mutex3r mutex3e \
mutex4 mutex6 mutex6n mutex6e mutex6r \
mutex6s mutex6es mutex6rs \
@@ -102,7 +102,7 @@ TESTS = sizes loadfree \
priority1 priority2 inherit1 \
spin1 spin2 spin3 spin4 \
exception1 exception2 exception3 \
- cancel9 create3
+ cancel9 create3 stress1
STRESSTESTS = \
stress1
@@ -184,8 +184,6 @@ benchtest3.bench:
benchtest4.bench:
benchtest5.bench:
-stress1.pass:
-
barrier1.pass: semaphore4.pass
barrier2.pass: barrier1.pass
barrier3.pass: barrier2.pass
@@ -228,6 +226,7 @@ create2.pass: create1.pass
create3.pass:
delay1.pass: cancel2.pass
delay2.pass: delay1.pass
+detach1.pass: join0.pass
equal1.pass: create1.pass
errno1.pass: mutex3.pass
exception1.pass: cancel4.pass
@@ -307,6 +306,7 @@ spin1.pass:
spin2.pass: spin1.pass
spin3.pass: spin2.pass
spin4.pass: spin3.pass
+stress1.pass:
tsd1.pass: barrier5.pass join1.pass
tsd2.pass: tsd1.pass
valid1.pass: join1.pass
diff --git a/tests/Makefile b/tests/Makefile
index d12a1f1..b00f52b 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -90,7 +90,7 @@ PASSES= sizes.pass loadfree.pass \
exit1.pass create1.pass create2.pass reuse1.pass reuse2.pass equal1.pass \
kill1.pass valid1.pass valid2.pass \
exit2.pass exit3.pass exit4.pass exit5.pass \
- join0.pass join1.pass join2.pass join3.pass \
+ join0.pass join1.pass detach1.pass join2.pass join3.pass \
mutex4.pass mutex6.pass mutex6n.pass mutex6e.pass mutex6r.pass \
mutex6s.pass mutex6es.pass mutex6rs.pass \
mutex7.pass mutex7n.pass mutex7e.pass mutex7r.pass \
@@ -115,13 +115,13 @@ PASSES= sizes.pass loadfree.pass \
priority1.pass priority2.pass inherit1.pass \
spin1.pass spin2.pass spin3.pass spin4.pass \
exception1.pass exception2.pass exception3.pass \
- cancel9.pass create3.pass
+ cancel9.pass create3.pass stress1.pass
BENCHRESULTS = \
benchtest1.bench benchtest2.bench benchtest3.bench benchtest4.bench benchtest5.bench
STRESSRESULTS = \
- stress1.pass
+ stress1.stress
STATICRESULTS = \
self1.pass
@@ -274,8 +274,6 @@ benchtest3.bench:
benchtest4.bench:
benchtest5.bench:
-stress1.pass:
-
barrier1.pass: semaphore4.pass
barrier2.pass: barrier1.pass
barrier3.pass: barrier2.pass
@@ -317,6 +315,7 @@ create2.pass: create1.pass
create3.pass:
delay1.pass:
delay2.pass: delay1.pass
+detach1.pass: join0.pass
equal1.pass: create1.pass
errno1.pass: mutex3.pass
exception1.pass: cancel4.pass
@@ -396,6 +395,7 @@ spin1.pass:
spin2.pass: spin1.pass
spin3.pass: spin2.pass
spin4.pass: spin3.pass
+stress1.pass: condvar9.pass barrier5.pass
tsd1.pass: barrier5.pass join1.pass
tsd2.pass: tsd1.pass
valid1.pass: join1.pass
diff --git a/tests/Wmakefile b/tests/Wmakefile
index 4f003df..5f900e8 100644
--- a/tests/Wmakefile
+++ b/tests/Wmakefile
@@ -32,7 +32,7 @@
#
-DLL_VER = 2
+DLL_VER = 1
.EXTENSIONS:
@@ -86,7 +86,7 @@ PASSES = sizes.pass loadfree.pass &
exit1.pass create1.pass create2.pass reuse1.pass reuse2.pass equal1.pass &
kill1.pass valid1.pass valid2.pass &
exit2.pass exit3.pass exit4 exit5 &
- join0.pass join1.pass join2.pass join3.pass &
+ join0.pass join1.pass detach1.pass join2.pass join3.pass &
mutex4.pass mutex6.pass mutex6n.pass mutex6e.pass mutex6r.pass &
mutex6s.pass mutex6es.pass mutex6rs.pass &
mutex7.pass mutex7n.pass mutex7e.pass mutex7r.pass &
@@ -111,7 +111,7 @@ PASSES = sizes.pass loadfree.pass &
spin1.pass spin2.pass spin3.pass spin4.pass &
barrier1.pass barrier2.pass barrier3.pass barrier4.pass barrier5.pass &
exception1.pass exception2.pass exception3.pass &
- cancel9.pass
+ cancel9.pass create3.pass stress1.pass
BENCHRESULTS = &
benchtest1.bench benchtest2.bench benchtest3.bench benchtest4.bench benchtest5.bench
@@ -255,8 +255,10 @@ context1.pass: cancel2.pass
count1.pass: join1.pass
create1.pass: mutex2.pass
create2.pass: create1.pass
+create3.pass:
delay1.pass:
delay2.pass: delay1.pass
+detach1.pass: join0.pass
equal1.pass: create1.pass
errno1.pass: mutex3.pass
exception1.pass: cancel4.pass
@@ -335,6 +337,7 @@ spin1.pass:
spin2.pass: spin1.pass
spin3.pass: spin2.pass
spin4.pass: spin3.pass
+stress1.pass:
tsd1.pass: join1.pass
valid1.pass: join1.pass
valid2.pass: valid1.pass
diff --git a/tests/create3.c b/tests/create3.c
index 530a2f1..98bd520 100644
--- a/tests/create3.c
+++ b/tests/create3.c
@@ -92,7 +92,7 @@ threadFunc(void * arg)
}
int
-main(int argc, char argv[])
+main(int argc, char * argv[])
{
int i;
pthread_t mt;
diff --git a/tests/detach1.c b/tests/detach1.c
new file mode 100644
index 0000000..b0835c5
--- /dev/null
+++ b/tests/detach1.c
@@ -0,0 +1,88 @@
+/*
+ * Test for pthread_detach().
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2005 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@callisto.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Depends on API functions: pthread_create(), pthread_detach(), pthread_exit().
+ */
+
+#include "test.h"
+
+void *
+func(void * arg)
+{
+ int i = (int) arg;
+
+ Sleep(i * 100);
+
+ pthread_exit(arg);
+
+ /* Never reached. */
+ exit(1);
+}
+
+int
+main(int argc, char * argv[])
+{
+ pthread_t id[4];
+ int i;
+
+ /* Create a few threads and then exit. */
+ for (i = 0; i < 4; i++)
+ {
+ assert(pthread_create(&id[i], NULL, func, (void *) i) == 0);
+ }
+
+ /* Some threads will finish before they are detached, some after. */
+ Sleep(2 * 100 + 50);
+
+ for (i = 0; i < 4; i++)
+ {
+ assert(pthread_detach(id[i]) == 0);
+ }
+
+ Sleep(6 * 100);
+
+ /*
+ * Check that all threads are now invalid.
+ * This relies on unique thread IDs - e.g. works with
+ * pthreads-w32 or Solaris, but may not work for Linux, BSD etc.
+ */
+ for (i = 0; i < 4; i++)
+ {
+ assert(pthread_kill(id[i], 0) == ESRCH);
+ }
+
+ /* Success. */
+ return 0;
+}
diff --git a/tests/join0.c b/tests/join0.c
index bece19c..a6cb25d 100644
--- a/tests/join0.c
+++ b/tests/join0.c
@@ -60,12 +60,7 @@ main(int argc, char * argv[])
assert(pthread_join(id, (void **) &result) == 0);
-#if ! defined (__MINGW32__) || defined (__MSVCRT__)
assert(result == 123);
-#else
-# warning pthread_join not fully supported in this configuration.
- assert(result == 0);
-#endif
/* Success. */
return 0;
diff --git a/tests/join1.c b/tests/join1.c
index 8f52ae7..8b11e95 100644
--- a/tests/join1.c
+++ b/tests/join1.c
@@ -43,7 +43,7 @@ func(void * arg)
{
int i = (int) arg;
- Sleep(i * 500);
+ Sleep(i * 100);
pthread_exit(arg);
@@ -65,17 +65,12 @@ main(int argc, char * argv[])
}
/* Some threads will finish before they are joined, some after. */
- Sleep(1000);
+ Sleep(2 * 100 + 50);
for (i = 0; i < 4; i++)
{
assert(pthread_join(id[i], (void **) &result) == 0);
-#if ! defined (__MINGW32__) || defined (__MSVCRT__)
assert(result == i);
-#else
-# warning pthread_join not fully supported in this configuration.
- assert(result == 0);
-#endif
}
/* Success. */
diff --git a/tests/join2.c b/tests/join2.c
index 89a3633..4fa3012 100644
--- a/tests/join2.c
+++ b/tests/join2.c
@@ -61,11 +61,7 @@ main(int argc, char * argv[])
for (i = 0; i < 4; i++)
{
assert(pthread_join(id[i], (void **) &result) == 0);
-#if ! defined (__MINGW32__) || defined (__MSVCRT__)
- /* CRTDLL _beginthread doesn't support return value, so
- the assertion is guaranteed to fail. */
assert(result == i);
-#endif
}
/* Success. */
diff --git a/tests/join3.c b/tests/join3.c
index ccc13dd..70cf3e9 100644
--- a/tests/join3.c
+++ b/tests/join3.c
@@ -67,11 +67,7 @@ main(int argc, char * argv[])
for (i = 0; i < 4; i++)
{
assert(pthread_join(id[i], (void **) &result) == 0);
-#if ! defined (__MINGW32__) || defined (__MSVCRT__)
- /* CRTDLL _beginthread doesn't support return value, so
- the assertion is guaranteed to fail. */
assert(result == i);
-#endif
}
/* Success. */
diff --git a/tests/reuse2.c b/tests/reuse2.c
index 9851dde..e573a31 100644
--- a/tests/reuse2.c
+++ b/tests/reuse2.c
@@ -84,15 +84,27 @@ enum {
};
+static int dummy = 19;
static long done = 0;
void * func(void * arg)
{
+ int i;
+ int j;
+
sched_yield();
+ for (i = 1; i < 10000; i++)
+ {
+ if (i * dummy % dummy == 0)
+ {
+ j = dummy;
+ }
+ }
+
InterlockedIncrement(&done);
- return (void *) 0;
+ return (void *) j;
}
int