Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -200,16 +200,10 @@ AC_MSG_ERROR([libobjc not found!]) ]) ;; esac -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]) ]) @@ -375,16 +369,10 @@ AC_SUBST(OFTHREAD_M, "OFThread.m") AC_SUBST(OFTHREADTESTS_M, "OFThreadTests.m") AC_SUBST(OFHTTPREQUESTTESTS_M, "OFHTTPRequestTests.m") AC_SUBST(THREADING_H, "threading.h") - AC_CHECK_FUNC(objc_sync_enter,, [ - AC_SUBST(OBJC_SYNC_M, "objc_sync.m") - AC_DEFINE(NEED_OBJC_SYNC_INIT, 1, - [Whether objc_sync_init needs to be called]) - ]) - atomic_ops="none" AC_MSG_CHECKING(whether we have an atomic ops assembly implementation) AC_EGREP_CPP(yes, [ #if defined(__GNUC__) && (defined(__i386__) || \ Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -94,17 +94,15 @@ OFString_UTF8.m \ OFTCPSocket+SOCKS5.m \ ${ASPRINTF_M} \ ${FOUNDATION_COMPAT_M} \ iso_8859_15.m \ - windows_1252.m \ - ${OBJC_PROPERTIES_M} \ - ${OBJC_SYNC_M} + windows_1252.m OBJS_EXTRA = ${EXCEPTIONS_EXCEPTIONS_A} ${RUNTIME_RUNTIME_A} LIB_OBJS_EXTRA = ${EXCEPTIONS_EXCEPTIONS_LIB_A} ${RUNTIME_RUNTIME_LIB_A} include ../buildsys.mk CPPFLAGS += -I. -I.. -Iexceptions -Iruntime LD = ${OBJC} LDFLAGS += ${REEXPORT_LIBOBJC} ${MACH_ALIAS_LIST} Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -88,15 +88,12 @@ static SEL cxx_destruct = NULL; size_t of_pagesize; size_t of_num_cpus; -#ifdef NEED_OBJC_SYNC_INIT +#ifdef OF_OBJFW_RUNTIME extern BOOL objc_sync_init(); -#endif - -#ifdef NEED_OBJC_PROPERTIES_INIT extern BOOL objc_properties_init(); #endif #if defined(OF_APPLE_RUNTIME) && __OBJC2__ static void @@ -183,18 +180,16 @@ } @implementation OFObject + (void)load { -#ifdef NEED_OBJC_SYNC_INIT +#ifdef OF_OBJFW_RUNTIME 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(); } DELETED src/objc_properties.m Index: src/objc_properties.m ================================================================== --- src/objc_properties.m +++ src/objc_properties.m @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#include - -#import "OFObject.h" - -#ifdef OF_THREADS -# import "threading.h" -# define NUM_SPINLOCKS 8 /* needs to be a power of 2 */ -# define SPINLOCK_HASH(p) ((unsigned)((uintptr_t)p >> 4) & (NUM_SPINLOCKS - 1)) -static of_spinlock_t spinlocks[NUM_SPINLOCKS]; -#endif - -BOOL -objc_properties_init(void) -{ -#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*)(void*)((char*)self + offset); -#ifdef OF_THREADS - unsigned hash = SPINLOCK_HASH(ptr); - - assert(of_spinlock_lock(&spinlocks[hash])); - - @try { - return [[*ptr retain] autorelease]; - } @finally { - assert(of_spinlock_unlock(&spinlocks[hash])); - } -#else - return [[*ptr retain] autorelease]; -#endif - } - - return *(id*)(void*)((char*)self + offset); -} - -void -objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id value, BOOL atomic, - signed char copy) -{ - if (atomic) { - id *ptr = (id*)(void*)((char*)self + offset); -#ifdef OF_THREADS - unsigned hash = SPINLOCK_HASH(ptr); - - assert(of_spinlock_lock(&spinlocks[hash])); - - @try { -#endif - id old = *ptr; - - switch (copy) { - case 0: - *ptr = [value retain]; - break; - case 2: - *ptr = [value mutableCopy]; - break; - default: - *ptr = [value copy]; - } - - [old release]; -#ifdef OF_THREADS - } @finally { - assert(of_spinlock_unlock(&spinlocks[hash])); - } -#endif - - return; - } - - id *ptr = (id*)(void*)((char*)self + offset); - id old = *ptr; - - switch (copy) { - case 0: - *ptr = [value retain]; - break; - case 2: - /* - * Apple uses this to indicate that the copy should be mutable. - * Please hit them for abusing a poor BOOL! - */ - *ptr = [value mutableCopy]; - break; - default: - *ptr = [value copy]; - } - - [old release]; -} - -/* The following methods are only required for GCC >= 4.6 */ -void -objc_getPropertyStruct(void *dest, const void *src, ptrdiff_t size, BOOL atomic, - BOOL strong) -{ - if (atomic) { -#ifdef OF_THREADS - unsigned hash = SPINLOCK_HASH(src); - - assert(of_spinlock_lock(&spinlocks[hash])); -#endif - - memcpy(dest, src, size); - -#ifdef OF_THREADS - assert(of_spinlock_unlock(&spinlocks[hash])); -#endif - - return; - } - - memcpy(dest, src, size); -} - -void -objc_setPropertyStruct(void *dest, const void *src, ptrdiff_t size, BOOL atomic, - BOOL strong) -{ - if (atomic) { -#ifdef OF_THREADS - unsigned hash = SPINLOCK_HASH(src); - - assert(of_spinlock_lock(&spinlocks[hash])); -#endif - - memcpy(dest, src, size); - -#ifdef OF_THREADS - assert(of_spinlock_unlock(&spinlocks[hash])); -#endif - - return; - } - - memcpy(dest, src, size); -} DELETED src/objc_sync.m Index: src/objc_sync.m ================================================================== --- src/objc_sync.m +++ src/objc_sync.m @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2008, 2009, 2010, 2011, 2012 - * Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include -#include -#include - -#include - -#ifdef OF_OBJFW_RUNTIME -# import "runtime.h" -#else -# import -#endif - -#import "threading.h" - -struct lock_s { - id object; - size_t count; - size_t recursion; - of_thread_t thread; - of_mutex_t mutex; -}; - -static of_mutex_t mutex; -static struct lock_s *locks = NULL; -static ssize_t numLocks = 0; - -#define SYNC_ERR(f) \ - { \ - fprintf(stderr, "WARNING: %s failed in line %d!\n" \ - "WARNING: This might result in a race " \ - "condition!\n", f, __LINE__); \ - return 1; \ - } - -BOOL -objc_sync_init(void) -{ - return of_mutex_new(&mutex); -} - -int -objc_sync_enter(id object) -{ - ssize_t i; - - if (object == nil) - return 0; - - if (!of_mutex_lock(&mutex)) - SYNC_ERR("of_mutex_lock(&mutex)"); - - for (i = numLocks - 1; i >= 0; i--) { - if (locks[i].object == object) { - if (of_thread_is_current(locks[i].thread)) - locks[i].recursion++; - else { - /* Make sure objc_sync_exit doesn't free it */ - locks[i].count++; - - /* Unlock so objc_sync_exit can return */ - if (!of_mutex_unlock(&mutex)) - SYNC_ERR("of_mutex_unlock(&mutex)"); - - if (!of_mutex_lock(&locks[i].mutex)) { - of_mutex_unlock(&mutex); - SYNC_ERR( - "of_mutex_lock(&locks[i].mutex"); - } - - if (!of_mutex_lock(&mutex)) - SYNC_ERR("of_mutex_lock(&mutex)"); - - assert(locks[i].recursion == 0); - - /* Update lock's active thread */ - locks[i].thread = of_thread_current(); - } - - if (!of_mutex_unlock(&mutex)) - SYNC_ERR("of_mutex_unlock(&mutex)"); - - return 0; - } - } - - if (locks == NULL) { - if ((locks = malloc(sizeof(struct lock_s))) == NULL) { - of_mutex_unlock(&mutex); - SYNC_ERR("malloc(...)"); - } - } else { - struct lock_s *new_locks; - - if ((new_locks = realloc(locks, (numLocks + 1) * - sizeof(struct lock_s))) == NULL) { - of_mutex_unlock(&mutex); - SYNC_ERR("realloc(...)"); - } - - locks = new_locks; - } - - locks[numLocks].object = object; - locks[numLocks].count = 1; - locks[numLocks].recursion = 0; - locks[numLocks].thread = of_thread_current(); - - if (!of_mutex_new(&locks[numLocks].mutex)) { - of_mutex_unlock(&mutex); - SYNC_ERR("of_mutex_new(&locks[numLocks].mutex"); - } - - if (!of_mutex_lock(&locks[numLocks].mutex)) { - of_mutex_unlock(&mutex); - SYNC_ERR("of_mutex_lock(&locks[numLocks].mutex"); - } - - numLocks++; - - if (!of_mutex_unlock(&mutex)) - SYNC_ERR("of_mutex_unlock(&mutex)"); - - return 0; -} - -int -objc_sync_exit(id object) -{ - ssize_t i; - - if (object == nil) - return 0; - - if (!of_mutex_lock(&mutex)) - SYNC_ERR("of_mutex_lock(&mutex)"); - - for (i = numLocks - 1; i >= 0; i--) { - if (locks[i].object == object) { - if (locks[i].recursion > 0 && - of_thread_is_current(locks[i].thread)) { - locks[i].recursion--; - - if (!of_mutex_unlock(&mutex)) - SYNC_ERR("of_mutex_unlock(&mutex)"); - - return 0; - } - - if (!of_mutex_unlock(&locks[i].mutex)) { - of_mutex_unlock(&mutex); - SYNC_ERR("of_mutex_unlock(&locks[i].mutex)"); - } - - locks[i].count--; - - if (locks[i].count == 0) { - struct lock_s *new_locks = NULL; - - if (!of_mutex_free(&locks[i].mutex)) { - of_mutex_unlock(&mutex); - SYNC_ERR( - "of_mutex_free(&locks[i].mutex"); - } - - numLocks--; - locks[i] = locks[numLocks]; - - if (numLocks == 0) { - free(locks); - new_locks = NULL; - } else if ((new_locks = realloc(locks, - numLocks * sizeof(struct lock_s))) == - NULL) { - of_mutex_unlock(&mutex); - SYNC_ERR("realloc(...)"); - } - - locks = new_locks; - } - - if (!of_mutex_unlock(&mutex)) - SYNC_ERR("of_mutex_unlock(&mutex)"); - - return 0; - } - } - - of_mutex_unlock(&mutex); - SYNC_ERR("objc_sync_exit()"); -} Index: src/runtime/Makefile ================================================================== --- src/runtime/Makefile +++ src/runtime/Makefile @@ -8,18 +8,20 @@ hashtable.m \ init.m \ lookup.m \ lookup-amd64-elf.S \ lookup-x86-elf.S \ + property.m \ protocol.m \ selector.m \ sparsearray.m \ static-instances.m \ + synchronized.m \ threading.m INCLUDES = runtime.h include ../../buildsys.mk CPPFLAGS += -I. -I.. -I../.. AS = ${OBJC} ASFLAGS = ${CPPFLAGS} LD = ${OBJC} ADDED src/runtime/property.m Index: src/runtime/property.m ================================================================== --- src/runtime/property.m +++ src/runtime/property.m @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include + +#include + +#import "OFObject.h" + +#ifdef OF_THREADS +# import "threading.h" +# define NUM_SPINLOCKS 8 /* needs to be a power of 2 */ +# define SPINLOCK_HASH(p) ((unsigned)((uintptr_t)p >> 4) & (NUM_SPINLOCKS - 1)) +static of_spinlock_t spinlocks[NUM_SPINLOCKS]; +#endif + +BOOL +objc_properties_init(void) +{ +#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*)(void*)((char*)self + offset); +#ifdef OF_THREADS + unsigned hash = SPINLOCK_HASH(ptr); + + assert(of_spinlock_lock(&spinlocks[hash])); + + @try { + return [[*ptr retain] autorelease]; + } @finally { + assert(of_spinlock_unlock(&spinlocks[hash])); + } +#else + return [[*ptr retain] autorelease]; +#endif + } + + return *(id*)(void*)((char*)self + offset); +} + +void +objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id value, BOOL atomic, + signed char copy) +{ + if (atomic) { + id *ptr = (id*)(void*)((char*)self + offset); +#ifdef OF_THREADS + unsigned hash = SPINLOCK_HASH(ptr); + + assert(of_spinlock_lock(&spinlocks[hash])); + + @try { +#endif + id old = *ptr; + + switch (copy) { + case 0: + *ptr = [value retain]; + break; + case 2: + *ptr = [value mutableCopy]; + break; + default: + *ptr = [value copy]; + } + + [old release]; +#ifdef OF_THREADS + } @finally { + assert(of_spinlock_unlock(&spinlocks[hash])); + } +#endif + + return; + } + + id *ptr = (id*)(void*)((char*)self + offset); + id old = *ptr; + + switch (copy) { + case 0: + *ptr = [value retain]; + break; + case 2: + /* + * Apple uses this to indicate that the copy should be mutable. + * Please hit them for abusing a poor BOOL! + */ + *ptr = [value mutableCopy]; + break; + default: + *ptr = [value copy]; + } + + [old release]; +} + +/* The following methods are only required for GCC >= 4.6 */ +void +objc_getPropertyStruct(void *dest, const void *src, ptrdiff_t size, BOOL atomic, + BOOL strong) +{ + if (atomic) { +#ifdef OF_THREADS + unsigned hash = SPINLOCK_HASH(src); + + assert(of_spinlock_lock(&spinlocks[hash])); +#endif + + memcpy(dest, src, size); + +#ifdef OF_THREADS + assert(of_spinlock_unlock(&spinlocks[hash])); +#endif + + return; + } + + memcpy(dest, src, size); +} + +void +objc_setPropertyStruct(void *dest, const void *src, ptrdiff_t size, BOOL atomic, + BOOL strong) +{ + if (atomic) { +#ifdef OF_THREADS + unsigned hash = SPINLOCK_HASH(src); + + assert(of_spinlock_lock(&spinlocks[hash])); +#endif + + memcpy(dest, src, size); + +#ifdef OF_THREADS + assert(of_spinlock_unlock(&spinlocks[hash])); +#endif + + return; + } + + memcpy(dest, src, size); +} ADDED src/runtime/synchronized.m Index: src/runtime/synchronized.m ================================================================== --- src/runtime/synchronized.m +++ src/runtime/synchronized.m @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include +#include +#include + +#include + +#import "runtime.h" +#import "threading.h" + +struct lock_s { + id object; + size_t count; + size_t recursion; + of_thread_t thread; + of_mutex_t mutex; +}; + +static of_mutex_t mutex; +static struct lock_s *locks = NULL; +static ssize_t numLocks = 0; + +#define SYNC_ERR(f) \ + { \ + fprintf(stderr, "WARNING: %s failed in line %d!\n" \ + "WARNING: This might result in a race " \ + "condition!\n", f, __LINE__); \ + return 1; \ + } + +BOOL +objc_sync_init(void) +{ + return of_mutex_new(&mutex); +} + +int +objc_sync_enter(id object) +{ + ssize_t i; + + if (object == nil) + return 0; + + if (!of_mutex_lock(&mutex)) + SYNC_ERR("of_mutex_lock(&mutex)"); + + for (i = numLocks - 1; i >= 0; i--) { + if (locks[i].object == object) { + if (of_thread_is_current(locks[i].thread)) + locks[i].recursion++; + else { + /* Make sure objc_sync_exit doesn't free it */ + locks[i].count++; + + /* Unlock so objc_sync_exit can return */ + if (!of_mutex_unlock(&mutex)) + SYNC_ERR("of_mutex_unlock(&mutex)"); + + if (!of_mutex_lock(&locks[i].mutex)) { + of_mutex_unlock(&mutex); + SYNC_ERR( + "of_mutex_lock(&locks[i].mutex"); + } + + if (!of_mutex_lock(&mutex)) + SYNC_ERR("of_mutex_lock(&mutex)"); + + assert(locks[i].recursion == 0); + + /* Update lock's active thread */ + locks[i].thread = of_thread_current(); + } + + if (!of_mutex_unlock(&mutex)) + SYNC_ERR("of_mutex_unlock(&mutex)"); + + return 0; + } + } + + if (locks == NULL) { + if ((locks = malloc(sizeof(struct lock_s))) == NULL) { + of_mutex_unlock(&mutex); + SYNC_ERR("malloc(...)"); + } + } else { + struct lock_s *new_locks; + + if ((new_locks = realloc(locks, (numLocks + 1) * + sizeof(struct lock_s))) == NULL) { + of_mutex_unlock(&mutex); + SYNC_ERR("realloc(...)"); + } + + locks = new_locks; + } + + locks[numLocks].object = object; + locks[numLocks].count = 1; + locks[numLocks].recursion = 0; + locks[numLocks].thread = of_thread_current(); + + if (!of_mutex_new(&locks[numLocks].mutex)) { + of_mutex_unlock(&mutex); + SYNC_ERR("of_mutex_new(&locks[numLocks].mutex"); + } + + if (!of_mutex_lock(&locks[numLocks].mutex)) { + of_mutex_unlock(&mutex); + SYNC_ERR("of_mutex_lock(&locks[numLocks].mutex"); + } + + numLocks++; + + if (!of_mutex_unlock(&mutex)) + SYNC_ERR("of_mutex_unlock(&mutex)"); + + return 0; +} + +int +objc_sync_exit(id object) +{ + ssize_t i; + + if (object == nil) + return 0; + + if (!of_mutex_lock(&mutex)) + SYNC_ERR("of_mutex_lock(&mutex)"); + + for (i = numLocks - 1; i >= 0; i--) { + if (locks[i].object == object) { + if (locks[i].recursion > 0 && + of_thread_is_current(locks[i].thread)) { + locks[i].recursion--; + + if (!of_mutex_unlock(&mutex)) + SYNC_ERR("of_mutex_unlock(&mutex)"); + + return 0; + } + + if (!of_mutex_unlock(&locks[i].mutex)) { + of_mutex_unlock(&mutex); + SYNC_ERR("of_mutex_unlock(&locks[i].mutex)"); + } + + locks[i].count--; + + if (locks[i].count == 0) { + struct lock_s *new_locks = NULL; + + if (!of_mutex_free(&locks[i].mutex)) { + of_mutex_unlock(&mutex); + SYNC_ERR( + "of_mutex_free(&locks[i].mutex"); + } + + numLocks--; + locks[i] = locks[numLocks]; + + if (numLocks == 0) { + free(locks); + new_locks = NULL; + } else if ((new_locks = realloc(locks, + numLocks * sizeof(struct lock_s))) == + NULL) { + of_mutex_unlock(&mutex); + SYNC_ERR("realloc(...)"); + } + + locks = new_locks; + } + + if (!of_mutex_unlock(&mutex)) + SYNC_ERR("of_mutex_unlock(&mutex)"); + + return 0; + } + } + + of_mutex_unlock(&mutex); + SYNC_ERR("objc_sync_exit()"); +}