diff options
| -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; | 
