ObjFW  Check-in [921b158d17]

Overview
Comment:Change spinlock implementation, add fallbacks and move to threading.h.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 921b158d17b26c1aeb6b3bee85234d78eb220645a448439af65d7609d0dce73f
User & Date: js on 2010-01-30 01:17:15
Other Links: manifest | tags
Context
2010-01-30
01:50
Fall back to spinlocks if atomic ops are unavailable. check-in: bd6a71aad3 user: js tags: trunk
01:17
Change spinlock implementation, add fallbacks and move to threading.h. check-in: 921b158d17 user: js tags: trunk
00:50
Add -[tryLock] to OFMutex. check-in: 20e1c0e24b user: js tags: trunk
Changes

Modified configure.ac from [9eadb6c419] to [2dac0a970f].

72
73
74
75
76
77
78


79
80
81
82
83
84
85
	], [
	AC_DEFINE(OF_APPLE_RUNTIME, 1, [Whether we use the Apple ObjC runtime])
	AC_SUBST(RUNTIME_DEF, "-DOF_APPLE_RUNTIME")
	objc_runtime="Apple"])
AC_MSG_RESULT($objc_runtime)

AC_CHECK_FUNC(objc_getProperty,, [


	AC_SUBST(OBJC_PROPERTIES_M, "objc_properties.m")])

AC_CHECK_FUNC(objc_enumerationMutation, [
	AC_DEFINE(HAVE_OBJC_ENUMERATIONMUTATION, 1,
		[Whether we have objc_enumerationMutation])])

BUILDSYS_LIB







>
>







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
	], [
	AC_DEFINE(OF_APPLE_RUNTIME, 1, [Whether we use the Apple ObjC runtime])
	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])])

BUILDSYS_LIB
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163






164
165
166
167
168
169
170
171
172
173

AC_CHECK_LIB(dl, dlopen, LIBS="$LIBS -ldl")

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!)])
			;;
	esac

	AC_DEFINE(OF_THREADS, 1, [Whether we have threads])
	AC_SUBST(OFTHREAD_M, "OFThread.m")
	AC_SUBST(THREADING_H, "threading.h")

	AC_CHECK_FUNC(objc_sync_enter,, [







|
|
|
|
|
|
|
|
|
|
>
>
>
>
>
>
|
|
|







149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181

AC_CHECK_LIB(dl, dlopen, LIBS="$LIBS -ldl")

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_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")

	AC_CHECK_FUNC(objc_sync_enter,, [
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
		AC_DEFINE(OF_ATOMIC_OPS, 1, [Whether we have atomic operations])
		AC_MSG_RESULT(gcc builtins)
	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

AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket")







<







220
221
222
223
224
225
226

227
228
229
230
231
232
233
		AC_DEFINE(OF_ATOMIC_OPS, 1, [Whether we have atomic operations])
		AC_MSG_RESULT(gcc builtins)
	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)

	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

AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket")

Modified src/OFObject.m from [14884d461d] to [f35a66b387].

45
46
47
48
49
50
51




52
53
54
55
56
57
58
static struct {
	Class isa;
} alloc_failed_exception;

#ifdef NEED_OBJC_SYNC_INIT
extern BOOL objc_sync_init();
#endif





static void
enumeration_mutation_handler(id obj)
{
	@throw [OFEnumerationMutationException newWithClass: [obj class]];
}








>
>
>
>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
static struct {
	Class isa;
} 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]];
}

69
70
71
72
73
74
75








76
77
78
79
80
81
82
{
#ifdef NEED_OBJC_SYNC_INIT
	if (!objc_sync_init()) {
		fputs("Runtime error: objc_sync_init() failed!\n", stderr);
		abort();
	}
#endif









#ifdef OF_APPLE_RUNTIME
	objc_setEnumerationMutationHandler(enumeration_mutation_handler);
#endif
}

+ (void)initialize







>
>
>
>
>
>
>
>







73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
{
#ifdef NEED_OBJC_SYNC_INIT
	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
}

+ (void)initialize

Modified src/atomic.h from [a774b233fa] to [a1c4c931ea].

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# error No atomic operations available!
#endif

#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







<
<
<
<
<
<
<
<
<
39
40
41
42
43
44
45









# error No atomic operations available!
#endif

#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









Modified src/objc_properties.m from [684035ffa6] to [63edddc2b7].

11
12
13
14
15
16
17

18
19
20
21
22















23
24
25
26
27
28

29
30
31
32
33
34
35
36
37



38
39
40
41
42
43
44
45
46
47
48

49
50
51
52
53

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

73
74
75

76
77
78
79
80
81
82

#include "config.h"

#import <objc/objc.h>

#import "OFExceptions.h"


#import "atomic.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] = {};
















id
objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic)
{
	if (atomic) {
		id *ptr = (id*)((char*)self + offset);

		unsigned hash = SPINLOCK_HASH(ptr);

		of_spinlock_lock(spinlocks[hash]);

		@try {
			return [[*ptr retain] autorelease];
		} @finally {
			of_spinlock_unlock(spinlocks[hash]);
		}



	}

	return *(id*)((char*)self + offset);
}

void
objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id value, BOOL atomic,
    BOOL copy)
{
	if (atomic) {
		id *ptr = (id*)((char*)self + offset);

		unsigned hash = SPINLOCK_HASH(ptr);

		of_spinlock_lock(spinlocks[hash]);

		@try {

			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];

		} @finally {
			of_spinlock_unlock(spinlocks[hash]);
		}


		return;
	}

	id *ptr = (id*)((char*)self + offset);
	id old = *ptr;








>
|



|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






>


|




|

>
>
>











>


|


>



















>

|

>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106

#include "config.h"

#import <objc/objc.h>

#import "OFExceptions.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];
#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]);

		@try {
			return [[*ptr retain] autorelease];
		} @finally {
			of_spinlock_unlock(&spinlocks[hash]);
		}
#else
		return [[*ptr retain] autorelease];
#endif
	}

	return *(id*)((char*)self + offset);
}

void
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]);

		@try {
#endif
			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];
#ifdef OF_THREADS
		} @finally {
			of_spinlock_unlock(&spinlocks[hash]);
		}
#endif

		return;
	}

	id *ptr = (id*)((char*)self + offset);
	id old = *ptr;

Modified src/objfw-defs.h.in from [59fa4d3305] to [e92fcadc33].

1
2
3
4
5
6
7
8


9
10
11
#undef OF_APPLE_RUNTIME
#undef OF_ATOMIC_OPS
#undef OF_BIG_ENDIAN
#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_PLUGINS
#undef OF_THREADS
#undef SIZE_MAX








>
>



1
2
3
4
5
6
7
8
9
10
11
12
13
#undef OF_APPLE_RUNTIME
#undef OF_ATOMIC_OPS
#undef OF_BIG_ENDIAN
#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

Modified src/threading.h from [118d170b8a] to [f8a41f877f].

181
182
183
184
185
186
187






























{
#if defined(OF_HAVE_PTHREADS)
	return (pthread_key_delete(key) ? NO : YES);
#elif defined(_WIN32)
	return (TlsFree(key) ? YES : NO);
#endif
}





































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
{
#if defined(OF_HAVE_PTHREADS)
	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