summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS8
-rw-r--r--ChangeLog46
-rw-r--r--FAQ101
-rw-r--r--GNUmakefile3
-rw-r--r--README56
-rw-r--r--dll.c117
-rw-r--r--global.c5
-rw-r--r--implement.h5
-rw-r--r--nonportable.c208
-rw-r--r--private.c157
-rw-r--r--pthread.def8
-rw-r--r--pthread.h27
-rw-r--r--tests/ChangeLog19
-rw-r--r--tests/GNUmakefile9
-rw-r--r--tests/Makefile4
-rw-r--r--tests/cleanup2.c2
-rw-r--r--tests/cleanup3.c2
-rw-r--r--tests/exception1.c453
-rw-r--r--tests/exception2.c120
-rw-r--r--tests/exception3.c164
-rw-r--r--tests/eyal1.c4
21 files changed, 1080 insertions, 438 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index dee0d33..aa4dd3e 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -22,6 +22,8 @@ Todd Owen towen@lucidcalm.dropbear.id.au
Jason Nye jnye@nbnet.nb.ca
Fred Forester fforest@eticomm.net
Kevin D. Clark kclark@cabletron.com
-David Baggett dmb.itasoftware.com
-Paul Redondo paul.matchvision.com
-Scott McCaskill scott.3dfx.om
+David Baggett dmb.itasoftware.com
+Paul Redondo paul.matchvision.com
+Scott McCaskill scott.3dfx.om
+Thomas Pfaff tpfaff@gmx.net
+Franco Bez ???
diff --git a/ChangeLog b/ChangeLog
index 5bb5109..01dbd10 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+2000-12-28 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * 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
+ set_terminate() to override the default behaviour which is
+ to call ptw32_terminate(). Ptw32_terminate() cleans up some
+ POSIX thread stuff before calling the system default function
+ which calls abort(). The users termination function should conform
+ to standard C++ semantics which is to not return. It should
+ exit the thread (call pthread_exit()) or exit the application.
+ * private.c (ptw32_terminate): Added as the default set_terminate()
+ function. It calls the system default function after cleaning up
+ some POSIX thread stuff.
+
+ * implement.h (ptw32_try_enter_critical_section): Move
+ declaration.
+ * global.c (ptw32_try_enter_critical_section): Moved
+ from dll.c.
+ * dll.c: Move process and thread attach/detach code into
+ functions in nonportable.c.
+ * nonportable.c (pthread_win32_process_attach_np): Process
+ attach code from dll.c is now available to static linked
+ applications.
+ * nonportable.c (pthread_win32_process_detach_np): Likewise.
+ * nonportable.c (pthread_win32_thread_attach_np): Likewise.
+ * nonportable.c (pthread_win32_thread_detach_np): Likewise.
+
+ * pthread.h: Add new non-portable prototypes for static
+ linked applications.
+
+ * GNUmakefile (OPT): Increase optimisation flag and remove
+ debug info flag.
+
+ * pthread.def: Add new non-portable exports for static
+ linked applications.
+
+2000-12-11 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * FAQ: Update Answer 6 re getting a fully working
+ Mingw32 built library.
+
2000-09-13 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
* mutex.c (pthread_mutex_init): Call
@@ -7,6 +49,10 @@
function, eg. Windows 95
- "Jef Gearhart" <jgearhart@tpssys.com>
+2000-09-09 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * pthread.h (ctime_r): Fix arg.
+
2000-09-08 Ross Johnson <rpj@special.ise.canberra.edu.au>
* GNUmakefile(_WIN32_WINNT=0x400): Define in CFLAGS;
diff --git a/FAQ b/FAQ
index 6d8876c..5d19b86 100644
--- a/FAQ
+++ b/FAQ
@@ -16,7 +16,7 @@ Q 4 Cancelation doesn't work for me, why?
Q 5 Thread won't block after two calls to mutex_lock
-Q 6 How do I generate libpthread.a for use with Mingw32?
+Q 6 How do I generate pthreadGCE.dll and libpthreadw32.a for use with Mingw32?
=============================================================================
@@ -89,7 +89,8 @@ Q 2 Now that pthreads-win32 builds under Mingw32, why do I get
A 2
---
Note:
-The latest Mingw32 package now has thread-safe exception handling.
+The latest Mingw32 package has thread-safe exception handling.
+Make sure you also read A 6 below to get a fully working build.
The following email exchange describes the problem. Until this issue
is resolved people without the Microsoft compiler can obtain the current
@@ -207,7 +208,7 @@ A 4
> win32 programming, so I don't really understand how the *Event() family of
> calls work.
-Async cancelation should be in post-snapshot-1999-11-02 versions
+Async cancelation should be in versions post snapshot-1999-11-02
of pthreads-win32 (currently only for x86 architectures).
The answer to your first question is, normal POSIX behaviour would
@@ -241,6 +242,7 @@ recognise are those the library implements itself, ie.
pthread_cond_timedwait
pthread_join
sem_wait
+ pthread_delay_np
Pthreads-win32 also provides two functions that allow you to create
cancelation points within your application, but only for cases where
@@ -294,23 +296,88 @@ Ross
------------------------------------------------------------------------------
-Q 6 How do I generate libpthread.a for use with Mingw32?
+Q 6 How do I generate pthreadGCE.dll and libpthreadw32.a for use with Mingw32?
---
A 6
---
-> I'm lacking the libpthread.a that
-> used to come with the pre-compiled package. The last time this
-> library appeared was in 1999-08-12. Without this library I cannot
-> use the pre-compiled dll.
+Once you've followed Thomas Pfaff's instructions below to fix
+Mingw32, then you can simply run "make" to build the library and dll.
+
+
+From - Sat Dec 9 22:56:10 2000
+From: "Thomas Pfaff" <tpfaff@gmx.net>
+To: <mingw-users@lists.sourceforge.net>, <pthreads-win32@sources.redhat.com>
+Subject: mingw32 DLLs, threads and exceptions HOWTO
+Date: Thu, 7 Dec 2000 11:12:43 +0100
+
+Dear all,
+
+this is a summary that should help users to have thread safe exception
+handling over DLL exported functions.
+If you don't care about c++ exceptions you can stop reading here.
+
+The first time i struggled with c++ exceptions was when i tried to throw an
+exception in a dll exported function where the exception handler resides in
+the program module.
+Instead of catching the exception the program stopped with an abnormal
+termination.
+The reason was that the exception code is in libgcc.a. Since this is a
+static library the code and some static variables are both in the dll and in
+the program module, each module runs in its own context.
+It was Franco Bez that pointed me in the right direction, that is convert
+libgcc.a into a dll.
+
+That done i tried to build the pthreads-win32 library, but some tests failed
+with an access violation. Due to the fact that the dll was not build
+was -mthreads support, eh_context_static instead of eh_context_specific (the
+mthreads version) was used for exception handling.
+I did a rebuild of the gcc dll with -mthreads, now all tests are passed
+(except a nonportable exception test that relies on a MSVC feature).
+
+To build the gcc dll i did the following steps.
+
+1. create a temporary directory libgcc
+2. copy libgcc.a from gcc-2.95.2\lib\gcc-lib\i386-mingw32\gcc-2.95.2 to that
+directory
+3. ar -x libgcc.a
+4. create a directory tmp and move __main.o, _exit.o and __dummy.o in that
+directory
+5. build the dll
+gcc -shared -mthreads -o gcc.dll *.o
+strip gcc.dll
+Move this dll into your gcc\bin directory
+6. Move _chkstk.o and frame.o to the tmp directory, otherwise you break the
+builtin alloca.
+7. Build the import library libgcc.a
+dllwrap --export-all --dllname=gcc.dll --output-def=libgcc.def --output-lib=
+libgcc.a *.o
+ar -q libgcc.a tmp/*.o
+strip --strip-debug libgcc.a
+ranlib libgcc.a
+8. save your old libgcc.a, copy the new libgcc.a into
+gcc-2.95.2\lib\gcc-lib\i386-mingw32\gcc-2.95.2
+
+I am using gcc-2.95.2-1 with Mumits patched binutils-19990818-1and msvcrt
+runtime-2000-03-27.
+I don't know if this is still required with the current binutils and gcc
+since i have seen no sources until now.
+
+I believe that these steps are at least necessary if you are trying to use
+the pthreads-win32 library (which is required if you want to use gtk+ on
+win32).
+They will make mingw32 a real replacement for MSVC (at least for me).
+
+What is left:
+
+1. Include the mingwm10.dll function into the gcc.dll to have only one dll
+left.
+2. make -mthreads and -fnative-struct default compiler options.
+3. convert libstdc++ to a dll by adding the declspec dllexport and dllimport
+to every class definition.
-You can create libpthread.a from the .def file, should work along these
-lines:
-
-$(DLLTOOL) --as $(AS) -k --dllname libpthread.dll --output-lib
-libpthread.a --def $(srcdir)/libpthread.def
-
-Where DLLTOOL is i686-pc-cygwin-dlltool
-and AS i686-pc-cygwin-as.
+Regards,
+ Thomas
-Thomas Sailer <sailer@ife.ee.ethz.ch>
+------------------------------------------------------------------------------
+
diff --git a/GNUmakefile b/GNUmakefile
index 5710343..9ad6119 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -30,7 +30,8 @@ AR = ar
LD = gcc -mdll
-OPT = -g -O0
+#OPT = -g -O0
+OPT = -O3
## Mingw32
CFLAGS = $(OPT) -x $(GLANG) -I. -mthreads -D_WIN32_WINNT=0x400 -DHAVE_CONFIG_H -DPTW32_BUILD -Wall
diff --git a/README b/README
index 25792ca..93bf8cd 100644
--- a/README
+++ b/README
@@ -71,17 +71,6 @@ Known bugs in this snapshot
1. Asynchronous cancelation only works on Intel X86 machines.
-2. Running the test "join1.c" with the library built with Mingw32
-and the GNUmakefile included, the test fails with a segmentation (invalid
-page access) exception. The fault appears to be in the assembler code
-emmitted by the compiler [to handle exception contexts] at the
-end of the try block in ptw32_threadStart().
-
-3. There are problems using the libpthreadw32.a stub archive derived
-from either of pthreadVSE.dll or pthreadVCE.dll. The cleanup1.c test
-fails. This is now an expected result of having different EH and cleanup
-handler schemes in the library and application.
-
Caveats
-------
@@ -144,6 +133,34 @@ pthread_getw32threadhandle_np(pthread_t thread);
win32 specific attributes of the thread.
int
+pthread_delay_np (const struct timespec *interval);
+
+ This routine causes a thread to delay execution for a specific period of time.
+ This period ends at the current time plus the specified interval. The routine
+ will not return before the end of the period is reached, but may return an
+ arbitrary amount of time after the period has gone by. This can be due to
+ system load, thread priorities, and system timer granularity.
+
+ Specifying an interval of zero (0) seconds and zero (0) nanoseconds is
+ allowed and can be used to force the thread to give up the processor or to
+ deliver a pending cancelation request.
+
+ This routine is a cancelation point.
+
+ The timespec structure contains the following two fields:
+
+ tv_sec is an integer number of seconds.
+ tv_nsec is an integer number of nanoseconds.
+
+ Return Values
+
+ If an error condition occurs, this routine returns an integer value
+ indicating the type of error. Possible return values are as follows:
+
+ 0 Successful completion.
+ [EINVAL] The value specified by interval is invalid.
+
+int
pthreadCancelableWait (HANDLE waitHandle);
int
@@ -156,7 +173,7 @@ pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout);
pthread_cancel has been called. It is implemented using
WaitForMultipleObjects on 'waitHandle' and a manually
reset w32 event used to implement pthread_cancel.
-
+
Building under VC++ using either C++ EH or Structured EH
--------------------------------------------------------
@@ -182,20 +199,15 @@ nmake clean VSE
Building under Mingw32
----------------------
-The dll can be built with Mingw32 gcc-2.95.2 or later.
+The dll can be built with Mingw32 gcc-2.95.2-1 after you've
+made the changes to Mingw32 desribed in Question 6 of the FAQ.
+Hopefully versions after gcc-2.95.2-1 won't require the fix.
+
Run "make" in the source directory (uses GNUmakefile). This builds
pthreadGCE.dll and libpthreadw32.a.
-To generate the libpthreadw32.a file from pthreadVCE.dll rather than
-building the library with G++, run "make fake.a". (You must have
-pthreadVCE.dll already built - see above.)
-Please note that VC++ and GNU exception handling is implemented
-completely differently and so automatic cleanup of objects and
-the propagation of exceptions themselves between the two schemes is not
-going to happen.
-
You can run the testsuite by changing to the "tests" directory and
-running "make clean" and then "make". See the "Known bugs" section above.
+running "make clean" and then "make".
Building the library under Cygwin
diff --git a/dll.c b/dll.c
index 15c1bda..96552a3 100644
--- a/dll.c
+++ b/dll.c
@@ -27,22 +27,9 @@
#include "pthread.h"
#include "implement.h"
-
-/*
- * Function pointer to TryEnterCriticalSection if it exists; otherwise NULL
- */
-BOOL (WINAPI *ptw32_try_enter_critical_section)(LPCRITICAL_SECTION) = NULL;
-
-/*
- * We use this to double-check that TryEnterCriticalSection works.
- */
-CRITICAL_SECTION cs;
-
-/*
- * Handle to kernel32.dll
- */
-static HINSTANCE ptw32_h_kernel32;
-
+#if 1
+#include <stdio.h>
+#endif
#ifdef _MSC_VER
/*
@@ -79,110 +66,26 @@ DllMain (
{
case DLL_PROCESS_ATTACH:
- /*
- * The DLL is being mapped into the process's address space
- */
- result = ptw32_processInitialize ();
-
- /* Load KERNEL32 and try to get address of TryEnterCriticalSection */
- ptw32_h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL"));
- ptw32_try_enter_critical_section =
- (BOOL (PT_STDCALL *)(LPCRITICAL_SECTION))
-
-#if defined(NEED_UNICODE_CONSTS)
- GetProcAddress(ptw32_h_kernel32,
- (const TCHAR *)TEXT("TryEnterCriticalSection"));
-#else
- GetProcAddress(ptw32_h_kernel32,
- (LPCSTR) "TryEnterCriticalSection");
-#endif
-
- if (ptw32_try_enter_critical_section != NULL)
- {
- InitializeCriticalSection(&cs);
- if ((*ptw32_try_enter_critical_section)(&cs))
- {
- LeaveCriticalSection(&cs);
- }
- else
- {
- /*
- * Not really supported (Win98?).
- */
- ptw32_try_enter_critical_section = NULL;
- }
- DeleteCriticalSection(&cs);
- }
-
- if (ptw32_try_enter_critical_section == NULL)
- {
- /*
- * If TryEnterCriticalSection is not being used, then free
- * the kernel32.dll handle now, rather than leaving it until
- * DLL_PROCESS_DETACH.
- *
- * Note: this is not a pedantic exercise in freeing unused
- * resources! It is a work-around for a bug in Windows 95
- * (see microsoft knowledge base article, Q187684) which
- * does Bad Things when FreeLibrary is called within
- * the DLL_PROCESS_DETACH code, in certain situations.
- * Since w95 just happens to be a platform which does not
- * provide TryEnterCriticalSection, the bug will be
- * effortlessly avoided.
- */
- (void) FreeLibrary(ptw32_h_kernel32);
- ptw32_h_kernel32 = 0;
- }
+ result = pthread_win32_process_attach_np();
break;
case DLL_THREAD_ATTACH:
/*
* A thread is being created
*/
- result = TRUE;
+ result = pthread_win32_thread_attach_np();
break;
case DLL_THREAD_DETACH:
- case DLL_PROCESS_DETACH:
/*
* A thread is exiting cleanly
- * NOTE: The "main" thread detaches using
- * DLL_PROCESS_DETACH
*/
- {
- pthread_t self;
-
- if (ptw32_processInitialized)
- {
- self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey);
-
- /*
- * Detached threads have their resources automatically
- * cleaned up upon exit (others must be 'joined').
- */
- if (self != NULL &&
- self->detachState == PTHREAD_CREATE_DETACHED)
- {
- pthread_setspecific (ptw32_selfThreadKey, NULL);
- ptw32_threadDestroy (self);
- }
-
- if (fdwReason == DLL_PROCESS_DETACH)
- {
- /*
- * The DLL is being unmapped into the process's address space
- */
- ptw32_processTerminate ();
-
- if (ptw32_h_kernel32)
- {
- (void) FreeLibrary(ptw32_h_kernel32);
- }
- }
- }
+ result = pthread_win32_thread_detach_np();
+ break;
- result = TRUE;
- }
+ case DLL_PROCESS_DETACH:
+ (void) pthread_win32_thread_detach_np();
+ result = pthread_win32_process_detach_np();
break;
}
return (result);
diff --git a/global.c b/global.c
index a094459..128a17b 100644
--- a/global.c
+++ b/global.c
@@ -32,6 +32,11 @@ int ptw32_processInitialized = FALSE;
pthread_key_t ptw32_selfThreadKey = NULL;
pthread_key_t ptw32_cleanupKey = NULL;
+/*
+ * Function pointer to TryEnterCriticalSection if it exists; otherwise NULL
+ */
+BOOL (WINAPI *ptw32_try_enter_critical_section)(LPCRITICAL_SECTION) = NULL;
+
/*
* Global lock for testing internal state of PTHREAD_MUTEX_INITIALIZER
* created mutexes.
diff --git a/implement.h b/implement.h
index ed01bda..623e474 100644
--- a/implement.h
+++ b/implement.h
@@ -301,9 +301,6 @@ struct ThreadKeyAssoc {
#define PTW32_EPS_EXIT 1
-/* Function pointer to TryEnterCriticalSection if it exists; otherwise NULL */
-extern BOOL (WINAPI *ptw32_try_enter_critical_section)(LPCRITICAL_SECTION);
-
/* Declared in global.c */
extern int ptw32_processInitialized;
extern pthread_key_t ptw32_selfThreadKey;
@@ -311,6 +308,8 @@ extern pthread_key_t ptw32_cleanupKey;
extern CRITICAL_SECTION ptw32_mutex_test_init_lock;
extern CRITICAL_SECTION ptw32_cond_test_init_lock;
extern CRITICAL_SECTION ptw32_rwlock_test_init_lock;
+extern BOOL (WINAPI *ptw32_try_enter_critical_section)(LPCRITICAL_SECTION);
+
/* Declared in misc.c */
#ifdef NEED_CALLOC
diff --git a/nonportable.c b/nonportable.c
index 1eb5f04..49548dd 100644
--- a/nonportable.c
+++ b/nonportable.c
@@ -64,3 +64,211 @@ pthread_getw32threadhandle_np(pthread_t thread)
{
return (thread != NULL) ? (thread->threadH) : 0;
}
+
+
+/*
+ * Provide pthread_delay_np posix function for NT
+ *
+ * DESCRIPTION
+ *
+ * This routine causes a thread to delay execution for a specific period of time.
+ * This period ends at the current time plus the specified interval. The routine
+ * will not return before the end of the period is reached, but may return an
+ * arbitrary amount of time after the period has gone by. This can be due to
+ * system load, thread priorities, and system timer granularity.
+ *
+ * Specifying an interval of zero (0) seconds and zero (0) nanoseconds is
+ * allowed and can be used to force the thread to give up the processor or to
+ * deliver a pending cancelation request.
+ *
+ * The timespec structure contains the following two fields:
+ *
+ * tv_sec is an integer number of seconds.
+ * tv_nsec is an integer number of nanoseconds.
+ *
+ * Return Values
+ *
+ * If an error condition occurs, this routine returns an integer value indicating
+ * the type of error. Possible return values are as follows:
+ *
+ * 0
+ * Successful completion.
+ * [EINVAL]
+ * The value specified by interval is invalid.
+ *
+ * Example
+ *
+ * The following code segment would wait for 5 and 1/2 seconds
+ *
+ * struct timespec tsWait;
+ * int intRC;
+ *
+ * tsWait.tv_sec = 5;
+ * tsWait.tv_nsec = 500000000L;
+ * intRC = pthread_delay_np(&tsWait);
+ */
+
+int
+pthread_delay_np (struct timespec * interval)
+{
+ DWORD wait_time, secs_in_millisecs, millisecs;
+
+ /*
+ * We are a cancelation point.
+ */
+ pthread_testcancel();
+
+ if (interval->tv_sec < 0 || interval->tv_nsec < 0)
+ {
+ return (EINVAL);
+ }
+
+ secs_in_millisecs = interval->tv_sec * 1000L; /* convert secs to millisecs */
+
+ /*
+ * Pedantically, we're ensuring that we don't return before the time is up,
+ * even by a fraction of a millisecond.
+ */
+ millisecs = (interval->tv_nsec + 999999L) / 1000000L; /* convert nanosecs to millisecs */
+
+ wait_time = secs_in_millisecs + millisecs;
+
+ Sleep(wait_time);
+
+ pthread_testcancel();
+
+ return (0);
+}
+
+
+/*
+ * Handle to kernel32.dll
+ */
+static HINSTANCE ptw32_h_kernel32;
+
+
+BOOL
+pthread_win32_process_attach_np ()
+{
+ BOOL result = TRUE;
+
+ /*
+ * We use this to double-check that TryEnterCriticalSection works.
+ */
+ CRITICAL_SECTION cs;
+
+ result = ptw32_processInitialize ();
+
+ /*
+ * Load KERNEL32 and try to get address of TryEnterCriticalSection
+ */
+ ptw32_h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL"));
+ ptw32_try_enter_critical_section = (BOOL (PT_STDCALL *)(LPCRITICAL_SECTION))
+
+#if defined(NEED_UNICODE_CONSTS)
+ GetProcAddress(ptw32_h_kernel32,
+ (const TCHAR *)TEXT("TryEnterCriticalSection"));
+#else
+ GetProcAddress(ptw32_h_kernel32,
+ (LPCSTR) "TryEnterCriticalSection");
+#endif
+
+ if (ptw32_try_enter_critical_section != NULL)
+ {
+ InitializeCriticalSection(&cs);
+ if ((*ptw32_try_enter_critical_section)(&cs))
+ {
+ LeaveCriticalSection(&cs);
+ }
+ else
+ {
+ /*
+ * Not really supported (Win98?).
+ */
+ ptw32_try_enter_critical_section = NULL;
+ }
+ DeleteCriticalSection(&cs);
+ }
+
+ if (ptw32_try_enter_critical_section == NULL)
+ {
+ /*
+ * If TryEnterCriticalSection is not being used, then free
+ * the kernel32.dll handle now, rather than leaving it until
+ * DLL_PROCESS_DETACH.
+ *
+ * Note: this is not a pedantic exercise in freeing unused
+ * resources! It is a work-around for a bug in Windows 95
+ * (see microsoft knowledge base article, Q187684) which
+ * does Bad Things when FreeLibrary is called within
+ * the DLL_PROCESS_DETACH code, in certain situations.
+ * Since w95 just happens to be a platform which does not
+ * provide TryEnterCriticalSection, the bug will be
+ * effortlessly avoided.
+ */
+ (void) FreeLibrary(ptw32_h_kernel32);
+ ptw32_h_kernel32 = 0;
+ }
+
+ return result;
+}
+
+BOOL
+pthread_win32_process_detach_np ()
+{
+ if (ptw32_processInitialized)
+ {
+ pthread_t self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey);
+
+ /*
+ * Detached threads have their resources automatically
+ * cleaned up upon exit (others must be 'joined').
+ */
+ if (self != NULL &&
+ self->detachState == PTHREAD_CREATE_DETACHED)
+ {
+ pthread_setspecific (ptw32_selfThreadKey, NULL);
+ ptw32_threadDestroy (self);
+ }
+
+ /*
+ * The DLL is being unmapped into the process's address space
+ */
+ ptw32_processTerminate ();
+
+ if (ptw32_h_kernel32)
+ {
+ (void) FreeLibrary(ptw32_h_kernel32);
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL
+pthread_win32_thread_attach_np ()
+{
+ return TRUE;
+}
+
+BOOL
+pthread_win32_thread_detach_np ()
+{
+ if (ptw32_processInitialized)
+ {
+ pthread_t self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey);
+
+ /*
+ * Detached threads have their resources automatically
+ * cleaned up upon exit (others must be 'joined').
+ */
+ if (self != NULL &&
+ self->detachState == PTHREAD_CREATE_DETACHED)
+ {
+ pthread_setspecific (ptw32_selfThreadKey, NULL);
+ ptw32_threadDestroy (self);
+ }
+ }
+
+ return TRUE;
+} \ No newline at end of file
diff --git a/private.c b/private.c
index 0e94d5f..977eb67 100644
--- a/private.c
+++ b/private.c
@@ -154,22 +154,77 @@ ptw32_processTerminate (void)
} /* processTerminate */
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__cplusplus)
static DWORD
ExceptionFilter (EXCEPTION_POINTERS * ep, DWORD * ei)
{
- DWORD param;
- DWORD numParams = ep->ExceptionRecord->NumberParameters;
-
- numParams = (numParams > 3) ? 3 : numParams;
-
- for (param = 0; param < numParams; param++)
+ switch (ep->ExceptionRecord->ExceptionCode)
{
- ei[param] = ep->ExceptionRecord->ExceptionInformation[param];
+ case EXCEPTION_PTW32_SERVICES:
+ {
+ DWORD param;
+ DWORD numParams = ep->ExceptionRecord->NumberParameters;
+
+ numParams = (numParams > 3) ? 3 : numParams;
+
+ for (param = 0; param < numParams; param++)
+ {
+ ei[param] = ep->ExceptionRecord->ExceptionInformation[param];
+ }
+
+ return EXCEPTION_EXECUTE_HANDLER;
+ break;
+ }
+ default:
+ {
+ /*
+ * A system unexpected exception has occurred running the user's
+ * routine. We need to cleanup before letting the exception
+ * out of thread scope.
+ */
+ pthread_t self = pthread_self();
+
+ (void) pthread_mutex_destroy(&self->cancelLock);
+ ptw32_callUserDestroyRoutines(self);
+
+ return EXCEPTION_CONTINUE_SEARCH;
+ break;
+ }
}
+}
+
+#elif defined(__cplusplus)
+
+#if defined(_MSC_VER)
+#include <eh.h>
+static terminate_function ptw32_oldTerminate;
+#else
+#include <new.h>
+static terminate_handler ptw32_oldTerminate;
+#endif
- return EXCEPTION_EXECUTE_HANDLER;
+#if 0
+#include <stdio.h>
+static pthread_mutex_t termLock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+void
+ptw32_terminate ()
+{
+ pthread_t self = pthread_self();
+#if 0
+ FILE * fp;
+ pthread_mutex_lock(&termLock);
+ fp = fopen("pthread.log", "a");
+ fprintf(fp, "Terminate\n");
+ fclose(fp);
+ pthread_mutex_unlock(&termLock);
+#endif
+ set_terminate(ptw32_oldTerminate);
+ (void) pthread_mutex_destroy(&self->cancelLock);
+ ptw32_callUserDestroyRoutines(self);
+ terminate();
}
#endif /* _MSC_VER */
@@ -189,7 +244,7 @@ ptw32_threadStart (ThreadParms * threadParms)
DWORD ei[] = {0,0,0};
#endif
- void * status;
+ void * status = (void *) 0;
self = threadParms->tid;
start = threadParms->start;
@@ -226,53 +281,64 @@ ptw32_threadStart (ThreadParms * threadParms)
}
__except (ExceptionFilter(GetExceptionInformation(), ei))
{
- DWORD ec = GetExceptionCode();
-
- if (ec == EXCEPTION_PTW32_SERVICES)
- {
- switch (ei[0])
- {
- case PTW32_EPS_CANCEL:
- status = PTHREAD_CANCELED;
- break;
- case PTW32_EPS_EXIT:
- status = self->exitStatus;
- break;
- default:
- status = PTHREAD_CANCELED;
+ switch (ei[0])
+ {
+ case PTW32_EPS_CANCEL:
+ status = PTHREAD_CANCELED;
break;
- }
- }
- else
- {
- /*
- * A system unexpected exception had occurred running the user's
- * routine. We get control back within this block because
- * we can't allow the exception to pass out of thread scope.
- */
- status = PTHREAD_CANCELED;
- }
+ case PTW32_EPS_EXIT:
+ status = self->exitStatus;
+ break;
+ default:
+ status = PTHREAD_CANCELED;
+ break;
+ }
}
#else /* _MSC_VER && !__cplusplus */
#ifdef __cplusplus
+ ptw32_oldTerminate = set_terminate(&ptw32_terminate);
+
try
{
/*
- * Run the caller's routine;
+ * Run the caller's routine in a nested try block so that we
+ * can run the user's terminate function, which may call
+ * pthread_exit() or be canceled.
*/
- status = self->exitStatus = (*start) (arg);
+ try
+ {
+ status = self->exitStatus = (*start) (arg);
+ }
+ catch (ptw32_exception &)
+ {
+ /*
+ * Pass these through to the outer block.
+ */
+ throw;
+ }
+ catch(...)
+ {
+ /*
+ * We want to run the user's terminate function if supplied.
+ * That function may call pthread_exit() or be canceled, which will
+ * be handled by the outer try block.
+ *
+ * ptw32_terminate() will be called if there is no user supplied function.
+ */
+ (void) terminate();
+ }
}
- catch (ptw32_exception_cancel)
+ catch (ptw32_exception_cancel &)
{
/*
* Thread was cancelled.
*/
status = self->exitStatus = PTHREAD_CANCELED;
}
- catch (ptw32_exception_exit)
+ catch (ptw32_exception_exit &)
{
/*
* Thread was exited via pthread_exit().
@@ -282,11 +348,18 @@ ptw32_threadStart (ThreadParms * threadParms)
catch (...)
{
/*
- * A system unexpected exception had occurred running the user's
- * routine. We get control back within this block because
- * we can't allow the exception out of thread scope.
+ * A system unexpected exception has occurred running the user's
+ * terminate routine. We get control back within this block - cleanup
+ * and release the exception out of thread scope.
*/
status = self->exitStatus = PTHREAD_CANCELED;
+ (void) pthread_mutex_destroy(&self->cancelLock);
+ ptw32_callUserDestroyRoutines(self);
+ throw;
+
+ /*
+ * Never reached.
+ */
}
#else /* __cplusplus */
diff --git a/pthread.def b/pthread.def
index 395f156..9371ce9 100644
--- a/pthread.def
+++ b/pthread.def
@@ -1,5 +1,5 @@
; pthread.def
-; Last updated: $Date: 2000/08/18 08:02:29 $
+; Last updated: $Date: 2000/12/28 05:32:07 $
; Currently unimplemented functions are commented out.
@@ -103,8 +103,14 @@ pthread_rwlock_unlock
;
pthread_mutexattr_setforcecs_np
pthread_getw32threadhandle_np
+pthread_delay_np
pthreadCancelableWait
pthreadCancelableTimedWait
+; For use when linking statically
+pthread_win32_process_attach_np
+pthread_win32_process_detach_np
+pthread_win32_thread_attach_np
+pthread_win32_thread_detach_np
;
; Needed if !defined(_MSC_VER) && !defined(__cplusplus)
;
diff --git a/pthread.h b/pthread.h
index b0c9946..e5a3a3e 100644
--- a/pthread.h
+++ b/pthread.h
@@ -230,8 +230,8 @@
#ifndef HAVE_STRUCT_TIMESPEC
struct timespec {
- int tv_sec;
- int tv_nsec;
+ long tv_sec;
+ long tv_nsec;
};
#endif /* HAVE_STRUCT_TIMESPEC */
@@ -724,12 +724,6 @@ struct ptw32_cleanup_t
*/
/*
- * Useful if an application wants to statically link
- * the lib rather than load the DLL at run-time.
- */
-int pthread_win32_initialize_np(void);
-
-/*
* PThread Attribute Functions
*/
int pthread_attr_init (pthread_attr_t * attr);
@@ -902,14 +896,29 @@ int pthread_rwlock_wrlock(pthread_rwlock_t *lock);
int pthread_rwlock_unlock(pthread_rwlock_t *lock);
+
/*
* Non-portable functions
*/
+
+/* Possibly supported by other POSIX threads implimentations */
+int pthread_delay_np (struct timespec * interval);
+
+/* Pthread Win32 specific */
int pthread_mutexattr_setforcecs_np(pthread_mutexattr_t *attr,
int forcecs);
HANDLE pthread_getw32threadhandle_np(pthread_t thread);
+/*
+ * Useful if an application wants to statically link
+ * the lib rather than load the DLL at run-time.
+ */
+int pthread_win32_process_attach_np(void);
+int pthread_win32_process_detach_np(void);
+int pthread_win32_thread_attach_np(void);
+int pthread_win32_thread_detach_np(void);
+
/*
* Protected Methods
@@ -955,7 +964,7 @@ int * _errno( void );
(_buf) )
#define ctime_r( _clock, _buf ) \
- ( strcpy( (_buf), ctime( (_tm) ) ), \
+ ( strcpy( (_buf), ctime( (_clock) ) ), \
(_buf) )
#define gmtime_r( _clock, _result ) \
diff --git a/tests/ChangeLog b/tests/ChangeLog
index a809dca..db66602 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,22 @@
+2000-12-28 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * eyal1.c: Increase thread work loads.
+ * exception2.c: New test.
+ * exception3.c: New test.
+ * Makefile: Add new tests exception2.c and exception3.c.
+ * GNUmakefile: Likewise.
+
+2000-12-11 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * cleanup3.c: Remove unused variable.
+ * cleanup2.c: Likewise.
+ * exception1.c: Throw an exception rather than use
+ a deliberate zero divide so that catch(...) will
+ handle it under Mingw32. Mingw32 now builds the
+ library correctly to pass all tests - see Thomas
+ Pfaff's detailed instructions re needed changes
+ to Mingw32 in the Pthreads-Win32 FAQ.
+
2000-09-08 Ross Johnson <rpj@special.ise.canberra.edu.au>
* cancel5.c: New; tests calling pthread_cancel()
diff --git a/tests/GNUmakefile b/tests/GNUmakefile
index a775e10..7b4fd64 100644
--- a/tests/GNUmakefile
+++ b/tests/GNUmakefile
@@ -3,6 +3,7 @@
CP = copy
+MV = rename
RM = erase
MKDIR = mkdir
TOUCH = echo Passed >
@@ -13,7 +14,8 @@ ECHO = @echo
#
GLANG = c++
CC = gcc
-CFLAGS = -g -O0 -mthreads -UNDEBUG -Wall -x $(GLANG)
+#CFLAGS = -g -O0 -mthreads -UNDEBUG -Wall -x $(GLANG)
+CFLAGS = -O3 -mthreads -UNDEBUG -Wall -x $(GLANG)
BUILD_DIR = ..
INCLUDES = -I.
LIBS = -L. -lpthreadw32
@@ -37,7 +39,7 @@ TESTS = loadfree \
rwlock1 rwlock2 rwlock3 rwlock4 rwlock5 rwlock6 \
context1 cancel3 cancel4 cancel5 \
cleanup0 cleanup1 cleanup2 cleanup3 \
- exception1
+ exception1 exception2 exception3
PASSES = $(TESTS:%=%.pass)
@@ -89,7 +91,10 @@ cleanup1.pass: cleanup0.pass
cleanup2.pass: cleanup1.pass
cleanup3.pass: cleanup2.pass
exception1.pass: cancel4.pass
+exception2.pass: exception1.pass
+exception3.pass: exception2.pass
+#%.pass: %.exe $(HDR)
%.pass: %.exe $(LIB) $(DLL) $(HDR)
$*
@ $(ECHO) Passed
diff --git a/tests/Makefile b/tests/Makefile
index 41e202c..208b438 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -49,7 +49,7 @@ PASSES= loadfree.pass \
context1.pass \
cancel3.pass cancel4.pass cancel5.pass \
cleanup0.pass cleanup1.pass cleanup2.pass cleanup3.pass \
- exception1.pass
+ exception1.pass exception2.pass exception3.pass
all:
@ $(ECHO) Run one of the following command lines:
@@ -146,3 +146,5 @@ cleanup1.pass: cleanup0.pass
cleanup2.pass: cleanup1.pass
cleanup3.pass: cleanup2.pass
exception1.pass: cancel4.pass
+exception2.pass: exception1.pass
+exception3.pass: exception2.pass
diff --git a/tests/cleanup2.c b/tests/cleanup2.c
index 6d07d53..3c5e039 100644
--- a/tests/cleanup2.c
+++ b/tests/cleanup2.c
@@ -60,8 +60,6 @@ struct bag_t_ {
static bag_t threadbag[NUMTHREADS + 1];
-static pthread_mutex_t waitLock = PTHREAD_MUTEX_INITIALIZER;
-
static int pop_count = 0;
static void
diff --git a/tests/cleanup3.c b/tests/cleanup3.c
index 56b1a8f..1e24acf 100644
--- a/tests/cleanup3.c
+++ b/tests/cleanup3.c
@@ -61,8 +61,6 @@ struct bag_t_ {
static bag_t threadbag[NUMTHREADS + 1];
-static pthread_mutex_t waitLock = PTHREAD_MUTEX_INITIALIZER;
-
static int pop_count = 0;
static void
diff --git a/tests/exception1.c b/tests/exception1.c
index 609e5ed..1452d1a 100644
--- a/tests/exception1.c
+++ b/tests/exception1.c
@@ -1,224 +1,229 @@
-/*
- * File: exception1.c
- *
- * Test Synopsis: Test passing of exceptions back to the application.
- *
- * 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
-};
-
-void *
-exceptionedThread(void * arg)
-{
- int result = ((int)PTHREAD_CANCELED + 1);
- int one = 1;
- int zero = 0;
- int dummy = 0;
-
- /* Set to async cancelable */
-
- assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0);
-
- assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0);
-
- Sleep(100);
-
-#if defined(_MSC_VER) && !defined(__cplusplus)
- __try
- {
- /* Avoid being optimised out */
- if (dummy == one/zero)
- Sleep(0);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- /* Should get into here. */
- result = ((int)PTHREAD_CANCELED + 2);
- }
-#elif defined(__cplusplus)
- try
- {
- /* Avoid being optimised out */
- if (dummy == one/zero)
- Sleep(0);
- }
-#if defined(PtW32CatchAll)
- PtW32CatchAll
-#else
- catch (...)
-#endif
- {
- /* Should get into here. */
- result = ((int)PTHREAD_CANCELED + 2);
- }
-#endif
-
- return (void *) result;
-}
-
-void *
-canceledThread(void * arg)
-{
- int result = ((int)PTHREAD_CANCELED + 1);
- int count;
-
- /* Set to async cancelable */
-
- assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0);
-
- assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0);
-
-#if defined(_MSC_VER) && !defined(__cplusplus)
- __try
- {
- /*
- * We wait up to 10 seconds, waking every 0.1 seconds,
- * for a cancelation to be applied to us.
- */
- for (count = 0; count < 100; count++)
- Sleep(100);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- /* Should NOT get into here. */
- result = ((int)PTHREAD_CANCELED + 2);
- }
-#elif defined(__cplusplus)
- try
- {
- /*
- * We wait up to 10 seconds, waking every 0.1 seconds,
- * for a cancelation to be applied to us.
- */
- for (count = 0; count < 100; count++)
- Sleep(100);
- }
-#if defined(PtW32CatchAll)
- PtW32CatchAll
-#else
- catch (...)
-#endif
- {
- /* Should NOT get into here. */
- result = ((int)PTHREAD_CANCELED + 2);
- }
-#endif
-
- return (void *) result;
-}
-
-int
-main()
-{
- int failed = 0;
- int i;
- pthread_t mt;
- pthread_t et[NUMTHREADS];
- pthread_t ct[NUMTHREADS];
-
- assert((mt = pthread_self()) != NULL);
-
- for (i = 0; i < NUMTHREADS; i++)
- {
- assert(pthread_create(&et[i], NULL, exceptionedThread, NULL) == 0);
- assert(pthread_create(&ct[i], NULL, canceledThread, NULL) == 0);
- }
-
- /*
- * Code to control or munipulate child threads should probably go here.
- */
- Sleep(500);
-
- for (i = 0; i < NUMTHREADS; i++)
- {
- assert(pthread_cancel(ct[i]) == 0);
- }
-
- /*
- * Give threads time to run.
- */
- Sleep(NUMTHREADS * 100);
-
- /*
- * Check any results here. Set "failed" and only print output on failure.
- */
- failed = 0;
- for (i = 0; i < NUMTHREADS; i++)
- {
- int fail = 0;
- int result = 0;
-
- /* Canceled thread */
- assert(pthread_join(ct[i], (void **) &result) == 0);
- fail = (result != (int) PTHREAD_CANCELED);
-
- failed = (failed || fail);
-
- /* Exception thread */
- assert(pthread_join(et[i], (void **) &result) == 0);
- fail = (result != ((int) PTHREAD_CANCELED + 2));
-
- failed = (failed || fail);
- }
-
- assert(!failed);
-
- /*
- * Success.
- */
- return 0;
-}
-
-#else /* defined(_MSC_VER) || defined(__cplusplus) */
-
-int
-main()
-{
- fprintf(stderr, "Test N/A for this compiler environment.\n");
- return 0;
-}
-
-#endif /* defined(_MSC_VER) || defined(__cplusplus) */
+/*
+ * File: exception1.c
+ *
+ * Test Synopsis: Test passing of exceptions back to the application.
+ *
+ * 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
+};
+
+void *
+exceptionedThread(void * arg)
+{
+ int dummy = 0;
+ int result = ((int)PTHREAD_CANCELED + 1);
+ /* Set to async cancelable */
+
+ assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0);
+
+ assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0);
+
+ Sleep(100);
+
+#if defined(_MSC_VER) && !defined(__cplusplus)
+ __try
+ {
+ int zero = 0;
+ int one = 1;
+ /*
+ * The deliberate exception condition (zero devide) is
+ * in an "if" to avoid being optimised out.
+ */
+ if (dummy == one/zero)
+ Sleep(0);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Should get into here. */
+ result = ((int)PTHREAD_CANCELED + 2);
+ }
+#elif defined(__cplusplus)
+ try
+ {
+ /*
+ * I had a zero divide exception here but it
+ * wasn't being caught by the catch(...)
+ * below under Mingw32. That could be a problem.
+ */
+ throw dummy;
+ }
+#if defined(PtW32CatchAll)
+ PtW32CatchAll
+#else
+ catch (...)
+#endif
+ {
+ /* Should get into here. */
+ result = ((int)PTHREAD_CANCELED + 2);
+ }
+#endif
+
+ return (void *) result;
+}
+
+void *
+canceledThread(void * arg)
+{
+ int result = ((int)PTHREAD_CANCELED + 1);
+ int count;
+
+ /* Set to async cancelable */
+
+ assert(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) == 0);
+
+ assert(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL) == 0);
+
+#if defined(_MSC_VER) && !defined(__cplusplus)
+ __try
+ {
+ /*
+ * We wait up to 10 seconds, waking every 0.1 seconds,
+ * for a cancelation to be applied to us.
+ */
+ for (count = 0; count < 100; count++)
+ Sleep(100);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Should NOT get into here. */
+ result = ((int)PTHREAD_CANCELED + 2);
+ }
+#elif defined(__cplusplus)
+ try
+ {
+ /*
+ * We wait up to 10 seconds, waking every 0.1 seconds,
+ * for a cancelation to be applied to us.
+ */
+ for (count = 0; count < 100; count++)
+ Sleep(100);
+ }
+#if defined(PtW32CatchAll)
+ PtW32CatchAll
+#else
+ catch (...)
+#endif
+ {
+ /* Should NOT get into here. */
+ result = ((int)PTHREAD_CANCELED + 2);
+ }
+#endif
+
+ return (void *) result;
+}
+
+int
+main()
+{
+ int failed = 0;
+ int i;
+ pthread_t mt;
+ pthread_t et[NUMTHREADS];
+ pthread_t ct[NUMTHREADS];
+
+ assert((mt = pthread_self()) != NULL);
+
+ for (i = 0; i < NUMTHREADS; i++)
+ {
+ assert(pthread_create(&et[i], NULL, exceptionedThread, NULL) == 0);
+ assert(pthread_create(&ct[i], NULL, canceledThread, NULL) == 0);
+ }
+
+ /*
+ * Code to control or munipulate child threads should probably go here.
+ */
+ Sleep(1000);
+
+ for (i = 0; i < NUMTHREADS; i++)
+ {
+ assert(pthread_cancel(ct[i]) == 0);
+ }
+
+ /*
+ * Give threads time to run.
+ */
+ Sleep(NUMTHREADS * 1000);
+
+ /*
+ * Check any results here. Set "failed" and only print output on failure.
+ */
+ failed = 0;
+ for (i = 0; i < NUMTHREADS; i++)
+ {
+ int fail = 0;
+ int result = 0;
+
+ /* Canceled thread */
+ assert(pthread_join(ct[i], (void **) &result) == 0);
+ assert(!(fail = (result != (int) PTHREAD_CANCELED)));
+
+ failed = (failed || fail);
+
+ /* Exceptioned thread */
+ assert(pthread_join(et[i], (void **) &result) == 0);
+ assert(!(fail = (result != ((int) PTHREAD_CANCELED + 2))));
+
+ failed = (failed || fail);
+ }
+
+ assert(!failed);
+
+ /*
+ * Success.
+ */
+ return 0;
+}
+
+#else /* defined(_MSC_VER) || defined(__cplusplus) */
+
+int
+main()
+{
+ fprintf(stderr, "Test N/A for this compiler environment.\n");
+ return 0;
+}
+
+#endif /* defined(_MSC_VER) || defined(__cplusplus) */
diff --git a/tests/exception2.c b/tests/exception2.c
new file mode 100644
index 0000000..da3d3b4
--- /dev/null
+++ b/tests/exception2.c
@@ -0,0 +1,120 @@
+/*
+ * File: exception2.c
+ *
+ * Test Synopsis: Test passing of exceptions out of thread scope.
+ *
+ * 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 <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.
+ */
+enum {
+ NUMTHREADS = 1
+};
+
+
+void *
+exceptionedThread(void * arg)
+{
+ int dummy = 0x1;
+
+#if defined(_MSC_VER) && !defined(__cplusplus)
+
+ RaiseException(dummy, 0, 0, NULL);
+
+#elif defined(__cplusplus)
+
+ throw dummy;
+
+#endif
+
+ return (void *) 100;
+}
+
+int
+main(int argc, char argv[])
+{
+ int i;
+ pthread_t mt;
+ pthread_t et[NUMTHREADS];
+
+ if (argc <= 1)
+ {
+ int result;
+
+ printf("You should see an \"abnormal termination\" message\n");
+ fflush(stdout);
+ result = system("exception2.exe die");
+ exit(0);
+ }
+
+ assert((mt = pthread_self()) != NULL);
+
+ for (i = 0; i < NUMTHREADS; i++)
+ {
+ assert(pthread_create(&et[i], NULL, exceptionedThread, NULL) == 0);
+ }
+
+ Sleep(1000);
+
+ /*
+ * Success.
+ */
+ return 0;
+}
+
+#else /* defined(_MSC_VER) || defined(__cplusplus) */
+
+int
+main()
+{
+ fprintf(stderr, "Test N/A for this compiler environment.\n");
+ return 0;
+}
+
+#endif /* defined(_MSC_VER) || defined(__cplusplus) */
diff --git a/tests/exception3.c b/tests/exception3.c
new file mode 100644
index 0000000..b820b4b
--- /dev/null
+++ b/tests/exception3.c
@@ -0,0 +1,164 @@
+/*
+ * File: exception3.c
+ *
+ * Test Synopsis: Test running of user supplied teerminate() function.
+ *
+ * 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 <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.
+ */
+enum {
+ NUMTHREADS = 20
+};
+
+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
+ {
+ FILE * fp = fopen("pthread.log", "a");
+ fprintf(fp, "Caught = %d\n", caught);
+ fclose(fp);
+ }
+#endif
+ pthread_mutex_unlock(&caughtLock);
+ pthread_exit((void *) 0);
+}
+
+#endif
+
+void *
+exceptionedThread(void * arg)
+{
+ int dummy = 0x1;
+
+ {
+#if defined(_MSC_VER) && !defined(__cplusplus)
+
+ RaiseException(dummy, 0, 0, NULL);
+
+#elif defined(__cplusplus)
+
+ (void) set_terminate(&terminateFunction);
+
+ throw dummy;
+
+#endif
+ }
+
+ return (void *) 100;
+}
+
+int
+main()
+{
+ int i;
+ pthread_t mt;
+ pthread_t et[NUMTHREADS];
+
+ 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
+
+ Sleep(30000);
+ }
+
+ printf("Caught = %d\n", caught);
+ assert(caught == NUMTHREADS);
+
+ /*
+ * Success.
+ */
+ return 0;
+}
+
+#else /* defined(_MSC_VER) || defined(__cplusplus) */
+
+int
+main()
+{
+ fprintf(stderr, "Test N/A for this compiler environment.\n");
+ return 0;
+}
+
+#endif /* defined(_MSC_VER) || defined(__cplusplus) */
diff --git a/tests/eyal1.c b/tests/eyal1.c
index 843cb33..a9ba909 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 = 14;
-static int nwork = 100;
+static int nthreads = 10;
+static int nwork = 1000;
static int quiet = 0;
static int todo = -1;