/* Threads compatibility routines for libgcc2 and libobjc. */
/* Compile this one with gcc. */
-/* Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+
+/* Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
This file is part of GCC.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* As a special exception, if you link this library with other files,
some of which are compiled with GCC, to produce an executable,
This may cause incorrect error return due to truncation values on
hw where sizeof (DWORD) > sizeof (int).
- 3. We might consider using Critical Sections instead of Windows32
- mutexes for better performance, but emulating __gthread_mutex_trylock
- interface becomes more complicated (Win9x does not support
- TryEnterCriticalSectioni, while NT does).
+ 3. We are currently using a special mutex instead of the Critical
+ Sections, since Win9x does not support TryEnterCriticalSection
+ (while NT does).
The basic framework should work well enough. In the long term, GCC
needs to use Structured Exception Handling on Windows32. */
#ifdef _LIBOBJC
/* This is necessary to prevent windef.h (included from windows.h) from
- defining it's own BOOL as a typedef. */
+ defining its own BOOL as a typedef. */
#ifndef __OBJC__
#define __OBJC__
#endif
int
__gthread_objc_init_thread_system (void)
{
- /* Initialize the thread storage key */
+ /* Initialize the thread storage key. */
if ((__gthread_objc_data_tls = TlsAlloc ()) != (DWORD) -1)
return 0;
else
long started;
} __gthread_once_t;
-typedef void* __gthread_mutex_t;
+typedef struct {
+ long counter;
+ void *sema;
+} __gthread_mutex_t;
+
+typedef struct {
+ long counter;
+ long depth;
+ unsigned long owner;
+ void *sema;
+} __gthread_recursive_mutex_t;
#define __GTHREAD_ONCE_INIT {0, -1}
#define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
-#define __GTHREAD_MUTEX_INIT_DEFAULT 0
+#define __GTHREAD_MUTEX_INIT_DEFAULT {-1, 0}
+#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION \
+ __gthread_recursive_mutex_init_function
+#define __GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT {-1, 0, 0, 0}
#if __MINGW32_MAJOR_VERSION >= 1 || \
(__MINGW32_MAJOR_VERSION == 0 && __MINGW32_MINOR_VERSION > 2)
extern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
#endif /* __MINGW32__ version */
+/* The Windows95 kernel does not export InterlockedCompareExchange.
+ This provides a substitute. When building apps that reference
+ gthread_mutex_try_lock, the __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
+ macro must be defined if Windows95 is a target. Currently
+ gthread_mutex_try_lock is not referenced by libgcc or libstdc++. */
+#ifdef __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
+static inline long
+__gthr_i486_lock_cmp_xchg(long *dest, long xchg, long comperand)
+{
+ long result;
+ __asm__ __volatile__ ("\n\
+ lock\n\
+ cmpxchg{l} {%4, %1|%1, %4}\n"
+ : "=a" (result), "=m" (*dest)
+ : "0" (comperand), "m" (*dest), "r" (xchg)
+ : "cc");
+ return result;
+}
+#define __GTHR_W32_InterlockedCompareExchange __gthr_i486_lock_cmp_xchg
+#else /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
+#define __GTHR_W32_InterlockedCompareExchange InterlockedCompareExchange
+#endif /* __GTHREAD_I486_INLINE_LOCK_PRIMITIVES */
+
static inline int
__gthread_active_p (void)
{
extern int __gthr_win32_mutex_lock (__gthread_mutex_t *);
extern int __gthr_win32_mutex_trylock (__gthread_mutex_t *);
extern int __gthr_win32_mutex_unlock (__gthread_mutex_t *);
+extern void
+ __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *);
+extern int __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *);
+extern int
+ __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *);
+extern int __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *);
static inline int
__gthread_once (__gthread_once_t *once, void (*func) (void))
return 0;
}
+static inline void
+__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
+{
+ __gthr_win32_recursive_mutex_init_function (mutex);
+}
+
+static inline int
+__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
+{
+ if (__gthread_active_p ())
+ return __gthr_win32_recursive_mutex_lock (mutex);
+ else
+ return 0;
+}
+
+static inline int
+__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
+{
+ if (__gthread_active_p ())
+ return __gthr_win32_recursive_mutex_trylock (mutex);
+ else
+ return 0;
+}
+
+static inline int
+__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
+{
+ if (__gthread_active_p ())
+ return __gthr_win32_recursive_mutex_unlock (mutex);
+ else
+ return 0;
+}
+
#else /* ! __GTHREAD_HIDE_WIN32API */
#include <windows.h>
static inline void
__gthread_mutex_init_function (__gthread_mutex_t *mutex)
{
- /* Create unnamed mutex with default security attr and no initial owner. */
- *mutex = CreateMutex (NULL, 0, NULL);
+ mutex->counter = -1;
+ mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
}
static inline int
if (__gthread_active_p ())
{
- if (WaitForSingleObject (*mutex, INFINITE) == WAIT_OBJECT_0)
+ if (InterlockedIncrement (&mutex->counter) == 0 ||
+ WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
status = 0;
else
- status = 1;
+ {
+ /* WaitForSingleObject returns WAIT_FAILED, and we can only do
+ some best-effort cleanup here. */
+ InterlockedDecrement (&mutex->counter);
+ status = 1;
+ }
}
return status;
}
if (__gthread_active_p ())
{
- if (WaitForSingleObject (*mutex, 0) == WAIT_OBJECT_0)
+ if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
status = 0;
else
status = 1;
__gthread_mutex_unlock (__gthread_mutex_t *mutex)
{
if (__gthread_active_p ())
- return (ReleaseMutex (*mutex) != 0) ? 0 : 1;
- else
- return 0;
+ {
+ if (InterlockedDecrement (&mutex->counter) >= 0)
+ return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
+ }
+ return 0;
+}
+
+static inline void
+__gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
+{
+ mutex->counter = -1;
+ mutex->depth = 0;
+ mutex->owner = 0;
+ mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
+}
+
+static inline int
+__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
+{
+ if (__gthread_active_p ())
+ {
+ DWORD me = GetCurrentThreadId();
+ if (InterlockedIncrement (&mutex->counter) == 0)
+ {
+ mutex->depth = 1;
+ mutex->owner = me;
+ }
+ else if (mutex->owner == me)
+ {
+ InterlockedDecrement (&mutex->counter);
+ ++(mutex->depth);
+ }
+ else if (WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
+ {
+ mutex->depth = 1;
+ mutex->owner = me;
+ }
+ else
+ {
+ /* WaitForSingleObject returns WAIT_FAILED, and we can only do
+ some best-effort cleanup here. */
+ InterlockedDecrement (&mutex->counter);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static inline int
+__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
+{
+ if (__gthread_active_p ())
+ {
+ DWORD me = GetCurrentThreadId();
+ if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
+ {
+ mutex->depth = 1;
+ mutex->owner = me;
+ }
+ else if (mutex->owner == me)
+ ++(mutex->depth);
+ else
+ return 1;
+ }
+ return 0;
+}
+
+static inline int
+__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
+{
+ if (__gthread_active_p ())
+ {
+ --(mutex->depth);
+ if (mutex->depth == 0)
+ {
+ mutex->owner = 0;
+
+ if (InterlockedDecrement (&mutex->counter) >= 0)
+ return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
+ }
+ }
+ return 0;
}
#endif /* __GTHREAD_HIDE_WIN32API */