summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrpj <rpj>2000-07-25 16:14:23 +0000
committerrpj <rpj>2000-07-25 16:14:23 +0000
commite2fd6e2de322cc12d9153da548ab76379049c11c (patch)
tree0e055e3496bbe45a4003d3e140e09a763d116fda
parentb035ed05977fdef5ced4691028284b7f0ebaba19 (diff)
2000-07-25 Ross Johnson <rpj@special.ise.canberra.edu.au>
* sched.c (sched_get_priority_max): Handle different WinCE and Win32 priority values together. (sched_get_priority_min): Ditto. - Tristan Savatier <tristan@mpegtv.com> * create.c (pthread_create): Force new threads to wait until pthread_create has the new thread's handle; we also retain a local copy of the handle for internal use until pthread_create returns. * private.c (_pthread_threadStart): Initialise ei[]. (_pthread_threadStart): When beginthread is used to start the thread, force waiting until the creator thread had the thread handle. * cancel.c (_pthread_cancel_thread): Include context switch code for defined(_X86_) environments in addition to _M_IX86. * rwlock.c (pthread_rwlock_destroy): Assignment changed to avoid compiler warning. * private.c (_pthread_get_exception_services_code): Cast NULL return value to avoid compiler warning. * cleanup.c (pthread_pop_cleanup): Initialise "cleanup" variable to avoid compiler warnings. * misc.c (_pthread_new): Change "new" variable to "t" to avoid confusion with the C++ keyword of the same name. * condvar.c (cond_wait_cleanup): Initialise lastWaiter variable. (cond_timedwait): Remove unused local variables. to avoid compiler warnings. * dll.c (dllMain): Remove 2000-07-21 change - problem appears to be in pthread_create(). 2000-07-22 Ross Johnson <rpj@special.ise.canberra.edu.au> * tsd.c (pthread_key_create): If a destructor was given and the pthread_mutex_init failed, then would try to reference a NULL pointer (*key); eliminate this section of code by using a dynamically initialised mutex (PTHREAD_MUTEX_INITIALIZER). * tsd.c (pthread_setspecific): Return an error if unable to set the value; simplify cryptic conditional. * tsd.c (pthread_key_delete): Locking threadsLock relied on mutex_lock returning an error if the key has no destructor. ThreadsLock is only initialised if the key has a destructor. Making this mutex a static could reduce the number of mutexes used by an application since it is actually created only at first use and it's often destroyed soon after. 2000-07-22 Ross Johnson <rpj@special.ise.canberra.edu.au> * FAQ: Added Q5 and Q6. tests/ChangeLog: 2000-07-25 Ross Johnson <rpj@special.ise.canberra.edu.au> * runtest.bat: modified to work under W98. * runall.bat: Add new tests; modified to work under W98. It was ok under NT. * Makefile: Add new tests. * exception1.c: New; Test passing exceptions back to the application and retaining library internal exceptions. * join0.c: New; Test a single join.
-rw-r--r--ChangeLog90
-rw-r--r--FAQ68
-rw-r--r--GNUmakefile140
-rw-r--r--Makefile12
-rw-r--r--README.WinCE13
-rw-r--r--TODO23
-rw-r--r--attr.c9
-rw-r--r--cancel.c14
-rw-r--r--cleanup.c19
-rw-r--r--condvar.c4
-rw-r--r--config.h16
-rw-r--r--config.h.in16
-rw-r--r--create.c44
-rw-r--r--dll.c6
-rw-r--r--implement.h2
-rw-r--r--misc.c16
-rw-r--r--mutex.c35
-rw-r--r--private.c34
-rw-r--r--pthread.h31
-rw-r--r--rwlock.c2
-rw-r--r--sched.c30
-rw-r--r--signal.c2
-rw-r--r--tests/ChangeLog14
-rw-r--r--tests/Makefile7
-rw-r--r--tests/cancel2.c3
-rw-r--r--tests/cancel3.c4
-rw-r--r--tests/cancel4.c2
-rw-r--r--tests/ccl.bat18
-rw-r--r--tests/join1.c13
-rw-r--r--tests/loadfree.c2
-rw-r--r--tests/runall.bat130
-rw-r--r--tests/runtest.bat150
-rw-r--r--tsd.c63
33 files changed, 695 insertions, 337 deletions
diff --git a/ChangeLog b/ChangeLog
index e1adedd..8a1a53c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,64 @@
-2000-07-25 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
+2000-07-25 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * sched.c (sched_get_priority_max): Handle different WinCE and
+ Win32 priority values together.
+ (sched_get_priority_min): Ditto.
+ - Tristan Savatier <tristan@mpegtv.com>
+
+ * create.c (pthread_create): Force new threads to wait until
+ pthread_create has the new thread's handle; we also retain
+ a local copy of the handle for internal use until
+ pthread_create returns.
+
+ * private.c (_pthread_threadStart): Initialise ei[].
+ (_pthread_threadStart): When beginthread is used to start the
+ thread, force waiting until the creator thread had the
+ thread handle.
+
+ * cancel.c (_pthread_cancel_thread): Include context switch
+ code for defined(_X86_) environments in addition to _M_IX86.
+
+ * rwlock.c (pthread_rwlock_destroy): Assignment changed
+ to avoid compiler warning.
+
+ * private.c (_pthread_get_exception_services_code): Cast
+ NULL return value to avoid compiler warning.
+
+ * cleanup.c (pthread_pop_cleanup): Initialise "cleanup" variable
+ to avoid compiler warnings.
+
+ * misc.c (_pthread_new): Change "new" variable to "t" to avoid
+ confusion with the C++ keyword of the same name.
+
+ * condvar.c (cond_wait_cleanup): Initialise lastWaiter variable.
+ (cond_timedwait): Remove unused local variables. to avoid
+ compiler warnings.
* dll.c (dllMain): Remove 2000-07-21 change - problem
appears to be in pthread_create().
+2000-07-22 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * tsd.c (pthread_key_create): If a destructor was given
+ and the pthread_mutex_init failed, then would try to
+ reference a NULL pointer (*key); eliminate this section of
+ code by using a dynamically initialised mutex
+ (PTHREAD_MUTEX_INITIALIZER).
+
+ * tsd.c (pthread_setspecific): Return an error if
+ unable to set the value; simplify cryptic conditional.
+
+ * tsd.c (pthread_key_delete): Locking threadsLock relied
+ on mutex_lock returning an error if the key has no destructor.
+ ThreadsLock is only initialised if the key has a destructor.
+ Making this mutex a static could reduce the number of mutexes
+ used by an application since it is actually created only at
+ first use and it's often destroyed soon after.
+
+2000-07-22 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * FAQ: Added Q5 and Q6.
+
2000-07-21 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
* create.c (pthread_create): Set threadH to 0 (zero)
@@ -29,6 +85,38 @@
* signal.c (pthread_sigmask): return an error value if
pthread_self() returns NULL.
+2000-03-02 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * attr.c (pthread_attr_init): Set default stacksize to zero (0)
+ rather than PTHREAD_STACK_MIN even though these are now the same.
+
+ * pthread.h (PTHREAD_STACK_MIN): Lowered to 0.
+
+2000-01-28 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * mutex.c (pthread_mutex_init): Free mutex if it has been alloced;
+ if critical sections can be used instead of Win32 mutexes, test
+ that the critical section works and return an error if not.
+
+2000-01-07 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * cleanup.c (pthread_pop_cleanup): Include SEH code only if MSC is not
+ compiling as C++.
+ (pthread_push_cleanup): Include SEH code only if MSC is not
+ compiling as C++.
+
+ * pthread.h: Include SEH code only if MSC is not
+ compiling as C++.
+
+ * implement.h: Include SEH code only if MSC is not
+ compiling as C++.
+
+ * cancel.c (_pthread_cancel_thread): Add _M_IX86 check.
+ (pthread_testcancel): Include SEH code only if MSC is not
+ compiling as C++.
+ (_pthread_cancel_self): Include SEH code only if MSC is not
+ compiling as C++.
+
2000-01-06 Ross Johnson <rpj@special.ise.canberra.edu.au>
* Makefile: Remove inconsistencies in 'cl' args
diff --git a/FAQ b/FAQ
index 426e92c..f6da212 100644
--- a/FAQ
+++ b/FAQ
@@ -14,6 +14,10 @@ Q 3 How do I use pthread.dll for Win32 (Visual C++ 5.0)
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 1 Should I use Cygwin or Mingw32 as a development environment?
@@ -253,3 +257,67 @@ a thread is going to block on a Win32 handle. These are:
Regards.
Ross
+------------------------------------------------------------------------------
+
+Q 5 Thread won't block after two calls to mutex_lock
+---
+
+A 5
+---
+
+> i was testing this pthread for win32 in my prog.
+> when i checked if it was blocking mutex_lock calls, i was surprised when it
+> didnt lock
+>
+> pthread_mutex_t DBlock;
+>
+> pthread_mutex_init( &DBlock, NULL );
+> pthread_mutex_lock( &DBlock );
+> pthread_mutex_lock( &DBlock );
+>
+> ^^ these two calls didnt block
+
+POSIX leaves the result "undefined" for a thread that tries
+to recursively lock the same mutex (one that it owns already).
+That means the actual semantics are left up to the
+implementation, but should not be relied upon for code that
+will be ported to different POSIX threads implementations.
+
+In the pthreads-win32 implementation a thread won't deadlock
+itself by relocking the mutex. Subsequent calls to
+pthread_mutex_lock() as in your example above increment
+the lock count but the thread continues on. Consequently,
+the thread must ensure that it unlocks the mutex once for
+each lock operation. That is, pthreads-win32 mutexes are
+always recursive.
+
+You may want to look at the other synchronisation devices
+available in the library, such as condition variables or
+read-write locks.
+
+Ross
+
+------------------------------------------------------------------------------
+
+Q 6 How do I generate libpthread.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.
+
+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.
+
+Thomas Sailer <sailer@ife.ee.ethz.ch>
+
diff --git a/GNUmakefile b/GNUmakefile
index f0d8982..4c94cc7 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -1,69 +1,71 @@
-#
-# Pthreads-win32 - POSIX Threads Library for Win32
-# Copyright (C) 1998
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Library General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Library General Public License for more details.
-#
-# You should have received a copy of the GNU Library General Public
-# License along with this library; if not, write to the Free
-# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
-# MA 02111-1307, USA
-#
-
-RM = erase
-
-CC = g++
-
-AR = ar
-
-LD = gcc -mdll
-
-OPT = -g -O2
-
-## Mingw32
-CFLAGS = $(OPT) -I. -DHAVE_CONFIG_H -Wall
-
-## Cygwin G++
-#CFLAGS = $(OPT) -fhandle-exceptions -I. -DHAVE_CONFIG_H -Wall
-
-OBJS = attr.o cancel.o cleanup.o condvar.o create.o dll.o errno.o \
- exit.o fork.o global.o misc.o mutex.o private.o rwlock.o \
- sched.o semaphore.o signal.o sync.o tsd.o
-
-INCL = implement.h semaphore.h pthread.h windows.h
-
-DLL = pthread.dll
-
-LIB = libpthread32.a
-
-
-all: $(LIB)
-
-$(LIB): $(DLL)
- dlltool --def $(DLL:.dll=.def) --output-lib $@ --dllname $(DLL)
-
-.SUFFIXES: .dll
-
-$(DLL): $(OBJS)
- $(LD) -o $@ $^ -Wl,--base-file,$*.base
- dlltool --base-file=$*.base --def $*.def --output-exp $*.exp --dllname $@
- $(LD) -o $@ $^ -Wl,--base-file,$*.base,$*.exp
- dlltool --base-file=$*.base --def $*.def --output-exp $*.exp --dllname $@
- $(LD) -o $@ $^ -Wl,$*.exp
-
-clean:
- -$(RM) *~
- -$(RM) $(LIB)
- -$(RM) *.o
- -$(RM) *.exe
- -$(RM) $(DLL)
- -$(RM) $(DLL:.dll=.base)
- -$(RM) $(DLL:.dll=.exp)
+#
+# Pthreads-win32 - POSIX Threads Library for Win32
+# Copyright (C) 1998
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+# MA 02111-1307, USA
+#
+
+GLANG = c++
+
+RM = erase
+
+CC = gcc
+
+AR = ar
+
+LD = gcc -mdll
+
+OPT = -g -O2 -x $(GLANG)
+
+## Mingw32
+CFLAGS = $(OPT) -I. -DHAVE_CONFIG_H -Wall
+
+## Cygwin G++
+#CFLAGS = $(OPT) -fhandle-exceptions -I. -DHAVE_CONFIG_H -Wall
+
+OBJS = attr.o cancel.o cleanup.o condvar.o create.o dll.o errno.o \
+ exit.o fork.o global.o misc.o mutex.o private.o rwlock.o \
+ sched.o semaphore.o signal.o sync.o tsd.o
+
+INCL = implement.h semaphore.h pthread.h windows.h
+
+DLL = pthread.dll
+
+LIB = libpthread32.a
+
+
+all: $(LIB)
+
+$(LIB): $(DLL)
+ dlltool --def $(DLL:.dll=.def) --output-lib $@ --dllname $(DLL)
+
+.SUFFIXES: .dll
+
+$(DLL): $(OBJS)
+ $(LD) -o $@ $^ -Wl,--base-file,$*.base
+ dlltool --base-file=$*.base --def $*.def --output-exp $*.exp --dllname $@
+ $(LD) -o $@ $^ -Wl,--base-file,$*.base,$*.exp
+ dlltool --base-file=$*.base --def $*.def --output-exp $*.exp --dllname $@
+ $(LD) -o $@ $^ -Wl,$*.exp
+
+clean:
+ -$(RM) *~
+ -$(RM) $(LIB)
+ -$(RM) *.o
+ -$(RM) *.exe
+ -$(RM) $(DLL)
+ -$(RM) $(DLL:.dll=.base)
+ -$(RM) $(DLL:.dll=.exp)
diff --git a/Makefile b/Makefile
index b5b10e5..1264af9 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,9 @@ DEVROOT=e:
DLLDEST=$(DEVROOT)\dll
LIBDEST=$(DEVROOT)\lib
-CLIB=/MD
+#CLIB = /MD
+CLIB = /MT
+CFLAGS = #/EHsc /TP
OBJ=attr.obj \
cancel.obj \
@@ -46,10 +48,14 @@ install: all
copy pthread.lib $(LIBDEST)
pthread.dll: $(OBJ) pthread.def
- cl /LDd /Zi $(CLIB) $(OBJ) /Fepthread.dll pthread.def
+ cl /LD /Zi $(CFLAGS) $(OBJ) /Fepthread.dll /link \
+ /nodefaultlib:libcmt \
+ /implib:pthread.lib \
+ msvcrt.lib \
+ /def:pthread.def
.c.obj::
- cl /W3 $(CLIB) /nologo /Yd /Zi /I. \
+ cl /W3 $(CLIB) $(CFLAGS) /nologo /Yd /Zi /I. \
/D_WIN32_WINNT=0x400 \
/DSTDCALL=_stdcall \
-c $<
diff --git a/README.WinCE b/README.WinCE
index 2d4212e..a2cd8c2 100644
--- a/README.WinCE
+++ b/README.WinCE
@@ -2,14 +2,5 @@ WinCE port
----------
(See the file WinCE-PORT for a detailed explanation.)
-In config.h:
-
-you need to define the following which are undefined by default:
-
-#define NEED_DUPLICATEHANDLE
-#define NEED_CREATETHREAD
-#define NEED_ERRNO
-#define NEED_CALLOC
-#define NEED_FTIME
-#define NEED_SEM
-
+Make sure you define "WINCE" amongst your compiler flags (eg. -DWINCE).
+The config.h file will define all the necessary defines for you.
diff --git a/TODO b/TODO
index fabce6d..32cd822 100644
--- a/TODO
+++ b/TODO
@@ -1,3 +1,20 @@
-- Check behaviour of calling pthread_exit from main().
- The main thread should wait for other threads to exit
- before calling exit.
+====
+Automate the build/test cycle so that I can
+expand to test both library and applications in different
+environments and cross-environments.
+
+Eg.
+ Applications | SEH | C++ | G++ | C | GCC |
+ Library | | | | | |
+ ----------------+-----+-----+-----+-----+-----+
+ SEH | X | X | X | X | X |
+ ----------------+-----+-----+-----+-----+-----+
+ C++ (MSC) | X | X | X | X | X |
+ ----------------+-----+-----+-----+-----+-----+
+ G++ (GNU) | ? | ? | X | ? | X |
+ ----------------+-----+-----+-----+-----+-----+
+
+'?' indicates combinations that may not be doable.
+
+====
+
diff --git a/attr.c b/attr.c
index fa7de12..84c35a5 100644
--- a/attr.c
+++ b/attr.c
@@ -84,7 +84,7 @@ pthread_attr_setstacksize(pthread_attr_t *attr,
{
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
- /* Verify that the stack size is within range. */
+ /* Verify that the stack size is within range. */
if (stacksize < PTHREAD_STACK_MIN)
{
return EINVAL;
@@ -324,7 +324,12 @@ pthread_attr_init(pthread_attr_t *attr)
}
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
- attr_result->stacksize = PTHREAD_STACK_MIN;
+ /*
+ * Default to zero size. Unless changed explicitly this
+ * will allow Win32 to set the size to that of the
+ * main thread.
+ */
+ attr_result->stacksize = 0;
#endif
#ifdef _POSIX_THREAD_ATTR_STACKADDR
diff --git a/cancel.c b/cancel.c
index b687c78..c072d44 100644
--- a/cancel.c
+++ b/cancel.c
@@ -30,7 +30,7 @@
static void
_pthread_cancel_self(void)
{
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__cplusplus)
DWORD exceptionInformation[3];
@@ -44,7 +44,7 @@ _pthread_cancel_self(void)
3,
exceptionInformation);
-#else /* _MSC_VER */
+#else /* _MSC_VER && ! __cplusplus */
# ifdef __cplusplus
@@ -52,7 +52,7 @@ _pthread_cancel_self(void)
# endif /* __cplusplus */
-#endif /* _MSC_VER */
+#endif /* _MSC_VER && ! __cplusplus */
/* Never reached */
}
@@ -72,11 +72,13 @@ _pthread_cancel_thread(pthread_t thread)
if (WaitForSingleObject(threadH, 0) == WAIT_TIMEOUT)
{
+#if defined(_M_IX86) || defined(_X86_)
CONTEXT context;
context.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(threadH, &context);
context.Eip = (DWORD) _pthread_cancel_self;
SetThreadContext(threadH, &context);
+#endif
ResumeThread(threadH);
}
@@ -292,7 +294,7 @@ pthread_testcancel (void)
* Canceling!
*/
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__cplusplus)
DWORD exceptionInformation[3];
@@ -306,7 +308,7 @@ pthread_testcancel (void)
3,
exceptionInformation);
-#else /* _MSC_VER */
+#else /* _MSC_VER && ! __cplusplus */
#ifdef __cplusplus
@@ -314,7 +316,7 @@ pthread_testcancel (void)
#endif /* __cplusplus */
-#endif /* _MSC_VER */
+#endif /* _MSC_VER && ! __cplusplus */
}
} /* pthread_testcancel */
diff --git a/cleanup.c b/cleanup.c
index b92d502..14ed0af 100644
--- a/cleanup.c
+++ b/cleanup.c
@@ -2,8 +2,9 @@
* cleanup.c
*
* Description:
- * This translation unit implements routines associated cleaning up
- * threads.
+ * This translation unit implements routines associated
+ * with cleaning up threads.
+ *
*
* Pthreads-win32 - POSIX Threads Library for Win32
* Copyright (C) 1998
@@ -33,6 +34,12 @@
#include "pthread.h"
#include "implement.h"
+/*
+ * The functions pthread_pop_cleanup and pthread_push_cleanup
+ * are implemented here for applications written in C with no
+ * SEH or C++ destructor support.
+ */
+
_pthread_cleanup_t *
pthread_pop_cleanup (int execute)
/*
@@ -60,7 +67,7 @@ pthread_pop_cleanup (int execute)
* ------------------------------------------------------
*/
{
- _pthread_cleanup_t *cleanup;
+ _pthread_cleanup_t *cleanup = NULL;
cleanup = (_pthread_cleanup_t *) pthread_getspecific (_pthread_cleanupKey);
@@ -69,7 +76,7 @@ pthread_pop_cleanup (int execute)
if (execute && (cleanup->routine != NULL))
{
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__cplusplus)
__try
{
@@ -87,7 +94,7 @@ pthread_pop_cleanup (int execute)
*/
}
-#else /* _MSC_VER */
+#else /* _MSC_VER && ! __cplusplus */
#ifdef __cplusplus
@@ -114,7 +121,7 @@ pthread_pop_cleanup (int execute)
*/
(*cleanup->routine) (cleanup->arg);
-#endif /* __cplusplus */
+#endif /* __cplusplus && ! __cplusplus */
#endif /* _MSC_VER */
diff --git a/condvar.c b/condvar.c
index 69ce69f..98f1f23 100644
--- a/condvar.c
+++ b/condvar.c
@@ -540,7 +540,7 @@ cond_wait_cleanup(void * args)
pthread_cond_t cv = cleanup_args->cv;
int * resultPtr = cleanup_args->resultPtr;
int lock_result;
- int lastWaiter;
+ int lastWaiter = FALSE;
if ((lock_result = pthread_mutex_lock (&(cv->waitersLock))) == 0)
{
@@ -590,8 +590,6 @@ cond_timedwait (pthread_cond_t * cond,
const struct timespec *abstime)
{
int result = 0;
- int internal_result = 0;
- int lastWaiter = FALSE;
pthread_cond_t cv;
cond_wait_cleanup_args_t cleanup_args;
diff --git a/config.h b/config.h
index 41f703f..acea758 100644
--- a/config.h
+++ b/config.h
@@ -23,3 +23,19 @@
/* Define if you don't have Win32 semaphores. (eg. WinCE) */
#undef NEED_SEM
+
+/* Define if you need to convert string parameters to unicode. (eg. WinCE) */
+#undef NEED_UNICODE_CONSTS
+
+/*
+ * Target specific groups
+ */
+#ifdef WINCE
+#define NEED_DUPLICATEHANDLE
+#define NEED_CREATETHREAD
+#define NEED_ERRNO
+#define NEED_CALLOC
+#define NEED_FTIME
+#define NEED_SEM
+#define NEED_UNICODE_CONSTS
+#endif
diff --git a/config.h.in b/config.h.in
index 41f703f..acea758 100644
--- a/config.h.in
+++ b/config.h.in
@@ -23,3 +23,19 @@
/* Define if you don't have Win32 semaphores. (eg. WinCE) */
#undef NEED_SEM
+
+/* Define if you need to convert string parameters to unicode. (eg. WinCE) */
+#undef NEED_UNICODE_CONSTS
+
+/*
+ * Target specific groups
+ */
+#ifdef WINCE
+#define NEED_DUPLICATEHANDLE
+#define NEED_CREATETHREAD
+#define NEED_ERRNO
+#define NEED_CALLOC
+#define NEED_FTIME
+#define NEED_SEM
+#define NEED_UNICODE_CONSTS
+#endif
diff --git a/create.c b/create.c
index ac1384f..48d0984 100644
--- a/create.c
+++ b/create.c
@@ -68,6 +68,7 @@ pthread_create (pthread_t * tid,
*/
{
pthread_t thread;
+ HANDLE threadH = 0;
int result = EAGAIN;
int run = TRUE;
ThreadParms *parms = NULL;
@@ -90,8 +91,7 @@ pthread_create (pthread_t * tid,
goto FAIL0;
}
- if ((parms = (ThreadParms *) malloc (sizeof (*parms))) ==
- NULL)
+ if ((parms = (ThreadParms *) malloc (sizeof (*parms))) == NULL)
{
goto FAIL0;
}
@@ -117,7 +117,7 @@ pthread_create (pthread_t * tid,
/*
* Default stackSize
*/
- stackSize = 0;
+ stackSize = PTHREAD_STACK_MIN;
}
thread->state = run
@@ -126,20 +126,40 @@ pthread_create (pthread_t * tid,
thread->keys = NULL;
+ /*
+ * Threads must be started in suspended mode and resumed if necessary
+ * after _beginthreadex returns us the handle. Otherwise we set up a
+ * race condition between the creating and the created threads.
+ * Note that we also retain a local copy of the handle for use
+ * by us in case thread->threadH gets NULLed later but before we've
+ * finished with it here.
+ */
+
#if ! defined (__MINGW32__) || defined (__MSVCRT__)
- thread->threadH = (HANDLE)
+ thread->threadH = threadH = (HANDLE)
_beginthreadex (
(void *) NULL, /* No security info */
(unsigned) stackSize, /* default stack size */
(unsigned (PT_STDCALL *) (void *)) _pthread_threadStart,
parms,
- (unsigned) run ? 0 : CREATE_SUSPENDED,
+ (unsigned) CREATE_SUSPENDED,
(unsigned *) &(thread->thread));
+ if (threadH != 0 && run)
+ {
+ ResumeThread(threadH);
+ }
+
#else /* __MINGW32__ && ! __MSVCRT__ */
- thread->threadH = (HANDLE)
+ /*
+ * This lock will force pthread_threadStart() to wait until we have
+ * the thread handle.
+ */
+ (void) pthread_mutex_lock(&thread->cancelLock);
+
+ thread->threadH = threadH = (HANDLE)
_beginthread (
(void (*) (void *)) _pthread_threadStart,
(unsigned) stackSize, /* default stack size */
@@ -148,23 +168,25 @@ pthread_create (pthread_t * tid,
/*
* Make the return code match _beginthreadex's.
*/
- if (thread->threadH == (HANDLE)-1L)
+ if (threadH == (HANDLE) -1L)
{
- thread->threadH = 0;
+ thread->threadH = threadH = 0;
}
else if (! run)
{
- /*
+ /*
* beginthread does not allow for create flags, so we do it now.
* Note that beginthread itself creates the thread in SUSPENDED
* mode, and then calls ResumeThread to start it.
*/
- SuspendThread (thread->threadH);
+ SuspendThread (threadH);
}
+ (void) pthread_mutex_unlock(&thread->cancelLock);
+
#endif /* __MINGW32__ && ! __MSVCRT__ */
- result = (thread->threadH != 0) ? 0 : EAGAIN;
+ result = (threadH != 0) ? 0 : EAGAIN;
/*
* Fall Through Intentionally
diff --git a/dll.c b/dll.c
index b0d4d2a..ef724bf 100644
--- a/dll.c
+++ b/dll.c
@@ -88,8 +88,14 @@ DllMain (
_pthread_h_kernel32 = LoadLibrary(TEXT("KERNEL32.DLL"));
_pthread_try_enter_critical_section =
(BOOL (PT_STDCALL *)(LPCRITICAL_SECTION))
+
+#if defined(NEED_UNICODE_CONSTS)
+ GetProcAddress(_pthread_h_kernel32,
+ (const TCHAR *)TEXT("TryEnterCriticalSection"));
+#else
GetProcAddress(_pthread_h_kernel32,
(LPCSTR) "TryEnterCriticalSection");
+#endif
if (_pthread_try_enter_critical_section != NULL)
{
diff --git a/implement.h b/implement.h
index 4012301..76adb1f 100644
--- a/implement.h
+++ b/implement.h
@@ -239,7 +239,7 @@ struct ThreadKeyAssoc {
};
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__cplusplus)
/*
* --------------------------------------------------------------
* MAKE_SOFTWARE_EXCEPTION
diff --git a/misc.c b/misc.c
index f2f5695..aa78752 100644
--- a/misc.c
+++ b/misc.c
@@ -383,19 +383,19 @@ pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout)
pthread_t
_pthread_new (void)
{
- pthread_t new;
+ pthread_t t;
- new = (pthread_t) calloc (1, sizeof (*new));
+ t = (pthread_t) calloc (1, sizeof (*t));
- if (new != NULL)
+ if (t != NULL)
{
- new->detachState = PTHREAD_CREATE_JOINABLE;
- new->cancelState = PTHREAD_CANCEL_ENABLE;
- new->cancelType = PTHREAD_CANCEL_DEFERRED;
- new->cancelLock = PTHREAD_MUTEX_INITIALIZER;
+ t->detachState = PTHREAD_CREATE_JOINABLE;
+ t->cancelState = PTHREAD_CANCEL_ENABLE;
+ t->cancelType = PTHREAD_CANCEL_DEFERRED;
+ t->cancelLock = PTHREAD_MUTEX_INITIALIZER;
}
- return new;
+ return t;
}
diff --git a/mutex.c b/mutex.c
index bef116e..448ad2a 100644
--- a/mutex.c
+++ b/mutex.c
@@ -22,7 +22,7 @@
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA
*/
-
+
/* errno.h or a replacement file is included by pthread.h */
//#include <errno.h>
@@ -125,11 +125,12 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
#error ERROR [__FILE__, line __LINE__]: Process shared mutexes are not supported yet.
- mx->mutex = CreateMutex (
- NULL,
- FALSE,
- ????);
- result = (mx->mutex == 0) ? EAGAIN : 0;
+ mx->mutex = CreateMutex(NULL, FALSE, "FIXME FIXME FIXME");
+
+ if (mx->mutex == 0)
+ {
+ result = EAGAIN;
+ }
#else
@@ -149,6 +150,20 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
* Create a critical section.
*/
InitializeCriticalSection(&mx->cs);
+
+ /*
+ * Check that it works ok - since InitializeCriticalSection doesn't
+ * return success or failure.
+ */
+ if (TryEnterCriticalSection(&mx->cs))
+ {
+ LeaveCriticalSection(&mx->cs);
+ }
+ else
+ {
+ DeleteCriticalSection(&mx->cs);
+ result = EAGAIN;
+ }
}
else
{
@@ -163,12 +178,16 @@ pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
if (mx->mutex == 0)
{
result = EAGAIN;
- mx = NULL;
- goto FAIL0;
}
}
}
+ if (result != 0 && mx != NULL)
+ {
+ free(mx);
+ mx = NULL;
+ }
+
FAIL0:
*mutex = mx;
diff --git a/private.c b/private.c
index 5af936b..f374e27 100644
--- a/private.c
+++ b/private.c
@@ -187,7 +187,7 @@ _pthread_threadStart (ThreadParms * threadParms)
#ifdef _MSC_VER
- DWORD ei[3];
+ DWORD ei[] = {0,0,0};
#endif
@@ -197,13 +197,24 @@ _pthread_threadStart (ThreadParms * threadParms)
start = threadParms->start;
arg = threadParms->arg;
+ free (threadParms);
+
#if defined (__MINGW32__) && ! defined (__MSVCRT__)
- /* beginthread does not return the thread id, and so we do it here. */
+ /*
+ * beginthread does not return the thread id and is running
+ * before it returns us the thread handle, and so we do it here.
+ */
self->thread = GetCurrentThreadId ();
+ if (pthread_mutex_lock(&self->cancelLock) == 0)
+ {
+ /*
+ * We got the lock which means that our creator has
+ * our thread handle. Unlock and continue on.
+ */
+ (void) pthread_mutex_unlock(&self->cancelLock);
+ }
#endif
- free (threadParms);
-
pthread_setspecific (_pthread_selfThreadKey, self);
#ifdef _MSC_VER
@@ -231,6 +242,7 @@ _pthread_threadStart (ThreadParms * threadParms)
break;
default:
status = PTHREAD_CANCELED;
+ break;
}
}
else
@@ -366,7 +378,9 @@ _pthread_tkAssocCreate (ThreadKeyAssoc ** assocP,
* key on which to create an association.
* Returns:
* 0 - if successful,
- * -1 - general error
+ * ENOMEM - not enough memory to create assoc or other object
+ * EINVAL - an internal error occurred
+ * ENOSYS - an internal error occurred
* -------------------------------------------------------------------
*/
{
@@ -382,12 +396,11 @@ _pthread_tkAssocCreate (ThreadKeyAssoc ** assocP,
if (assoc == NULL)
{
- result = -1;
+ result = ENOMEM;
goto FAIL0;
}
- if ((result = pthread_mutex_init (&(assoc->lock), NULL)) !=
- 0)
+ if ((result = pthread_mutex_init (&(assoc->lock), NULL)) != 0)
{
goto FAIL1;
}
@@ -398,8 +411,7 @@ _pthread_tkAssocCreate (ThreadKeyAssoc ** assocP,
/*
* Register assoc with key
*/
- if ((result = pthread_mutex_lock (&(key->threadsLock))) !=
- 0)
+ if ((result = pthread_mutex_lock (&(key->threadsLock))) != 0)
{
goto FAIL2;
}
@@ -793,7 +805,7 @@ _pthread_get_exception_services_code(void)
#else
- return NULL;
+ return (DWORD) NULL;
#endif
}
diff --git a/pthread.h b/pthread.h
index bed1ae3..822152c 100644
--- a/pthread.h
+++ b/pthread.h
@@ -282,8 +282,12 @@ struct timespec {
#ifdef __MINGW32__
#define PT_STDCALL
#else
+#ifdef __cplusplus
+#define PT_STDCALL __cdecl
+#else
#define PT_STDCALL __stdcall
#endif
+#endif
#ifdef __cplusplus
extern "C"
@@ -420,8 +424,12 @@ extern "C"
* simply simulating keys.
*
* PTHREADS_STACK_MIN
- * artibrarily chose 1K. By default, WIN32
- * selects 1Meg stacks.
+ * POSIX specifies 0 which is also the value WIN32
+ * interprets as allowing the system to
+ * set the size to that of the main thread. The
+ * maximum stack size in Win32 is 1Meg. WIN32
+ * allocates more stack as required up to the 1Meg
+ * limit.
*
* PTHREAD_THREADS_MAX
* Not documented by WIN32. Wrote a test program
@@ -431,7 +439,7 @@ extern "C"
*/
#define PTHREAD_DESTRUCTOR_ITERATIONS 4
#define PTHREAD_KEYS_MAX 64
-#define PTHREAD_STACK_MIN 1024
+#define PTHREAD_STACK_MIN 0
#define PTHREAD_THREADS_MAX 2019
@@ -584,7 +592,7 @@ struct _pthread_cleanup_t
#endif /* !_MSC_VER && ! __cplusplus */
};
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__cplusplus)
/*
* WIN32 SEH version of cancel cleanup.
*/
@@ -609,7 +617,7 @@ struct _pthread_cleanup_t
} \
}
-#else /* _MSC_VER */
+#else /* _MSC_VER && ! __cplusplus */
#ifndef __cplusplus
@@ -703,9 +711,9 @@ struct _pthread_cleanup_t
cleanup.execute( _execute ); \
}
-#endif /* !__cplusplus */
+#endif /* !__cplusplus) */
-#endif /* _MSC_VER */
+#endif /* _MSC_VER && ! __cplusplus */
/*
* ===============
@@ -958,12 +966,14 @@ int * _errno( void );
rand()
-#ifdef _MSC_VER
+/* FIXME: This is only required if the library was built using SEH */
/*
* Get internal SEH tag
*/
DWORD _pthread_get_exception_services_code(void);
+#if defined(_MSC_VER) && !defined(__cplusplus)
+
/*
* Redefine the SEH __except keyword to ensure that applications
* propagate our internal exceptions up to the library's internal handlers.
@@ -972,9 +982,12 @@ DWORD _pthread_get_exception_services_code(void);
__except((GetExceptionCode() == _pthread_get_exception_services_code()) \
? EXCEPTION_CONTINUE_SEARCH : (E))
-#endif
+#endif /* _MSC_VER && ! __cplusplus */
#ifdef __cplusplus
+
+/* FIXME: This is only required if the library was built using C++EH */
+
/*
* Internal exceptions
*/
diff --git a/rwlock.c b/rwlock.c
index fd3f1f7..a4cdd5f 100644
--- a/rwlock.c
+++ b/rwlock.c
@@ -182,7 +182,7 @@ pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
}
else
{
- rw->rw_magic = (int) NULL;
+ rw->rw_magic = 0;
(void) pthread_mutex_unlock(&(rw->rw_lock));
(void) pthread_cond_destroy(&(rw->rw_condreaders));
(void) pthread_cond_destroy(&(rw->rw_condwriters));
diff --git a/sched.c b/sched.c
index 88889de..a4451ce 100644
--- a/sched.c
+++ b/sched.c
@@ -128,6 +128,22 @@ int pthread_getschedparam(pthread_t thread, int *policy,
return 0;
}
+
+/*
+ * On Windows98, THREAD_PRIORITY_LOWEST is (-2) and
+ * THREAD_PRIORITY_HIGHEST is 2, and everything works just fine.
+ *
+ * On WinCE 3.0, it so happen that THREAD_PRIORITY_LOWEST is 5
+ * and THREAD_PRIORITY_HIGHEST is 1 (yes, I know, it is funny:
+ * highest priority use smaller numbers) and the following happens:
+ *
+ * sched_get_priority_min() returns 5
+ * sched_get_priority_max() returns 1
+ */
+
+#define sched_Max(a,b) ((a)<(b)?(b):(a))
+#define sched_Min(a,b) ((a)>(b)?(b):(a))
+
int sched_get_priority_max(int policy)
{
if (policy < SCHED_MIN || policy > SCHED_MAX)
@@ -135,8 +151,13 @@ int sched_get_priority_max(int policy)
return EINVAL;
}
+#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL)
+ /* WinCE? */
+ return sched_Max(THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL);
+#else
/* This is independent of scheduling policy in Win32. */
- return THREAD_PRIORITY_HIGHEST;
+ return sched_Max(THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_HIGHEST);
+#endif
}
int sched_get_priority_min(int policy)
@@ -146,8 +167,13 @@ int sched_get_priority_min(int policy)
return EINVAL;
}
+#if (THREAD_PRIORITY_LOWEST > THREAD_PRIORITY_NORMAL)
+ /* WinCE? */
+ return sched_Min(THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL);
+#else
/* This is independent of scheduling policy in Win32. */
- return THREAD_PRIORITY_LOWEST;
+ return sched_Min(THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_HIGHEST);
+#endif
}
int sched_yield(void)
diff --git a/signal.c b/signal.c
index f944e0b..ba0edeb 100644
--- a/signal.c
+++ b/signal.c
@@ -23,7 +23,7 @@
* MA 02111-1307, USA
*/
-/* errno.h or a replacement file is included by pthread.h */
+/* errno.h or a replacement file is included by pthread.h */
//#include <errno.h>
#include "pthread.h"
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 8e65a35..902a809 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,17 @@
+2000-07-25 Ross Johnson <rpj@special.ise.canberra.edu.au>
+
+ * runtest.bat: modified to work under W98.
+
+ * runall.bat: Add new tests; modified to work under W98.
+ It was ok under NT.
+
+ * Makefile: Add new tests.
+
+ * exception1.c: New; Test passing exceptions back to the
+ application and retaining library internal exceptions.
+
+ * join0.c: New; Test a single join.
+
2000-01-06 Ross Johnson <rpj@special.ise.canberra.edu.au>
* cleanup1.c: New; Test cleanup handler executes (when thread is
diff --git a/tests/Makefile b/tests/Makefile
index ef1d30f..5931855 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -39,12 +39,13 @@ COPYFILES = $(HDR) $(LIB) $(DLL)
TESTS = loadfree \
mutex1 condvar1 condvar2 exit1 create1 equal1 \
exit2 exit3 \
- join1 join2 mutex2 mutex3 \
+ join0 join1 join2 mutex2 mutex3 \
count1 once1 tsd1 self1 self2 cancel1 eyal1 \
condvar3 condvar4 condvar5 condvar6 condvar7 condvar8 condvar9 \
errno1 \
rwlock1 rwlock2 rwlock3 rwlock4 rwlock5 rwlock6 \
- context1 cancel3 cancel4 cleanup1 cleanup2 cleanup3
+ context1 cancel3 cancel4 cleanup1 cleanup2 cleanup3 \
+ exception1
PASSES = $(TESTS:%=%.pass)
@@ -63,6 +64,7 @@ mutex3.pass: create1.pass
equal1.pass: create1.pass
exit2.pass: create1.pass
exit3.pass: create1.pass
+join0.pass: create1.pass
join1.pass: create1.pass
join2.pass: create1.pass
count1.pass: join1.pass
@@ -90,6 +92,7 @@ cancel4.pass: cancel3.pass
cleanup1.pass: cancel4.pass
cleanup2.pass: cleanup1.pass
cleanup3.pass: cleanup2.pass
+exception1.pass: cancel4.pass
%.pass: %.exe $(LIB) $(DLL) $(HDR)
$*
diff --git a/tests/cancel2.c b/tests/cancel2.c
index 1a10c64..44d1b77 100644
--- a/tests/cancel2.c
+++ b/tests/cancel2.c
@@ -48,7 +48,7 @@
* Create NUMTHREADS threads in addition to the Main thread.
*/
enum {
- NUMTHREADS = 4
+ NUMTHREADS = 1
};
typedef struct bag_t_ bag_t;
@@ -113,7 +113,6 @@ mythread(void * arg)
/*
* Should not get into here.
*/
- printf("SEH code=%x, MyCode=%x\n", GetExceptionCode(), _pthread_get_exception_services_code());
result += 100;
}
diff --git a/tests/cancel3.c b/tests/cancel3.c
index ff1d286..cb6f3d2 100644
--- a/tests/cancel3.c
+++ b/tests/cancel3.c
@@ -65,7 +65,7 @@ static pthread_mutex_t waitLock = PTHREAD_MUTEX_INITIALIZER;
void *
mythread(void * arg)
{
- int result = 0;
+ int result = ((int)PTHREAD_CANCELED + 1);
bag_t * bag = (bag_t *) arg;
assert(bag == &threadbag[bag->threadnum]);
@@ -85,7 +85,7 @@ mythread(void * arg)
for (bag->count = 0; bag->count < 100; bag->count++)
Sleep(100);
- return result;
+ return (void *) result;
}
int
diff --git a/tests/cancel4.c b/tests/cancel4.c
index 9ce6880..59c2f8e 100644
--- a/tests/cancel4.c
+++ b/tests/cancel4.c
@@ -68,7 +68,7 @@ static bag_t threadbag[NUMTHREADS + 1];
void *
mythread(void * arg)
{
- int result = 0;
+ int result = ((int)PTHREAD_CANCELED + 1);
bag_t * bag = (bag_t *) arg;
assert(bag == &threadbag[bag->threadnum]);
diff --git a/tests/ccl.bat b/tests/ccl.bat
index 473ff42..d80ea03 100644
--- a/tests/ccl.bat
+++ b/tests/ccl.bat
@@ -1,9 +1,9 @@
-REM Generate preprocessor output
-REM cl /E /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c ..\%1.c > ..\%1.e
-
-REM Generate object file
-cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c ..\%1.c
-
-REM Generate executable
-cl /Feaout.exe /Zi %1.obj .\pthread.lib
-del %1.obj > nul:
+REM Generate preprocessor output
+REM cl /E /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c ..\%1.c > ..\%1.e
+
+REM Generate object file
+cl /W3 /MT /nologo /Yd /Zi -I. -D_WIN32_WINNT=0x400 -DSTDCALL=_stdcall -c ..\%1.c
+
+REM Generate executable
+cl /Feaout.exe /Zi %1.obj .\pthread.lib
+del %1.obj > nul:
diff --git a/tests/join1.c b/tests/join1.c
index f206c0b..c29e5e6 100644
--- a/tests/join1.c
+++ b/tests/join1.c
@@ -9,12 +9,14 @@
void *
func(void * arg)
{
- Sleep(1000);
+ int i = (int) arg;
+
+ Sleep(i * 500);
- pthread_exit(arg);
+ pthread_exit(arg);
- /* Never reached. */
- exit(1);
+ /* Never reached. */
+ exit(1);
}
int
@@ -30,6 +32,9 @@ main(int argc, char * argv[])
assert(pthread_create(&id[i], NULL, func, (void *) i) == 0);
}
+ /* Some threads will finish before they are joined, some after. */
+ Sleep(1000);
+
for (i = 0; i < 4; i++)
{
assert(pthread_join(id[i], (void *) &result) == 0);
diff --git a/tests/loadfree.c b/tests/loadfree.c
index 3aba61b..b9b14c3 100644
--- a/tests/loadfree.c
+++ b/tests/loadfree.c
@@ -28,7 +28,7 @@
int main() {
HINSTANCE hinst;
- assert((hinst = LoadLibrary("pthread")) != 0);
+ assert((hinst = LoadLibrary("pthread")) != (HINSTANCE) 0);
Sleep(100);
diff --git a/tests/runall.bat b/tests/runall.bat
index ace1962..f2f492b 100644
--- a/tests/runall.bat
+++ b/tests/runall.bat
@@ -1,64 +1,66 @@
-@echo off
-
-if NOT x%1==x-f goto noforce
-if EXIST *.pass echo y | erase *.pass > nul:
-if EXIST *.fail echo y | erase *.fail > nul:
-if EXIST *.notrun echo y | erase *.notrun > nul:
-
-:noforce
-call runtest cl loadfree _
-call runtest cl mutex1 _
-call runtest cl mutex2 _
-call runtest cl exit1 _
-call runtest cl condvar1 _
-call runtest cl self1 _
-call runtest cl condvar2 condvar1
-call runtest cl create1 mutex2
-call runtest cl mutex3 create1
-call runtest cl equal1 create1
-call runtest cl exit2 create1
-call runtest cl exit3 create1
-call runtest cl join1 create1
-call runtest cl join2 create1
-call runtest cl count1 join1
-call runtest cl once1 create1
-call runtest cl tsd1 join1
-call runtest cl self2 create1
-call runtest cl cancel1 self2
-call runtest cl cancel2 cancel1
-call runtest cl eyal1 tsd1
-call runtest cl condvar3 create1
-call runtest cl condvar4 create1
-call runtest cl condvar5 condvar4
-call runtest cl condvar6 condvar5
-call runtest cl errno1 mutex3
-call runtest cl rwlock1 condvar6
-call runtest cl rwlock2 rwlock1
-call runtest cl rwlock3 rwlock2
-call runtest cl rwlock4 rwlock3
-call runtest cl rwlock5 rwlock4
-call runtest cl rwlock6 rwlock5
-call runtest cl context1 cancel2
-call runtest cl cancel3 context1
-call runtest cl cancel4 cancel3
-call runtest cl cleanup1 cancel4
-call runtest cl cleanup2 cleanup1
-call runtest cl cleanup3 cleanup2
-call runtest cl condvar7 cleanup1
-call runtest cl condvar8 condvar7
-call runtest cl condvar9 condvar8
-
-if NOT EXIST *.notrun goto skip1
-echo The following tests did not run (because prerequisite didn't pass?):
-for %%f in (*.notrun) do echo %%f
-goto skip2
-:skip1
-echo All tests ran.
-:skip2
-if NOT EXIST *.fail goto skip3
-echo The following tests failed:
-for %%f in (*.fail) do echo %%f
-goto skip4
-:skip3
-echo No tests failed.
-:skip4
+@echo off
+
+if NOT x%1==x-f goto noforce
+if EXIST *.pass echo y | erase *.pass > nul:
+if EXIST *.fail echo y | erase *.fail > nul:
+if EXIST *.notrun echo y | erase *.notrun > nul:
+
+:noforce
+call runtest cl loadfree _
+call runtest cl mutex1 _
+call runtest cl mutex2 _
+call runtest cl exit1 _
+call runtest cl condvar1 _
+call runtest cl self1 _
+call runtest cl condvar2 condvar1
+call runtest cl create1 mutex2
+call runtest cl mutex3 create1
+call runtest cl equal1 create1
+call runtest cl exit2 create1
+call runtest cl exit3 create1
+call runtest cl join0 create1
+call runtest cl join1 create1
+call runtest cl join2 create1
+call runtest cl count1 join1
+call runtest cl once1 create1
+call runtest cl tsd1 join1
+call runtest cl self2 create1
+call runtest cl cancel1 self2
+call runtest cl cancel2 cancel1
+call runtest cl eyal1 tsd1
+call runtest cl condvar3 create1
+call runtest cl condvar4 create1
+call runtest cl condvar5 condvar4
+call runtest cl condvar6 condvar5
+call runtest cl errno1 mutex3
+call runtest cl rwlock1 condvar6
+call runtest cl rwlock2 rwlock1
+call runtest cl rwlock3 rwlock2
+call runtest cl rwlock4 rwlock3
+call runtest cl rwlock5 rwlock4
+call runtest cl rwlock6 rwlock5
+call runtest cl context1 cancel2
+call runtest cl cancel3 context1
+call runtest cl cancel4 cancel3
+call runtest cl cleanup1 cancel4
+call runtest cl cleanup2 cleanup1
+call runtest cl cleanup3 cleanup2
+call runtest cl condvar7 cleanup1
+call runtest cl condvar8 condvar7
+call runtest cl condvar9 condvar8
+call runtest cl exception1 cancel4
+
+if NOT EXIST *.notrun goto skip1
+echo The following tests did not run (because prerequisite didn't pass?):
+for %%f in (*.notrun) do echo %%f
+goto skip2
+:skip1
+echo All tests ran.
+:skip2
+if NOT EXIST *.fail goto skip3
+echo The following tests failed:
+for %%f in (*.fail) do echo %%f
+goto skip4
+:skip3
+echo No tests failed.
+:skip4
diff --git a/tests/runtest.bat b/tests/runtest.bat
index dc36666..1129b9b 100644
--- a/tests/runtest.bat
+++ b/tests/runtest.bat
@@ -1,69 +1,81 @@
-@echo off
-
-REM Usage: runtest cl|gcc testname prerequisit testarg ...
-
-if %3==_ goto noprereq
-if NOT EXIST %3.pass goto needprereq
-
-:noprereq
-if EXIST %2.fail goto forcetest
-if EXIST %2.pass goto bypass
-
-:forcetest
-if EXIST %2.fail erase %2.fail
-
-REM Make sure we start with only those files we expect to need
-if exist tmp\*.* echo y | erase tmp\*.* > nul:
-rmdir tmp
-mkdir tmp
-
-copy ..\pthread.dll tmp > nul:
-copy ..\pthread.h tmp > nul:
-copy ..\semaphore.h tmp > nul:
-copy ..\sched.h tmp > nul:
-copy test.h tmp > nul:
-copy ..\pthread.lib tmp > nul:
-copy ..\libpthread32.a tmp > nul:
-
-cd tmp
-
-REM Compile the test case
-REM produces aout.exe using the compiler given as %1
-call ..\c%1.bat %2 > ..\%2.%1log
-
-if ERRORLEVEL 1 goto cleanup
-
-REM erase ..\%2.%1log
-
-echo TEST: %2 [%1]
-
-REM Run the test case
-if EXIST %2.pass erase %2.pass
-if EXIST %2.fail erase %2.fail
-if EXIST %2.notrun erase %2.notrun
-aout.exe %4 %5 %6 %7 %8 %9
-
-set RESULT=%ERRORLEVEL%
-
-if %RESULT% NEQ 0 echo Failed [%RESULT%] > ..\%2.fail
-if %RESULT% EQU 0 echo Passed > ..\%2.pass
-
-:cleanup
-
-cd ..
-
-REM Clean up
-if exist tmp\*.* echo y | erase tmp\*.* > nul:
-
-if EXIST %2.fail echo Failed [%RESULT%]
-if EXIST %2.pass echo Passed [%RESULT%]
-
-:bypass
-goto end
-
-:needprereq
-echo Test %2 requires %3 to pass before it can run.
-echo No Prereq > ..\%2.notrun
-goto end
-
-:end
+@echo off
+
+REM Usage: runtest cl testname prerequisit testarg ...
+REM or: runtest gcc testname prerequisit testarg ...
+
+if %3==_ goto noprereq
+if NOT EXIST %3.pass goto needprereq
+
+:noprereq
+if EXIST %2.fail goto forcetest
+if EXIST %2.pass goto bypass
+
+:forcetest
+if EXIST %2.fail erase %2.fail
+
+REM Make sure we start with only those files we expect to need
+if not exist tmp\*.* goto skip1
+echo y | erase tmp\*.* > nul:
+rmdir tmp
+mkdir tmp
+:skip1
+
+copy ..\pthread.dll tmp > nul:
+copy ..\pthread.h tmp > nul:
+copy ..\semaphore.h tmp > nul:
+copy ..\sched.h tmp > nul:
+copy test.h tmp > nul:
+copy ..\pthread.lib tmp > nul:
+REM copy ..\libpthread32.a tmp > nul:
+
+cd tmp
+
+REM Compile the test case
+REM produces aout.exe using the compiler given as %1
+call ..\c%1.bat %2 > ..\%2.%1log
+
+if ERRORLEVEL 1 goto cleanup
+
+REM erase ..\%2.%1log
+
+echo TEST: %2 [%1]
+
+REM Run the test case
+if EXIST %2.pass erase %2.pass
+if EXIST %2.fail erase %2.fail
+if EXIST %2.notrun erase %2.notrun
+aout.exe %4 %5 %6 %7 %8 %9
+
+set RESULT=1
+if ERRORLEVEL 0 set RESULT=0
+
+REM set RESULT=%ERRORLEVEL%
+
+if %RESULT%==0 goto passed
+echo Failed [%RESULT%] > ..\%2.fail
+goto cleanup
+
+:passed
+echo Passed > ..\%2.pass
+
+:cleanup
+
+cd ..
+
+REM Clean up
+if not exist tmp\*.* goto skip2
+echo y | erase tmp\*.* > nul:
+:skip2
+
+if EXIST %2.fail echo Failed [%RESULT%]
+if EXIST %2.pass echo Passed [%RESULT%]
+
+:bypass
+goto end
+
+:needprereq
+echo Test %2 requires %3 to pass before it can run.
+echo No Prereq > ..\%2.notrun
+goto end
+
+:end
diff --git a/tsd.c b/tsd.c
index 5183cd7..1381ce2 100644
--- a/tsd.c
+++ b/tsd.c
@@ -71,9 +71,6 @@ pthread_key_create (pthread_key_t * key, void (*destructor) (void *))
}
else if (((*key)->key = TlsAlloc ()) == TLS_OUT_OF_INDEXES)
{
- /*
- * Create system key
- */
result = EAGAIN;
free (*key);
@@ -86,6 +83,13 @@ pthread_key_create (pthread_key_t * key, void (*destructor) (void *))
* Therefore, need a lock that allows multiple threads
* to gain exclusive access to the key->threads list
*/
+#if 1
+ /*
+ * The mutex will only be created when it is first locked.
+ */
+ (*key)->threadsLock = PTHREAD_MUTEX_INITIALIZER;
+ (*key)->destructor = destructor;
+#else
result = pthread_mutex_init (&((*key)->threadsLock), NULL);
if (result != 0)
@@ -95,7 +99,11 @@ pthread_key_create (pthread_key_t * key, void (*destructor) (void *))
free (*key);
*key = NULL;
}
- (*key)->destructor = destructor;
+ else
+ {
+ (*key)->destructor = destructor;
+ }
+#endif
}
return (result);
@@ -134,6 +142,7 @@ pthread_key_delete (pthread_key_t key)
if (key != NULL)
{
if (key->threads != NULL &&
+ key->destructor != NULL &&
pthread_mutex_lock (&(key->threadsLock)) == 0)
{
/*
@@ -194,25 +203,24 @@ pthread_setspecific (pthread_key_t key, const void *value)
/*
* ------------------------------------------------------
* DOCPUBLIC
- * This function initializes an unnamed semaphore. the
- * initial value of the semaphore is 'value'
+ * This function sets the value of the thread specific
+ * key in the calling thread.
*
* PARAMETERS
- * sem
- * pointer to an instance of sem_t
+ * key
+ * an instance of pthread_key_t
+ * value
+ * the value to set key to
*
*
* DESCRIPTION
- * This function initializes an unnamed semaphore. The
- * initial value of the semaphore is set to 'value'.
+ * This function sets the value of the thread specific
+ * key in the calling thread.
*
* RESULTS
- * 0 successfully created semaphore,
- * EINVAL 'sem' is not a valid semaphore,
- * ENOSPC a required resource has been exhausted,
- * ENOSYS semaphores are not supported,
- * EPERM the process lacks appropriate privilege
- * ENOENT the thread couldn't find it's own handle
+ * 0 successfully set value
+ * EAGAIN could not set value
+ * ENOENT SERIOUS!!
*
* ------------------------------------------------------
*/
@@ -229,9 +237,9 @@ pthread_setspecific (pthread_key_t key, const void *value)
*/
self = pthread_self ();
if (self == NULL)
- {
- return ENOENT;
- }
+ {
+ return ENOENT;
+ }
}
else
{
@@ -284,20 +292,21 @@ pthread_setspecific (pthread_key_t key, const void *value)
/*
* create an association if not found
*/
- result = (assoc == NULL)
- ? _pthread_tkAssocCreate (&assoc, self, key)
- : 0;
- }
- else
- {
- result = 0;
+ if (assoc == NULL)
+ {
+ result = _pthread_tkAssocCreate (&assoc, self, key);
+ }
}
if (result == 0)
{
- TlsSetValue (key->key, (LPVOID) value);
+ if ( ! TlsSetValue (key->key, (LPVOID) value))
+ {
+ result = EAGAIN;
+ }
}
}
+
return (result);
} /* pthread_setspecific */