2010-02-28 09:10:16 +00:00
|
|
|
#include "ObjectiveC2/runtime.h"
|
2010-02-14 15:29:20 +00:00
|
|
|
|
|
|
|
/* Ensure Unix98 compatible pthreads for glibc */
|
|
|
|
#if defined __GLIBC__
|
2010-02-19 12:51:02 +00:00
|
|
|
# define __USE_UNIX98 1
|
2010-02-14 15:29:20 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
@interface Fake
|
2010-02-19 15:30:27 +00:00
|
|
|
+ (void) dealloc;
|
2010-02-14 15:29:20 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
static pthread_mutex_t at_sync_init_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
static unsigned long long lockClassId;
|
|
|
|
|
|
|
|
IMP objc_msg_lookup(id, SEL);
|
|
|
|
|
|
|
|
static void deallocLockClass(id obj, SEL _cmd);
|
|
|
|
|
2010-02-19 12:51:02 +00:00
|
|
|
static inline Class
|
|
|
|
findLockClass(id obj)
|
2010-02-14 15:29:20 +00:00
|
|
|
{
|
2010-02-19 12:51:02 +00:00
|
|
|
struct objc_object object = { obj->isa };
|
|
|
|
SEL dealloc = @selector(dealloc);
|
|
|
|
Class lastClass;
|
|
|
|
|
|
|
|
// Find the first class where this lookup is correct
|
|
|
|
if (objc_msg_lookup((id)&object, dealloc) != (IMP)deallocLockClass)
|
|
|
|
{
|
|
|
|
do {
|
|
|
|
object.isa = class_getSuperclass(object.isa);
|
|
|
|
} while (Nil != object.isa
|
|
|
|
&& objc_msg_lookup((id)&object, dealloc) != (IMP)deallocLockClass);
|
2010-02-19 15:30:27 +00:00
|
|
|
}
|
2010-02-19 12:51:02 +00:00
|
|
|
if (Nil == object.isa)
|
|
|
|
{
|
|
|
|
return Nil;
|
|
|
|
}
|
|
|
|
/* object->isa is now either the lock class, or a class which inherits from
|
|
|
|
* the lock class
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
lastClass = object.isa;
|
|
|
|
object.isa = class_getSuperclass(object.isa);
|
|
|
|
} while (Nil != object.isa
|
|
|
|
&& objc_msg_lookup((id)&object, dealloc) == (IMP)deallocLockClass);
|
|
|
|
return lastClass;
|
2010-02-14 15:29:20 +00:00
|
|
|
}
|
|
|
|
|
2010-02-19 12:51:02 +00:00
|
|
|
static inline Class
|
|
|
|
initLockObject(id obj)
|
2010-02-14 15:29:20 +00:00
|
|
|
{
|
2010-02-19 12:51:02 +00:00
|
|
|
Class lockClass;
|
|
|
|
const char *types;
|
|
|
|
pthread_mutex_t *lock;
|
2010-02-23 22:33:05 +00:00
|
|
|
pthread_mutexattr_t attr;
|
2010-02-19 12:51:02 +00:00
|
|
|
|
2010-02-27 19:23:58 +00:00
|
|
|
if (class_isMetaClass(obj->isa))
|
|
|
|
{
|
|
|
|
lockClass = objc_allocateMetaClass(obj, sizeof(pthread_mutex_t));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char nameBuffer[40];
|
|
|
|
|
|
|
|
snprintf(nameBuffer, 39, "hiddenlockClass%lld", lockClassId++);
|
|
|
|
lockClass = objc_allocateClassPair(obj->isa, nameBuffer,
|
|
|
|
sizeof(pthread_mutex_t));
|
|
|
|
}
|
|
|
|
|
2010-02-19 12:51:02 +00:00
|
|
|
types = method_getTypeEncoding(class_getInstanceMethod(obj->isa,
|
|
|
|
@selector(dealloc)));
|
|
|
|
class_addMethod(lockClass, @selector(dealloc), (IMP)deallocLockClass, types);
|
2010-02-27 19:23:58 +00:00
|
|
|
|
|
|
|
if (!class_isMetaClass(obj->isa))
|
|
|
|
{
|
|
|
|
objc_registerClassPair(lockClass);
|
|
|
|
}
|
2010-02-19 12:51:02 +00:00
|
|
|
|
|
|
|
lock = object_getIndexedIvars(lockClass);
|
|
|
|
pthread_mutexattr_init(&attr);
|
|
|
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
|
|
|
pthread_mutex_init(lock, &attr);
|
|
|
|
pthread_mutexattr_destroy(&attr);
|
|
|
|
|
|
|
|
obj->isa = lockClass;
|
|
|
|
return lockClass;
|
2010-02-14 15:29:20 +00:00
|
|
|
}
|
|
|
|
|
2010-02-19 12:51:02 +00:00
|
|
|
static void
|
|
|
|
deallocLockClass(id obj, SEL _cmd)
|
2010-02-14 15:29:20 +00:00
|
|
|
{
|
2010-02-19 12:51:02 +00:00
|
|
|
Class lockClass = findLockClass(obj);
|
|
|
|
Class realClass = class_getSuperclass(lockClass);
|
|
|
|
// Free the lock
|
|
|
|
pthread_mutex_t *lock = object_getIndexedIvars(lockClass);
|
|
|
|
|
|
|
|
pthread_mutex_destroy(lock);
|
|
|
|
// Free the class
|
|
|
|
objc_disposeClassPair(lockClass);
|
|
|
|
// Reset the class then call the real -dealloc
|
|
|
|
obj->isa = realClass;
|
|
|
|
[obj dealloc];
|
2010-02-14 15:29:20 +00:00
|
|
|
}
|
|
|
|
|
2010-02-19 12:51:02 +00:00
|
|
|
void
|
|
|
|
objc_sync_enter(id obj)
|
2010-02-14 15:29:20 +00:00
|
|
|
{
|
2010-02-19 12:51:02 +00:00
|
|
|
Class lockClass = findLockClass(obj);
|
|
|
|
pthread_mutex_t *lock;
|
|
|
|
|
|
|
|
if (Nil == lockClass)
|
|
|
|
{
|
|
|
|
pthread_mutex_lock(&at_sync_init_lock);
|
|
|
|
// Test again in case two threads call objc_sync_enter at once
|
|
|
|
lockClass = findLockClass(obj);
|
|
|
|
if (Nil == lockClass)
|
2010-02-14 15:29:20 +00:00
|
|
|
{
|
2010-02-19 12:51:02 +00:00
|
|
|
lockClass = initLockObject(obj);
|
2010-02-14 15:29:20 +00:00
|
|
|
}
|
2010-02-19 12:51:02 +00:00
|
|
|
pthread_mutex_unlock(&at_sync_init_lock);
|
|
|
|
}
|
|
|
|
lock = object_getIndexedIvars(lockClass);
|
|
|
|
pthread_mutex_lock(lock);
|
2010-02-14 15:29:20 +00:00
|
|
|
}
|
2010-02-19 12:51:02 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
objc_sync_exit(id obj)
|
2010-02-14 15:29:20 +00:00
|
|
|
{
|
2010-02-19 12:51:02 +00:00
|
|
|
Class lockClass = findLockClass(obj);
|
|
|
|
pthread_mutex_t *lock = object_getIndexedIvars(lockClass);
|
|
|
|
pthread_mutex_unlock(lock);
|
2010-02-14 15:29:20 +00:00
|
|
|
}
|