summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrpj <rpj>2000-12-28 05:43:49 +0000
committerrpj <rpj>2000-12-28 05:43:49 +0000
commitbab1896412f2d292ebd8d44bc9d6ddb58a8702b0 (patch)
tree09ecfc5f9042224f9b64c5e0aaaa09fcba22dd92
parentc94735ecdde19c4de652efd144faeec1a729b1e0 (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--ChangeLog23
-rw-r--r--Makefile20
-rw-r--r--implement.h1
-rw-r--r--misc.c31
-rw-r--r--mutex.c48
-rw-r--r--pthread.h4
-rw-r--r--signal.c76
-rw-r--r--tests/mutex4.c62
8 files changed, 250 insertions, 15 deletions
diff --git a/ChangeLog b/ChangeLog
index 01dbd10..28ff9d4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/Makefile b/Makefile
index 976d9f2..1f63c31 100644
--- a/Makefile
+++ b/Makefile
@@ -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;
};
diff --git a/misc.c b/misc.c
index e79819d..ec5f9fa 100644
--- a/misc.c
+++ b/misc.c
@@ -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
diff --git a/mutex.c b/mutex.c
index 091c61e..d31b3b2 100644
--- a/mutex.c
+++ b/mutex.c
@@ -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);
}
diff --git a/pthread.h b/pthread.h
index e5a3a3e..21f4be9 100644
--- a/pthread.h
+++ b/pthread.h
@@ -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
diff --git a/signal.c b/signal.c
index ba0edeb..75bec84 100644
--- a/signal.c
+++ b/signal.c
@@ -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;
+}