diff --git a/ChangeLog b/ChangeLog index 30447cb0e..40b8618a9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21,6 +21,45 @@ Changes to add support for 64bit transitions used by v2+ of the timezone format. +2021-07-14 Frederik Seiffert + + * Headers/Foundation/NSLock.h: + * Headers/Foundation/NSThread.h: + * Headers/GNUstepBase/GSConfig.h.in: + * Headers/GNUstepBase/config.h.in: + * Source/Additions/GCObject.m: + * Source/Additions/GSObjCRuntime.m: + * Source/Additions/Unicode.m: + * Source/GSAtomic.h: + * Source/GSFFCallInvocation.m: + * Source/GSFFIInvocation.m: + * Source/GSPThread.h: + * Source/NSArray.m: + * Source/NSCharacterSet.m: + * Source/NSDebug.m: + * Source/NSException.m: + * Source/NSLock.m: + * Source/NSObject.m: + * Source/NSScanner.m: + * Source/NSString.m: + * Source/NSThread.m: + * Source/NSTimeZone.m: + * Source/NSZone.m: + * Tests/base/NSThread/GNUmakefile.preamble: + * Tests/base/NSThread/late_unregister.m: + * Tests/base/NSThread/lazy_thread.m: + * config/config.initialize.m: + * configure: + * configure.ac: + Use native threading and locking APIs on Windows, removing dependency + on pthread library and using fast Slim Reader/Writer (SRW) locks for + NSLock/NSRecursiveLock/NSCondition/NSConditionLock as well as all + internal locks. Adds GS_MUTEX_*() macros in GSPThread.h, that are being + used for all internal locking instead of pthread APIs. + Also adds support for thread priorities on Windows, fixes method + signature of +[NSThread setThreadPriority:] to match Apple platforms, + and adds error handling in same method. + 2021-07-16 Frederik Seiffert * Source/GSICUString.h: diff --git a/Headers/Foundation/NSLock.h b/Headers/Foundation/NSLock.h index 5f819ec8b..a2eeef4e7 100644 --- a/Headers/Foundation/NSLock.h +++ b/Headers/Foundation/NSLock.h @@ -74,7 +74,7 @@ GS_EXPORT_CLASS { #if GS_EXPOSE(NSLock) @protected - gs_mutex_t _mutex; + gs_mutex_public_t _mutex; NSString *_name; #endif } @@ -126,8 +126,8 @@ GS_EXPORT_CLASS { #if GS_EXPOSE(NSCondition) @protected - gs_cond_t _condition; - gs_mutex_t _mutex; + gs_cond_public_t _condition; + gs_mutex_public_t _mutex; NSString *_name; #endif } @@ -278,7 +278,7 @@ GS_EXPORT_CLASS { #if GS_EXPOSE(NSRecursiveLock) @protected - gs_mutex_t _mutex; + gs_mutex_public_t _mutex; NSString *_name; #endif } diff --git a/Headers/Foundation/NSThread.h b/Headers/Foundation/NSThread.h index 4bc9a6e45..079276dcf 100644 --- a/Headers/Foundation/NSThread.h +++ b/Headers/Foundation/NSThread.h @@ -134,7 +134,7 @@ GS_EXPORT_CLASS #if OS_API_VERSION(MAC_OS_X_VERSION_10_2,GS_API_LATEST) \ && GS_API_VERSION( 10200,GS_API_LATEST) -+ (void) setThreadPriority: (double)pri; ++ (BOOL) setThreadPriority: (double)pri; + (double) threadPriority; #endif diff --git a/Headers/GNUstepBase/GSConfig.h.in b/Headers/GNUstepBase/GSConfig.h.in index d7d44b745..5c188cf59 100644 --- a/Headers/GNUstepBase/GSConfig.h.in +++ b/Headers/GNUstepBase/GSConfig.h.in @@ -254,10 +254,13 @@ typedef gsuaddr gsaddr; */ typedef struct { uint8_t dummy[@GS_SIZEOF_COND_T@]; -} gs_cond_t __attribute__((aligned (@GS_ALIGNOF_COND_T@))); +} gs_cond_public_t __attribute__((aligned (@GS_ALIGNOF_COND_T@))); +typedef struct { + uint8_t dummy[@GS_SIZEOF_COND_MUTEX_T@]; +} gs_cond_mutex_public_t __attribute__((aligned (@GS_ALIGNOF_COND_MUTEX_T@))); typedef struct { uint8_t dummy[@GS_SIZEOF_MUTEX_T@]; -} gs_mutex_t __attribute__((aligned (@GS_ALIGNOF_MUTEX_T@))); +} gs_mutex_public_t __attribute__((aligned (@GS_ALIGNOF_MUTEX_T@))); #define OBJC2RUNTIME @OBJC2RUNTIME@ #define BASE_NATIVE_OBJC_EXCEPTIONS @BASE_NATIVE_OBJC_EXCEPTIONS@ @@ -272,6 +275,7 @@ typedef struct { #define GS_USE_LIBDISPATCH_RUNLOOP @HAVE_LIBDISPATCH_RUNLOOP@ #define GS_HAVE_NSURLSESSION @GS_HAVE_NSURLSESSION@ #define GS_HAVE_OBJC_ROOT_CLASS_ATTR @GS_HAVE_OBJC_ROOT_CLASS_ATTR@ +#define GS_USE_WIN32_THREADS_AND_LOCKS @HAVE_WIN32_THREADS_AND_LOCKS@ #ifndef __has_include # define __has_include(x) 0 diff --git a/Headers/GNUstepBase/config.h.in b/Headers/GNUstepBase/config.h.in index 51ca9aea7..35ab6d35f 100644 --- a/Headers/GNUstepBase/config.h.in +++ b/Headers/GNUstepBase/config.h.in @@ -3,12 +3,21 @@ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD +/* The normal alignment of `CONDITION_VARIABLE', in bytes. */ +#undef ALIGNOF_CONDITION_VARIABLE + +/* The normal alignment of `gs_mutex_t', in bytes. */ +#undef ALIGNOF_GS_MUTEX_T + /* The normal alignment of `pthread_cond_t', in bytes. */ #undef ALIGNOF_PTHREAD_COND_T /* The normal alignment of `pthread_mutex_t', in bytes. */ #undef ALIGNOF_PTHREAD_MUTEX_T +/* The normal alignment of `SRWLOCK', in bytes. */ +#undef ALIGNOF_SRWLOCK + /* Define if SO_REUSEADDR is broken on this system */ #undef BROKEN_SO_REUSEADDR @@ -858,12 +867,18 @@ /* Define to 1 if the `setpgrp' function takes no argument. */ #undef SETPGRP_VOID +/* The size of `CONDITION_VARIABLE', as computed by sizeof. */ +#undef SIZEOF_CONDITION_VARIABLE + /* The size of `double', as computed by sizeof. */ #undef SIZEOF_DOUBLE /* The size of `float', as computed by sizeof. */ #undef SIZEOF_FLOAT +/* The size of `gs_mutex_t', as computed by sizeof. */ +#undef SIZEOF_GS_MUTEX_T + /* The size of `int', as computed by sizeof. */ #undef SIZEOF_INT @@ -882,6 +897,9 @@ /* The size of `short', as computed by sizeof. */ #undef SIZEOF_SHORT +/* The size of `SRWLOCK', as computed by sizeof. */ +#undef SIZEOF_SRWLOCK + /* The size of `void*', as computed by sizeof. */ #undef SIZEOF_VOIDP diff --git a/Source/Additions/GCObject.m b/Source/Additions/GCObject.m index a9c924d4f..dbfbbd8d5 100644 --- a/Source/Additions/GCObject.m +++ b/Source/Additions/GCObject.m @@ -37,7 +37,7 @@ #import "GNUstepBase/GCObject.h" -#include +#import "../GSPThread.h" /* * The head of a linked list of all garbage collecting objects is a @@ -65,27 +65,20 @@ static GCObject *allObjects = nil; static BOOL isCollecting = NO; - -#ifdef NeXT_RUNTIME -static void *allocationLock = NULL; -#define pthread_mutex_lock(lock) -#define pthread_mutex_unlock(lock) -#else -static pthread_mutex_t *allocationLock = NULL; -#endif +static gs_mutex_t *allocationLock = NULL; + (void) _becomeMultiThreaded: (NSNotification *)aNotification { if (allocationLock == NULL) { # ifndef NeXT_RUNTIME - allocationLock = malloc(sizeof(pthread_mutex_t)); + allocationLock = malloc(sizeof(gs_mutex_t)); if (allocationLock == NULL) { abort(); } - pthread_mutex_init(allocationLock, NULL); + GS_MUTEX_INIT(*allocationLock); # endif } } @@ -100,7 +93,7 @@ static pthread_mutex_t *allocationLock = NULL; if (allocationLock != 0) { - pthread_mutex_lock(allocationLock); + GS_MUTEX_LOCK(*allocationLock); } o->gc.next = allObjects; o->gc.previous = allObjects->gc.previous; @@ -109,7 +102,7 @@ static pthread_mutex_t *allocationLock = NULL; o->gc.flags.refCount = 1; if (allocationLock != 0) { - pthread_mutex_unlock(allocationLock); + GS_MUTEX_UNLOCK(*allocationLock); } return o; @@ -150,13 +143,13 @@ static pthread_mutex_t *allocationLock = NULL; if (allocationLock != 0) { - pthread_mutex_lock(allocationLock); + GS_MUTEX_LOCK(*allocationLock); } if (isCollecting == YES) { if (allocationLock != 0) { - pthread_mutex_unlock(allocationLock); + GS_MUTEX_UNLOCK(*allocationLock); } return; // Don't allow recursion. } @@ -216,7 +209,7 @@ static pthread_mutex_t *allocationLock = NULL; isCollecting = NO; if (allocationLock != 0) { - pthread_mutex_unlock(allocationLock); + GS_MUTEX_UNLOCK(*allocationLock); } } @@ -267,7 +260,7 @@ static pthread_mutex_t *allocationLock = NULL; if (allocationLock != 0) { - pthread_mutex_lock(allocationLock); + GS_MUTEX_LOCK(*allocationLock); } // p = anObject->gc.previous; // n = anObject->gc.next; @@ -279,7 +272,7 @@ static pthread_mutex_t *allocationLock = NULL; [n gcSetPreviousObject: p]; if (allocationLock != 0) { - pthread_mutex_unlock(allocationLock); + GS_MUTEX_UNLOCK(*allocationLock); } } @@ -294,7 +287,7 @@ static pthread_mutex_t *allocationLock = NULL; if (allocationLock != 0) { - pthread_mutex_lock(allocationLock); + GS_MUTEX_LOCK(*allocationLock); } o->gc.next = allObjects; o->gc.previous = allObjects->gc.previous; @@ -303,7 +296,7 @@ static pthread_mutex_t *allocationLock = NULL; o->gc.flags.refCount = 1; if (allocationLock != 0) { - pthread_mutex_unlock(allocationLock); + GS_MUTEX_UNLOCK(*allocationLock); } return o; } @@ -321,7 +314,7 @@ static pthread_mutex_t *allocationLock = NULL; if (allocationLock != 0) { - pthread_mutex_lock(allocationLock); + GS_MUTEX_LOCK(*allocationLock); } // p = anObject->gc.previous; // n = anObject->gc.next; @@ -333,7 +326,7 @@ static pthread_mutex_t *allocationLock = NULL; [n gcSetPreviousObject: p]; if (allocationLock != 0) { - pthread_mutex_unlock(allocationLock); + GS_MUTEX_UNLOCK(*allocationLock); } [super dealloc]; } @@ -416,7 +409,7 @@ static pthread_mutex_t *allocationLock = NULL; { if (allocationLock != 0) { - pthread_mutex_lock(allocationLock); + GS_MUTEX_LOCK(*allocationLock); } if (gc.flags.refCount > 0 && gc.flags.refCount-- == 1) { @@ -425,7 +418,7 @@ static pthread_mutex_t *allocationLock = NULL; } if (allocationLock != 0) { - pthread_mutex_unlock(allocationLock); + GS_MUTEX_UNLOCK(*allocationLock); } } @@ -436,12 +429,12 @@ static pthread_mutex_t *allocationLock = NULL; { if (allocationLock != 0) { - pthread_mutex_lock(allocationLock); + GS_MUTEX_LOCK(*allocationLock); } gc.flags.refCount++; if (allocationLock != 0) { - pthread_mutex_unlock(allocationLock); + GS_MUTEX_UNLOCK(*allocationLock); } return self; } diff --git a/Source/Additions/GSObjCRuntime.m b/Source/Additions/GSObjCRuntime.m index 6141e0c67..1dbbb8957 100644 --- a/Source/Additions/GSObjCRuntime.m +++ b/Source/Additions/GSObjCRuntime.m @@ -48,16 +48,15 @@ #import "GNUstepBase/NSObject+GNUstepBase.h" #import "../GSPrivate.h" +#import "../GSPThread.h" #include #include #include -#ifndef NeXT_RUNTIME -#include -#endif #ifdef __GNUSTEP_RUNTIME__ +GS_IMPORT extern struct objc_slot *objc_get_slot(Class, SEL); #endif @@ -728,18 +727,17 @@ gs_string_hash(const char *s) #define GSI_MAP_VTYPES GSUNION_PTR #include "GNUstepBase/GSIMap.h" -#include static GSIMapTable_t protocol_by_name; static BOOL protocol_by_name_init = NO; -static pthread_mutex_t protocol_by_name_lock = PTHREAD_MUTEX_INITIALIZER; +static gs_mutex_t protocol_by_name_lock = GS_MUTEX_INIT_STATIC; /* Not sure about the semantics of inlining functions with static variables. */ static void gs_init_protocol_lock(void) { - pthread_mutex_lock(&protocol_by_name_lock); + GS_MUTEX_LOCK(protocol_by_name_lock); if (protocol_by_name_init == NO) { GSIMapInitWithZoneAndCapacity (&protocol_by_name, @@ -747,7 +745,7 @@ gs_init_protocol_lock(void) 128); protocol_by_name_init = YES; } - pthread_mutex_unlock(&protocol_by_name_lock); + GS_MUTEX_UNLOCK(protocol_by_name_lock); } void @@ -762,7 +760,7 @@ GSRegisterProtocol(Protocol *proto) { GSIMapNode node; - pthread_mutex_lock(&protocol_by_name_lock); + GS_MUTEX_LOCK(protocol_by_name_lock); node = GSIMapNodeForKey(&protocol_by_name, (GSIMapKey)protocol_getName(proto)); if (node == 0) @@ -771,7 +769,7 @@ GSRegisterProtocol(Protocol *proto) (GSIMapKey)(void*)protocol_getName(proto), (GSIMapVal)(void*)proto); } - pthread_mutex_unlock(&protocol_by_name_lock); + GS_MUTEX_UNLOCK(protocol_by_name_lock); } } @@ -793,7 +791,7 @@ GSProtocolFromName(const char *name) } else { - pthread_mutex_lock(&protocol_by_name_lock); + GS_MUTEX_LOCK(protocol_by_name_lock); node = GSIMapNodeForKey(&protocol_by_name, (GSIMapKey) name); if (node) @@ -812,7 +810,7 @@ GSProtocolFromName(const char *name) (GSIMapVal)(void*)p); } } - pthread_mutex_unlock(&protocol_by_name_lock); + GS_MUTEX_UNLOCK(protocol_by_name_lock); } diff --git a/Source/Additions/Unicode.m b/Source/Additions/Unicode.m index 87ceae25e..15bff0db5 100644 --- a/Source/Additions/Unicode.m +++ b/Source/Additions/Unicode.m @@ -137,7 +137,7 @@ internal_unicode_enc(void) #define UNICODE_UTF32 "" #endif -static pthread_mutex_t local_lock = PTHREAD_MUTEX_INITIALIZER; +static gs_mutex_t local_lock = GS_MUTEX_INIT_STATIC; typedef unsigned char unc; static NSStringEncoding defEnc = GSUndefinedEncoding; @@ -279,7 +279,7 @@ static void GSSetupEncodingTable(void) { if (encodingTable == 0) { - (void)pthread_mutex_lock(&local_lock); + GS_MUTEX_LOCK(local_lock); if (encodingTable == 0) { static struct _strenc_ **encTable = 0; @@ -355,7 +355,7 @@ static void GSSetupEncodingTable(void) } encodingTable = encTable; } - (void)pthread_mutex_unlock(&local_lock); + GS_MUTEX_UNLOCK(local_lock); } } @@ -2735,7 +2735,7 @@ GSPrivateAvailableEncodings() if (_availableEncodings == 0) { GSSetupEncodingTable(); - (void)pthread_mutex_lock(&local_lock); + GS_MUTEX_LOCK(local_lock); if (_availableEncodings == 0) { NSStringEncoding *encodings; @@ -2761,7 +2761,7 @@ GSPrivateAvailableEncodings() encodings[pos] = 0; _availableEncodings = encodings; } - (void)pthread_mutex_unlock(&local_lock); + GS_MUTEX_UNLOCK(local_lock); } return _availableEncodings; } @@ -2903,10 +2903,10 @@ GSPrivateDefaultCStringEncoding() GSSetupEncodingTable(); - (void)pthread_mutex_lock(&local_lock); + GS_MUTEX_LOCK(local_lock); if (defEnc != GSUndefinedEncoding) { - (void)pthread_mutex_unlock(&local_lock); + GS_MUTEX_UNLOCK(local_lock); return defEnc; } @@ -2950,7 +2950,7 @@ GSPrivateDefaultCStringEncoding() defEnc = NSISOLatin1StringEncoding; } - (void)pthread_mutex_unlock(&local_lock); + GS_MUTEX_UNLOCK(local_lock); } return defEnc; } diff --git a/Source/GSAtomic.h b/Source/GSAtomic.h new file mode 100644 index 000000000..81687182d --- /dev/null +++ b/Source/GSAtomic.h @@ -0,0 +1,72 @@ +/* + * Provides atomic load and store functions using either native C11 atomic + * types and operations if available, or otherwise using fallback + * implementations (e.g. with GCC where stdatomic.h is not useable from + * Objective-C). + * + * Adopted from FreeBSD's stdatomic.h. + */ +#ifndef _GSAtomic_h_ +#define _GSAtomic_h_ + +#ifndef __has_extension +#define __has_extension(x) 0 +#endif + +#if __has_extension(c_atomic) || __has_extension(cxx_atomic) + +/* + * Use native C11 atomic operations. _Atomic() should be defined by the + * compiler. + */ +#define atomic_load_explicit(object, order) \ + __c11_atomic_load(object, order) +#define atomic_store_explicit(object, desired, order) \ + __c11_atomic_store(object, desired, order) + +#else + +/* + * No native support for _Atomic(). Place object in structure to prevent + * most forms of direct non-atomic access. + */ +#define _Atomic(T) struct { T volatile __val; } +#if __has_builtin(__sync_swap) +/* Clang provides a full-barrier atomic exchange - use it if available. */ +#define atomic_exchange_explicit(object, desired, order) \ + ((void)(order), __sync_swap(&(object)->__val, desired)) +#else +/* + * __sync_lock_test_and_set() is only an acquire barrier in theory (although in + * practice it is usually a full barrier) so we need an explicit barrier before + * it. + */ +#define atomic_exchange_explicit(object, desired, order) \ +__extension__ ({ \ + __typeof__(object) __o = (object); \ + __typeof__(desired) __d = (desired); \ + (void)(order); \ + __sync_synchronize(); \ + __sync_lock_test_and_set(&(__o)->__val, __d); \ +}) +#endif +#define atomic_load_explicit(object, order) \ + ((void)(order), __sync_fetch_and_add(&(object)->__val, 0)) +#define atomic_store_explicit(object, desired, order) \ + ((void)atomic_exchange_explicit(object, desired, order)) + +#endif + +#ifndef __ATOMIC_SEQ_CST +#define __ATOMIC_SEQ_CST 5 +#endif + +/* + * Convenience functions. + */ +#define atomic_load(object) \ + atomic_load_explicit(object, __ATOMIC_SEQ_CST) +#define atomic_store(object, desired) \ + atomic_store_explicit(object, desired, __ATOMIC_SEQ_CST) + +#endif // _GSAtomic_h_ diff --git a/Source/GSFFCallInvocation.m b/Source/GSFFCallInvocation.m index dc9a7230a..680b72de3 100644 --- a/Source/GSFFCallInvocation.m +++ b/Source/GSFFCallInvocation.m @@ -26,6 +26,7 @@ #import "Foundation/NSCoder.h" #import "Foundation/NSDistantObject.h" #import "GSInvocation.h" +#import "GSPThread.h" #import #import #import "callframe.h" @@ -34,10 +35,6 @@ # include #endif -#include - -#import "GSInvocation.h" - #ifndef GS_STATIC_INLINE #define GS_STATIC_INLINE static inline #endif @@ -140,7 +137,7 @@ static GSIMapTable_t ff_callback_map; /* Lock that protects the ff_callback_map */ -static pthread_mutex_t ff_callback_map_lock = PTHREAD_MUTEX_INITIALIZER; +static gs_mutex_t ff_callback_map_lock = GS_MUTEX_INIT_STATIC; /* Static pre-computed return type info */ @@ -486,7 +483,7 @@ static IMP gs_objc_msg_forward (SEL sel) GSIMapNode node; // Lock - pthread_mutex_lock (&ff_callback_map_lock); + GS_MUTEX_LOCK(ff_callback_map_lock); node = GSIMapNodeForKey (&ff_callback_map, (GSIMapKey) ((void *) &returnInfo)); @@ -512,7 +509,7 @@ static IMP gs_objc_msg_forward (SEL sel) (GSIMapVal) forwarding_callback); } // Unlock - pthread_mutex_unlock (&ff_callback_map_lock); + GS_MUTEX_UNLOCK(ff_callback_map_lock); } return forwarding_callback; } diff --git a/Source/GSFFIInvocation.m b/Source/GSFFIInvocation.m index 98a8d50d2..73aee0af7 100644 --- a/Source/GSFFIInvocation.m +++ b/Source/GSFFIInvocation.m @@ -34,8 +34,8 @@ #import "Foundation/NSDistantObject.h" #import "Foundation/NSData.h" #import "GSInvocation.h" +#import "GSPThread.h" #import "GNUstepBase/GSObjCRuntime.h" -#import #import "cifframe.h" #import "GSPrivate.h" @@ -190,18 +190,18 @@ IMP gs_objc_msg_forward (SEL sel) return gs_objc_msg_forward2 (nil, sel); } #ifdef __GNUSTEP_RUNTIME__ -pthread_key_t thread_slot_key; +gs_thread_key_t thread_slot_key; static struct objc_slot * gs_objc_msg_forward3(id receiver, SEL op) { /* The slot has its version set to 0, so it can not be cached. This makes it * safe to free it when the thread exits. */ - struct objc_slot *slot = pthread_getspecific(thread_slot_key); + struct objc_slot *slot = GS_THREAD_KEY_GET(thread_slot_key); if (NULL == slot) { slot = calloc(sizeof(struct objc_slot), 1); - pthread_setspecific(thread_slot_key, slot); + GS_THREAD_KEY_SET(thread_slot_key, slot); } slot->method = gs_objc_msg_forward2(receiver, op); return slot; @@ -259,7 +259,7 @@ static id gs_objc_proxy_lookup(id receiver, SEL op) + (void) load { #ifdef __GNUSTEP_RUNTIME__ - pthread_key_create(&thread_slot_key, free); + GS_THREAD_KEY_INIT(thread_slot_key, free); __objc_msg_forward3 = gs_objc_msg_forward3; __objc_msg_forward2 = gs_objc_msg_forward2; objc_proxy_lookup = gs_objc_proxy_lookup; diff --git a/Source/GSPThread.h b/Source/GSPThread.h index dbe0f2085..dbec4e213 100644 --- a/Source/GSPThread.h +++ b/Source/GSPThread.h @@ -23,26 +23,97 @@ #ifndef _GSPThread_h_ #define _GSPThread_h_ +#if GS_USE_WIN32_THREADS_AND_LOCKS + +#include +#include +#include "GSAtomic.h" + +typedef enum { + gs_mutex_attr_normal = 0, + gs_mutex_attr_errorcheck = 1, + gs_mutex_attr_recursive = 2 +} gs_mutex_attr_t; + +typedef struct { + SRWLOCK lock; + _Atomic(DWORD) owner; + DWORD depth; + gs_mutex_attr_t attr; +} gs_mutex_t; + +typedef SRWLOCK gs_cond_mutex_t; +typedef CONDITION_VARIABLE gs_cond_t; + +/* + * Locking primitives. + */ +#define GS_MUTEX_INIT_STATIC {.lock = SRWLOCK_INIT, .attr = gs_mutex_attr_normal} +#define GS_MUTEX_INIT(x) gs_mutex_init(&(x), gs_mutex_attr_normal) +#define GS_MUTEX_INIT_RECURSIVE(x) gs_mutex_init(&(x), gs_mutex_attr_recursive) + +#define GS_MUTEX_LOCK(x) gs_mutex_lock(&(x)) +#define GS_MUTEX_TRYLOCK(x) gs_mutex_trylock(&(x)) +#define GS_MUTEX_UNLOCK(x) gs_mutex_unlock(&(x)) +#define GS_MUTEX_DESTROY(x) + +#define GS_COND_WAIT(cond, mutex) gs_cond_wait(cond, mutex) +#define GS_COND_SIGNAL(cond) WakeConditionVariable(&(cond)) +#define GS_COND_BROADCAST(cond) WakeAllConditionVariable(&(cond)) + +/* Pthread-like locking primitives defined in NSLock.m */ +void gs_mutex_init(gs_mutex_t *l, gs_mutex_attr_t attr); +int gs_mutex_lock(gs_mutex_t *l); +int gs_mutex_trylock(gs_mutex_t *l); +int gs_mutex_unlock(gs_mutex_t *l); +int gs_cond_wait(gs_cond_t *cond, gs_mutex_t *mutex); +int gs_cond_timedwait(gs_cond_t *cond, gs_mutex_t *mutex, DWORD millisecs); + +/* + * Threading primitives. + * + * Use Fiber Local Storage (FLS), as in contrast to Thread Local Storage (TLS) + * they provide a destructor callback and will just manipulate the FLS + * associated with the current thread if fibers are not being used. + */ +#define GS_THREAD_KEY_INIT(key, dtor) \ + ((key = FlsAlloc(dtor)) != FLS_OUT_OF_INDEXES) +#define GS_THREAD_KEY_GET(key) FlsGetValue(key) +#define GS_THREAD_KEY_SET(key, val) FlsSetValue(key, val) + +#define GS_THREAD_ID_SELF() GetCurrentThreadId() + +#define GS_YIELD() Sleep(0) + +typedef DWORD gs_thread_key_t; +typedef DWORD gs_thread_id_t; + +#else /* GS_USE_WIN32_THREADS_AND_LOCKS */ + #include -#import "Foundation/NSLock.h" +typedef pthread_mutex_t gs_mutex_t; +typedef pthread_mutex_t gs_cond_mutex_t; +typedef pthread_cond_t gs_cond_t; -@class GSStackTrace; -@class NSArray; -@class NSMapTable; +/* + * Locking primitives + */ +#define GS_MUTEX_INIT_STATIC PTHREAD_MUTEX_INITIALIZER +#define GS_MUTEX_INIT(x) pthread_mutex_init(&(x), NULL) /* * Macro to initialize recursive mutexes in a portable way. Adopted from * libobjc2 (lock.h). */ # ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP -# define GS_INIT_RECURSIVE_MUTEX(x) \ +# define GS_MUTEX_INIT_RECURSIVE(x) \ x = (pthread_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP # elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER) -# define GS_INIT_RECURSIVE_MUTEX(x) \ +# define GS_MUTEX_INIT_RECURSIVE(x) \ x = (pthread_mutex_t) PTHREAD_RECURSIVE_MUTEX_INITIALIZER # else -# define GS_INIT_RECURSIVE_MUTEX(x) GSPThreadInitRecursiveMutex(&(x)) +# define GS_MUTEX_INIT_RECURSIVE(x) GSPThreadInitRecursiveMutex(&(x)) static inline void GSPThreadInitRecursiveMutex(pthread_mutex_t *x) { @@ -54,6 +125,39 @@ static inline void GSPThreadInitRecursiveMutex(pthread_mutex_t *x) } # endif // PTHREAD_RECURSIVE_MUTEX_INITIALIZER(_NP) +#define GS_MUTEX_LOCK(x) pthread_mutex_lock(&(x)) +#define GS_MUTEX_TRYLOCK(x) pthread_mutex_trylock(&(x)) +#define GS_MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x)) +#define GS_MUTEX_DESTROY(x) pthread_mutex_destroy(&(x)) + +#define GS_COND_WAIT(cond, mutex) pthread_cond_wait(cond, mutex) +#define GS_COND_SIGNAL(cond) pthread_cond_signal(&(cond)) +#define GS_COND_BROADCAST(cond) pthread_cond_broadcast(&(cond)) + +/* + * Threading primitives. + */ +#define GS_THREAD_KEY_INIT(key, dtor) (pthread_key_create(&(key), dtor) == 0) +#define GS_THREAD_KEY_GET(key) pthread_getspecific(key) +#define GS_THREAD_KEY_SET(key, val) pthread_setspecific(key, val) + +#define GS_THREAD_ID_SELF() pthread_self() + +#define GS_YIELD() sched_yield() + +typedef pthread_key_t gs_thread_key_t; +typedef pthread_t gs_thread_id_t; + +#endif /* GS_USE_WIN32_THREADS_AND_LOCKS */ + + +#ifdef __OBJC__ /* Enables including file in autoconf check */ + +#import "Foundation/NSLock.h" + +@class GSStackTrace; +@class NSArray; +@class NSMapTable; /* Class to obtain/encapsulate a stack trace for exception reporting and/or * lock tracing. @@ -109,4 +213,6 @@ static inline void GSPThreadInitRecursiveMutex(pthread_mutex_t *x) - (GSStackTrace*) stack; @end +#endif // __OBJC__ + #endif // _GSPThread_h_ diff --git a/Source/NSArray.m b/Source/NSArray.m index fc957df99..adc2e7b46 100644 --- a/Source/NSArray.m +++ b/Source/NSArray.m @@ -86,7 +86,7 @@ static Class GSPlaceholderArrayClass; static GSPlaceholderArray *defaultPlaceholderArray; static NSMapTable *placeholderMap; -static pthread_mutex_t placeholderLock = PTHREAD_MUTEX_INITIALIZER; +static gs_mutex_t placeholderLock = GS_MUTEX_INIT_STATIC; /** @@ -167,7 +167,7 @@ static SEL rlSel; * locate the correct placeholder in the (lock protected) * table of placeholders. */ - (void)pthread_mutex_lock(&placeholderLock); + GS_MUTEX_LOCK(placeholderLock); obj = (id)NSMapGet(placeholderMap, (void*)z); if (obj == nil) { @@ -178,7 +178,7 @@ static SEL rlSel; obj = (id)NSAllocateObject(GSPlaceholderArrayClass, 0, z); NSMapInsert(placeholderMap, (void*)z, (void*)obj); } - (void)pthread_mutex_unlock(&placeholderLock); + GS_MUTEX_UNLOCK(placeholderLock); return obj; } } diff --git a/Source/NSCharacterSet.m b/Source/NSCharacterSet.m index 3693413e6..6aa8154de 100644 --- a/Source/NSCharacterSet.m +++ b/Source/NSCharacterSet.m @@ -736,9 +736,9 @@ static Class concreteMutableClass = nil; length: (unsigned)length number: (int)number { - static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER; + static gs_mutex_t cache_lock = GS_MUTEX_INIT_STATIC; - pthread_mutex_lock(&cache_lock); + GS_MUTEX_LOCK(cache_lock); if (cache_set[number] == nil && bytes != 0) { NSData *bitmap; @@ -751,7 +751,7 @@ static Class concreteMutableClass = nil; [[NSObject leakAt: &cache_set[number]] release]; RELEASE(bitmap); } - pthread_mutex_unlock(&cache_lock); + GS_MUTEX_UNLOCK(cache_lock); return cache_set[number]; } diff --git a/Source/NSDebug.m b/Source/NSDebug.m index ac42a1cdf..55f772139 100644 --- a/Source/NSDebug.m +++ b/Source/NSDebug.m @@ -93,7 +93,7 @@ static table_entry* the_table = 0; static BOOL debug_allocation = NO; static BOOL debug_byte_size = NO; -static pthread_mutex_t uniqueLock; +static gs_mutex_t uniqueLock; static void _GSDebugAllocationFetch(list_entry *items, BOOL difference); static void _GSDebugAllocationFetchAll(list_entry *items); @@ -106,8 +106,8 @@ static void (*_GSDebugAllocationAddFunc)(Class c, id o) static void (*_GSDebugAllocationRemoveFunc)(Class c, id o) = _GSDebugAllocationRemove; -#define doLock() pthread_mutex_lock(&uniqueLock) -#define unLock() pthread_mutex_unlock(&uniqueLock) +#define doLock() GS_MUTEX_LOCK(uniqueLock) +#define unLock() GS_MUTEX_UNLOCK(uniqueLock) @interface GSDebugAlloc : NSObject + (void) initialize; @@ -116,7 +116,7 @@ static void (*_GSDebugAllocationRemoveFunc)(Class c, id o) @implementation GSDebugAlloc + (void) initialize { - GS_INIT_RECURSIVE_MUTEX(uniqueLock); + GS_MUTEX_INIT_RECURSIVE(uniqueLock); } @end diff --git a/Source/NSException.m b/Source/NSException.m index 67d7edeab..fda46f051 100644 --- a/Source/NSException.m +++ b/Source/NSException.m @@ -491,7 +491,7 @@ static void find_address (bfd *abfd, asection *section, @end -static pthread_mutex_t modLock; +static gs_mutex_t modLock; static NSMutableDictionary *stackModules = nil; // initialize stack trace info @@ -500,7 +500,7 @@ GSLoadModule(NSString *fileName) { GSBinaryFileInfo *module = nil; - (void)pthread_mutex_lock(&modLock); + GS_MUTEX_LOCK(modLock); if (stackModules == nil) { @@ -549,7 +549,7 @@ GSLoadModule(NSString *fileName) } } } - (void)pthread_mutex_unlock(&modLock); + GS_MUTEX_UNLOCK(modLock); if (module == (id)[NSNull null]) { @@ -564,9 +564,9 @@ GSListModules() NSArray *result; GSLoadModule(nil); // initialise - (void)pthread_mutex_lock(&modLock); + GS_MUTEX_LOCK(modLock); result = [stackModules allValues]; - (void)pthread_mutex_unlock(&modLock); + GS_MUTEX_UNLOCK(modLock); return result; } @@ -615,7 +615,7 @@ static SymInitializeType initSym = 0; static SymSetOptionsType optSym = 0; static SymFromAddrType fromSym = 0; static HANDLE hProcess = 0; -static pthread_mutex_t traceLock; +static gs_mutex_t traceLock; #define MAXFRAMES 62 /* Limitation of windows-xp */ #else #define MAXFRAMES 128 /* 1KB buffer on 64bit machine */ @@ -902,7 +902,7 @@ GSPrivateReturnAddresses(NSUInteger **returns) #if defined(_WIN32) && !defined(USE_BFD) NSUInteger addr[MAXFRAMES]; - (void)pthread_mutex_lock(&traceLock); + GS_MUTEX_LOCK(traceLock); if (0 == hProcess) { hProcess = GetCurrentProcess(); @@ -916,7 +916,7 @@ GSPrivateReturnAddresses(NSUInteger **returns) { fprintf(stderr, "Failed to load kernel32.dll with error: %d\n", (int)GetLastError()); - (void)pthread_mutex_unlock(&traceLock); + GS_MUTEX_UNLOCK(traceLock); return 0; } capture = (CaptureStackBackTraceType)GetProcAddress( @@ -925,7 +925,7 @@ GSPrivateReturnAddresses(NSUInteger **returns) { fprintf(stderr, "Failed to find RtlCaptureStackBackTrace: %d\n", (int)GetLastError()); - (void)pthread_mutex_unlock(&traceLock); + GS_MUTEX_UNLOCK(traceLock); return 0; } hModule = LoadLibrary("dbghelp.dll"); @@ -933,7 +933,7 @@ GSPrivateReturnAddresses(NSUInteger **returns) { fprintf(stderr, "Failed to load dbghelp.dll with error: %d\n", (int)GetLastError()); - (void)pthread_mutex_unlock(&traceLock); + GS_MUTEX_UNLOCK(traceLock); return 0; } optSym = (SymSetOptionsType)GetProcAddress( @@ -942,7 +942,7 @@ GSPrivateReturnAddresses(NSUInteger **returns) { fprintf(stderr, "Failed to find SymSetOptions: %d\n", (int)GetLastError()); - (void)pthread_mutex_unlock(&traceLock); + GS_MUTEX_UNLOCK(traceLock); return 0; } initSym = (SymInitializeType)GetProcAddress( @@ -951,7 +951,7 @@ GSPrivateReturnAddresses(NSUInteger **returns) { fprintf(stderr, "Failed to find SymInitialize: %d\n", (int)GetLastError()); - (void)pthread_mutex_unlock(&traceLock); + GS_MUTEX_UNLOCK(traceLock); return 0; } fromSym = (SymFromAddrType)GetProcAddress( @@ -960,7 +960,7 @@ GSPrivateReturnAddresses(NSUInteger **returns) { fprintf(stderr, "Failed to find SymFromAddr: %d\n", (int)GetLastError()); - (void)pthread_mutex_unlock(&traceLock); + GS_MUTEX_UNLOCK(traceLock); return 0; } } @@ -972,13 +972,13 @@ GSPrivateReturnAddresses(NSUInteger **returns) fprintf(stderr, "SymInitialize failed with error: %d\n", (int)GetLastError()); fromSym = 0; - (void)pthread_mutex_unlock(&traceLock); + GS_MUTEX_UNLOCK(traceLock); return 0; } } if (0 == capture) { - (void)pthread_mutex_unlock(&traceLock); + GS_MUTEX_UNLOCK(traceLock); return 0; } @@ -989,7 +989,7 @@ GSPrivateReturnAddresses(NSUInteger **returns) memcpy(*returns, addr, numReturns * sizeof(void*)); } - (void)pthread_mutex_unlock(&traceLock); + GS_MUTEX_UNLOCK(traceLock); #elif defined(HAVE_BACKTRACE) void *addr[MAXFRAMES*sizeof(void*)]; @@ -1112,10 +1112,10 @@ GSPrivateReturnAddresses(NSUInteger **returns) + (void) initialize { #if defined(_WIN32) && !defined(USE_BFD) - GS_INIT_RECURSIVE_MUTEX(traceLock); + GS_MUTEX_INIT_RECURSIVE(traceLock); #endif #if defined(USE_BFD) - GS_INIT_RECURSIVE_MUTEX(modLock); + GS_MUTEX_INIT_RECURSIVE(modLock); #endif } @@ -1257,7 +1257,7 @@ GSPrivateReturnAddresses(NSUInteger **returns) symbol->MaxNameLen = 1024; symbol->SizeOfStruct = sizeof(SYMBOL_INFO); - (void)pthread_mutex_lock(&traceLock); + GS_MUTEX_LOCK(traceLock); for (i = 0; i < count; i++) { NSUInteger addr = (NSUInteger)*ptrs++; @@ -1273,7 +1273,7 @@ GSPrivateReturnAddresses(NSUInteger **returns) @"unknown - %p", symbol->Name, addr]; } } - (void)pthread_mutex_unlock(&traceLock); + GS_MUTEX_UNLOCK(traceLock); free(symbol); symbols = [[NSArray alloc] initWithObjects: syms count: count]; diff --git a/Source/NSLock.m b/Source/NSLock.m index 88ca1078c..420480638 100644 --- a/Source/NSLock.m +++ b/Source/NSLock.m @@ -24,25 +24,25 @@ #import "common.h" -#include -#import "GSPrivate.h" -#define gs_cond_t pthread_cond_t -#define gs_mutex_t pthread_mutex_t -#include - #define EXPOSE_NSLock_IVARS 1 #define EXPOSE_NSRecursiveLock_IVARS 1 #define EXPOSE_NSCondition_IVARS 1 #define EXPOSE_NSConditionLock_IVARS 1 +#define gs_cond_public_t gs_cond_t +#define gs_cond_mutex_public_t gs_cond_mutex_t +#define gs_mutex_public_t gs_mutex_t + +#import "GSPrivate.h" +#import "GSPThread.h" +#include + #import "common.h" #import "Foundation/NSLock.h" #import "Foundation/NSException.h" #import "Foundation/NSThread.h" -#import "GSPThread.h" - #define class_createInstance(C,E) NSAllocateObject(C,E,NSDefaultMallocZone()) static Class baseConditionClass = Nil; @@ -178,13 +178,13 @@ static BOOL traceLocks = NO; #define MFINALIZE \ - (void) finalize\ {\ - pthread_mutex_destroy(&_mutex);\ + GS_MUTEX_DESTROY(_mutex);\ } #define MLOCK \ - (void) lock\ {\ - int err = pthread_mutex_lock(&_mutex);\ + int err = GS_MUTEX_LOCK(_mutex);\ if (EDEADLK == err)\ {\ (*_NSLock_error_handler)(self, _cmd, YES, @"deadlock");\ @@ -200,13 +200,13 @@ static BOOL traceLocks = NO; {\ do\ {\ - int err = pthread_mutex_trylock(&_mutex);\ + int err = GS_MUTEX_TRYLOCK(_mutex);\ if (0 == err)\ - {\ + {\ CHK(Hold) \ - return YES;\ - }\ - sched_yield();\ + return YES;\ + }\ + GS_YIELD();\ } while ([limit timeIntervalSinceNow] > 0);\ return NO;\ } @@ -230,7 +230,7 @@ static BOOL traceLocks = NO; #define MTRYLOCK \ - (BOOL) tryLock\ {\ - int err = pthread_mutex_trylock(&_mutex);\ + int err = GS_MUTEX_TRYLOCK(_mutex);\ if (0 == err) \ { \ CHK(Hold) \ @@ -245,7 +245,7 @@ static BOOL traceLocks = NO; #define MUNLOCK \ - (void) unlock\ {\ - if (0 != pthread_mutex_unlock(&_mutex))\ + if (0 != GS_MUTEX_UNLOCK(_mutex))\ {\ [NSException raise: NSLockException\ format: @"failed to unlock mutex"];\ @@ -253,10 +253,12 @@ static BOOL traceLocks = NO; CHK(Drop) \ } -static pthread_mutex_t deadlock; +static gs_mutex_t deadlock; +#if !GS_USE_WIN32_THREADS_AND_LOCKS static pthread_mutexattr_t attr_normal; static pthread_mutexattr_t attr_reporting; static pthread_mutexattr_t attr_recursive; +#endif /* * OS X 10.5 compatibility function to allow debugging deadlock conditions. @@ -267,7 +269,7 @@ void _NSLockError(id obj, SEL _cmd, BOOL stop, NSString *msg) msg, obj); NSLog(@"*** Break on _NSLockError() to debug."); if (YES == stop) - pthread_mutex_lock(&deadlock); + GS_MUTEX_LOCK(deadlock); } NSLock_error_handler *_NSLock_error_handler = _NSLockError; @@ -295,6 +297,7 @@ NSString *NSLockException = @"NSLockException"; { beenHere = YES; +#if !GS_USE_WIN32_THREADS_AND_LOCKS /* Initialise attributes for the different types of mutex. * We do it once, since attributes can be shared between multiple * mutexes. @@ -312,14 +315,19 @@ NSString *NSLockException = @"NSLockException"; pthread_mutexattr_settype(&attr_reporting, PTHREAD_MUTEX_ERRORCHECK); pthread_mutexattr_init(&attr_recursive); pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE); +#endif /* To emulate OSX behavior, we need to be able both to detect deadlocks * (so we can log them), and also hang the thread when one occurs. * the simple way to do that is to set up a locked mutex we can * force a deadlock on. */ +#if GS_USE_WIN32_THREADS_AND_LOCKS + gs_mutex_init(&deadlock, gs_mutex_attr_normal); +#else pthread_mutex_init(&deadlock, &attr_normal); - pthread_mutex_lock(&deadlock); +#endif + GS_MUTEX_LOCK(deadlock); baseConditionClass = [NSCondition class]; baseConditionLockClass = [NSConditionLock class]; @@ -349,10 +357,14 @@ MFINALIZE { if (nil != (self = [super init])) { +#if GS_USE_WIN32_THREADS_AND_LOCKS + gs_mutex_init(&_mutex, gs_mutex_attr_errorcheck); +#else if (0 != pthread_mutex_init(&_mutex, &attr_reporting)) - { - DESTROY(self); - } + { + DESTROY(self); + } +#endif } return self; } @@ -364,17 +376,17 @@ MLOCK { do { - int err = pthread_mutex_trylock(&_mutex); + int err = GS_MUTEX_TRYLOCK(_mutex); if (0 == err) - { + { CHK(Hold) - return YES; - } + return YES; + } if (EDEADLK == err) - { - (*_NSLock_error_handler)(self, _cmd, NO, @"deadlock"); - } - sched_yield(); + { + (*_NSLock_error_handler)(self, _cmd, NO, @"deadlock"); + } + GS_YIELD(); } while ([limit timeIntervalSinceNow] > 0); return NO; } @@ -410,10 +422,14 @@ MFINALIZE { if (nil != (self = [super init])) { +#if GS_USE_WIN32_THREADS_AND_LOCKS + gs_mutex_init(&_mutex, gs_mutex_attr_recursive); +#else if (0 != pthread_mutex_init(&_mutex, &attr_recursive)) - { - DESTROY(self); - } + { + DESTROY(self); + } +#endif } return self; } @@ -445,7 +461,7 @@ MUNLOCK - (void) broadcast { - pthread_cond_broadcast(&_condition); + GS_COND_BROADCAST(_condition); } MDEALLOC @@ -453,23 +469,30 @@ MDESCRIPTION - (void) finalize { +#if !GS_USE_WIN32_THREADS_AND_LOCKS pthread_cond_destroy(&_condition); - pthread_mutex_destroy(&_mutex); +#endif + GS_MUTEX_DESTROY(_mutex); } - (id) init { if (nil != (self = [super init])) { +#if GS_USE_WIN32_THREADS_AND_LOCKS + InitializeConditionVariable(&_condition); + gs_mutex_init(&_mutex, gs_mutex_attr_errorcheck); +#else if (0 != pthread_cond_init(&_condition, NULL)) - { - DESTROY(self); - } + { + DESTROY(self); + } else if (0 != pthread_mutex_init(&_mutex, &attr_reporting)) - { - pthread_cond_destroy(&_condition); - DESTROY(self); - } + { + pthread_cond_destroy(&_condition); + DESTROY(self); + } +#endif } return self; } @@ -481,7 +504,7 @@ MNAME - (void) signal { - pthread_cond_signal(&_condition); + GS_COND_SIGNAL(_condition); } MSTACK @@ -490,15 +513,25 @@ MUNLOCK - (void) wait { - pthread_cond_wait(&_condition, &_mutex); + GS_COND_WAIT(&_condition, &_mutex); } - (BOOL) waitUntilDate: (NSDate*)limit { + int retVal = 0; + +#if GS_USE_WIN32_THREADS_AND_LOCKS + NSTimeInterval ti = [limit timeIntervalSinceNow]; + if (ti < 0) { + ti = 0.0; // handle timeout in the past + } + + retVal = gs_cond_timedwait(&_condition, &_mutex, ti * 1000.0); +#else NSTimeInterval ti = [limit timeIntervalSince1970]; + double secs, subsecs; struct timespec timeout; - int retVal = 0; // Split the float into seconds and fractions of a second subsecs = modf(ti, &secs); @@ -510,6 +543,8 @@ MUNLOCK */ retVal = pthread_cond_timedwait(&_condition, &_mutex, &timeout); +#endif /* GS_USE_WIN32_THREADS_AND_LOCKS */ + if (retVal == 0) { return YES; @@ -518,10 +553,8 @@ MUNLOCK { return NO; } - if (retVal == EINVAL) - { - NSLog(@"Invalid arguments to pthread_cond_timedwait"); - } + + NSLog(@"Error calling pthread_cond_timedwait: %d", retVal); return NO; } @@ -694,7 +727,7 @@ MSTACK NSThread *t = GSCurrentThread(); \ int err; \ CHKT(t,Wait) \ - err = pthread_mutex_lock(&_mutex);\ + err = GS_MUTEX_LOCK(_mutex);\ if (EDEADLK == err)\ {\ CHKT(t,Drop) \ @@ -735,17 +768,28 @@ MTRYLOCK NSThread *t = GSCurrentThread(); CHKT(t,Drop) CHKT(t,Wait) - pthread_cond_wait(&_condition, &_mutex); + GS_COND_WAIT(&_condition, &_mutex); CHKT(t,Hold) } - (BOOL) waitUntilDate: (NSDate*)limit { + int retVal = 0; + NSThread *t = GSCurrentThread(); + +#if GS_USE_WIN32_THREADS_AND_LOCKS + NSTimeInterval ti = [limit timeIntervalSinceNow]; + if (ti < 0) { + ti = 0.0; // handle timeout in the past + } + + CHKT(t,Drop) + retVal = gs_cond_timedwait(&_condition, &_mutex, ti * 1000.0); +#else NSTimeInterval ti = [limit timeIntervalSince1970]; - NSThread *t = GSCurrentThread(); + double secs, subsecs; struct timespec timeout; - int retVal = 0; // Split the float into seconds and fractions of a second subsecs = modf(ti, &secs); @@ -758,6 +802,8 @@ MTRYLOCK CHKT(t,Drop) retVal = pthread_cond_timedwait(&_condition, &_mutex, &timeout); +#endif /* GS_USE_WIN32_THREADS_AND_LOCKS */ + if (retVal == 0) { CHKT(t,Hold) @@ -769,10 +815,7 @@ MTRYLOCK return NO; } - if (retVal == EINVAL) - { - NSLog(@"Invalid arguments to pthread_cond_timedwait"); - } + NSLog(@"Error calling pthread_cond_timedwait: %d", retVal); return NO; } @@ -854,3 +897,165 @@ MUNLOCK } @end + +/* + * Pthread-like locking primitives using Windows SRWLock. Provides + * normal, recursive, and error-checked locks. + */ +#if GS_USE_WIN32_THREADS_AND_LOCKS + +void +gs_mutex_init(gs_mutex_t *mutex, gs_mutex_attr_t attr) +{ + memset(mutex, 0, sizeof(gs_mutex_t)); + InitializeSRWLock(&mutex->lock); + mutex->attr = attr; +} + +int +gs_mutex_lock(gs_mutex_t *mutex) +{ + DWORD thisThread = GetCurrentThreadId(); + DWORD ownerThread; + + // fast path if lock is not taken + if (TryAcquireSRWLockExclusive(&mutex->lock)) + { + assert(mutex->depth == 0); + mutex->depth = 1; + atomic_store(&mutex->owner, thisThread); + return 0; + } + + // needs to be atomic because another thread can concurrently set it + ownerThread = atomic_load(&mutex->owner); + if (ownerThread == thisThread) + { + // this thread already owns this lock + switch (mutex->attr) + { + case gs_mutex_attr_normal: + // deadlock + assert(mutex->depth == 1); + AcquireSRWLockExclusive(&mutex->lock); + assert(false); // not reached + return 0; + + case gs_mutex_attr_errorcheck: + // return deadlock error + assert(mutex->depth == 1); + return EDEADLK; + + case gs_mutex_attr_recursive: + // recursive lock + mutex->depth++; + return 0; + } + } + + // wait for another thread to release the lock + AcquireSRWLockExclusive(&mutex->lock); + assert(mutex->depth == 0); + mutex->depth = 1; + atomic_store(&mutex->owner, thisThread); + return 0; +} + +int +gs_mutex_trylock(gs_mutex_t *mutex) +{ + DWORD thisThread = GetCurrentThreadId(); + DWORD ownerThread; + + if (TryAcquireSRWLockExclusive(&mutex->lock)) + { + assert(mutex->depth == 0); + mutex->depth = 1; + atomic_store(&mutex->owner, thisThread); + return 0; + } + + // needs to be atomic because another thread can concurrently set it + ownerThread = atomic_load(&mutex->owner); + if (ownerThread == thisThread && mutex->attr == gs_mutex_attr_recursive) + { + // this thread already owns this lock and it's recursive + assert(mutex->depth > 0); + mutex->depth++; + return 0; + } + + // lock is taken + return EBUSY; +} + +int +gs_mutex_unlock(gs_mutex_t *mutex) +{ + switch (mutex->attr) + { + case gs_mutex_attr_normal: + break; + case gs_mutex_attr_errorcheck: + case gs_mutex_attr_recursive: { + // return error if lock is not held by this thread + DWORD thisThread = GetCurrentThreadId(); + DWORD ownerThread = atomic_load(&mutex->owner); + if (ownerThread != thisThread) { + return EPERM; + } + break; + } + } + + if (mutex->attr == gs_mutex_attr_recursive && mutex->depth > 1) + { + // recursive lock releasing inner lock + mutex->depth--; + return 0; + } + else + { + assert(mutex->depth == 1); + mutex->depth = 0; + atomic_store(&mutex->owner, 0); + ReleaseSRWLockExclusive(&mutex->lock); + return 0; + } +} + +// NB: timeout specified in milliseconds relative to now +int +gs_cond_timedwait(gs_cond_t *cond, gs_mutex_t *mutex, DWORD millisecs) +{ + int retVal = 0; + + assert(mutex->depth == 1); + mutex->depth = 0; + atomic_store(&mutex->owner, 0); + + if (!SleepConditionVariableSRW(cond, &mutex->lock, millisecs, 0)) + { + DWORD lastError = GetLastError(); + if (lastError == ERROR_TIMEOUT) { + retVal = ETIMEDOUT; + } else { + retVal = lastError; + } + } + + assert(mutex->depth == 0); + mutex->depth = 1; + atomic_store(&mutex->owner, GetCurrentThreadId()); + + return retVal; +} + +inline int +gs_cond_wait(gs_cond_t *cond, gs_mutex_t *mutex) +{ + return gs_cond_timedwait(cond, mutex, INFINITE); +} + +#endif /* GS_USE_WIN32_THREADS_AND_LOCKS */ + diff --git a/Source/NSObject.m b/Source/NSObject.m index 7701d01d1..cb8da3c89 100644 --- a/Source/NSObject.m +++ b/Source/NSObject.m @@ -131,7 +131,7 @@ GS_ROOT_CLASS @interface NSZombie /* allocationLock is needed when for protecting the map table of zombie * information and if atomic operations are not available. */ -static pthread_mutex_t allocationLock = PTHREAD_MUTEX_INITIALIZER; +static gs_mutex_t allocationLock = GS_MUTEX_INIT_STATIC; BOOL NSZombieEnabled = NO; BOOL NSDeallocateZombies = NO; @@ -146,12 +146,12 @@ static void GSMakeZombie(NSObject *o, Class c) object_setClass(o, zombieClass); if (0 != zombieMap) { - pthread_mutex_lock(&allocationLock); + GS_MUTEX_LOCK(allocationLock); if (0 != zombieMap) { NSMapInsert(zombieMap, (void*)o, (void*)c); } - pthread_mutex_unlock(&allocationLock); + GS_MUTEX_UNLOCK(allocationLock); } } #endif @@ -162,12 +162,12 @@ static void GSLogZombie(id o, SEL sel) if (0 != zombieMap) { - pthread_mutex_lock(&allocationLock); + GS_MUTEX_LOCK(allocationLock); if (0 != zombieMap) { c = NSMapGet(zombieMap, (void*)o); } - pthread_mutex_unlock(&allocationLock); + GS_MUTEX_UNLOCK(allocationLock); } if (c == 0) { @@ -395,6 +395,8 @@ GSAtomicDecrement(gsatomic_t X) #if !defined(GSATOMICREAD) +#include + typedef int gsrefcount_t; // No atomics, use a simple integer /* Having just one allocationLock for all leads to lock contention @@ -841,12 +843,12 @@ NSDeallocateObject(id anObject) #ifdef OBJC_CAP_ARC if (0 != zombieMap) { - pthread_mutex_lock(&allocationLock); + GS_MUTEX_LOCK(allocationLock); if (0 != zombieMap) { NSMapInsert(zombieMap, (void*)anObject, (void*)aClass); } - pthread_mutex_unlock(&allocationLock); + GS_MUTEX_UNLOCK(allocationLock); } if (NSDeallocateZombies == YES) { @@ -1117,10 +1119,10 @@ static id gs_weak_load(id obj) + (void) _atExit { NSMapTable *m = nil; - pthread_mutex_lock(&allocationLock); + GS_MUTEX_LOCK(allocationLock); m = zombieMap; zombieMap = nil; - pthread_mutex_unlock(&allocationLock); + GS_MUTEX_UNLOCK(allocationLock); DESTROY(m); } @@ -2500,12 +2502,12 @@ static id gs_weak_load(id obj) if (0 != zombieMap) { - pthread_mutex_lock(&allocationLock); + GS_MUTEX_LOCK(allocationLock); if (0 != zombieMap) { c = NSMapGet(zombieMap, (void*)self); } - pthread_mutex_unlock(&allocationLock); + GS_MUTEX_UNLOCK(allocationLock); } return c; } @@ -2527,9 +2529,9 @@ static id gs_weak_load(id obj) { return nil; } - pthread_mutex_lock(&allocationLock); + GS_MUTEX_LOCK(allocationLock); c = zombieMap ? NSMapGet(zombieMap, (void*)self) : Nil; - pthread_mutex_unlock(&allocationLock); + GS_MUTEX_UNLOCK(allocationLock); return [c instanceMethodSignatureForSelector: aSelector]; } diff --git a/Source/NSScanner.m b/Source/NSScanner.m index 191ff3046..6a0202761 100644 --- a/Source/NSScanner.m +++ b/Source/NSScanner.m @@ -246,11 +246,11 @@ typedef GSString *ivars; */ + (BOOL) _scanDouble: (double*)value from: (NSString*)str { - static pthread_mutex_t myLock = PTHREAD_MUTEX_INITIALIZER; + static gs_mutex_t myLock = GS_MUTEX_INIT_STATIC; static NSScanner *doubleScanner = nil; BOOL ok = NO; - pthread_mutex_lock(&myLock); + GS_MUTEX_LOCK(myLock); if (nil == doubleScanner) { doubleScanner = [[self alloc] initWithString: _empty]; @@ -258,7 +258,7 @@ typedef GSString *ivars; [doubleScanner _setString: str]; ok = [doubleScanner scanDouble: value]; [doubleScanner _setString: _empty]; // Release scanned string - pthread_mutex_unlock(&myLock); + GS_MUTEX_UNLOCK(myLock); return ok; } diff --git a/Source/NSString.m b/Source/NSString.m index c8f522aa8..3ca766687 100644 --- a/Source/NSString.m +++ b/Source/NSString.m @@ -153,7 +153,7 @@ static Class GSPlaceholderStringClass; static GSPlaceholderString *defaultPlaceholderString; static NSMapTable *placeholderMap; -static pthread_mutex_t placeholderLock = PTHREAD_MUTEX_INITIALIZER; +static gs_mutex_t placeholderLock = GS_MUTEX_INIT_STATIC; static SEL cMemberSel = 0; @@ -305,14 +305,14 @@ pathSeps(void) { if (rPathSeps == nil) { - (void)pthread_mutex_lock(&placeholderLock); + GS_MUTEX_LOCK(placeholderLock); if (rPathSeps == nil) { rPathSeps = [NSCharacterSet characterSetWithCharactersInString: @"/\\"]; rPathSeps = [NSObject leakAt: &rPathSeps]; } - (void)pthread_mutex_unlock(&placeholderLock); + GS_MUTEX_UNLOCK(placeholderLock); } return rPathSeps; } @@ -320,14 +320,14 @@ pathSeps(void) { if (uPathSeps == nil) { - (void)pthread_mutex_lock(&placeholderLock); + GS_MUTEX_LOCK(placeholderLock); if (uPathSeps == nil) { uPathSeps = [NSCharacterSet characterSetWithCharactersInString: @"/"]; uPathSeps = [NSObject leakAt: &uPathSeps]; } - (void)pthread_mutex_unlock(&placeholderLock); + GS_MUTEX_UNLOCK(placeholderLock); } return uPathSeps; } @@ -335,14 +335,14 @@ pathSeps(void) { if (wPathSeps == nil) { - (void)pthread_mutex_lock(&placeholderLock); + GS_MUTEX_LOCK(placeholderLock); if (wPathSeps == nil) { wPathSeps = [NSCharacterSet characterSetWithCharactersInString: @"\\"]; wPathSeps = [NSObject leakAt: &wPathSeps]; } - (void)pthread_mutex_unlock(&placeholderLock); + GS_MUTEX_UNLOCK(placeholderLock); } return wPathSeps; } @@ -897,7 +897,7 @@ GSICUCollatorOpen(NSStringCompareOptions mask, NSLocale *locale) * locate the correct placeholder in the (lock protected) * table of placeholders. */ - (void)pthread_mutex_lock(&placeholderLock); + GS_MUTEX_LOCK(placeholderLock); obj = (id)NSMapGet(placeholderMap, (void*)z); if (obj == nil) { @@ -908,7 +908,7 @@ GSICUCollatorOpen(NSStringCompareOptions mask, NSLocale *locale) obj = (id)[GSPlaceholderStringClass allocWithZone: z]; NSMapInsert(placeholderMap, (void*)z, (void*)obj); } - (void)pthread_mutex_unlock(&placeholderLock); + GS_MUTEX_UNLOCK(placeholderLock); return obj; } } diff --git a/Source/NSThread.m b/Source/NSThread.m index 2e1228d2e..17414bfbb 100644 --- a/Source/NSThread.m +++ b/Source/NSThread.m @@ -37,7 +37,7 @@ // Dummy implementatation // cleaner than IFDEF'ing the code everywhere -#if !(HAVE_PTHREAD_SPIN_LOCK) +#ifndef HAVE_PTHREAD_SPIN_LOCK typedef volatile int pthread_spinlock_t; int pthread_spin_init(pthread_spinlock_t *lock, int pshared) { @@ -58,7 +58,11 @@ int pthread_spin_lock(pthread_spinlock_t *lock) { // If it is already 1, let another thread play with the CPU for a // bit then try again. +#if defined(_WIN32) + Sleep(0); +#else sleep(0); +#endif } } #else @@ -78,7 +82,7 @@ int pthread_spin_destroy(pthread_spinlock_t *lock) { return 0; } -#endif +#endif /* HAVE_PTHREAD_SPIN_LOCK */ /** Structure for holding lock information for a thread. */ @@ -90,7 +94,7 @@ typedef struct { #define EXPOSE_NSThread_IVARS 1 #define GS_NSThread_IVARS \ - pthread_t _pthreadID; \ + gs_thread_id_t _pthreadID; \ NSUInteger _threadID; \ GSLockInfo _lockInfo @@ -326,7 +330,7 @@ GSSleepUntilIntervalSinceReferenceDate(NSTimeInterval when) /* We don't need to wait, but since we are willing to wait at this * point, we should let other threads have preference over this one. */ - sched_yield(); + GS_YIELD(); return; } @@ -458,12 +462,12 @@ static BOOL entered_multi_threaded_state = NO; static NSThread *defaultThread; static BOOL keyInitialized = NO; -static pthread_key_t thread_object_key; +static gs_thread_key_t thread_object_key; static NSHashTable *_activeBlocked = nil; static NSHashTable *_activeThreads = nil; -static pthread_mutex_t _activeLock = PTHREAD_MUTEX_INITIALIZER; +static gs_mutex_t _activeLock = GS_MUTEX_INIT_STATIC; /** * pthread_t is an opaque type. It might be a scalar type or @@ -473,10 +477,10 @@ static pthread_mutex_t _activeLock = PTHREAD_MUTEX_INITIALIZER; * This follows the CoreFoundation 'create rule' and returns an object with * a reference count of 1. */ -static inline NSValue* NSValueCreateFromPthread(pthread_t thread) +static inline NSValue* NSValueCreateFromPthread(gs_thread_id_t thread) { return [[NSValue alloc] initWithBytes: &thread - objCType: @encode(pthread_t)]; + objCType: @encode(gs_thread_id_t)]; } /** @@ -484,14 +488,14 @@ static inline NSValue* NSValueCreateFromPthread(pthread_t thread) * from an NSValue. */ static inline void -_getPthreadFromNSValue(const void *value, pthread_t *thread_ptr) +_getPthreadFromNSValue(const void *value, gs_thread_id_t *thread_ptr) { const char *enc; NSCAssert(thread_ptr, @"No storage for thread reference"); # ifndef NS_BLOCK_ASSERTIONS enc = [(NSValue*)value objCType]; - NSCAssert(enc != NULL && (0 == strcmp(@encode(pthread_t),enc)), + NSCAssert(enc != NULL && (0 == strcmp(@encode(gs_thread_id_t),enc)), @"Invalid NSValue container for thread reference"); # endif [(NSValue*)value getValue: (void*)thread_ptr]; @@ -506,12 +510,17 @@ _boxedPthreadIsEqual(NSMapTable *t, const void *boxed, const void *boxedOther) { - pthread_t thread; - pthread_t otherThread; + gs_thread_id_t thread; + gs_thread_id_t otherThread; _getPthreadFromNSValue(boxed, &thread); _getPthreadFromNSValue(boxedOther, &otherThread); + +#if GS_USE_WIN32_THREADS_AND_LOCKS + return thread == otherThread; +#else return pthread_equal(thread, otherThread); +#endif } /** @@ -576,7 +585,7 @@ static const NSMapTableKeyCallBacks _boxedPthreadKeyCallBacks = * thred if called from within the late-cleanup function. */ static NSMapTable *_exitingThreads = nil; -static pthread_mutex_t _exitingThreadsLock = PTHREAD_MUTEX_INITIALIZER; +static gs_mutex_t _exitingThreadsLock = GS_MUTEX_INIT_STATIC; /** @@ -588,7 +597,7 @@ static pthread_mutex_t _exitingThreadsLock = PTHREAD_MUTEX_INITIALIZER; static inline void _willLateUnregisterThread(NSValue *boxedThread, NSThread *specific) { - pthread_mutex_lock(&_exitingThreadsLock); + GS_MUTEX_LOCK(_exitingThreadsLock); /* The map table is created lazily/late so that the NSThread * +initialize method can be called without causing other * classes to be initialized. @@ -603,7 +612,7 @@ static inline void _willLateUnregisterThread(NSValue *boxedThread, } NSMapInsert(_exitingThreads, (const void*)boxedThread, (const void*)specific); - pthread_mutex_unlock(&_exitingThreadsLock); + GS_MUTEX_UNLOCK(_exitingThreadsLock); } /** @@ -617,12 +626,12 @@ static inline void _didLateUnregisterCurrentThread(NSValue *boxedThread) * because the exception handler stores information in the current * thread variables ... which causes recursion. */ - pthread_mutex_lock(&_exitingThreadsLock); + GS_MUTEX_LOCK(_exitingThreadsLock); if (nil != _exitingThreads) { NSMapRemove(_exitingThreads, (const void*)boxedThread); } - pthread_mutex_unlock(&_exitingThreadsLock); + GS_MUTEX_UNLOCK(_exitingThreadsLock); } /* @@ -654,14 +663,14 @@ static void exitedThread(void *thread) /* On some systems this is called with a null thread pointer, * so try to get the NSThread object for the current thread. */ - thread = pthread_getspecific(thread_object_key); + thread = GS_THREAD_KEY_GET(thread_object_key); if (0 == thread) { return; // no thread info } } RETAIN((NSThread*)thread); - ref = NSValueCreateFromPthread(pthread_self()); + ref = NSValueCreateFromPthread(GS_THREAD_ID_SELF()); _willLateUnregisterThread(ref, (NSThread*)thread); { @@ -701,17 +710,17 @@ GSCurrentThread(void) if (NO == keyInitialized) { - if (pthread_key_create(&thread_object_key, exitedThread)) + if (!GS_THREAD_KEY_INIT(thread_object_key, exitedThread)) { [NSException raise: NSInternalInconsistencyException format: @"Unable to create thread key!"]; } keyInitialized = YES; } - thr = pthread_getspecific(thread_object_key); + thr = GS_THREAD_KEY_GET(thread_object_key); if (nil == thr) { - NSValue *selfThread = NSValueCreateFromPthread(pthread_self()); + NSValue *selfThread = NSValueCreateFromPthread(GS_THREAD_ID_SELF()); /* NB this locked section cannot be protected by an exception handler * because the exception handler stores information in the current @@ -719,15 +728,15 @@ GSCurrentThread(void) */ if (nil != _exitingThreads) { - pthread_mutex_lock(&_exitingThreadsLock); + GS_MUTEX_LOCK(_exitingThreadsLock); thr = NSMapGet(_exitingThreads, (const void*)selfThread); - pthread_mutex_unlock(&_exitingThreadsLock); + GS_MUTEX_UNLOCK(_exitingThreadsLock); } DESTROY(selfThread); if (nil == thr) { GSRegisterCurrentThread(); - thr = pthread_getspecific(thread_object_key); + thr = GS_THREAD_KEY_GET(thread_object_key); if ((nil == defaultThread) && IS_MAIN_PTHREAD) { defaultThread = RETAIN(thr); @@ -763,7 +772,7 @@ GSCurrentThreadDictionary(void) static void gnustep_base_thread_callback(void) { - static pthread_mutex_t threadLock = PTHREAD_MUTEX_INITIALIZER; + static gs_mutex_t threadLock = GS_MUTEX_INIT_STATIC; /* * Protect this function with locking ... to avoid any possibility * of multiple threads registering with the system simultaneously, @@ -772,7 +781,7 @@ gnustep_base_thread_callback(void) */ if (entered_multi_threaded_state == NO) { - pthread_mutex_lock(&threadLock); + GS_MUTEX_LOCK(threadLock); if (entered_multi_threaded_state == NO) { /* @@ -823,7 +832,7 @@ gnustep_base_thread_callback(void) NS_ENDHANDLER LEAVE_POOL } - pthread_mutex_unlock(&threadLock); + GS_MUTEX_UNLOCK(threadLock); } } @@ -834,9 +843,9 @@ gnustep_base_thread_callback(void) * pthread specific memory before we do anything which might need to * check what the current thread is (like getting the ID)! */ - pthread_setspecific(thread_object_key, self); + GS_THREAD_KEY_SET(thread_object_key, self); threadID = GSPrivateThreadID(); - pthread_mutex_lock(&_activeLock); + GS_MUTEX_LOCK(_activeLock); /* The hash table is created lazily/late so that the NSThread * +initialize method can be called without causing other * classes to be initialized. @@ -850,7 +859,7 @@ gnustep_base_thread_callback(void) NSNonRetainedObjectHashCallBacks, 100); } NSHashInsert(_activeThreads, (const void*)self); - pthread_mutex_unlock(&_activeLock); + GS_MUTEX_UNLOCK(_activeLock); } @end @@ -888,7 +897,7 @@ unregisterActiveThread(NSThread *thread) [(GSRunLoopThreadInfo*)thread->_runLoopInfo invalidate]; LEAVE_POOL RELEASE(thread); - pthread_setspecific(thread_object_key, nil); + GS_THREAD_KEY_SET(thread_object_key, nil); } } @@ -906,7 +915,7 @@ unregisterActiveThread(NSThread *thread) + (BOOL) _createThreadForCurrentPthread { - NSThread *t = pthread_getspecific(thread_object_key); + NSThread *t = GS_THREAD_KEY_GET(thread_object_key); if (t == nil) { @@ -962,7 +971,11 @@ unregisterActiveThread(NSThread *thread) } else { +#if GS_USE_WIN32_THREADS_AND_LOCKS + _endthread(); +#else pthread_exit(NULL); +#endif } } } @@ -976,7 +989,7 @@ unregisterActiveThread(NSThread *thread) { if (NO == keyInitialized) { - if (pthread_key_create(&thread_object_key, exitedThread)) + if (!GS_THREAD_KEY_INIT(thread_object_key, exitedThread)) { [NSException raise: NSInternalInconsistencyException format: @"Unable to create thread key!"]; @@ -1014,9 +1027,34 @@ unregisterActiveThread(NSThread *thread) * range 0.0 (lowest) to 1.0 (highest) which is mapped to the underlying * system priorities. */ -+ (void) setThreadPriority: (double)pri ++ (BOOL) setThreadPriority: (double)pri { -#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING > 0) +#if GS_USE_WIN32_THREADS_AND_LOCKS + // convert [0.0,1.0] priority to Windows defines + int winPri; + if (pri <= 0.0) { + winPri = THREAD_PRIORITY_IDLE; + } else if (pri <= 0.25) { + winPri = THREAD_PRIORITY_LOWEST; + } else if (pri < 0.5) { + winPri = THREAD_PRIORITY_BELOW_NORMAL; + } else if (pri >= 1.0) { + winPri = THREAD_PRIORITY_TIME_CRITICAL; + } else if (pri >= 0.75) { + winPri = THREAD_PRIORITY_HIGHEST; + } else if (pri > 0.5) { + winPri = THREAD_PRIORITY_ABOVE_NORMAL; + } else { + winPri = THREAD_PRIORITY_NORMAL; + } + + if (!SetThreadPriority(GetCurrentThread(), winPri)) { + NSLog(@"Failed to set thread priority %d: %@", winPri, [NSError _last]); + return NO; + } + return YES; +#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING > 0) + int res; int policy; struct sched_param param; @@ -1028,9 +1066,18 @@ unregisterActiveThread(NSThread *thread) pri *= (PTHREAD_MAX_PRIORITY - PTHREAD_MIN_PRIORITY); pri += PTHREAD_MIN_PRIORITY; - pthread_getschedparam(pthread_self(), &policy, ¶m); - param.sched_priority = pri; - pthread_setschedparam(pthread_self(), policy, ¶m); + res = pthread_getschedparam(pthread_self(), &policy, ¶m); + if (res == 0) { + param.sched_priority = pri; + res = pthread_setschedparam(pthread_self(), policy, ¶m); + } + if (res != 0) { + NSLog(@"Failed to set thread priority %f: %d", pri, res); + return NO; + } + return YES; +#else + return NO; #endif } @@ -1054,21 +1101,61 @@ unregisterActiveThread(NSThread *thread) + (double) threadPriority { double pri = 0; -#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING > 0) + +#if GS_USE_WIN32_THREADS_AND_LOCKS + // convert [0.0,1.0] priority to Windows defines + int winPri = GetThreadPriority(GetCurrentThread()); + if (winPri == THREAD_PRIORITY_ERROR_RETURN) { + NSLog(@"Failed to get thread priority: %@", [NSError _last]); + return pri; + } + + switch (winPri) + { + case THREAD_PRIORITY_IDLE: + pri = 0.0; + break; + case THREAD_PRIORITY_LOWEST: + pri = 0.2; + break; + case THREAD_PRIORITY_BELOW_NORMAL: + pri = 0.4; + break; + case THREAD_PRIORITY_TIME_CRITICAL: + pri = 1.0; + break; + case THREAD_PRIORITY_HIGHEST: + pri = 0.8; + break; + case THREAD_PRIORITY_ABOVE_NORMAL: + pri = 0.6; + break; + case THREAD_PRIORITY_NORMAL: + pri = 0.5; + break; + default: + NSLog(@"Unknown thread priority: %d", winPri); + break; + } +#elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING > 0) + int res; int policy; struct sched_param param; - pthread_getschedparam(pthread_self(), &policy, ¶m); - pri = param.sched_priority; - // Scale pri based on the range of the host system. - pri -= PTHREAD_MIN_PRIORITY; - pri /= (PTHREAD_MAX_PRIORITY - PTHREAD_MIN_PRIORITY); - + res = pthread_getschedparam(pthread_self(), &policy, ¶m); + if (res == 0) { + pri = param.sched_priority; + // Scale pri based on the range of the host system. + pri -= PTHREAD_MIN_PRIORITY; + pri /= (PTHREAD_MAX_PRIORITY - PTHREAD_MIN_PRIORITY); + } else { + NSLog(@"Failed to get thread priority: %d", res); + } #else #warning Your pthread implementation does not support thread priorities #endif - return pri; + return pri; } @@ -1132,9 +1219,9 @@ unregisterActiveThread(NSThread *thread) DESTROY(_gcontext); if (_activeThreads) { - pthread_mutex_lock(&_activeLock); + GS_MUTEX_LOCK(_activeLock); NSHashRemove(_activeThreads, self); - pthread_mutex_unlock(&_activeLock); + GS_MUTEX_UNLOCK(_activeLock); } if (GS_EXISTS_INTERNAL) { @@ -1311,7 +1398,12 @@ unregisterActiveThread(NSThread *thread) /** * Trampoline function called to launch the thread */ -static void * +static +#if GS_USE_WIN32_THREADS_AND_LOCKS +void __cdecl +#else +void * +#endif nsthreadLauncher(void *thread) { NSThread *t = (NSThread*)thread; @@ -1335,12 +1427,16 @@ nsthreadLauncher(void *thread) [NSThread exit]; // Not reached +#if !GS_USE_WIN32_THREADS_AND_LOCKS return NULL; +#endif } - (void) start { +#if !GS_USE_WIN32_THREADS_AND_LOCKS pthread_attr_t attr; +#endif if (_active == YES) { @@ -1377,6 +1473,16 @@ nsthreadLauncher(void *thread) _active = YES; errno = 0; + +#if GS_USE_WIN32_THREADS_AND_LOCKS + if (_beginthread(nsthreadLauncher, _stackSize, self) == -1) + { + DESTROY(self); + [NSException raise: NSInternalInconsistencyException + format: @"Unable to detach thread (last error %d)", + errno]; + } +#else pthread_attr_init(&attr); /* Create this thread detached, because we never use the return state from * threads. @@ -1396,6 +1502,7 @@ nsthreadLauncher(void *thread) format: @"Unable to detach thread (last error %@)", [NSError _last]]; } +#endif } /** @@ -1563,7 +1670,7 @@ lockInfoErr(NSString *str) * This also ensures that no more than one thread can be checking for * deadlocks at a time (no interference between checks). */ - pthread_mutex_lock(&_activeLock); + GS_MUTEX_LOCK(_activeLock); /* As we isolate dependencies (a thread holding the lock another thread * is waiting for) we disable locking in each thread and record the @@ -1695,7 +1802,7 @@ lockInfoErr(NSString *str) /* Finished check ... re-enable thread activity changes. */ - pthread_mutex_unlock(&_activeLock); + GS_MUTEX_UNLOCK(_activeLock); if (nil != dependencies) diff --git a/Source/NSTimeZone.m b/Source/NSTimeZone.m index 13ee66ec7..8e4527fe3 100644 --- a/Source/NSTimeZone.m +++ b/Source/NSTimeZone.m @@ -289,7 +289,7 @@ static NSMutableDictionary *abbreviationDictionary = nil; static NSMutableDictionary *abbreviationMap = nil; /* Lock for creating time zones. */ -static pthread_mutex_t zone_mutex; +static gs_mutex_t zone_mutex; static Class NSTimeZoneClass; static Class GSPlaceholderTimeZoneClass; @@ -387,14 +387,14 @@ static NSString *_time_zone_path(NSString *subpath, NSString *type) * Return a cached time zone if possible. * NB. if data of cached zone does not match new data ... don't use cache */ - pthread_mutex_lock(&zone_mutex); + GS_MUTEX_LOCK(zone_mutex); zone = [zoneDictionary objectForKey: name]; if (data != nil && [data isEqual: [zone data]] == NO) { zone = nil; } IF_NO_GC(RETAIN(zone)); - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); if (zone == nil) { @@ -657,9 +657,9 @@ static NSMapTable *absolutes = 0; { if (offset != uninitialisedOffset) { - pthread_mutex_lock(&zone_mutex); + GS_MUTEX_LOCK(zone_mutex); NSMapRemove(absolutes, (void*)(uintptr_t)offset); - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); } RELEASE(name); RELEASE(detail); @@ -715,7 +715,7 @@ static NSMapTable *absolutes = 0; } } - pthread_mutex_lock(&zone_mutex); + GS_MUTEX_LOCK(zone_mutex); z = (GSAbsTimeZone*)NSMapGet(absolutes, (void*)(uintptr_t)anOffset); if (z != nil) { @@ -766,7 +766,7 @@ static NSMapTable *absolutes = 0; commonAbsolutes[index] = RETAIN(self); } } - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); return z; } @@ -986,7 +986,7 @@ static NSMapTable *absolutes = 0; { return abbreviationDictionary; } - pthread_mutex_lock(&zone_mutex); + GS_MUTEX_LOCK(zone_mutex); if (abbreviationDictionary == nil) { NSAutoreleasePool *pool = [NSAutoreleasePool new]; @@ -1043,7 +1043,7 @@ static NSMapTable *absolutes = 0; } [pool drain]; } - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); return abbreviationDictionary; } @@ -1061,7 +1061,7 @@ static NSMapTable *absolutes = 0; { return abbreviationMap; } - pthread_mutex_lock(&zone_mutex); + GS_MUTEX_LOCK(zone_mutex); if (abbreviationMap == nil) { NSAutoreleasePool *pool = [NSAutoreleasePool new]; @@ -1095,7 +1095,7 @@ static NSMapTable *absolutes = 0; #endif if (file == NULL) { - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); [NSException raise: NSInternalInconsistencyException format: @"Failed to open time zone abbreviation map."]; @@ -1186,7 +1186,7 @@ static NSMapTable *absolutes = 0; } [pool drain]; } - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); return abbreviationMap; } @@ -1204,7 +1204,7 @@ static NSMapTable *absolutes = 0; return namesArray; } - pthread_mutex_lock(&zone_mutex); + GS_MUTEX_LOCK(zone_mutex); if (namesArray == nil) { unsigned i; @@ -1230,7 +1230,7 @@ static NSMapTable *absolutes = 0; RELEASE(ma); } } - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); return namesArray; } @@ -1260,7 +1260,7 @@ static NSMapTable *absolutes = 0; * locate the correct placeholder in the (lock protected) * table of placeholders. */ - pthread_mutex_lock(&zone_mutex); + GS_MUTEX_LOCK(zone_mutex); obj = (id)NSMapGet(placeholderMap, (void*)z); if (obj == nil) { @@ -1271,7 +1271,7 @@ static NSMapTable *absolutes = 0; obj = (id)NSAllocateObject(GSPlaceholderTimeZoneClass, 0, z); NSMapInsert(placeholderMap, (void*)z, (void*)obj); } - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); return obj; } } @@ -1288,7 +1288,7 @@ static NSMapTable *absolutes = 0; { NSTimeZone *zone; - pthread_mutex_lock(&zone_mutex); + GS_MUTEX_LOCK(zone_mutex); if (defaultTimeZone == nil) { zone = [self systemTimeZone]; @@ -1297,7 +1297,7 @@ static NSMapTable *absolutes = 0; { zone = AUTORELEASE(RETAIN(defaultTimeZone)); } - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); return zone; } @@ -1306,7 +1306,7 @@ static NSMapTable *absolutes = 0; if (self == [NSTimeZone class]) { NSTimeZoneClass = self; - GS_INIT_RECURSIVE_MUTEX(zone_mutex); + GS_MUTEX_INIT_RECURSIVE(zone_mutex); GSPlaceholderTimeZoneClass = [GSPlaceholderTimeZone class]; zoneDictionary = [[NSMutableDictionary alloc] init]; [[NSObject leakAt: &zoneDictionary] release]; @@ -1351,9 +1351,9 @@ static NSMapTable *absolutes = 0; */ + (void) resetSystemTimeZone { - pthread_mutex_lock(&zone_mutex); + GS_MUTEX_LOCK(zone_mutex); DESTROY(systemTimeZone); - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); [[NSNotificationCenter defaultCenter] postNotificationName: NSSystemTimeZoneDidChangeNotification object: nil]; @@ -1374,9 +1374,9 @@ static NSMapTable *absolutes = 0; { aTimeZone = [self systemTimeZone]; } - pthread_mutex_lock(&zone_mutex); + GS_MUTEX_LOCK(zone_mutex); ASSIGN(defaultTimeZone, aTimeZone); - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); } } @@ -1387,7 +1387,7 @@ static NSMapTable *absolutes = 0; { NSTimeZone *zone = nil; - pthread_mutex_lock(&zone_mutex); + GS_MUTEX_LOCK(zone_mutex); if (systemTimeZone == nil) { NSFileManager *dflt = [NSFileManager defaultManager]; @@ -1727,7 +1727,7 @@ localZoneString, [zone name], sign, s/3600, (s/60)%60); ASSIGN(systemTimeZone, zone); } zone = AUTORELEASE(RETAIN(systemTimeZone)); - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); return zone; } @@ -1746,7 +1746,7 @@ localZoneString, [zone name], sign, s/3600, (s/60)%60); { return regionsArray; } - pthread_mutex_lock(&zone_mutex); + GS_MUTEX_LOCK(zone_mutex); if (regionsArray == nil) { NSAutoreleasePool *pool = [NSAutoreleasePool new]; @@ -1778,7 +1778,7 @@ localZoneString, [zone name], sign, s/3600, (s/60)%60); #endif if (fp == NULL) { - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); [NSException raise: NSInternalInconsistencyException format: @"Failed to open time zone regions array file."]; @@ -1878,7 +1878,7 @@ localZoneString, [zone name], sign, s/3600, (s/60)%60); regionsArray = [[NSArray alloc] initWithObjects: temp_array count: 24]; [pool drain]; } - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); return regionsArray; } @@ -1921,9 +1921,9 @@ localZoneString, [zone name], sign, s/3600, (s/60)%60); } else { - pthread_mutex_lock(&zone_mutex); + GS_MUTEX_LOCK(zone_mutex); zone = (NSTimeZone*)NSMapGet(absolutes, (void*)(uintptr_t)seconds); - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); } if (nil == zone) { @@ -2403,7 +2403,7 @@ static NSString *zoneDirs[] = { if (beenHere == NO && tzdir == nil) { - pthread_mutex_lock(&zone_mutex); + GS_MUTEX_LOCK(zone_mutex); if (beenHere == NO && tzdir == nil) { NSFileManager *mgr = [NSFileManager defaultManager]; @@ -2424,7 +2424,7 @@ static NSString *zoneDirs[] = { } beenHere = YES; } - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); } /* Use the system zone info if possible, otherwise, use our installed info. */ @@ -3198,9 +3198,9 @@ newDetailInZoneForType(GSTimeZone *zone, TypeInfo *type) } } - pthread_mutex_lock(&zone_mutex); + GS_MUTEX_LOCK(zone_mutex); [zoneDictionary setObject: self forKey: timeZoneName]; - pthread_mutex_unlock(&zone_mutex); + GS_MUTEX_UNLOCK(zone_mutex); } NS_HANDLER { diff --git a/Source/NSZone.m b/Source/NSZone.m index b63c6f4a7..9c5a601c0 100644 --- a/Source/NSZone.m +++ b/Source/NSZone.m @@ -93,7 +93,7 @@ #import "GSPrivate.h" #import "GSPThread.h" -static pthread_mutex_t zoneLock = PTHREAD_MUTEX_INITIALIZER; +static gs_mutex_t zoneLock = GS_MUTEX_INIT_STATIC; /** * Try to get more memory - the normal process has failed. @@ -205,12 +205,12 @@ NSSetZoneName (NSZone *zone, NSString *name) { if (!zone) zone = NSDefaultMallocZone(); - pthread_mutex_lock(&zoneLock); + GS_MUTEX_LOCK(zoneLock); name = [name copy]; if (zone->name != nil) [zone->name release]; zone->name = name; - pthread_mutex_unlock(&zoneLock); + GS_MUTEX_UNLOCK(zoneLock); } GS_DECLARE NSString* @@ -303,7 +303,7 @@ struct _ffree_free_link struct _ffree_zone_struct { NSZone common; - pthread_mutex_t lock; + gs_mutex_t lock; ff_block *blocks; // Linked list of blocks ff_link *segheadlist[MAX_SEG]; // Segregated list, holds heads ff_link *segtaillist[MAX_SEG]; // Segregated list, holds tails @@ -452,7 +452,7 @@ chunkPrev(ff_block *ptr) struct _nfree_zone_struct { NSZone common; - pthread_mutex_t lock; + gs_mutex_t lock; /* Linked list of blocks in decreasing order of free space, except maybe for the first block. */ nf_block *blocks; @@ -542,7 +542,7 @@ fmalloc (NSZone *zone, size_t size) ff_block *chunkhead; void *result; - pthread_mutex_lock(&(zptr->lock)); + GS_MUTEX_LOCK(zptr->lock); bufsize = zptr->bufsize; while ((i < bufsize) && (chunksize > size_buf[i])) i++; @@ -581,7 +581,7 @@ fmalloc (NSZone *zone, size_t size) chunkhead = get_chunk(zptr, chunksize); if (chunkhead == NULL) { - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); if (zone->name != nil) [NSException raise: NSMallocException format: @"Zone %@ has run out of memory", zone->name]; @@ -600,7 +600,7 @@ fmalloc (NSZone *zone, size_t size) *((char*)chunkhead->next) = (char)42; chunkSetLive(chunkhead); result = chunkToPointer(chunkhead); - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); return result; } @@ -624,7 +624,7 @@ frealloc (NSZone *zone, void *ptr, size_t size) if (ptr == NULL) return fmalloc(zone, size); chunkhead = pointerToChunk(ptr); - pthread_mutex_lock(&(zptr->lock)); + GS_MUTEX_LOCK(zptr->lock); realsize = chunkSize(chunkhead); NSAssert(chunkIsInUse(chunkhead), NSInternalInconsistencyException); @@ -680,7 +680,7 @@ frealloc (NSZone *zone, void *ptr, size_t size) newchunk = get_chunk(zptr, chunksize); if (newchunk == NULL) { - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); if (zone->name != nil) [NSException raise: NSMallocException format: @"Zone %@ has run out of memory", @@ -698,7 +698,7 @@ frealloc (NSZone *zone, void *ptr, size_t size) *((char*)chunkhead->next) = (char)42; chunkSetLive(chunkhead); result = chunkToPointer(chunkhead); - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); return result; } @@ -708,14 +708,14 @@ ffree (NSZone *zone, void *ptr) { ff_block *chunk; NSAssert(NSZoneFromPointer(ptr) == zone, NSInternalInconsistencyException); - pthread_mutex_lock(&(((ffree_zone*)zone)->lock)); + GS_MUTEX_LOCK(((ffree_zone*)zone)->lock); chunk = pointerToChunk(ptr); if (chunkIsLive(chunk) == 0) [NSException raise: NSMallocException format: @"Attempt to free freed memory"]; NSAssert(*((char*)chunk->next) == (char)42, NSInternalInconsistencyException); add_buf((ffree_zone*)zone, chunk); - pthread_mutex_unlock(&(((ffree_zone*)zone)->lock)); + GS_MUTEX_UNLOCK(((ffree_zone*)zone)->lock); } static BOOL @@ -725,7 +725,7 @@ frecycle1(NSZone *zone) ff_block *block; ff_block *nextblock; - pthread_mutex_lock(&(zptr->lock)); + GS_MUTEX_LOCK(zptr->lock); flush_buf(zptr); block = zptr->blocks; while (block != NULL) @@ -747,10 +747,10 @@ frecycle1(NSZone *zone) } block = nextblock; } - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); if (zptr->blocks == 0) { - pthread_mutex_destroy(&(zptr->lock)); + GS_MUTEX_DESTROY(zptr->lock); return YES; } return NO; @@ -760,7 +760,7 @@ frecycle1(NSZone *zone) static void frecycle (NSZone *zone) { - pthread_mutex_lock(&zoneLock); + GS_MUTEX_LOCK(zoneLock); if (zone->name != nil) { NSString *name = zone->name; @@ -776,17 +776,17 @@ frecycle (NSZone *zone) zone->free = rffree; zone->recycle = rrecycle; } - pthread_mutex_unlock(&zoneLock); + GS_MUTEX_UNLOCK(zoneLock); } static void rffree (NSZone *zone, void *ptr) { ffree(zone, ptr); - pthread_mutex_lock(&zoneLock); + GS_MUTEX_LOCK(zoneLock); if (frecycle1(zone)) destroy_zone(zone); - pthread_mutex_unlock(&zoneLock); + GS_MUTEX_UNLOCK(zoneLock); } @@ -799,7 +799,7 @@ fcheck (NSZone *zone) ffree_zone *zptr = (ffree_zone*)zone; ff_block *block; - pthread_mutex_lock(&(zptr->lock)); + GS_MUTEX_LOCK(zptr->lock); /* Check integrity of each block the zone owns. */ block = zptr->blocks; while (block != NULL) @@ -892,11 +892,11 @@ fcheck (NSZone *zone) if ((zptr->size_buf[i] != chunkSize(chunk)) || !chunkIsInUse(chunk)) goto inconsistent; } - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); return YES; inconsistent: // Jump here if an inconsistency was found. - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); return NO; } @@ -907,7 +907,7 @@ flookup (NSZone *zone, void *ptr) ff_block *block; BOOL found = NO; - pthread_mutex_lock(&(zptr->lock)); + GS_MUTEX_LOCK(zptr->lock); for (block = zptr->blocks; block != NULL; block = block->next) { if (ptr >= (void*)block && ptr < (void*)chunkNext(block)) @@ -916,7 +916,7 @@ flookup (NSZone *zone, void *ptr) break; } } - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); return found; } @@ -935,7 +935,7 @@ fstats (NSZone *zone) stats.bytes_used = 0; stats.chunks_free = 0; stats.bytes_free = 0; - pthread_mutex_lock(&(zptr->lock)); + GS_MUTEX_LOCK(zptr->lock); block = zptr->blocks; /* Go through each block. */ while (block != NULL) @@ -970,7 +970,7 @@ fstats (NSZone *zone) stats.bytes_used -= zptr->size_buf[i]; stats.bytes_free += zptr->size_buf[i]; } - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); /* Remove overhead. */ stats.bytes_used -= FBSZ*stats.chunks_used; return stats; @@ -1291,7 +1291,7 @@ nmalloc (NSZone *zone, size_t size) nf_block *block; size_t top; - pthread_mutex_lock(&(zptr->lock)); + GS_MUTEX_LOCK(zptr->lock); block = zptr->blocks; top = block->top; freesize = block->size-top; @@ -1326,7 +1326,7 @@ nmalloc (NSZone *zone, size_t size) block = malloc(blocksize); if (block == NULL) { - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); if (zone->name != nil) [NSException raise: NSMallocException format: @"Zone %@ has run out of memory", @@ -1344,7 +1344,7 @@ nmalloc (NSZone *zone, size_t size) block->top += chunksize; } zptr->use++; - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); return chunkhead; } @@ -1355,7 +1355,7 @@ nrecycle1 (NSZone *zone) { nfree_zone *zptr = (nfree_zone*)zone; - pthread_mutex_lock(&(zptr->lock)); + GS_MUTEX_LOCK(zptr->lock); if (zptr->use == 0) { nf_block *nextblock; @@ -1369,10 +1369,10 @@ nrecycle1 (NSZone *zone) } zptr->blocks = 0; } - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); if (zptr->blocks == 0) { - pthread_mutex_destroy(&(zptr->lock)); + GS_MUTEX_DESTROY(zptr->lock); return YES; } return NO; @@ -1382,7 +1382,7 @@ nrecycle1 (NSZone *zone) static void nrecycle (NSZone *zone) { - pthread_mutex_lock(&zoneLock); + GS_MUTEX_LOCK(zoneLock); if (zone->name != nil) { NSString *name = zone->name; @@ -1398,7 +1398,7 @@ nrecycle (NSZone *zone) zone->free = rnfree; zone->recycle = rrecycle; } - pthread_mutex_unlock(&zoneLock); + GS_MUTEX_UNLOCK(zoneLock); } static void* @@ -1409,7 +1409,7 @@ nrealloc (NSZone *zone, void *ptr, size_t size) if (ptr != 0) { - pthread_mutex_lock(&(zptr->lock)); + GS_MUTEX_LOCK(zptr->lock); if (tmp) { nf_block *block; @@ -1429,7 +1429,7 @@ nrealloc (NSZone *zone, void *ptr, size_t size) } } zptr->use--; - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); } return tmp; } @@ -1445,9 +1445,9 @@ nfree (NSZone *zone, void *ptr) { nfree_zone *zptr = (nfree_zone*)zone; - pthread_mutex_lock(&(zptr->lock)); + GS_MUTEX_LOCK(zptr->lock); zptr->use--; - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); } static void @@ -1458,10 +1458,10 @@ rnfree (NSZone *zone, void *ptr) nfree(zone, ptr); if (zptr->use == 0) { - pthread_mutex_lock(&zoneLock); + GS_MUTEX_LOCK(zoneLock); nrecycle1(zone); destroy_zone(zone); - pthread_mutex_unlock(&zoneLock); + GS_MUTEX_UNLOCK(zoneLock); } } @@ -1473,19 +1473,19 @@ ncheck (NSZone *zone) nfree_zone *zptr = (nfree_zone*)zone; nf_block *block; - pthread_mutex_lock(&(zptr->lock)); + GS_MUTEX_LOCK(zptr->lock); block = zptr->blocks; while (block != NULL) { if (block->size < block->top) { - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); return NO; } block = block->next; } /* FIXME: Do more checking? */ - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); return YES; } @@ -1496,7 +1496,7 @@ nlookup (NSZone *zone, void *ptr) nf_block *block; BOOL found = NO; - pthread_mutex_lock(&(zptr->lock)); + GS_MUTEX_LOCK(zptr->lock); for (block = zptr->blocks; block != NULL; block = block->next) { if (ptr >= (void*)block && ptr < ((void*)block)+block->size) @@ -1505,7 +1505,7 @@ nlookup (NSZone *zone, void *ptr) break; } } - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); return found; } @@ -1523,7 +1523,7 @@ nstats (NSZone *zone) stats.bytes_used = 0; stats.chunks_free = 0; stats.bytes_free = 0; - pthread_mutex_lock(&(zptr->lock)); + GS_MUTEX_LOCK(zptr->lock); block = zptr->blocks; while (block != NULL) { @@ -1544,7 +1544,7 @@ nstats (NSZone *zone) } block = block->next; } - pthread_mutex_unlock(&(zptr->lock)); + GS_MUTEX_UNLOCK(zptr->lock); return stats; } @@ -1585,7 +1585,7 @@ NSZoneFromPointer(void *ptr) /* * See if we can find the zone in our list of all zones. */ - pthread_mutex_lock(&zoneLock); + GS_MUTEX_LOCK(zoneLock); for (zone = zone_list; zone != 0; zone = zone->next) { if ((zone->lookup)(zone, ptr) == YES) @@ -1593,7 +1593,7 @@ NSZoneFromPointer(void *ptr) break; } } - pthread_mutex_unlock(&zoneLock); + GS_MUTEX_UNLOCK(zoneLock); return (zone == 0) ? &default_zone : zone; } @@ -1631,7 +1631,7 @@ NSCreateZone (NSUInteger start, NSUInteger gran, BOOL canFree) zone->common.stats = fstats; zone->common.gran = granularity; zone->common.name = nil; - GS_INIT_RECURSIVE_MUTEX(zone->lock); + GS_MUTEX_INIT_RECURSIVE(zone->lock); for (i = 0; i < MAX_SEG; i++) { zone->segheadlist[i] = NULL; @@ -1641,7 +1641,7 @@ NSCreateZone (NSUInteger start, NSUInteger gran, BOOL canFree) zone->blocks = malloc(startsize + 2*FBSZ); if (zone->blocks == NULL) { - pthread_mutex_destroy(&(zone->lock)); + GS_MUTEX_DESTROY(zone->lock); free(zone); [NSException raise: NSMallocException format: @"No memory to create zone"]; @@ -1686,12 +1686,12 @@ NSCreateZone (NSUInteger start, NSUInteger gran, BOOL canFree) zone->common.stats = nstats; zone->common.gran = granularity; zone->common.name = nil; - GS_INIT_RECURSIVE_MUTEX(zone->lock); + GS_MUTEX_INIT_RECURSIVE(zone->lock); zone->blocks = malloc(startsize); zone->use = 0; if (zone->blocks == NULL) { - pthread_mutex_destroy(&(zone->lock)); + GS_MUTEX_DESTROY(zone->lock); free(zone); [NSException raise: NSMallocException format: @"No memory to create zone"]; @@ -1704,10 +1704,10 @@ NSCreateZone (NSUInteger start, NSUInteger gran, BOOL canFree) newZone = (NSZone*)zone; } - pthread_mutex_lock(&zoneLock); + GS_MUTEX_LOCK(zoneLock); newZone->next = zone_list; zone_list = newZone; - pthread_mutex_unlock(&zoneLock); + GS_MUTEX_UNLOCK(zoneLock); return newZone; } diff --git a/Tests/base/NSThread/GNUmakefile.preamble b/Tests/base/NSThread/GNUmakefile.preamble index 368fe0930..de21ee9f4 100644 --- a/Tests/base/NSThread/GNUmakefile.preamble +++ b/Tests/base/NSThread/GNUmakefile.preamble @@ -1 +1,8 @@ -ADDITIONAL_TOOL_LIBS += -lpthread + +ifneq ($(GNUSTEP_TARGET_OS), mingw32) + ifneq ($(GNUSTEP_TARGET_OS), mingw64) + ifneq ($(GNUSTEP_TARGET_OS), windows) + ADDITIONAL_TOOL_LIBS += -lpthread + endif + endif +endif diff --git a/Tests/base/NSThread/late_unregister.m b/Tests/base/NSThread/late_unregister.m index edb2494f5..6fa636a62 100644 --- a/Tests/base/NSThread/late_unregister.m +++ b/Tests/base/NSThread/late_unregister.m @@ -2,10 +2,12 @@ #import #import #import + +#if defined(_WIN32) +#include +#else #include - - - +#endif @interface ThreadExpectation : NSObject { @@ -98,10 +100,17 @@ } @end -void *thread(void *expectation) +#if defined(_WIN32) +void __cdecl +#else +void * +#endif +thread(void *expectation) { [(ThreadExpectation*)expectation inThread: [NSThread currentThread]]; - return nil; +#if !defined(_WIN32) + return NULL; +#endif } @@ -116,13 +125,18 @@ void *thread(void *expectation) */ int main(void) { + NSAutoreleasePool *arp = [NSAutoreleasePool new]; + ThreadExpectation *expectation = [ThreadExpectation new]; + +#if defined(_WIN32) + _beginthread(thread, 0, expectation); +#else pthread_t thr; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - NSAutoreleasePool *arp = [NSAutoreleasePool new]; - ThreadExpectation *expectation = [ThreadExpectation new]; pthread_create(&thr, &attr, thread, expectation); +#endif NSDate *start = [NSDate date]; [expectation lock]; diff --git a/Tests/base/NSThread/lazy_thread.m b/Tests/base/NSThread/lazy_thread.m index 345f3cd30..efffdb619 100644 --- a/Tests/base/NSThread/lazy_thread.m +++ b/Tests/base/NSThread/lazy_thread.m @@ -1,27 +1,54 @@ #import "ObjectTesting.h" #import -#include -void *thread(void *ignored) +#if defined(_WIN32) +#include +#else +#include +#endif + +static NSThread *threadResult = nil; + +#if defined(_WIN32) +unsigned int __stdcall +#else +void * +#endif +thread(void *ignored) { - return [NSThread currentThread]; + threadResult = [NSThread currentThread]; + return 0; } int main(void) { + NSAutoreleasePool *arp = [NSAutoreleasePool new]; + +#if defined(_WIN32) + HANDLE thr; + thr = (HANDLE)_beginthreadex(NULL, 0, thread, NULL, 0, NULL); + WaitForSingleObject(thr, INFINITE); + CloseHandle(thr); +#else pthread_t thr; - void *ret; - pthread_create(&thr, NULL, thread, NULL); - pthread_join(thr, &ret); - PASS(ret != 0, "NSThread lazily created from POSIX thread"); + pthread_join(thr, NULL); +#endif + PASS(threadResult != 0, "NSThread lazily created from native thread"); testHopeful = YES; - PASS((ret != 0) && (ret != [NSThread mainThread]), + PASS((threadResult != 0) && (threadResult != [NSThread mainThread]), "Spawned thread is not main thread"); + +#if defined(_WIN32) + thr = (HANDLE)_beginthreadex(NULL, 0, thread, NULL, 0, NULL); + WaitForSingleObject(thr, INFINITE); + CloseHandle(thr); +#else pthread_create(&thr, NULL, thread, NULL); - pthread_join(thr, &ret); - PASS(ret != 0, "NSThread lazily created from POSIX thread"); - PASS((ret != 0) && (ret != [NSThread mainThread]), + pthread_join(thr, NULL); +#endif + PASS(threadResult != 0, "NSThread lazily created from native thread"); + PASS((threadResult != 0) && (threadResult != [NSThread mainThread]), "Spawned thread is not main thread"); NSThread *t = [NSThread currentThread]; @@ -29,7 +56,14 @@ int main(void) NSLog(@"Thread description is '%@'", t); NSRange r = [[t description] rangeOfString: @"name = xxxtestxxx"]; PASS(r.length > 0, "thread description contains name"); - + + PASS([NSThread threadPriority] == 0.5, "default thread priority is 0.5"); + PASS([NSThread setThreadPriority:0.8], "change thread priority to 0.8"); + PASS([NSThread threadPriority] == 0.8, "thread priority was changed to 0.8"); + PASS([NSThread setThreadPriority:0.2], "change thread priority to 0.2"); + PASS([NSThread threadPriority] == 0.2, "thread priority was changed to 0.2"); + + DESTROY(arp); return 0; } diff --git a/config/config.initialize.m b/config/config.initialize.m index c41fb47eb..faca82052 100644 --- a/config/config.initialize.m +++ b/config/config.initialize.m @@ -2,13 +2,24 @@ */ #include "objc-common.g" -#include #include #if defined(_WIN32) -# define mySleep(X) usleep(1000*(X)) + +#include +typedef unsigned thread_id_t; +#define CREATE_THREAD(threadId, start, arg) \ + _beginthreadex(NULL, 0, start, arg, 0, &threadId) != 0 +#define mySleep(X) usleep(1000*(X)) + #else -# define mySleep(X) sleep(X) + +#include +typedef pthread_t thread_id_t; +#define CREATE_THREAD(threadId, start, arg) \ + pthread_create(&threadId, 0, start, arg) == 0 +#define mySleep(X) sleep(X) + #endif #if _MSC_VER @@ -65,11 +76,11 @@ test(void *arg) int main() { - pthread_t t1; - pthread_t t2; + thread_id_t t1; + thread_id_t t2; unsigned counter; - if (0 == pthread_create(&t1, 0, test, 0)) + if (CREATE_THREAD(t1, test, 0)) { for (counter = 0; 0 == initialize_entered && counter < 5; counter++) { @@ -82,7 +93,7 @@ main() return 1; } - if (0 == pthread_create(&t2, 0, test, 0)) + if (CREATE_THREAD(t2, test, 0)) { /* Wait long enough for t2 to try calling +class */ diff --git a/configure b/configure index d242c7dbc..bc6d2b3b4 100755 --- a/configure +++ b/configure @@ -680,9 +680,12 @@ NX_CONST_STRING_CLASS NX_CONST_STRING_OBJCFLAGS GS_HAVE_OBJC_ROOT_CLASS_ATTR GS_ALIGNOF_COND_T +GS_ALIGNOF_COND_MUTEX_T GS_ALIGNOF_MUTEX_T GS_SIZEOF_COND_T +GS_SIZEOF_COND_MUTEX_T GS_SIZEOF_MUTEX_T +HAVE_WIN32_THREADS_AND_LOCKS DYNAMIC_LINKER BUGGY_PTR_LIMITS GS_UINTPTR_MAX @@ -3008,7 +3011,7 @@ then fi if test x"$GNUSTEP_TARGET_CONFIG_FILE" = x""; then case "$target_os" in - mingw*|windows*) + mingw*|windows) GNUSTEP_TARGET_CONFIG_FILE=./GNUstep.conf ;; *) GNUSTEP_TARGET_CONFIG_FILE="$GNUSTEP_MAKE_CONFIG" ;; @@ -3026,7 +3029,7 @@ $as_echo "$GNUSTEP_TARGET_CONFIG_FILE" >&6; } # location (used by gnustep-make when building). #----------------------------------------------------------------- case "$target_os" in - mingw*|windows*) enable_env_config=no;; + mingw*|windows) enable_env_config=no;; *) enable_env_config=yes;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the GNUstep.conf file path can be set in the environment" >&5 @@ -3306,7 +3309,7 @@ GNUSTEP_BASE_DOMAIN=$result # paths (relative to libgnustep-base.dll). # case "$target_os" in - mingw*|windows*) + mingw*|windows) # TODO: Improve this hack. # According to Wikipedia, this is the default for Windows 2000, # Windows XP and Windows Server 2003. For Windows Vista this will @@ -7251,10 +7254,39 @@ fi done +#-------------------------------------------------------------------- +# Windows: check if we have native threading APIs and SRW locks +#-------------------------------------------------------------------- +HAVE_WIN32_THREADS_AND_LOCKS=0 +case "$target_os" in + mingw*|windows) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for native Windows threads and locks" >&5 +$as_echo_n "checking for native Windows threads and locks... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #define GS_USE_WIN32_THREADS_AND_LOCKS 1 + #include "$srcdir/Source/GSPThread.h" + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + HAVE_WIN32_THREADS_AND_LOCKS=1 +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ;; +esac + + #-------------------------------------------------------------------- # Check for pthread.h #-------------------------------------------------------------------- -for ac_header in pthread.h +if test $HAVE_WIN32_THREADS_AND_LOCKS = 0; then + for ac_header in pthread.h do : ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" if test "x$ac_cv_header_pthread_h" = xyes; then : @@ -7266,12 +7298,12 @@ fi done -for ac_header in pthread_np.h + for ac_header in pthread_np.h do : ac_fn_c_check_header_compile "$LINENO" "pthread_np.h" "ac_cv_header_pthread_np_h" "$ac_includes_default - #ifdef HAVE_PTHREAD_H - #include - #endif + #ifdef HAVE_PTHREAD_H + #include + #endif " if test "x$ac_cv_header_pthread_np_h" = xyes; then : @@ -7283,8 +7315,8 @@ fi done -if test $ac_cv_header_pthread_h = yes ; then - # The cast to long int works around a bug in the HP C Compiler + if test $ac_cv_header_pthread_h = yes ; then + # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. @@ -7294,7 +7326,7 @@ if ${ac_cv_sizeof_pthread_mutex_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_mutex_t))" "ac_cv_sizeof_pthread_mutex_t" "$ac_includes_default -#include + #include "; then : else @@ -7319,27 +7351,31 @@ cat >>confdefs.h <<_ACEOF _ACEOF - GS_SIZEOF_MUTEX_T=$ac_cv_sizeof_pthread_mutex_t - if test $ac_cv_sizeof_pthread_mutex_t = 0 ; then - as_fn_error $? "Unable to find size of pthread_mutex_t (required)." "$LINENO" 5 - fi + GS_SIZEOF_MUTEX_T=$ac_cv_sizeof_pthread_mutex_t + if test $ac_cv_sizeof_pthread_mutex_t = 0 ; then + as_fn_error $? "Unable to find size of pthread_mutex_t (required)." "$LINENO" 5 + fi -# pthread_mutex_t.__data.__owner is non-standard since pthread_mutex_t is -# nominally an opaque type. We must not rely on this for anything other -# than debug output! - ac_fn_c_check_member "$LINENO" "pthread_mutex_t" "__data.__owner" "ac_cv_member_pthread_mutex_t___data___owner" "$ac_includes_default -#include + GS_SIZEOF_COND_MUTEX_T=$ac_cv_sizeof_pthread_mutex_t + + + # pthread_mutex_t.__data.__owner is non-standard since pthread_mutex_t is + # nominally an opaque type. We must not rely on this for anything other + # than debug output! + ac_fn_c_check_member "$LINENO" "pthread_mutex_t" "__data.__owner" "ac_cv_member_pthread_mutex_t___data___owner" "$ac_includes_default + #include " if test "x$ac_cv_member_pthread_mutex_t___data___owner" = xyes; then : fi - if test $ac_cv_member_pthread_mutex_t___data___owner = yes ; then + if test $ac_cv_member_pthread_mutex_t___data___owner = yes ; then $as_echo "#define HAVE_PTHREAD_MUTEX_OWNER 1" >>confdefs.h - fi - # The cast to long int works around a bug in the HP C Compiler + fi + + # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. @@ -7349,7 +7385,7 @@ if ${ac_cv_sizeof_pthread_cond_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_cond_t))" "ac_cv_sizeof_pthread_cond_t" "$ac_includes_default -#include + #include "; then : else @@ -7374,12 +7410,13 @@ cat >>confdefs.h <<_ACEOF _ACEOF - if test $ac_cv_sizeof_pthread_cond_t = 0 ; then - as_fn_error $? "Unable to find size of pthread_cond_t (required)." "$LINENO" 5 - fi - GS_SIZEOF_COND_T=$ac_cv_sizeof_pthread_cond_t + if test $ac_cv_sizeof_pthread_cond_t = 0 ; then + as_fn_error $? "Unable to find size of pthread_cond_t (required)." "$LINENO" 5 + fi + GS_SIZEOF_COND_T=$ac_cv_sizeof_pthread_cond_t - # The cast to long int works around a bug in the HP C Compiler, + + # The cast to long int works around a bug in the HP C Compiler, # see AC_CHECK_SIZEOF for more information. { $as_echo "$as_me:${as_lineno-$LINENO}: checking alignment of pthread_mutex_t" >&5 $as_echo_n "checking alignment of pthread_mutex_t... " >&6; } @@ -7387,7 +7424,7 @@ if ${ac_cv_alignof_pthread_mutex_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_pthread_mutex_t" "$ac_includes_default -#include + #include #ifndef offsetof # define offsetof(type, member) ((char *) &((type *) 0)->member - (char *) 0) @@ -7416,12 +7453,15 @@ cat >>confdefs.h <<_ACEOF _ACEOF - GS_ALIGNOF_MUTEX_T=$ac_cv_alignof_pthread_mutex_t - if test $ac_cv_alignof_pthread_mutex_t = 0 ; then - as_fn_error $? "Unable to find align of pthread_mutex_t (required)." "$LINENO" 5 - fi + GS_ALIGNOF_MUTEX_T=$ac_cv_alignof_pthread_mutex_t + if test $ac_cv_alignof_pthread_mutex_t = 0 ; then + as_fn_error $? "Unable to find align of pthread_mutex_t (required)." "$LINENO" 5 + fi - # The cast to long int works around a bug in the HP C Compiler, + GS_ALIGNOF_COND_MUTEX_T=$ac_cv_alignof_pthread_mutex_t + + + # The cast to long int works around a bug in the HP C Compiler, # see AC_CHECK_SIZEOF for more information. { $as_echo "$as_me:${as_lineno-$LINENO}: checking alignment of pthread_cond_t" >&5 $as_echo_n "checking alignment of pthread_cond_t... " >&6; } @@ -7429,7 +7469,7 @@ if ${ac_cv_alignof_pthread_cond_t+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_pthread_cond_t" "$ac_includes_default -#include + #include #ifndef offsetof # define offsetof(type, member) ((char *) &((type *) 0)->member - (char *) 0) @@ -7458,15 +7498,15 @@ cat >>confdefs.h <<_ACEOF _ACEOF - if test $ac_cv_alignof_pthread_cond_t = 0 ; then - as_fn_error $? "Unable to find align of pthread_cond_t (required)." "$LINENO" 5 - fi - GS_ALIGNOF_COND_T=$ac_cv_alignof_pthread_cond_t + if test $ac_cv_alignof_pthread_cond_t = 0 ; then + as_fn_error $? "Unable to find align of pthread_cond_t (required)." "$LINENO" 5 + fi + GS_ALIGNOF_COND_T=$ac_cv_alignof_pthread_cond_t -else - as_fn_error $? "Unable to find pthread.h (needed for thread support)." "$LINENO" 5 -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in -lpthread" >&5 + else + as_fn_error $? "Unable to find pthread.h (needed for thread support)." "$LINENO" 5 + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in -lpthread" >&5 $as_echo_n "checking for pthread_join in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_join+:} false; then : $as_echo_n "(cached) " >&6 @@ -7508,20 +7548,13 @@ else pthread_ok=no fi -ismingw=no -checkinlibc=no -case "$target_os" in - mingw*) ismingw=yes;; - windows) iswindows=yes;; - nto*) checkinlibc=yes;; - qnx*) checkinlibc=yes;; - *android*) checkinlibc=yes;; -esac -if test $pthread_ok = yes ; then - LIBS="$LIBS -lpthread" -else - if test $ismingw = yes ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in -lpthreadGC2" >&5 + + if test $pthread_ok = yes ; then + LIBS="$LIBS -lpthread" + else + case "$target_os" in + mingw*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in -lpthreadGC2" >&5 $as_echo_n "checking for pthread_join in -lpthreadGC2... " >&6; } if ${ac_cv_lib_pthreadGC2_pthread_join+:} false; then : $as_echo_n "(cached) " >&6 @@ -7563,12 +7596,12 @@ else pthread_ok=no fi - if test $pthread_ok = yes ; then - LIBS="$LIBS -lpthreadGC2" - fi - fi - if test $iswindows = yes ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in -lpthreadVC2" >&5 + if test $pthread_ok = yes ; then + LIBS="$LIBS -lpthreadGC2" + fi + ;; + windows) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in -lpthreadVC2" >&5 $as_echo_n "checking for pthread_join in -lpthreadVC2... " >&6; } if ${ac_cv_lib_pthreadVC2_pthread_join+:} false; then : $as_echo_n "(cached) " >&6 @@ -7610,13 +7643,13 @@ else pthread_ok=no fi - if test $pthread_ok = yes ; then - LIBS="$LIBS -lpthreadVC2" - fi - fi - # Android and QNX have pthread in libc instead of libpthread - if test $checkinlibc = yes ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in -lc" >&5 + if test $pthread_ok = yes ; then + LIBS="$LIBS -lpthreadVC2" + fi + ;; + nto*|qnx*|*android*) + # Android and QNX have pthread in libc instead of libpthread + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in -lc" >&5 $as_echo_n "checking for pthread_join in -lc... " >&6; } if ${ac_cv_lib_c_pthread_join+:} false; then : $as_echo_n "(cached) " >&6 @@ -7658,17 +7691,18 @@ else pthread_ok=no fi - if test $pthread_ok = yes ; then - LIBS="$LIBS -lc" - fi + if test $pthread_ok = yes ; then + LIBS="$LIBS -lc" + fi + ;; + esac + fi + if test $pthread_ok = no ; then + as_fn_error $? "Unable to find pthread library (needed for thread support)." "$LINENO" 5 fi -fi -if test $pthread_ok = no ; then - as_fn_error $? "Unable to find pthread library (needed for thread support)." "$LINENO" 5 -fi -# Check threading extensions -for ac_func in pthread_getthreadid_np pthread_main_np + # Check threading extensions + for ac_func in pthread_getthreadid_np pthread_main_np do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -7681,8 +7715,8 @@ fi done -# Typically need librt on Solaris for sched_yield -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lrt" >&5 + # Typically need librt on Solaris for sched_yield + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lrt" >&5 $as_echo_n "checking for sched_yield in -lrt... " >&6; } if ${ac_cv_lib_rt_sched_yield+:} false; then : $as_echo_n "(cached) " >&6 @@ -7728,62 +7762,8 @@ _ACEOF fi - -#-------------------------------------------------------------------- -# One of these function needed by NSThread.m and objc initialize test -#-------------------------------------------------------------------- -for ac_func in nanosleep usleep Sleep -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - -fi -done - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objc_root_class attribute support" >&5 -$as_echo_n "checking for objc_root_class attribute support... " >&6; } -saved_CFLAGS="$CFLAGS" -CFLAGS="$CFLAGS -Werror $OBJCFLAGS -x objective-c" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - __attribute__((objc_root_class)) @interface RootObject - @end - @implementation RootObject - @end -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 -$as_echo "found" >&6; } - gs_objc_root_class_attr=1 -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not present" >&5 -$as_echo "not present" >&6; } - gs_objc_root_class_attr=0 - -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -GS_HAVE_OBJC_ROOT_CLASS_ATTR=$gs_objc_root_class_attr - - -cat >>confdefs.h <<_ACEOF -#define HAVE_OBJC_ROOT_CLASS_ATTRIBUTE $gs_objc_root_class_attr -_ACEOF - -CFLAGS=$saved_CFLAGS - - -#-------------------------------------------------------------------- -# Check if we can name pthreads -#-------------------------------------------------------------------- - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_setname_np()" >&5 + # Check if we can name pthreads + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_setname_np()" >&5 $as_echo_n "checking for pthread_setname_np()... " >&6; } if ${gs_cv_pthread_setname_np+:} false; then : $as_echo_n "(cached) " >&6 @@ -7843,28 +7823,26 @@ rm -f core conftest.err conftest.$ac_objext \ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gs_cv_pthread_setname_np" >&5 $as_echo "$gs_cv_pthread_setname_np" >&6; } -case $gs_cv_pthread_setname_np in - darwin) + case $gs_cv_pthread_setname_np in + darwin) $as_echo "#define PTHREAD_SETNAME(a) pthread_setname_np(a)" >>confdefs.h - ;; - glibc) + ;; + glibc) $as_echo "#define PTHREAD_SETNAME(a) pthread_setname_np(pthread_self(),a)" >>confdefs.h - ;; - netbsd) + ;; + netbsd) $as_echo "#define PTHREAD_SETNAME(a) pthread_setname_np(pthread_self(),\"%s\",a)" >>confdefs.h - ;; -esac + ;; + esac -#-------------------------------------------------------------------- -# Check if we have spinlock support -#-------------------------------------------------------------------- -for ac_func in pthread_spin_lock + # Check if we have spinlock support + for ac_func in pthread_spin_lock do : ac_fn_c_check_func "$LINENO" "pthread_spin_lock" "ac_cv_func_pthread_spin_lock" if test "x$ac_cv_func_pthread_spin_lock" = xyes; then : @@ -7875,6 +7853,315 @@ _ACEOF fi done +fi + +#-------------------------------------------------------------------- +# Check Win32 lock sizes +#-------------------------------------------------------------------- +if test $HAVE_WIN32_THREADS_AND_LOCKS = 1; then + # The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of gs_mutex_t" >&5 +$as_echo_n "checking size of gs_mutex_t... " >&6; } +if ${ac_cv_sizeof_gs_mutex_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (gs_mutex_t))" "ac_cv_sizeof_gs_mutex_t" "$ac_includes_default + #define GS_USE_WIN32_THREADS_AND_LOCKS 1 + #include \"Source/GSPThread.h\" +"; then : + +else + if test "$ac_cv_type_gs_mutex_t" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (gs_mutex_t) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_gs_mutex_t=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_gs_mutex_t" >&5 +$as_echo "$ac_cv_sizeof_gs_mutex_t" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_GS_MUTEX_T $ac_cv_sizeof_gs_mutex_t +_ACEOF + + + GS_SIZEOF_MUTEX_T=$ac_cv_sizeof_gs_mutex_t + if test $ac_cv_sizeof_gs_mutex_t = 0 ; then + as_fn_error $? "Unable to find size of gs_mutex_t (required)." "$LINENO" 5 + fi + + + # The cast to long int works around a bug in the HP C Compiler, +# see AC_CHECK_SIZEOF for more information. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking alignment of gs_mutex_t" >&5 +$as_echo_n "checking alignment of gs_mutex_t... " >&6; } +if ${ac_cv_alignof_gs_mutex_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_gs_mutex_t" "$ac_includes_default + #define GS_USE_WIN32_THREADS_AND_LOCKS 1 + #include \"Source/GSPThread.h\" + +#ifndef offsetof +# define offsetof(type, member) ((char *) &((type *) 0)->member - (char *) 0) +#endif +typedef struct { char x; gs_mutex_t y; } ac__type_alignof_;"; then : + +else + if test "$ac_cv_type_gs_mutex_t" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute alignment of gs_mutex_t +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_alignof_gs_mutex_t=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_gs_mutex_t" >&5 +$as_echo "$ac_cv_alignof_gs_mutex_t" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define ALIGNOF_GS_MUTEX_T $ac_cv_alignof_gs_mutex_t +_ACEOF + + + GS_ALIGNOF_MUTEX_T=$ac_cv_alignof_gs_mutex_t + if test $ac_cv_alignof_gs_mutex_t = 0 ; then + as_fn_error $? "Unable to find align of gs_mutex_t (required)." "$LINENO" 5 + fi + + + # The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of CONDITION_VARIABLE" >&5 +$as_echo_n "checking size of CONDITION_VARIABLE... " >&6; } +if ${ac_cv_sizeof_CONDITION_VARIABLE+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (CONDITION_VARIABLE))" "ac_cv_sizeof_CONDITION_VARIABLE" "$ac_includes_default + #include +"; then : + +else + if test "$ac_cv_type_CONDITION_VARIABLE" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (CONDITION_VARIABLE) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_CONDITION_VARIABLE=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_CONDITION_VARIABLE" >&5 +$as_echo "$ac_cv_sizeof_CONDITION_VARIABLE" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_CONDITION_VARIABLE $ac_cv_sizeof_CONDITION_VARIABLE +_ACEOF + + + GS_SIZEOF_COND_T=$ac_cv_sizeof_CONDITION_VARIABLE + if test $ac_cv_sizeof_CONDITION_VARIABLE = 0 ; then + as_fn_error $? "Unable to find size of CONDITION_VARIABLE (required)." "$LINENO" 5 + fi + + + # The cast to long int works around a bug in the HP C Compiler, +# see AC_CHECK_SIZEOF for more information. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking alignment of CONDITION_VARIABLE" >&5 +$as_echo_n "checking alignment of CONDITION_VARIABLE... " >&6; } +if ${ac_cv_alignof_CONDITION_VARIABLE+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_CONDITION_VARIABLE" "$ac_includes_default + #include + +#ifndef offsetof +# define offsetof(type, member) ((char *) &((type *) 0)->member - (char *) 0) +#endif +typedef struct { char x; CONDITION_VARIABLE y; } ac__type_alignof_;"; then : + +else + if test "$ac_cv_type_CONDITION_VARIABLE" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute alignment of CONDITION_VARIABLE +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_alignof_CONDITION_VARIABLE=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_CONDITION_VARIABLE" >&5 +$as_echo "$ac_cv_alignof_CONDITION_VARIABLE" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define ALIGNOF_CONDITION_VARIABLE $ac_cv_alignof_CONDITION_VARIABLE +_ACEOF + + + GS_ALIGNOF_COND_T=$ac_cv_alignof_CONDITION_VARIABLE + if test $ac_cv_alignof_CONDITION_VARIABLE = 0 ; then + as_fn_error $? "Unable to find align of CONDITION_VARIABLE (required)." "$LINENO" 5 + fi + + + # The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of SRWLOCK" >&5 +$as_echo_n "checking size of SRWLOCK... " >&6; } +if ${ac_cv_sizeof_SRWLOCK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (SRWLOCK))" "ac_cv_sizeof_SRWLOCK" "$ac_includes_default + #include +"; then : + +else + if test "$ac_cv_type_SRWLOCK" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute sizeof (SRWLOCK) +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_sizeof_SRWLOCK=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_SRWLOCK" >&5 +$as_echo "$ac_cv_sizeof_SRWLOCK" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_SRWLOCK $ac_cv_sizeof_SRWLOCK +_ACEOF + + + GS_SIZEOF_COND_MUTEX_T=$ac_cv_sizeof_SRWLOCK + if test $ac_cv_sizeof_SRWLOCK = 0 ; then + as_fn_error $? "Unable to find size of SRWLOCK (required)." "$LINENO" 5 + fi + + + # The cast to long int works around a bug in the HP C Compiler, +# see AC_CHECK_SIZEOF for more information. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking alignment of SRWLOCK" >&5 +$as_echo_n "checking alignment of SRWLOCK... " >&6; } +if ${ac_cv_alignof_SRWLOCK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) offsetof (ac__type_alignof_, y)" "ac_cv_alignof_SRWLOCK" "$ac_includes_default + #include + +#ifndef offsetof +# define offsetof(type, member) ((char *) &((type *) 0)->member - (char *) 0) +#endif +typedef struct { char x; SRWLOCK y; } ac__type_alignof_;"; then : + +else + if test "$ac_cv_type_SRWLOCK" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "cannot compute alignment of SRWLOCK +See \`config.log' for more details" "$LINENO" 5; } + else + ac_cv_alignof_SRWLOCK=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_alignof_SRWLOCK" >&5 +$as_echo "$ac_cv_alignof_SRWLOCK" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define ALIGNOF_SRWLOCK $ac_cv_alignof_SRWLOCK +_ACEOF + + + GS_ALIGNOF_COND_MUTEX_T=$ac_cv_alignof_SRWLOCK + if test $ac_cv_alignof_SRWLOCK = 0 ; then + as_fn_error $? "Unable to find align of SRWLOCK (required)." "$LINENO" 5 + fi + +fi + +#-------------------------------------------------------------------- +# One of these function needed by NSThread.m and objc initialize test +#-------------------------------------------------------------------- +for ac_func in nanosleep usleep Sleep +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objc_root_class attribute support" >&5 +$as_echo_n "checking for objc_root_class attribute support... " >&6; } +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Werror $OBJCFLAGS -x objective-c" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + __attribute__((objc_root_class)) @interface RootObject + @end + @implementation RootObject + @end +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 +$as_echo "found" >&6; } + gs_objc_root_class_attr=1 +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not present" >&5 +$as_echo "not present" >&6; } + gs_objc_root_class_attr=0 + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +GS_HAVE_OBJC_ROOT_CLASS_ATTR=$gs_objc_root_class_attr + + +cat >>confdefs.h <<_ACEOF +#define HAVE_OBJC_ROOT_CLASS_ATTRIBUTE $gs_objc_root_class_attr +_ACEOF + +CFLAGS=$saved_CFLAGS #-------------------------------------------------------------------- # Check whether we can get the system thread ID @@ -9141,8 +9428,9 @@ $as_echo "#define HAVE_BFD_SECTION_VMA 1" >>confdefs.h fi -if test $ismingw = yes ; then - for ac_header in dbghelp.h +case "$target_os" in + mingw*) + for ac_header in dbghelp.h do : ac_fn_c_check_header_mongrel "$LINENO" "dbghelp.h" "ac_cv_header_dbghelp_h" "$ac_includes_default" if test "x$ac_cv_header_dbghelp_h" = xyes; then : @@ -9154,8 +9442,9 @@ fi done -else - for ac_header in execinfo.h + ;; + *) + for ac_header in execinfo.h do : ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default" if test "x$ac_cv_header_execinfo_h" = xyes; then : @@ -9167,7 +9456,7 @@ fi done - for ac_func in backtrace + for ac_func in backtrace do : ac_fn_c_check_func "$LINENO" "backtrace" "ac_cv_func_backtrace" if test "x$ac_cv_func_backtrace" = xyes; then : @@ -9178,7 +9467,8 @@ _ACEOF fi done -fi + ;; +esac for ac_func in __builtin_extract_return_address do : @@ -10774,7 +11064,7 @@ $as_echo "$as_me: WARNING: Using libkvm which is known to be buggy on some syste fi fi case "$target_os" in - mingw*|windows*) enable_fake_main=no; GS_FAKE_MAIN=0;; + mingw*|windows) enable_fake_main=no; GS_FAKE_MAIN=0;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_fake_main" >&5 diff --git a/configure.ac b/configure.ac index df7ecbeac..76f9e1710 100644 --- a/configure.ac +++ b/configure.ac @@ -235,7 +235,7 @@ then fi if test x"$GNUSTEP_TARGET_CONFIG_FILE" = x""; then case "$target_os" in - mingw*|windows*) + mingw*|windows) GNUSTEP_TARGET_CONFIG_FILE=./GNUstep.conf ;; *) GNUSTEP_TARGET_CONFIG_FILE="$GNUSTEP_MAKE_CONFIG" ;; @@ -252,7 +252,7 @@ AC_MSG_RESULT($GNUSTEP_TARGET_CONFIG_FILE) # location (used by gnustep-make when building). #----------------------------------------------------------------- case "$target_os" in - mingw*|windows*) enable_env_config=no;; + mingw*|windows) enable_env_config=no;; *) enable_env_config=yes;; esac AC_MSG_CHECKING([whether the GNUstep.conf file path can be set in the environment]) @@ -534,7 +534,7 @@ AC_SUBST(GNUSTEP_BASE_DOMAIN) # paths (relative to libgnustep-base.dll). # case "$target_os" in - mingw*|windows*) + mingw*|windows) # TODO: Improve this hack. # According to Wikipedia, this is the default for Windows 2000, # Windows XP and Windows Server 2003. For Windows Vista this will @@ -1702,99 +1702,209 @@ fi AC_CHECK_FUNCS(getaddrinfo) +#-------------------------------------------------------------------- +# Windows: check if we have native threading APIs and SRW locks +#-------------------------------------------------------------------- +HAVE_WIN32_THREADS_AND_LOCKS=0 +case "$target_os" in + mingw*|windows) + AC_MSG_CHECKING(for native Windows threads and locks) + AC_COMPILE_IFELSE( + [AC_LANG_SOURCE([ + #define GS_USE_WIN32_THREADS_AND_LOCKS 1 + #include "$srcdir/Source/GSPThread.h" + ])], + AC_MSG_RESULT([yes]) + HAVE_WIN32_THREADS_AND_LOCKS=1, + AC_MSG_RESULT([no])) + ;; +esac +AC_SUBST(HAVE_WIN32_THREADS_AND_LOCKS) + #-------------------------------------------------------------------- # Check for pthread.h #-------------------------------------------------------------------- -AC_CHECK_HEADERS([pthread.h]) -AC_CHECK_HEADERS([pthread_np.h],[],[],[AC_INCLUDES_DEFAULT - #ifdef HAVE_PTHREAD_H - #include - #endif - ]) -if test $ac_cv_header_pthread_h = yes ; then - AC_CHECK_SIZEOF(pthread_mutex_t,,[AC_INCLUDES_DEFAULT -#include ]) - GS_SIZEOF_MUTEX_T=$ac_cv_sizeof_pthread_mutex_t - if test $ac_cv_sizeof_pthread_mutex_t = 0 ; then - AC_MSG_ERROR([Unable to find size of pthread_mutex_t (required).]) +if test $HAVE_WIN32_THREADS_AND_LOCKS = 0; then + AC_CHECK_HEADERS([pthread.h]) + AC_CHECK_HEADERS([pthread_np.h],[],[],[AC_INCLUDES_DEFAULT + #ifdef HAVE_PTHREAD_H + #include + #endif + ]) + if test $ac_cv_header_pthread_h = yes ; then + AC_CHECK_SIZEOF(pthread_mutex_t,,[AC_INCLUDES_DEFAULT + #include ]) + GS_SIZEOF_MUTEX_T=$ac_cv_sizeof_pthread_mutex_t + if test $ac_cv_sizeof_pthread_mutex_t = 0 ; then + AC_MSG_ERROR([Unable to find size of pthread_mutex_t (required).]) + fi + AC_SUBST(GS_SIZEOF_MUTEX_T) + GS_SIZEOF_COND_MUTEX_T=$ac_cv_sizeof_pthread_mutex_t + AC_SUBST(GS_SIZEOF_COND_MUTEX_T) + + # pthread_mutex_t.__data.__owner is non-standard since pthread_mutex_t is + # nominally an opaque type. We must not rely on this for anything other + # than debug output! + AC_CHECK_MEMBER([pthread_mutex_t.__data.__owner],,,[AC_INCLUDES_DEFAULT + #include ]) + if test $ac_cv_member_pthread_mutex_t___data___owner = yes ; then + AC_DEFINE(HAVE_PTHREAD_MUTEX_OWNER, 1, + [Define if you have pthread_mutex_t.__data.__owner]) + fi + + AC_CHECK_SIZEOF(pthread_cond_t,,[AC_INCLUDES_DEFAULT + #include ]) + if test $ac_cv_sizeof_pthread_cond_t = 0 ; then + AC_MSG_ERROR([Unable to find size of pthread_cond_t (required).]) + fi + GS_SIZEOF_COND_T=$ac_cv_sizeof_pthread_cond_t + AC_SUBST(GS_SIZEOF_COND_T) + + AC_CHECK_ALIGNOF(pthread_mutex_t,[AC_INCLUDES_DEFAULT + #include ]) + GS_ALIGNOF_MUTEX_T=$ac_cv_alignof_pthread_mutex_t + if test $ac_cv_alignof_pthread_mutex_t = 0 ; then + AC_MSG_ERROR([Unable to find align of pthread_mutex_t (required).]) + fi + AC_SUBST(GS_ALIGNOF_MUTEX_T) + GS_ALIGNOF_COND_MUTEX_T=$ac_cv_alignof_pthread_mutex_t + AC_SUBST(GS_ALIGNOF_COND_MUTEX_T) + + AC_CHECK_ALIGNOF(pthread_cond_t,[AC_INCLUDES_DEFAULT + #include ]) + if test $ac_cv_alignof_pthread_cond_t = 0 ; then + AC_MSG_ERROR([Unable to find align of pthread_cond_t (required).]) + fi + GS_ALIGNOF_COND_T=$ac_cv_alignof_pthread_cond_t + AC_SUBST(GS_ALIGNOF_COND_T) + else + AC_MSG_ERROR([Unable to find pthread.h (needed for thread support).]) + fi + AC_CHECK_LIB(pthread, pthread_join, pthread_ok=yes, pthread_ok=no) + + if test $pthread_ok = yes ; then + LIBS="$LIBS -lpthread" + else + case "$target_os" in + mingw*) + AC_CHECK_LIB(pthreadGC2, pthread_join, pthread_ok=yes, pthread_ok=no) + if test $pthread_ok = yes ; then + LIBS="$LIBS -lpthreadGC2" + fi + ;; + windows) + AC_CHECK_LIB(pthreadVC2, pthread_join, pthread_ok=yes, pthread_ok=no) + if test $pthread_ok = yes ; then + LIBS="$LIBS -lpthreadVC2" + fi + ;; + nto*|qnx*|*android*) + # Android and QNX have pthread in libc instead of libpthread + AC_CHECK_LIB(c, pthread_join, pthread_ok=yes, pthread_ok=no) + if test $pthread_ok = yes ; then + LIBS="$LIBS -lc" + fi + ;; + esac + fi + if test $pthread_ok = no ; then + AC_MSG_ERROR([Unable to find pthread library (needed for thread support).]) + fi + + # Check threading extensions + AC_CHECK_FUNCS(pthread_getthreadid_np pthread_main_np) + + # Typically need librt on Solaris for sched_yield + AC_CHECK_LIB(rt, sched_yield) + + # Check if we can name pthreads + AC_CACHE_CHECK([for pthread_setname_np()], gs_cv_pthread_setname_np, + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM([#include ], + [pthread_setname_np("name");])], + [gs_cv_pthread_setname_np=darwin], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM([#include ], + [pthread_setname_np(pthread_self(), "name");])], + [gs_cv_pthread_setname_np=glibc], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM([#include ], + [pthread_setname_np(pthread_self(), "%s", "name");])], + [gs_cv_pthread_setname_np=netbsd], + [gs_cv_pthread_setname_np=none])])])]) + case $gs_cv_pthread_setname_np in + darwin) + AC_DEFINE(PTHREAD_SETNAME(a), pthread_setname_np(a), + [Description: Define set name function for pthread with one arg]) + ;; + glibc) + AC_DEFINE(PTHREAD_SETNAME(a), pthread_setname_np(pthread_self(),a), + [Description: Define setname function for pthread with two args]) + ;; + netbsd) + AC_DEFINE(PTHREAD_SETNAME(a), pthread_setname_np(pthread_self(),"%s",a), + [Description: Define setname function for pthread with three args]) + ;; + esac + + # Check if we have spinlock support + AC_CHECK_FUNCS(pthread_spin_lock) +fi + +#-------------------------------------------------------------------- +# Check Win32 lock sizes +#-------------------------------------------------------------------- +if test $HAVE_WIN32_THREADS_AND_LOCKS = 1; then + AC_CHECK_SIZEOF(gs_mutex_t,,[AC_INCLUDES_DEFAULT + #define GS_USE_WIN32_THREADS_AND_LOCKS 1 + #include "Source/GSPThread.h"]) + GS_SIZEOF_MUTEX_T=$ac_cv_sizeof_gs_mutex_t + if test $ac_cv_sizeof_gs_mutex_t = 0 ; then + AC_MSG_ERROR([Unable to find size of gs_mutex_t (required).]) fi AC_SUBST(GS_SIZEOF_MUTEX_T) -# pthread_mutex_t.__data.__owner is non-standard since pthread_mutex_t is -# nominally an opaque type. We must not rely on this for anything other -# than debug output! - AC_CHECK_MEMBER([pthread_mutex_t.__data.__owner],,,[AC_INCLUDES_DEFAULT -#include ]) - if test $ac_cv_member_pthread_mutex_t___data___owner = yes ; then - AC_DEFINE(HAVE_PTHREAD_MUTEX_OWNER, 1, - [Define if you have pthread_mutex_t.__data.__owner]) - fi - AC_CHECK_SIZEOF(pthread_cond_t,,[AC_INCLUDES_DEFAULT -#include ]) - if test $ac_cv_sizeof_pthread_cond_t = 0 ; then - AC_MSG_ERROR([Unable to find size of pthread_cond_t (required).]) - fi - GS_SIZEOF_COND_T=$ac_cv_sizeof_pthread_cond_t - AC_SUBST(GS_SIZEOF_COND_T) - AC_CHECK_ALIGNOF(pthread_mutex_t,[AC_INCLUDES_DEFAULT -#include ]) - GS_ALIGNOF_MUTEX_T=$ac_cv_alignof_pthread_mutex_t - if test $ac_cv_alignof_pthread_mutex_t = 0 ; then - AC_MSG_ERROR([Unable to find align of pthread_mutex_t (required).]) + + AC_CHECK_ALIGNOF(gs_mutex_t,[AC_INCLUDES_DEFAULT + #define GS_USE_WIN32_THREADS_AND_LOCKS 1 + #include "Source/GSPThread.h"]) + GS_ALIGNOF_MUTEX_T=$ac_cv_alignof_gs_mutex_t + if test $ac_cv_alignof_gs_mutex_t = 0 ; then + AC_MSG_ERROR([Unable to find align of gs_mutex_t (required).]) fi AC_SUBST(GS_ALIGNOF_MUTEX_T) - AC_CHECK_ALIGNOF(pthread_cond_t,[AC_INCLUDES_DEFAULT -#include ]) - if test $ac_cv_alignof_pthread_cond_t = 0 ; then - AC_MSG_ERROR([Unable to find align of pthread_cond_t (required).]) + + AC_CHECK_SIZEOF(CONDITION_VARIABLE,,[AC_INCLUDES_DEFAULT + #include ]) + GS_SIZEOF_COND_T=$ac_cv_sizeof_CONDITION_VARIABLE + if test $ac_cv_sizeof_CONDITION_VARIABLE = 0 ; then + AC_MSG_ERROR([Unable to find size of CONDITION_VARIABLE (required).]) + fi + AC_SUBST(GS_SIZEOF_COND_T) + + AC_CHECK_ALIGNOF(CONDITION_VARIABLE,[AC_INCLUDES_DEFAULT + #include ]) + GS_ALIGNOF_COND_T=$ac_cv_alignof_CONDITION_VARIABLE + if test $ac_cv_alignof_CONDITION_VARIABLE = 0 ; then + AC_MSG_ERROR([Unable to find align of CONDITION_VARIABLE (required).]) fi - GS_ALIGNOF_COND_T=$ac_cv_alignof_pthread_cond_t AC_SUBST(GS_ALIGNOF_COND_T) -else - AC_MSG_ERROR([Unable to find pthread.h (needed for thread support).]) -fi -AC_CHECK_LIB(pthread, pthread_join, pthread_ok=yes, pthread_ok=no) -ismingw=no -checkinlibc=no -case "$target_os" in - mingw*) ismingw=yes;; - windows) iswindows=yes;; - nto*) checkinlibc=yes;; - qnx*) checkinlibc=yes;; - *android*) checkinlibc=yes;; -esac -if test $pthread_ok = yes ; then - LIBS="$LIBS -lpthread" -else - if test $ismingw = yes ; then - AC_CHECK_LIB(pthreadGC2, pthread_join, pthread_ok=yes, pthread_ok=no) - if test $pthread_ok = yes ; then - LIBS="$LIBS -lpthreadGC2" - fi + + AC_CHECK_SIZEOF(SRWLOCK,,[AC_INCLUDES_DEFAULT + #include ]) + GS_SIZEOF_COND_MUTEX_T=$ac_cv_sizeof_SRWLOCK + if test $ac_cv_sizeof_SRWLOCK = 0 ; then + AC_MSG_ERROR([Unable to find size of SRWLOCK (required).]) fi - if test $iswindows = yes ; then - AC_CHECK_LIB(pthreadVC2, pthread_join, pthread_ok=yes, pthread_ok=no) - if test $pthread_ok = yes ; then - LIBS="$LIBS -lpthreadVC2" - fi - fi - # Android and QNX have pthread in libc instead of libpthread - if test $checkinlibc = yes ; then - AC_CHECK_LIB(c, pthread_join, pthread_ok=yes, pthread_ok=no) - if test $pthread_ok = yes ; then - LIBS="$LIBS -lc" - fi + AC_SUBST(GS_SIZEOF_COND_MUTEX_T) + + AC_CHECK_ALIGNOF(SRWLOCK,[AC_INCLUDES_DEFAULT + #include ]) + GS_ALIGNOF_COND_MUTEX_T=$ac_cv_alignof_SRWLOCK + if test $ac_cv_alignof_SRWLOCK = 0 ; then + AC_MSG_ERROR([Unable to find align of SRWLOCK (required).]) fi + AC_SUBST(GS_ALIGNOF_COND_MUTEX_T) fi -if test $pthread_ok = no ; then - AC_MSG_ERROR([Unable to find pthread library (needed for thread support).]) -fi - -# Check threading extensions -AC_CHECK_FUNCS(pthread_getthreadid_np pthread_main_np) - -# Typically need librt on Solaris for sched_yield -AC_CHECK_LIB(rt, sched_yield) - #-------------------------------------------------------------------- # One of these function needed by NSThread.m and objc initialize test @@ -1821,45 +1931,6 @@ AC_DEFINE_UNQUOTED(HAVE_OBJC_ROOT_CLASS_ATTRIBUTE,$gs_objc_root_class_attr, [Says whether the objc_root_class attribute works]) CFLAGS=$saved_CFLAGS - -#-------------------------------------------------------------------- -# Check if we can name pthreads -#-------------------------------------------------------------------- - -AC_CACHE_CHECK([for pthread_setname_np()], gs_cv_pthread_setname_np, -[AC_LINK_IFELSE( - [AC_LANG_PROGRAM([#include ], - [pthread_setname_np("name");])], - [gs_cv_pthread_setname_np=darwin], - [AC_LINK_IFELSE( - [AC_LANG_PROGRAM([#include ], - [pthread_setname_np(pthread_self(), "name");])], - [gs_cv_pthread_setname_np=glibc], - [AC_LINK_IFELSE( - [AC_LANG_PROGRAM([#include ], - [pthread_setname_np(pthread_self(), "%s", "name");])], - [gs_cv_pthread_setname_np=netbsd], - [gs_cv_pthread_setname_np=none])])])]) -case $gs_cv_pthread_setname_np in - darwin) - AC_DEFINE(PTHREAD_SETNAME(a), pthread_setname_np(a), - [Description: Define set name function for pthread with one arg]) - ;; - glibc) - AC_DEFINE(PTHREAD_SETNAME(a), pthread_setname_np(pthread_self(),a), - [Description: Define setname function for pthread with two args]) - ;; - netbsd) - AC_DEFINE(PTHREAD_SETNAME(a), pthread_setname_np(pthread_self(),"%s",a), - [Description: Define setname function for pthread with three args]) - ;; -esac - -#-------------------------------------------------------------------- -# Check if we have spinlock support -#-------------------------------------------------------------------- -AC_CHECK_FUNCS(pthread_spin_lock) - #-------------------------------------------------------------------- # Check whether we can get the system thread ID #-------------------------------------------------------------------- @@ -2362,12 +2433,15 @@ if test $bfd_section_vma = 1; then fi -if test $ismingw = yes ; then - AC_CHECK_HEADERS(dbghelp.h) -else - AC_CHECK_HEADERS(execinfo.h) - AC_CHECK_FUNCS(backtrace) -fi +case "$target_os" in + mingw*) + AC_CHECK_HEADERS(dbghelp.h) + ;; + *) + AC_CHECK_HEADERS(execinfo.h) + AC_CHECK_FUNCS(backtrace) + ;; +esac AC_CHECK_FUNCS(__builtin_extract_return_address) @@ -2815,7 +2889,7 @@ elif test "$enable_pass_arguments" = "no"; then fi fi case "$target_os" in - mingw*|windows*) enable_fake_main=no; GS_FAKE_MAIN=0;; + mingw*|windows) enable_fake_main=no; GS_FAKE_MAIN=0;; esac AC_SUBST(GS_FAKE_MAIN) AC_MSG_RESULT($enable_fake_main)