Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -74,10 +74,12 @@ AC_SUBST(RUNTIME_DEF, "-DOF_APPLE_RUNTIME") objc_runtime="Apple"]) AC_MSG_RESULT($objc_runtime) AC_CHECK_FUNC(objc_getProperty,, [ + AC_DEFINE(NEED_OBJC_PROPERTIES_INIT, 1, + [Whether objc_properties_init needs to be called]) AC_SUBST(OBJC_PROPERTIES_M, "objc_properties.m")]) AC_CHECK_FUNC(objc_enumerationMutation, [ AC_DEFINE(HAVE_OBJC_ENUMERATIONMUTATION, 1, [Whether we have objc_enumerationMutation])]) @@ -149,23 +151,29 @@ AC_ARG_ENABLE(threads, AS_HELP_STRING([--disable-threads], [disable thread support])) if test x"$enable_threads" != x"no"; then case "$host_os" in - mingw*) - AC_MSG_CHECKING(for threads) - AC_MSG_RESULT(win32) - ;; - *) - ACX_PTHREAD([ - CPPLAGS="$CPPFLAGS $PTHREAD_CFLAGS" - LIBS="$LIBS $PTHREAD_LIBS" - AC_DEFINE(OF_HAVE_PTHREADS, 1, - [Whether we have pthreads]) - ], [ - AC_MSG_ERROR(No supported threads found!)]) - ;; + mingw*) + AC_MSG_CHECKING(for threads) + AC_MSG_RESULT(win32) + ;; + *) + ACX_PTHREAD([ + CPPLAGS="$CPPFLAGS $PTHREAD_CFLAGS" + LIBS="$LIBS $PTHREAD_LIBS" + AC_DEFINE(OF_HAVE_PTHREADS, 1, + [Whether we have pthreads]) + AC_CHECK_FUNC(pthread_spin_lock, [ + AC_DEFINE(OF_HAVE_PTHREAD_SPINLOCKS, 1, + [Whether we have pthread spinlocks])]) + AC_CHECK_FUNC(sched_yield, [ + AC_DEFINE(OF_HAVE_SCHED_YIELD, 1, + [Whether we have sched_yield])]) + ], [ + AC_MSG_ERROR(No supported threads found!)]) + ;; esac AC_DEFINE(OF_THREADS, 1, [Whether we have threads]) AC_SUBST(OFTHREAD_M, "OFThread.m") AC_SUBST(THREADING_H, "threading.h") @@ -214,11 +222,10 @@ elif test x"$have_libkern_osatomic_h" = x"yes"; then AC_DEFINE(OF_ATOMIC_OPS, 1, [Whether we have atomic operations]) AC_MSG_RESULT(libkern/OSAtomic.h) else AC_MSG_RESULT(none) - AC_MSG_ERROR(No atomic operations found! Try --disable-threads.) fi else dnl We can only have one thread - therefore everything is atomic AC_DEFINE(OF_ATOMIC_OPS, 1, [Whether we have atomic operations]) fi Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -47,10 +47,14 @@ } alloc_failed_exception; #ifdef NEED_OBJC_SYNC_INIT extern BOOL objc_sync_init(); #endif + +#ifdef NEED_OBJC_PROPERTIES_INIT +extern BOOL objc_properties_init(); +#endif static void enumeration_mutation_handler(id obj) { @throw [OFEnumerationMutationException newWithClass: [obj class]]; @@ -71,10 +75,18 @@ if (!objc_sync_init()) { fputs("Runtime error: objc_sync_init() failed!\n", stderr); abort(); } #endif + +#ifdef NEED_OBJC_PROPERTIES_INIT + if (!objc_properties_init()) { + fputs("Runtime error: objc_properties_init() failed!\n", + stderr); + abort(); + } +#endif #ifdef OF_APPLE_RUNTIME objc_setEnumerationMutationHandler(enumeration_mutation_handler); #endif } Index: src/atomic.h ================================================================== --- src/atomic.h +++ src/atomic.h @@ -41,14 +41,5 @@ #if !defined(OF_THREADS) || defined(OF_HAVE_GCC_ATOMIC_OPS) # define of_atomic_inc32(p) of_atomic_add32(p, 1) # define of_atomic_dec32(p) of_atomic_sub32(p, 1) #endif - -typedef int32_t of_spinlock_t; -#ifdef OF_THREADS -# define of_spinlock_lock(s) while (!of_atomic_cmpswap32(&s, 0, 1)); -# define of_spinlock_unlock(s) s = 0 -#else -# define of_spinlock_lock(s) -# define of_spinlock_unlock(s) -#endif Index: src/objc_properties.m ================================================================== --- src/objc_properties.m +++ src/objc_properties.m @@ -13,30 +13,50 @@ #import #import "OFExceptions.h" -#import "atomic.h" +#ifdef OF_THREADS +#import "threading.h" #define NUM_SPINLOCKS 8 /* needs to be a power of 2 */ #define SPINLOCK_HASH(p) ((uintptr_t)p >> 4) & (NUM_SPINLOCKS - 1) -static of_spinlock_t spinlocks[NUM_SPINLOCKS] = {}; +static of_spinlock_t spinlocks[NUM_SPINLOCKS]; +#endif + +BOOL +objc_properties_init() +{ +#ifdef OF_THREADS + size_t i; + + for (i = 0; i < NUM_SPINLOCKS; i++) + if (!of_spinlock_new(&spinlocks[i])) + return NO; +#endif + + return YES; +} id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) { if (atomic) { id *ptr = (id*)((char*)self + offset); +#ifdef OF_THREADS unsigned hash = SPINLOCK_HASH(ptr); - of_spinlock_lock(spinlocks[hash]); + of_spinlock_lock(&spinlocks[hash]); @try { return [[*ptr retain] autorelease]; } @finally { - of_spinlock_unlock(spinlocks[hash]); + of_spinlock_unlock(&spinlocks[hash]); } +#else + return [[*ptr retain] autorelease]; +#endif } return *(id*)((char*)self + offset); } @@ -44,15 +64,17 @@ objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id value, BOOL atomic, BOOL copy) { if (atomic) { id *ptr = (id*)((char*)self + offset); +#ifdef OF_THREADS unsigned hash = SPINLOCK_HASH(ptr); - of_spinlock_lock(spinlocks[hash]); + of_spinlock_lock(&spinlocks[hash]); @try { +#endif id old = *ptr; switch (copy) { case 0: *ptr = [value retain]; @@ -68,13 +90,15 @@ default: *ptr = [value copy]; } [old release]; +#ifdef OF_THREADS } @finally { - of_spinlock_unlock(spinlocks[hash]); + of_spinlock_unlock(&spinlocks[hash]); } +#endif return; } id *ptr = (id*)((char*)self + offset); Index: src/objfw-defs.h.in ================================================================== --- src/objfw-defs.h.in +++ src/objfw-defs.h.in @@ -4,8 +4,10 @@ #undef OF_GNU_RUNTIME #undef OF_HAVE_ASPRINTF #undef OF_HAVE_GCC_ATOMIC_OPS #undef OF_HAVE_LIBKERN_OSATOMIC_H #undef OF_HAVE_PTHREADS +#undef OF_HAVE_PTHREAD_SPINLOCKS +#undef OF_HAVE_SCHED_YIELD #undef OF_PLUGINS #undef OF_THREADS #undef SIZE_MAX Index: src/threading.h ================================================================== --- src/threading.h +++ src/threading.h @@ -183,5 +183,35 @@ return (pthread_key_delete(key) ? NO : YES); #elif defined(_WIN32) return (TlsFree(key) ? YES : NO); #endif } + +#if defined(OF_ATOMIC_OPS) +# import "atomic.h" +typedef int32_t of_spinlock_t; +# define of_spinlock_new(s) ((*(s) = 0) + YES) +# define of_spinlock_trylock(s) (of_atomic_cmpswap32(s, 0, 1) ? YES : NO) +# ifdef OF_HAVE_SCHED_YIELD +# define of_spinlock_lock(s) \ + while (!of_spinlock_trylock(s)) \ + sched_yield() +# else +# define of_spinlock_lock(s) while (!of_spinlock_trylock(s)); +# endif +# define of_spinlock_unlock(s) *(s) = 0 +# define of_spinlock_free(s) YES +#elif defined(OF_HAVE_PTHREAD_SPINLOCKS) +typedef pthread_spinlock_t of_spinlock_t; +# define of_spinlock_new(s) (pthread_spin_init(s, 0) ? NO : YES) +# define of_spinlock_trylock(s) (pthread_spin_trylock(s) ? NO : YES) +# define of_spinlock_lock(s) pthread_spin_lock(s) +# define of_spinlock_unlock(s) pthread_spin_unlock(s) +# define of_spinlock_free(s) (pthread_spin_destroy(s) ? NO : YES) +#else +typedef of_mutex_t of_spinlock_t; +# define of_spinlock_new(s) of_mutex_new(s) +# define of_spinlock_trylock(s) of_mutex_trylock(s) +# define of_spinlock_lock(s) of_mutex_lock(s) +# define of_spinlock_unlock(s) of_mutex_unlock(s) +# define of_spinlock_free(s) of_mutex_free(s) +#endif