diff options
author | rpj <rpj> | 2000-12-28 05:32:07 +0000 |
---|---|---|
committer | rpj <rpj> | 2000-12-28 05:32:07 +0000 |
commit | c94735ecdde19c4de652efd144faeec1a729b1e0 (patch) | |
tree | 1780c2bfe14e0b41931d85f6a5ed2f5e2695b6b2 | |
parent | 548fc29a8cc3fd016eba997facc9566af8fd2d75 (diff) |
./ChangeLog:
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-09 Ross Johnson <rpj@special.ise.canberra.edu.au>
* pthread.h (ctime_r): Fix arg.
./tests/ChangeLog:
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.
-rw-r--r-- | CONTRIBUTORS | 8 | ||||
-rw-r--r-- | ChangeLog | 46 | ||||
-rw-r--r-- | FAQ | 101 | ||||
-rw-r--r-- | GNUmakefile | 3 | ||||
-rw-r--r-- | README | 56 | ||||
-rw-r--r-- | dll.c | 117 | ||||
-rw-r--r-- | global.c | 5 | ||||
-rw-r--r-- | implement.h | 5 | ||||
-rw-r--r-- | nonportable.c | 208 | ||||
-rw-r--r-- | private.c | 157 | ||||
-rw-r--r-- | pthread.def | 8 | ||||
-rw-r--r-- | pthread.h | 27 | ||||
-rw-r--r-- | tests/ChangeLog | 19 | ||||
-rw-r--r-- | tests/GNUmakefile | 9 | ||||
-rw-r--r-- | tests/Makefile | 4 | ||||
-rw-r--r-- | tests/cleanup2.c | 2 | ||||
-rw-r--r-- | tests/cleanup3.c | 2 | ||||
-rw-r--r-- | tests/exception1.c | 453 | ||||
-rw-r--r-- | tests/exception2.c | 120 | ||||
-rw-r--r-- | tests/exception3.c | 164 | ||||
-rw-r--r-- | tests/eyal1.c | 4 |
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 ???
@@ -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; @@ -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 @@ -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
@@ -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); @@ -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 @@ -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)
;
@@ -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; |