summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ANNOUNCE2
-rw-r--r--ChangeLog19
-rw-r--r--NEWS42
-rw-r--r--create.c2
-rw-r--r--dll.c2
-rw-r--r--global.c2
-rw-r--r--pthread.h10
-rw-r--r--pthread_cond_signal.c4
-rw-r--r--pthread_exit.c22
-rw-r--r--pthread_once.c2
-rw-r--r--pthread_win32_attach_detach_np.c4
-rw-r--r--ptw32_increase_semaphore.c4
-rw-r--r--ptw32_new.c4
-rw-r--r--ptw32_processInitialize.c8
-rw-r--r--ptw32_processTerminate.c2
-rw-r--r--ptw32_reuse.c6
-rw-r--r--ptw32_threadDestroy.c8
-rw-r--r--ptw32_throw.c48
-rw-r--r--sched_getscheduler.c2
-rw-r--r--sched_setscheduler.c2
-rw-r--r--sem_init.c4
-rw-r--r--tests/ChangeLog18
-rw-r--r--tests/GNUmakefile6
-rw-r--r--tests/Makefile6
-rw-r--r--tests/cancel7.c215
-rw-r--r--tests/exit4.c198
-rw-r--r--tests/exit5.c204
-rw-r--r--w32_CancelableWait.c2
28 files changed, 797 insertions, 51 deletions
diff --git a/ANNOUNCE b/ANNOUNCE
index 1fc61ef..7457afb 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -1,4 +1,4 @@
- PTHREADS-WIN32 SNAPSHOT 2003-08-19
+ PTHREADS-WIN32 SNAPSHOT 2003-09-03
----------------------------------
Web Site: http://sources.redhat.com/pthreads-win32/
FTP Site: ftp://sources.redhat.com/pub/pthreads-win32
diff --git a/ChangeLog b/ChangeLog
index 5232528..6d0effe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2003-09-02 Ross Johnson <rpj@callisto.canberra.edu.au>
+
+ * pthread_win32_attach_detach_np.c (pthread_win32_thread_detach_np):
+ Add comment.
+
+ * pthread_exit.c (pthread_exit): Fix to recycle the POSIX thread handle in
+ addition to calling user TSD destructors. Move the implicit POSIX thread exit
+ handling to ptw32_throw to centralise the logic.
+
+ * ptw32_throw.c (ptw32_throw): Implicit POSIX threads have no point
+ to jump or throw to, so cleanup and exit the thread here in this case. For
+ processes using the C runtime, the exit code will be set to the POSIX
+ reason for the throw (i.e. PTHREAD_CANCEL or the value given to pthread_exit).
+ Note that pthread_exit() already had similar logic, which has been moved to
+ here.
+
+ * ptw32_threadDestroy.c (ptw32_threadDestroy): Don't close the Win32 handle
+ of implicit POSIX threads - expect this to be done by Win32?
+
2003-09-01 Ross Johnson <rpj@callisto.canberra.edu.au>
* pthread_self.c (pthread_self): The newly aquired pthread_t must be
diff --git a/NEWS b/NEWS
index b4846a4..b54defe 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,45 @@
+SNAPSHOT 2003-09-03
+-------------------
+
+Bug fixes
+---------
+* pthread_self() would free the newly created implicit POSIX thread handle if
+DuplicateHandle failed instead of recycle it (very unlikely).
+
+* pthread_exit() was neither freeing nor recycling the POSIX thread struct
+for implicit POSIX threads.
+
+New feature - Cancelation of/by Win32 (non-POSIX) threads
+---------------------------------------------------------
+Since John Bossom's original implementation, the library has allowed non-POSIX
+initialised threads (Win32 threads) to call pthreads-win32 routines and
+therefore interact with POSIX threads. This is done by creating an on-the-fly
+POSIX thread ID for the Win32 thread that, once created, allows fully
+reciprical interaction. This did not extend to thread cancelation (async or
+deferred). Now it does.
+
+Any thread can be canceled by any other thread (Win32 or POSIX) if the former
+thread's POSIX pthread_t value is known. It's TSD destructors and POSIX
+cleanup handlers will be run before the thread exits with an exit code of
+PTHREAD_CANCELED (retrieved with GetExitCodeThread()).
+
+This allows a Win32 thread to, for example, call POSIX CV routines in the same way
+that POSIX threads would/should, with pthread_cond_wait() cancelability and
+cleanup handlers (pthread_cond_wait() is a POSIX cancelation point).
+
+By adding cancelation, Win32 threads should now be able to call all POSIX
+threads routines that make sense including semaphores, mutexes, condition
+variables, read/write locks, barriers, spinlocks, tsd, cleanup push/pop,
+cancelation, pthread_exit, scheduling, etc.
+
+Note that these on-the-fly 'implicit' POSIX thread IDs are initialised as detached
+(not joinable) with deferred cancelation type. The POSIX thread ID will be created
+automatically by any POSIX routines that need a POSIX handle (unless the routine
+needs a pthread_t as a parameter of course). A Win32 thread can discover it's own
+POSIX thread ID by calling pthread_self(), which will create the handle if
+necessary and return the pthread_t value.
+
+
SNAPSHOT 2003-08-19
-------------------
diff --git a/create.c b/create.c
index 3c84ac9..1b3825e 100644
--- a/create.c
+++ b/create.c
@@ -84,7 +84,7 @@ pthread_create (pthread_t * tid,
pthread_t thread;
HANDLE threadH = 0;
int result = EAGAIN;
- int run = TRUE;
+ int run = PTW32_TRUE;
ThreadParms *parms = NULL;
long stackSize;
diff --git a/dll.c b/dll.c
index f5f11fd..9c8d69d 100644
--- a/dll.c
+++ b/dll.c
@@ -63,7 +63,7 @@ DllMain (
LPVOID lpvReserved
)
{
- BOOL result = TRUE;
+ BOOL result = PTW32_TRUE;
switch (fdwReason)
{
diff --git a/global.c b/global.c
index 46a928d..59ebc45 100644
--- a/global.c
+++ b/global.c
@@ -39,7 +39,7 @@
#include "implement.h"
-int ptw32_processInitialized = FALSE;
+int ptw32_processInitialized = PTW32_FALSE;
pthread_t ptw32_threadReuseTop = PTW32_THREAD_REUSE_BOTTOM;
pthread_key_t ptw32_selfThreadKey = NULL;
pthread_key_t ptw32_cleanupKey = NULL;
diff --git a/pthread.h b/pthread.h
index 1a533c8..35b2828 100644
--- a/pthread.h
+++ b/pthread.h
@@ -201,6 +201,14 @@
#include <limits.h>
/*
+ * Boolean values to make us independent of system includes.
+ */
+enum {
+ PTW32_FALSE = 0,
+ PTW32_TRUE = (! PTW32_FALSE)
+};
+
+/*
* This is a duplicate of what is in the autoconf config.h,
* which is only used when building the pthread-win32 libraries.
*/
@@ -576,7 +584,7 @@ enum {
* ====================
* ====================
*/
-#define PTHREAD_ONCE_INIT { FALSE, -1 }
+#define PTHREAD_ONCE_INIT { PTW32_FALSE, -1 }
struct pthread_once_t_
{
diff --git a/pthread_cond_signal.c b/pthread_cond_signal.c
index 46bad94..156c0d0 100644
--- a/pthread_cond_signal.c
+++ b/pthread_cond_signal.c
@@ -348,8 +348,8 @@ pthread_cond_broadcast (pthread_cond_t * cond)
*/
{
/*
- * The '1'(TRUE) unblockAll arg means unblock ALL waiters.
+ * The TRUE unblockAll arg means unblock ALL waiters.
*/
- return (ptw32_cond_unblock(cond, 1));
+ return (ptw32_cond_unblock(cond, PTW32_TRUE));
} /* pthread_cond_broadcast */
diff --git a/pthread_exit.c b/pthread_exit.c
index dfbc45b..da19063 100644
--- a/pthread_exit.c
+++ b/pthread_exit.c
@@ -67,29 +67,33 @@ pthread_exit (void *value_ptr)
{
pthread_t self;
- /* If the current thread is implicit it was not started through
- pthread_create(), therefore we cleanup and end the thread
- here. Otherwise we raise an exception to unwind the exception
- stack. The exception will be caught by ptw32_threadStart(),
- which will cleanup and end the thread for us.
+ /*
+ * Don't use pthread_self() to avoid creating an implicit POSIX thread handle
+ * unnecessarily.
*/
-
self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey);
+
#ifdef _UWIN
if(--pthread_count <= 0)
exit((int)value_ptr);
#endif
- if (self == NULL || self->implicit)
+ if (NULL == self)
{
- ptw32_callUserDestroyRoutines(self);
+ /*
+ * A POSIX thread handle was never created. I.e. this is a
+ * Win32 thread that has never called a pthreads-win32 routine that
+ * required a POSIX handle.
+ *
+ * Implicit POSIX handles are cleaned up in ptw32_throw() now.
+ */
#if ! defined (__MINGW32__) || defined (__MSVCRT__)
_endthreadex ((unsigned) value_ptr);
#else
_endthread ();
#endif
-
+
/* Never reached */
}
diff --git a/pthread_once.c b/pthread_once.c
index 9446863..b698d68 100644
--- a/pthread_once.c
+++ b/pthread_once.c
@@ -97,7 +97,7 @@ pthread_once (
* First thread to increment the started variable
*/
(*init_routine) ();
- once_control->done = TRUE;
+ once_control->done = PTW32_TRUE;
}
else
diff --git a/pthread_win32_attach_detach_np.c b/pthread_win32_attach_detach_np.c
index c798d89..3a6f854 100644
--- a/pthread_win32_attach_detach_np.c
+++ b/pthread_win32_attach_detach_np.c
@@ -144,6 +144,10 @@ pthread_win32_thread_detach_np ()
{
if (ptw32_processInitialized)
{
+ /*
+ * Don't use pthread_self() to avoid creating an implicit POSIX thread handle
+ * unnecessarily.
+ */
pthread_t self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey);
/*
diff --git a/ptw32_increase_semaphore.c b/ptw32_increase_semaphore.c
index 7e2a730..9eafaed 100644
--- a/ptw32_increase_semaphore.c
+++ b/ptw32_increase_semaphore.c
@@ -59,11 +59,11 @@ ptw32_increase_semaphore(sem_t * sem, unsigned int n)
{
s->value += n;
SetEvent(s->event);
- result = TRUE;
+ result = PTW32_TRUE;
}
else
{
- result = FALSE;
+ result = PTW32_FALSE;
}
LeaveCriticalSection(&s->sem_lock_cs);
diff --git a/ptw32_new.c b/ptw32_new.c
index d0f632f..3e346d1 100644
--- a/ptw32_new.c
+++ b/ptw32_new.c
@@ -61,8 +61,8 @@ ptw32_new (void)
t->cancelLock = PTHREAD_MUTEX_INITIALIZER;
t->cancelEvent = CreateEvent (
0,
- (int) TRUE, /* manualReset */
- (int) FALSE, /* setSignaled */
+ (int) PTW32_TRUE, /* manualReset */
+ (int) PTW32_FALSE, /* setSignaled */
NULL);
if (t->cancelEvent == NULL)
diff --git a/ptw32_processInitialize.c b/ptw32_processInitialize.c
index 101d35b..a8371ec 100644
--- a/ptw32_processInitialize.c
+++ b/ptw32_processInitialize.c
@@ -65,16 +65,16 @@ ptw32_processInitialize (void)
{
if (ptw32_processInitialized) {
/*
- * ignore if already initialized. this is useful for
+ * Ignore if already initialized. this is useful for
* programs that uses a non-dll pthread
- * library. such programs must call ptw32_processInitialize() explicitely,
+ * library. Such programs must call ptw32_processInitialize() explicitly,
* since this initialization routine is automatically called only when
* the dll is loaded.
*/
- return TRUE;
+ return PTW32_TRUE;
}
- ptw32_processInitialized = TRUE;
+ ptw32_processInitialized = PTW32_TRUE;
/*
* Initialize Keys
diff --git a/ptw32_processTerminate.c b/ptw32_processTerminate.c
index aca8ffe..13c564d 100644
--- a/ptw32_processTerminate.c
+++ b/ptw32_processTerminate.c
@@ -110,7 +110,7 @@ ptw32_processTerminate (void)
DeleteCriticalSection(&ptw32_mutex_test_init_lock);
DeleteCriticalSection(&ptw32_thread_reuse_lock);
- ptw32_processInitialized = FALSE;
+ ptw32_processInitialized = PTW32_FALSE;
}
} /* processTerminate */
diff --git a/ptw32_reuse.c b/ptw32_reuse.c
index 9b495ce..b407b82 100644
--- a/ptw32_reuse.c
+++ b/ptw32_reuse.c
@@ -40,13 +40,9 @@
/*
* The thread reuse stack is a simple LIFO stack managed through a singly
- * linked list element in the pthread_t struct.
+ * linked list element in the pthread_t_ struct.
*
* All thread structs on the stack are clean and ready for reuse.
- *
- * The pthread_t_ struct's prevReuse element can be tested to check for an invalid
- * thread ID. A NULL value indicates a valid thread. Applications should use the
- * pthread_kill() function with a zero signal value to test for a valid thread ID.
*/
/*
diff --git a/ptw32_threadDestroy.c b/ptw32_threadDestroy.c
index 560c084..868b3f3 100644
--- a/ptw32_threadDestroy.c
+++ b/ptw32_threadDestroy.c
@@ -72,8 +72,12 @@ ptw32_threadDestroy (pthread_t thread)
(void) pthread_mutex_destroy(&threadCopy.cancelLock);
#if ! defined (__MINGW32__) || defined (__MSVCRT__)
- /* See documentation for endthread vs endthreadex. */
- if( threadCopy.threadH != 0 )
+ /*
+ * See documentation for endthread vs endthreadex.
+ * Don't close the Win32 handle of implicit POSIX threads
+ * because the process may want to call GetExitCodeThread().
+ */
+ if( threadCopy.threadH != 0 && ! threadCopy.implicit )
{
CloseHandle( threadCopy.threadH );
}
diff --git a/ptw32_throw.c b/ptw32_throw.c
index a329e5c..20bfcf5 100644
--- a/ptw32_throw.c
+++ b/ptw32_throw.c
@@ -38,14 +38,22 @@
#include "pthread.h"
#include "implement.h"
-
+/*
+ * ptw32_throw
+ *
+ * All canceled and explicitly exited POSIX threads go through
+ * here. This routine knows how to exit both POSIX initiated threads and
+ * 'implicit' POSIX threads for each of the possible language modes (C,
+ * C++, and SEH).
+ */
void
ptw32_throw(DWORD exception)
{
-#ifdef __CLEANUP_C
- pthread_t self = pthread_self();
-#endif
-
+ /*
+ * Don't use pthread_self() to avoid creating an implicit POSIX thread handle
+ * unnecessarily.
+ */
+ pthread_t self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey);
#ifdef __CLEANUP_SEH
DWORD exceptionInformation[3];
@@ -58,6 +66,36 @@ ptw32_throw(DWORD exception)
exit(1);
}
+ if (NULL == self || self->implicit)
+ {
+ /*
+ * We're inside a non-POSIX initialised Win32 thread
+ * so there is no point to jump or throw back to. Just do an
+ * explicit thread exit here after cleaning up POSIX
+ * residue (i.e. cleanup handlers, POSIX thread handle etc).
+ */
+ unsigned exitCode = 0;
+
+ switch (exception)
+ {
+ case PTW32_EPS_CANCEL:
+ exitCode = (unsigned) PTHREAD_CANCELED;
+ break;
+ case PTW32_EPS_EXIT:
+ exitCode = (unsigned) self->exitStatus;;
+ break;
+ }
+
+ pthread_win32_thread_detach_np();
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+ _endthreadex (exitCode);
+#else
+ _endthread ();
+#endif
+
+ }
+
#ifdef __CLEANUP_SEH
diff --git a/sched_getscheduler.c b/sched_getscheduler.c
index 2e751d5..5e7728a 100644
--- a/sched_getscheduler.c
+++ b/sched_getscheduler.c
@@ -52,7 +52,7 @@ sched_getscheduler(pid_t pid)
if (pid != selfPid)
{
- HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD) pid);
+ HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, PTW32_FALSE, (DWORD) pid);
if (NULL == h)
{
diff --git a/sched_setscheduler.c b/sched_setscheduler.c
index 54e0c9b..47564d5 100644
--- a/sched_setscheduler.c
+++ b/sched_setscheduler.c
@@ -54,7 +54,7 @@ sched_setscheduler(pid_t pid, int policy)
if (pid != selfPid)
{
- HANDLE h = OpenProcess(PROCESS_SET_INFORMATION, FALSE, (DWORD) pid);
+ HANDLE h = OpenProcess(PROCESS_SET_INFORMATION, PTW32_FALSE, (DWORD) pid);
if (NULL == h)
{
diff --git a/sem_init.c b/sem_init.c
index 5dcb88e..4841530 100644
--- a/sem_init.c
+++ b/sem_init.c
@@ -114,8 +114,8 @@ sem_init (sem_t * sem, int pshared, unsigned int value)
{
s->value = value;
s->event = CreateEvent (NULL,
- FALSE, /* manual reset */
- FALSE, /* initial state */
+ PTW32_FALSE, /* manual reset */
+ PTW32_FALSE, /* initial state */
NULL);
if (0 == s->event)
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 7dd3076..4873c31 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,11 +1,17 @@
+2003-09-03 Ross Johnson <rpj@callisto.canberra.edu.au>
+
+ * exit4.c: New test.
+ * exit5.c: New test.
+ * cancel7.c: New test.
+
2003-08-13 Ross Johnson <rpj@ise.canberra.edu.au>
- * reuse1.c: New test.
- * reuse1.c: New test.
- * valid1.c: New test.
- * valid2.c: New test.
- * kill1.c: New test.
- * create2.c: Now included in test regime.
+ * reuse1.c: New test.
+ * reuse1.c: New test.
+ * valid1.c: New test.
+ * valid2.c: New test.
+ * kill1.c: New test.
+ * create2.c: Now included in test regime.
2003-07-19 Ross Johnson <rpj@ise.canberra.edu.au>
diff --git a/tests/GNUmakefile b/tests/GNUmakefile
index d4ce2ce..769beaa 100644
--- a/tests/GNUmakefile
+++ b/tests/GNUmakefile
@@ -67,7 +67,7 @@ TESTS = loadfree \
condvar1 condvar1_1 condvar1_2 condvar2 condvar2_1 exit1 \
create1 create2 reuse1 reuse2 equal1 \
kill1 valid1 valid2 \
- exit2 exit3 \
+ exit2 exit3 exit4 exit5 \
join0 join1 join2 \
mutex2 mutex3 mutex4 mutex6 mutex6n mutex6e mutex6r \
mutex7 mutex7n mutex7e mutex7r mutex8 mutex8n mutex8e mutex8r \
@@ -79,6 +79,7 @@ TESTS = loadfree \
rwlock1 rwlock2 rwlock3 rwlock4 rwlock5 rwlock6 rwlock7 \
rwlock2_t rwlock3_t rwlock4_t rwlock5_t rwlock6_t rwlock6_t2 \
context1 cancel3 cancel4 cancel5 cancel6a cancel6d \
+ cancel7 \
cleanup0 cleanup1 cleanup2 cleanup3 \
priority1 priority2 inherit1 \
spin1 spin2 spin3 spin4 \
@@ -144,6 +145,7 @@ cancel4.pass: cancel3.pass
cancel5.pass: cancel3.pass
cancel6a.pass: cancel3.pass
cancel6d.pass: cancel3.pass
+cancel7.pass: kill1.pass
cleanup0.pass: cancel5.pass
cleanup1.pass: cleanup0.pass
cleanup2.pass: cleanup1.pass
@@ -177,6 +179,8 @@ exception3.pass: exception2.pass
exit1.pass:
exit2.pass: create1.pass
exit3.pass: create1.pass
+exit4.pass:
+exit5.pass: exit4.pass kill1.pass
eyal1.pass: tsd1.pass
inherit1.pass: join1.pass
join0.pass: create1.pass
diff --git a/tests/Makefile b/tests/Makefile
index 0000e8c..b743872 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -76,7 +76,7 @@ PASSES= loadfree.pass \
condvar1.pass condvar1_1.pass condvar1_2.pass condvar2.pass condvar2_1.pass \
exit1.pass create1.pass create2.pass reuse1.pass reuse2.pass equal1.pass \
kill1.pass valid1.pass valid2.pass \
- exit2.pass exit3.pass \
+ exit2.pass exit3.pass exit4 exit5 \
join0.pass join1.pass join2.pass \
mutex4.pass mutex6.pass mutex6n.pass mutex6e.pass mutex6r.pass \
mutex7.pass mutex7n.pass mutex7e.pass mutex7r.pass \
@@ -93,6 +93,7 @@ PASSES= loadfree.pass \
rwlock2_t.pass rwlock3_t.pass rwlock4_t.pass rwlock5_t.pass rwlock6_t.pass rwlock6_t2.pass \
context1.pass \
cancel3.pass cancel4.pass cancel5.pass cancel6a.pass cancel6d.pass \
+ cancel7 \
cleanup0.pass cleanup1.pass cleanup2.pass cleanup3.pass \
priority1.pass priority2.pass inherit1.pass \
spin1.pass spin2.pass spin3.pass spin4.pass \
@@ -211,6 +212,7 @@ cancel4.pass: cancel3.pass
cancel5.pass: cancel3.pass
cancel6a.pass: cancel3.pass
cancel6d.pass: cancel3.pass
+cancel7.pass: kill1.pass
cleanup0.pass: cancel5.pass
cleanup1.pass: cleanup0.pass
cleanup2.pass: cleanup1.pass
@@ -244,6 +246,8 @@ exception3.pass: exception2.pass
exit1.pass:
exit2.pass: create1.pass
exit3.pass: create1.pass
+exit4.pass:
+exit5.pass: kill1.pass
eyal1.pass: tsd1.pass
inherit1.pass: join1.pass
join0.pass: create1.pass
diff --git a/tests/cancel7.c b/tests/cancel7.c
new file mode 100644
index 0000000..eda393b
--- /dev/null
+++ b/tests/cancel7.c
@@ -0,0 +1,215 @@
+/*
+ * File: cancel7.c
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2003 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
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Test Synopsis: Test canceling a Win32 thread having created an
+ * implicit POSIX handle for it.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validate return value and that POSIX handle is created and destroyed.
+ *
+ * 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.
+ */
+
+#include "test.h"
+#ifndef _UWIN
+#include <process.h>
+#endif
+
+/*
+ * 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;
+ pthread_t self;
+};
+
+static bag_t threadbag[NUMTHREADS + 1];
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+unsigned __stdcall
+#else
+void
+#endif
+Win32thread(void * arg)
+{
+ int i;
+ bag_t * bag = (bag_t *) arg;
+
+ assert(bag == &threadbag[bag->threadnum]);
+ assert(bag->started == 0);
+ bag->started = 1;
+
+ assert((bag->self = pthread_self()) != NULL);
+ assert(pthread_kill(bag->self, 0) == 0);
+
+ for (i = 0; i < 100; i++)
+ {
+ Sleep(100);
+ pthread_testcancel();
+ }
+
+ return 0;
+}
+
+int
+main()
+{
+ int failed = 0;
+ int i;
+ HANDLE h[NUMTHREADS + 1];
+
+ for (i = 1; i <= NUMTHREADS; i++)
+ {
+ threadbag[i].started = 0;
+ threadbag[i].threadnum = i;
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+ h[i] = (HANDLE) _beginthreadex(NULL, 0, Win32thread, (void *) &threadbag[i], 0, NULL);
+#else
+ h[i] = (HANDLE) _beginthread(Win32thread, 0, (void *) &threadbag[i]);
+#endif
+ }
+
+ /*
+ * Code to control or munipulate child threads should probably go here.
+ */
+ Sleep(500);
+
+ /*
+ * Cancel all threads.
+ */
+ for (i = 1; i <= NUMTHREADS; i++)
+ {
+ assert(pthread_kill(threadbag[i].self, 0) == 0);
+ assert(pthread_cancel(threadbag[i].self) == 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;
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+ assert(GetExitCodeThread(h[i], (LPDWORD) &result) == TRUE);
+#else
+ /*
+ * Can't get a result code.
+ */
+ result = (int) PTHREAD_CANCELED;
+#endif
+
+ assert(threadbag[i].self != NULL);
+ assert(pthread_kill(threadbag[i].self, 0) == ESRCH);
+
+ 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;
+}
+
diff --git a/tests/exit4.c b/tests/exit4.c
new file mode 100644
index 0000000..6c2fea1
--- /dev/null
+++ b/tests/exit4.c
@@ -0,0 +1,198 @@
+/*
+ * File: exit4.c
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2003 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
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Test Synopsis: Test calling pthread_exit from a Win32 thread
+ * without having created an implicit POSIX handle for it.
+ *
+ * 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.
+ */
+
+#include "test.h"
+#ifndef _UWIN
+#include <process.h>
+#endif
+
+/*
+ * 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];
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+unsigned __stdcall
+#else
+void
+#endif
+Win32thread(void * arg)
+{
+ int result = 1;
+ bag_t * bag = (bag_t *) arg;
+
+ assert(bag == &threadbag[bag->threadnum]);
+ assert(bag->started == 0);
+ bag->started = 1;
+
+ /*
+ * Doesn't return and doesn't create an implicit POSIX handle.
+ */
+ pthread_exit((void *) result);
+
+ return 0;
+}
+
+int
+main()
+{
+ int failed = 0;
+ int i;
+ HANDLE h[NUMTHREADS + 1];
+
+ for (i = 1; i <= NUMTHREADS; i++)
+ {
+ threadbag[i].started = 0;
+ threadbag[i].threadnum = i;
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+ h[i] = (HANDLE) _beginthreadex(NULL, 0, Win32thread, (void *) &threadbag[i], 0, NULL);
+#else
+ h[i] = (HANDLE) _beginthread(Win32thread, 0, (void *) &threadbag[i]);
+#endif
+ }
+
+ /*
+ * Code to control or munipulate child threads should probably go here.
+ */
+ Sleep(500);
+
+ /*
+ * 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;
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+ assert(GetExitCodeThread(h[i], (LPDWORD) &result) == TRUE);
+#else
+ /*
+ * Can't get a result code.
+ */
+ result = 1;
+#endif
+
+ fail = (result != 1);
+
+ 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;
+}
+
diff --git a/tests/exit5.c b/tests/exit5.c
new file mode 100644
index 0000000..f554fce
--- /dev/null
+++ b/tests/exit5.c
@@ -0,0 +1,204 @@
+/*
+ * File: exit5.c
+ *
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2003 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
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Test Synopsis: Test calling pthread_exit from a Win32 thread
+ * having created an implicit POSIX handle for it.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validate return value and that POSIX handle is created and destroyed.
+ *
+ * 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.
+ */
+
+#include "test.h"
+#ifndef _UWIN
+#include <process.h>
+#endif
+
+/*
+ * 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;
+ pthread_t self;
+};
+
+static bag_t threadbag[NUMTHREADS + 1];
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+unsigned __stdcall
+#else
+void
+#endif
+Win32thread(void * arg)
+{
+ int result = 1;
+ bag_t * bag = (bag_t *) arg;
+
+ assert(bag == &threadbag[bag->threadnum]);
+ assert(bag->started == 0);
+ bag->started = 1;
+
+ assert((bag->self = pthread_self()) != NULL);
+ assert(pthread_kill(bag->self, 0) == 0);
+
+ /*
+ * Doesn't return.
+ */
+ pthread_exit((void *) result);
+
+ return 0;
+}
+
+int
+main()
+{
+ int failed = 0;
+ int i;
+ HANDLE h[NUMTHREADS + 1];
+
+ for (i = 1; i <= NUMTHREADS; i++)
+ {
+ threadbag[i].started = 0;
+ threadbag[i].threadnum = i;
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+ h[i] = (HANDLE) _beginthreadex(NULL, 0, Win32thread, (void *) &threadbag[i], 0, NULL);
+#else
+ h[i] = (HANDLE) _beginthread(Win32thread, 0, (void *) &threadbag[i]);
+#endif
+ }
+
+ /*
+ * Code to control or munipulate child threads should probably go here.
+ */
+ Sleep(500);
+
+ /*
+ * 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;
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+ assert(GetExitCodeThread(h[i], (LPDWORD) &result) == TRUE);
+#else
+ /*
+ * Can't get a result code.
+ */
+ result = 1;
+#endif
+
+ assert(threadbag[i].self != NULL && pthread_kill(threadbag[i].self, 0) == ESRCH);
+
+ fail = (result != 1);
+
+ 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;
+}
+
diff --git a/w32_CancelableWait.c b/w32_CancelableWait.c
index 5e48fa5..42f28f5 100644
--- a/w32_CancelableWait.c
+++ b/w32_CancelableWait.c
@@ -84,7 +84,7 @@ ptw32_cancelable_wait (HANDLE waitHandle, DWORD timeout)
status = WaitForMultipleObjects (
nHandles,
handles,
- FALSE,
+ PTW32_FALSE,
timeout);