diff options
author | rpj <rpj> | 2000-12-28 05:43:49 +0000 |
---|---|---|
committer | rpj <rpj> | 2000-12-28 05:43:49 +0000 |
commit | bab1896412f2d292ebd8d44bc9d6ddb58a8702b0 (patch) | |
tree | 09ecfc5f9042224f9b64c5e0aaaa09fcba22dd92 | |
parent | c94735ecdde19c4de652efd144faeec1a729b1e0 (diff) |
2000-10-10 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
* misc.c (pthread_self): Restore Win32 "last error"
cleared by TlsGetValue() call in
pthread_getspecific()
- "Steven Reddie" <smr@essemer.com.au>
2000-09-20 Ross Johnson <rpj@setup1.ise.canberra.edu.au>
* mutex.c (pthread_mutex_lock): Record the owner
of the mutex. This requires also keeping count of
recursive locks ourselves rather than leaving it
to Win32 since we need to know when to NULL the
thread owner when the mutex is unlocked.
(pthread_mutex_trylock): Likewise.
(pthread_mutex_unlock): Check that the calling
thread owns the mutex, decrement the recursive
lock count, and NULL the owner if zero. Return
EPERM if the mutex is owned by another thread.
* implement.h (pthread_mutex_t_): Add ownerThread
and lockCount members.
- reported by Arthur Kantor <akantor@bexusa.com>
-rw-r--r-- | ChangeLog | 23 | ||||
-rw-r--r-- | Makefile | 20 | ||||
-rw-r--r-- | implement.h | 1 | ||||
-rw-r--r-- | misc.c | 31 | ||||
-rw-r--r-- | mutex.c | 48 | ||||
-rw-r--r-- | pthread.h | 4 | ||||
-rw-r--r-- | signal.c | 76 | ||||
-rw-r--r-- | tests/mutex4.c | 62 |
8 files changed, 250 insertions, 15 deletions
@@ -40,6 +40,29 @@ * FAQ: Update Answer 6 re getting a fully working Mingw32 built library. +2000-10-10 Ross Johnson <rpj@setup1.ise.canberra.edu.au> + + * misc.c (pthread_self): Restore Win32 "last error" + cleared by TlsGetValue() call in + pthread_getspecific() + - "Steven Reddie" <smr@essemer.com.au> + +2000-09-20 Ross Johnson <rpj@setup1.ise.canberra.edu.au> + + * mutex.c (pthread_mutex_lock): Record the owner + of the mutex. This requires also keeping count of + recursive locks ourselves rather than leaving it + to Win32 since we need to know when to NULL the + thread owner when the mutex is unlocked. + (pthread_mutex_trylock): Likewise. + (pthread_mutex_unlock): Check that the calling + thread owns the mutex, decrement the recursive + lock count, and NULL the owner if zero. Return + EPERM if the mutex is owned by another thread. + * implement.h (pthread_mutex_t_): Add ownerThread + and lockCount members. + - reported by Arthur Kantor <akantor@bexusa.com> + 2000-09-13 Ross Johnson <rpj@setup1.ise.canberra.edu.au> * mutex.c (pthread_mutex_init): Call @@ -53,15 +53,21 @@ VSE: @ nmake /nologo EHFLAGS="$(VSEFLAGS)" pthreadVSE.dll
realclean: clean
- del *.dll
- del *.lib
+ @ for %%ext in (dll lib) do \
+ if exist *.%%ext del *.%%ext
+
+# del *.dll
+# del *.lib
clean:
- del *.obj
- del *.ilk
- del *.pdb
- del *.exp
- del *.o
+ @ for %%ext in (obj ilk pdb exp o) do \
+ if exist *.%%ext del *.%%ext
+
+# if exist *.obj del *.obj
+# if exist *.ilk del *.ilk
+# if exist *.pdb del *.pdb
+# if exist *.exp del *.exp
+# if exist *.o del *.o
install: $(DLLS)
diff --git a/implement.h b/implement.h index 623e474..9c74bb4 100644 --- a/implement.h +++ b/implement.h @@ -124,6 +124,7 @@ struct pthread_attr_t_ { struct pthread_mutex_t_ { HANDLE mutex; CRITICAL_SECTION cs; + pthread_t ownerThread; }; @@ -143,12 +143,37 @@ pthread_self (void) */ { pthread_t self = NULL; + DWORD lastErr; + /* - * need to ensure there always is a self + * Need to ensure there always is a self. + * + * The following call to pthread_getspecific uses TlsGetValue. + * Win32 functions that return indications of failure call SetLastError when + * they fail. They generally do not call SetLastError when they succeed. The + * TlsGetValue function is an exception to this general rule. The TlsGetValue + * function calls SetLastError to clear a thread's last error when it + * succeeds. + * + * We restore the last error if TlsGetValue succeeds. */ + lastErr = GetLastError(); + self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey); + if (GetLastError() == NO_ERROR) + { + SetLastError(lastErr); + } + else + { + /* + * What else can we do? GetLastError will tell the + * the caller more but this is not supposed to + * happen. + */ + return(NULL); + } - if ((self = (pthread_t) pthread_getspecific (ptw32_selfThreadKey)) - == NULL) + if (self == NULL) { /* * Need to create an implicit 'self' for the currently @@ -555,6 +555,12 @@ pthread_mutex_lock(pthread_mutex_t *mutex) } } + if (result == 0) + { + mx->ownerThread = pthread_self(); + mx->lockCount++; + } + return(result); } @@ -578,13 +584,43 @@ pthread_mutex_unlock(pthread_mutex_t *mutex) */ if (mx != (pthread_mutex_t) PTW32_OBJECT_AUTO_INIT) { - if (mx->mutex == 0) + pthread_t self = pthread_self(); + + if (pthread_equal(mx->ownerThread, self) == 0) { - LeaveCriticalSection(&mx->cs); + int oldCount = mx->lockCount; + pthread_t oldOwner = mx->ownerThread; + + if (mx->lockCount > 0) + { + mx->lockCount--; + } + + if (mx->lockCount == 0) + { + mx->ownerThread = NULL; + } + + if (mx->mutex == 0) + { + LeaveCriticalSection(&mx->cs); + } + else + { + if (!ReleaseMutex(mx->mutex)) + { + result = EINVAL; + /* + * Put things back the way they were. + */ + mx->lockCount = oldCount; + mx->ownerThread = oldOwner; + } + } } else { - result = (ReleaseMutex (mx->mutex) ? 0 : EINVAL); + result = EPERM; } } else @@ -643,5 +679,11 @@ pthread_mutex_trylock(pthread_mutex_t *mutex) } } + if (result == 0) + { + mx->ownerThread = pthread_self(); + mx->lockCount++; + } + return(result); } @@ -942,8 +942,12 @@ int pthreadCancelableTimedWait (HANDLE waitHandle, DWORD timeout); * Thread-Safe C Runtime Library Mappings. */ #if (! defined(NEED_ERRNO)) || (! defined( _REENTRANT ) && (! defined( _MT ) || ! defined( _MD ))) +#if defined(PTW32_BUILD) +__declspec( dllexport ) int * _errno( void ); +#else int * _errno( void ); #endif +#endif /* * WIN32 C runtime library had been made thread-safe @@ -23,13 +23,68 @@ * MA 02111-1307, USA */ -/* errno.h or a replacement file is included by pthread.h */ -//#include <errno.h> +/* + * Strategy for implementing pthread_kill() + * ======================================== + * + * Win32 does not implement signals. + * Signals are simply software interrupts. + * pthread_kill() asks the system to deliver a specified + * signal (interrupt) to a specified thread in the same + * process. + * Signals are always asynchronous (no deferred signals). + * Pthread-win32 has an async cancelation mechanism. + * A similar system can be written to deliver signals + * within the same process (on ix86 processors at least). + * + * Each thread maintains information about which + * signals it will respond to. Handler routines + * are set on a per-process basis - not per-thread. + * When signalled, a thread will check it's sigmask + * and, if the signal is not being ignored, call the + * handler routine associated with the signal. The + * thread must then (except for some signals) return to + * the point where it was interrupted. + * + * Ideally the system itself would check the target thread's + * mask before possibly needlessly bothering the thread + * itself. This could be done by pthread_kill(), that is, + * in the signaling thread since it has access to + * all pthread_t structures. It could also retrieve + * the handler routine address to minimise the target + * threads response overhead. This may also simplify + * serialisation of the access to the per-thread signal + * structures. + * + * pthread_kill() eventually calls a routine similar to + * ptw32_cancel_thread() which manipulates the target + * threads processor context to cause the thread to + * run the handler launcher routine. pthread_kill() must + * save the target threads current context so that the + * handler launcher routine can restore the context after + * the signal handler has returned. Some handlers will not + * return, eg. the default SIGKILL handler may simply + * call pthread_exit(). + * + * The current context is saved in the target threads + * pthread_t structure. + */ #include "pthread.h" #include "implement.h" #if HAVE_SIGSET_T + +static void +ptw32_signal_thread() +{ +} + +static void +ptw32_signal_callhandler() +{ +} + int pthread_sigmask(int how, sigset_t const *set, sigset_t *oset) { @@ -97,4 +152,21 @@ pthread_sigmask(int how, sigset_t const *set, sigset_t *oset) return 0; } + +int pthread_kill(pthread_t thread, + int signo) +{ +} + +int sigwait(const sigset_t *set, + int *sig) +{ +} + +int sigaction(int signum, + const struct sigaction *act, + struct sigaction *oldact) +{ +} + #endif /* HAVE_SIGSET_T */ diff --git a/tests/mutex4.c b/tests/mutex4.c new file mode 100644 index 0000000..5290f2a --- /dev/null +++ b/tests/mutex4.c @@ -0,0 +1,62 @@ +/* + * mutex4.c + * + * Thread A locks mutex - thread B tries to unlock. + * + * Depends on API functions: + * pthread_mutex_lock() + * pthread_mutex_trylock() + * pthread_mutex_unlock() + */ + +#include "test.h" + +pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t locker_done = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t unlocker_done = PTHREAD_MUTEX_INITIALIZER; + +static int washere = 0; + +void * locker(void * arg) +{ + assert(pthread_mutex_lock(&locker_start) == 0); + assert(pthread_mutex_lock(&mutex1) == 0); + assert(pthread_mutex_unlock(&locker_start) == 0); + + /* Wait for unlocker to finish */ + assert(pthread_mutex_lock(&unlocker_end) == 0); + assert(pthread_mutex_unlock(&mutex1) == 0); + + return 0; +} + +void * unlocker(void * arg) +{ + /* Wait for locker to lock mutex1 */ + assert(pthread_mutex_lock(&unlocker_start) == 0); + + assert(pthread_mutex_unlock(&mutex1) == EPERM); + + assert(pthread_mutex_unlock(&unlocker_start) == 0); + + return 0; +} + +int +main() +{ + pthread_t t; + + assert(pthread_mutex_lock(&locker_start) == 0); + assert(pthread_mutex_lock(&unlocker_start) == 0); + + assert(pthread_create(&t, NULL, locker, NULL) == 0); + assert(pthread_mutex_unlock(&locker_start) == 0); + Sleep(0); + + assert(pthread_create(&t, NULL, unlocker, NULL) == 0); + assert(pthread_mutex_unlock(&unlocker_start) == 0); + Sleep(0); + + return 0; +} |