ObjFW  Check-in [15a67e8ee5]

Overview
Comment:Move platform-specific threading stuff to threading.h.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 15a67e8ee5133ee931cde4d4244a865d9045b707d23e76c9bb891e1997033a8d
User & Date: js on 2009-09-21 11:15:27
Other Links: manifest | tags
Context
2009-09-21
11:26
Only check if snprintf returns required space if there's no asprintf. check-in: a6513f3228 user: js tags: trunk
11:15
Move platform-specific threading stuff to threading.h. check-in: 15a67e8ee5 user: js tags: trunk
2009-09-17
13:40
Update config.guess, config.sub and install-sh. check-in: c74def94fc user: js tags: trunk
Changes

Modified src/Makefile from [862b2d6a24] to [6fdc4aab1f].

29
30
31
32
33
34
35
36

37
38
39
40
41
42
43
44
45
46
       OFXMLElement.m		\
       OFXMLParser.m

INCLUDESTMP := ${SRCS:.c=.h}
INCLUDES := ${INCLUDESTMP:.m=.h}	\
	    OFMacros.h			\
	    asprintf.h			\
	    objfw.h


SRCS += ${OBJC_SYNC_M}	\
	${ASPRINTF_C}

include ../buildsys.mk

CPPFLAGS += -I..
CFLAGS += ${LIB_CFLAGS}
OBJCFLAGS += ${LIB_CFLAGS}
LD = ${OBJC}







|
>










29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
       OFXMLElement.m		\
       OFXMLParser.m

INCLUDESTMP := ${SRCS:.c=.h}
INCLUDES := ${INCLUDESTMP:.m=.h}	\
	    OFMacros.h			\
	    asprintf.h			\
	    objfw.h			\
	    threading.h

SRCS += ${OBJC_SYNC_M}	\
	${ASPRINTF_C}

include ../buildsys.mk

CPPFLAGS += -I..
CFLAGS += ${LIB_CFLAGS}
OBJCFLAGS += ${LIB_CFLAGS}
LD = ${OBJC}

Modified src/OFAutoreleasePool.m from [992a58ee6a] to [2c07550cc7].

9
10
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
107


108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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
174
175
176
177
 * the packaging of this file.
 */

#include "config.h"

#include <stdlib.h>

#ifndef _WIN32
#include <pthread.h>
#else
#include <windows.h>
#endif

#import "OFAutoreleasePool.h"
#import "OFList.h"
#import "OFThread.h"
#import "OFExceptions.h"



/*
 * Pay special attention to NULL and nil in this file, they might be different!
 * Use NULL for TLS values and nil for instance variables.
 */

#ifndef _WIN32
static pthread_key_t first_key, last_key;
#else
static DWORD first_key, last_key;
#endif

#ifndef _WIN32 /* Not used on Win32 yet */
static void
release_all(void *list)
{
#ifndef _WIN32
	void *first = pthread_getspecific(first_key);
#else
	void *first = TlsGetValue(first_key);
#endif

	if (first != NULL)
		[(OFAutoreleasePool*)first release];
}
#endif

@implementation OFAutoreleasePool
+ (void)initialize
{
	if (self != [OFAutoreleasePool class])
		return;

#ifndef _WIN32
	if (pthread_key_create(&first_key, release_all) ||
	    pthread_key_create(&last_key, NULL))
#else
	/* FIXME: Call destructor */
	if ((first_key = TlsAlloc()) == TLS_OUT_OF_INDEXES ||
	    (last_key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
#endif
		@throw [OFInitializationFailedException newWithClass: self];
}

+ (void)addObjectToTopmostPool: (OFObject*)obj
{
#ifndef _WIN32
	void *last = pthread_getspecific(last_key);
#else
	void *last = TlsGetValue(last_key);
#endif

	if (last == NULL) {
		@try {
			[[self alloc] init];
		} @catch (OFException *e) {
			[obj release];
			@throw e;
		}

#ifndef _WIN32
		last = pthread_getspecific(last_key);
#else
		last = TlsGetValue(last_key);
#endif
	}

	if (last == NULL) {
		[obj release];
		@throw [OFInitializationFailedException newWithClass: self];
	}

	@try {
		[(OFAutoreleasePool*)last addObject: obj];
	} @catch (OFException *e) {
		[obj release];
		@throw e;
	}
}

- init
{


	self = [super init];

#ifndef _WIN32
	void *first = pthread_getspecific(first_key);
	void *last = pthread_getspecific(last_key);
#else
	void *first = TlsGetValue(first_key);
	void *last = TlsGetValue(last_key);
#endif

#ifndef _WIN32
	if (pthread_setspecific(last_key, self)) {
#else
	if (!TlsSetValue(last_key, self)) {
#endif
		Class c = isa;
		[super dealloc];
		@throw [OFInitializationFailedException newWithClass: c];
	}

	if (first == NULL) {
#ifndef _WIN32
		if (pthread_setspecific(first_key, self)) {
#else
		if (!TlsSetValue(first_key, self)) {
#endif
			Class c = isa;

#ifndef _WIN32
			pthread_setspecific(last_key, last);
#else
			TlsSetValue(last_key, last);
#endif

			[super dealloc];
			@throw [OFInitializationFailedException
			    newWithClass: c];
		}
	}

	if (last != NULL) {
		prev = (OFAutoreleasePool*)last;
		prev->next = self;
	}

	return self;
}

- (void)dealloc
{
	[next dealloc];

	if (prev != nil)
		prev->next = nil;
#ifndef _WIN32
	pthread_setspecific(last_key, (prev != nil ? prev : NULL));
	if (pthread_getspecific(first_key) == self)
		pthread_setspecific(first_key, NULL);
#else
	TlsSetValue(last_key, (prev != nil ? prev : NULL));
	if (TlsGetValue(first_key) == self)
		TlsSetValue(first_key, NULL);
#endif

	[objects release];

	[super dealloc];
}

- addObject: (OFObject*)obj







<
<
<
<
<
<




>
>






<
|
<
<
<



|

<
<
<
<
<
|
<
<









<
|
|
<
<
<
<
<





<
<
<
|
<

|







<
<
<
|
<


|





|








>
>


<
<
<
<
|
|
<

<
<
<
|
<





|
<
<
<
|
<


<
<
<
|
<







|
<

<










|
|
<
<
<
|
|
|
<







9
10
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
107
108
109
110
111
112
113
114
115
116
117



118
119
120

121
122
123
124
125
126
127
 * the packaging of this file.
 */

#include "config.h"

#include <stdlib.h>







#import "OFAutoreleasePool.h"
#import "OFList.h"
#import "OFThread.h"
#import "OFExceptions.h"

#import "threading.h"

/*
 * Pay special attention to NULL and nil in this file, they might be different!
 * Use NULL for TLS values and nil for instance variables.
 */


static of_tlskey_t first_key, last_key;




#ifndef _WIN32 /* Not used on Win32 yet */
static void
release_all(id obj)
{





	[of_tlskey_get(first_key) release];


}
#endif

@implementation OFAutoreleasePool
+ (void)initialize
{
	if (self != [OFAutoreleasePool class])
		return;


	if (!of_tlskey_new(&first_key, release_all) ||
	    !of_tlskey_new(&last_key, NULL))





		@throw [OFInitializationFailedException newWithClass: self];
}

+ (void)addObjectToTopmostPool: (OFObject*)obj
{



	id last = of_tlskey_get(last_key);


	if (last == nil) {
		@try {
			[[self alloc] init];
		} @catch (OFException *e) {
			[obj release];
			@throw e;
		}




		last = of_tlskey_get(last_key);

	}

	if (last == nil) {
		[obj release];
		@throw [OFInitializationFailedException newWithClass: self];
	}

	@try {
		[last addObject: obj];
	} @catch (OFException *e) {
		[obj release];
		@throw e;
	}
}

- init
{
	id first;

	self = [super init];





	first = of_tlskey_get(first_key);
	prev = of_tlskey_get(last_key);





	if (!of_tlskey_set(last_key, self)) {

		Class c = isa;
		[super dealloc];
		@throw [OFInitializationFailedException newWithClass: c];
	}

	if (first == nil) {



		if (!of_tlskey_set(first_key, self)) {

			Class c = isa;




			of_tlskey_set(last_key, prev);


			[super dealloc];
			@throw [OFInitializationFailedException
			    newWithClass: c];
		}
	}

	if (prev != nil)

		prev->next = self;


	return self;
}

- (void)dealloc
{
	[next dealloc];

	if (prev != nil)
		prev->next = nil;

	/* FIXME: Add exception? */



	of_tlskey_set(last_key, prev);
	if (of_tlskey_get(first_key) == self)
		of_tlskey_set(first_key, nil);


	[objects release];

	[super dealloc];
}

- addObject: (OFObject*)obj

Modified src/OFExceptions.m from [a8fc13d28b] to [77ebe09448].

981
982
983
984
985
986
987

988
989
990
991
992
993
994
995
996
997
998
999
1000
	    @"Joining a thread of class %s failed! Most likely, another thread "
	    @"already waits for the thread to join.", [class className]];

	return string;
}
@end


@implementation OFThreadCanceledException
- (OFString*)string
{
	if (string != nil)
		return string;

	string = [[OFString alloc] initWithFormat:
	    @"The requested action cannot be performed because the thread of "
	    @"class %s was canceled!", [class className]];

	return string;
}
@end







>













981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
	    @"Joining a thread of class %s failed! Most likely, another thread "
	    @"already waits for the thread to join.", [class className]];

	return string;
}
@end

/* FIXME: Not needed anymore? */
@implementation OFThreadCanceledException
- (OFString*)string
{
	if (string != nil)
		return string;

	string = [[OFString alloc] initWithFormat:
	    @"The requested action cannot be performed because the thread of "
	    @"class %s was canceled!", [class className]];

	return string;
}
@end

Modified src/OFThread.h from [36e8a35200] to [894be3846a].

1
2
3
4
5
6
7
8
9
10
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
/*
 * Copyright (c) 2008 - 2009
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of libobjfw. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE included in
 * the packaging of this file.
 */

#ifndef _WIN32
#include <pthread.h>
#else
#include <windows.h>
#endif

#import "OFObject.h"

/**
 * A Thread Local Storage key.
 */
@interface OFTLSKey: OFObject
{
@public
#ifndef _WIN32
	pthread_key_t key;
#else
	DWORD key;
#endif
}

/**
 * \param destructor A destructor that is called when the thread is terminated
 * \return A new autoreleased Thread Local Storage key
 */
+ tlsKeyWithDestructor: (void(*)(void*))destructor;

/**
 * \param destructor A destructor that is called when the thread is terminated
 * \return An initialized Thread Local Storage key
 */
- initWithDestructor: (void(*)(void*))destructor;
@end

/**
 * The OFThread class provides portable threads.
 *
 * To use it, you should create a new class derived from it and reimplement
 * main.
 */
@interface OFThread: OFObject
{
	id object;
#ifndef _WIN32
	pthread_t thread;
#else
	HANDLE thread;

@public
	id retval;
#endif
}

/**
 * \param obj An object that is passed to the main method as a copy or nil
 * \return A new autoreleased thread
 */
+ threadWithObject: (id)obj;











|
<
<
<
<

|







<
|
<
<
<






|





|











<
|
<
<



<







1
2
3
4
5
6
7
8
9
10
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
/*
 * Copyright (c) 2008 - 2009
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of libobjfw. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE included in
 * the packaging of this file.
 */

#import "OFObject.h"





#import "threading.h"

/**
 * A Thread Local Storage key.
 */
@interface OFTLSKey: OFObject
{
@public

	of_tlskey_t key;



}

/**
 * \param destructor A destructor that is called when the thread is terminated
 * \return A new autoreleased Thread Local Storage key
 */
+ tlsKeyWithDestructor: (void(*)(id))destructor;

/**
 * \param destructor A destructor that is called when the thread is terminated
 * \return An initialized Thread Local Storage key
 */
- initWithDestructor: (void(*)(id))destructor;
@end

/**
 * The OFThread class provides portable threads.
 *
 * To use it, you should create a new class derived from it and reimplement
 * main.
 */
@interface OFThread: OFObject
{
	id object;

	of_thread_t thread;



@public
	id retval;

}

/**
 * \param obj An object that is passed to the main method as a copy or nil
 * \return A new autoreleased thread
 */
+ threadWithObject: (id)obj;
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
@end

/**
 * A class for creating mutual exclusions.
 */
@interface OFMutex: OFObject
{
#ifndef _WIN32
	pthread_mutex_t mutex;
#else
	CRITICAL_SECTION mutex;
#endif
}

/**
 * \return A new autoreleased mutex.
 */
+ mutex;








<
|
<
<
<







101
102
103
104
105
106
107

108



109
110
111
112
113
114
115
@end

/**
 * A class for creating mutual exclusions.
 */
@interface OFMutex: OFObject
{

	of_mutex_t mutex;



}

/**
 * \return A new autoreleased mutex.
 */
+ mutex;

Modified src/OFThread.m from [1a195479da] to [72efe40c4e].

10
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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
174
175
176
177
178
179
180
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
 */

#include "config.h"

#import "OFThread.h"
#import "OFExceptions.h"

#ifndef _WIN32
static void*
call_main(void *obj)
{
	return [(OFThread*)obj main];
}
#else
static DWORD WINAPI
call_main(LPVOID obj)
{

	/* Windows does not support returning a pointer. Nasty workaround. */


	((OFThread*)obj)->retval = [(OFThread*)obj main];

	return 0;
}
#endif

@implementation OFThread
+ threadWithObject: (id)obj
{
	return [[[self alloc] initWithObject: obj] autorelease];
}

+ setObject: (id)obj
  forTLSKey: (OFTLSKey*)key
{
	id old = [self objectForTLSKey: key];

#ifndef _WIN32
	if (pthread_setspecific(key->key, obj))
#else
	if (!TlsSetValue(key->key, obj))
#endif
		/* FIXME: Maybe another exception would be better */
		@throw [OFInvalidArgumentException newWithClass: self
						       selector: _cmd];

	[obj retain];
	[old release];

	return self;
}

+ (id)objectForTLSKey: (OFTLSKey*)key
{
	void *ret;

#ifndef _WIN32
	ret = pthread_getspecific(key->key);
#else
	ret = TlsGetValue(key->key);
#endif

	/*
	 * NULL and nil might be different on some platforms. NULL is returned
	 * if the key is missing, nil can be returned if it was explicitly set
	 * to nil to release the old object.
	 */
	if (ret == NULL)
		return nil;

	return (id)ret;
}

- init
{
	@throw [OFNotImplementedException newWithClass: isa
					      selector: _cmd];
}

- initWithObject: (id)obj
{
	Class c;

	self = [super init];
	object = [obj copy];

#ifndef _WIN32
	if (pthread_create(&thread, NULL, call_main, self)) {
#else
	if ((thread =
	    CreateThread(NULL, 0, call_main, self, 0, NULL)) == NULL) {
#endif
		c = isa;
		[super dealloc];
		@throw [OFInitializationFailedException newWithClass: c];
	}

	return self;
}

- main
{
	return nil;
}

- join
{
#ifndef _WIN32
	void *ret;

	if (pthread_join(thread, &ret))
		@throw [OFThreadJoinFailedException newWithClass: isa];

	if (ret == PTHREAD_CANCELED)
		@throw [OFThreadCanceledException newWithClass: isa];

	return (id)ret;
#else
	if (WaitForSingleObject(thread, INFINITE))
		@throw [OFThreadJoinFailedException newWithClass: isa];

	CloseHandle(thread);
	thread = INVALID_HANDLE_VALUE;

	return retval;
#endif
}

- (void)dealloc
{
	/*
	 * No need to handle errors - if canceling the thread fails, we can't
	 * do anything anyway. Most likely, it finished already or was already
	 * canceled.
	 */
#ifndef _WIN32
	pthread_cancel(thread);
#else
	if (thread != INVALID_HANDLE_VALUE) {
		TerminateThread(thread, 1);
		CloseHandle(thread);
	}
#endif

	[object release];
	[super dealloc];
}
@end

@implementation OFTLSKey
+ tlsKeyWithDestructor: (void(*)(void*))destructor
{
	return [[[self alloc] initWithDestructor: destructor] autorelease];
}

- initWithDestructor: (void(*)(void*))destructor
{
	Class c;

	self = [super init];

	/* FIXME: Call destructor on Win32 */
#ifndef _WIN32
	if (pthread_key_create(&key, destructor)) {
#else
	if ((key = TlsAlloc()) == TLS_OUT_OF_INDEXES) {
#endif
		c = isa;
		[super dealloc];
		@throw [OFInitializationFailedException newWithClass: c];
	}

	return self;
}


@end

@implementation OFMutex
+ mutex
{
	return [[[self alloc] init] autorelease];
}

- init
{
	self = [super init];

#ifndef _WIN32
	if (pthread_mutex_init(&mutex, NULL)) {
		Class c = isa;
		[self dealloc];
		@throw [OFInitializationFailedException newWithClass: c];
	}
#else
	InitializeCriticalSection(&mutex);
#endif

	return self;
}

- lock
{
#ifndef _WIN32
	/* FIXME: Add error-handling */
	pthread_mutex_lock(&mutex);
#else
	EnterCriticalSection(&mutex);
#endif

	return self;
}

- unlock
{
#ifndef _WIN32
	/* FIXME: Add error-handling */
	pthread_mutex_unlock(&mutex);
#else
	LeaveCriticalSection(&mutex);
#endif

	return self;
}

- (void)dealloc
{
#ifndef _WIN32
	/* FIXME: Add error-handling */
	pthread_mutex_destroy(&mutex);
#else
	DeleteCriticalSection(&mutex);
#endif

	[super dealloc];
}
@end







<
<
<
<
|
|
<
|
|

>
|
>
>
|



<










|

<
<
<
|
<




<







<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










<
<



<
|
<
<
<
<
|














<
<
<
|
<

<
<
<
<
<
<
<
<
<
<
<

<









<
|
<
<
<
<
<
<







|




|

<
<



<
|
<
<
<
|






>
>












<
|




<
<
<






<

|
<
<
<






<

|
<
<
<






<

|
<
<
<




10
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
107
108
109
110


111
112
113

114



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135

136
137
138
139
140



141
142
143
144
145
146

147
148



149
150
151
152
153
154

155
156



157
158
159
160
161
162

163
164



165
166
167
168
 */

#include "config.h"

#import "OFThread.h"
#import "OFExceptions.h"





#import "threading.h"


static id
call_main(id obj)
{
	/*
	 * Nasty workaround for thread implementations which can't return a
	 * value on join.
	 */
	((OFThread*)obj)->retval = [obj main];

	return 0;
}


@implementation OFThread
+ threadWithObject: (id)obj
{
	return [[[self alloc] initWithObject: obj] autorelease];
}

+ setObject: (id)obj
  forTLSKey: (OFTLSKey*)key
{
	id old = of_tlskey_get(key->key);




	if (!of_tlskey_set(key->key, [obj retain]))

		/* FIXME: Maybe another exception would be better */
		@throw [OFInvalidArgumentException newWithClass: self
						       selector: _cmd];


	[old release];

	return self;
}

+ (id)objectForTLSKey: (OFTLSKey*)key
{

	return [[of_tlskey_get(key->key) retain] autorelease];















}

- init
{
	@throw [OFNotImplementedException newWithClass: isa
					      selector: _cmd];
}

- initWithObject: (id)obj
{


	self = [super init];
	object = [obj copy];


	if (!of_thread_new(&thread, call_main, self)) {




		Class c = isa;
		[super dealloc];
		@throw [OFInitializationFailedException newWithClass: c];
	}

	return self;
}

- main
{
	return nil;
}

- join
{



	of_thread_join(thread);













	return retval;

}

- (void)dealloc
{
	/*
	 * No need to handle errors - if canceling the thread fails, we can't
	 * do anything anyway. Most likely, it finished already or was already
	 * canceled.
	 */

	of_thread_cancel(thread);







	[object release];
	[super dealloc];
}
@end

@implementation OFTLSKey
+ tlsKeyWithDestructor: (void(*)(id))destructor
{
	return [[[self alloc] initWithDestructor: destructor] autorelease];
}

- initWithDestructor: (void(*)(id))destructor
{


	self = [super init];

	/* FIXME: Call destructor on Win32 */

	if (!of_tlskey_new(&key, destructor)) {



		Class c = isa;
		[super dealloc];
		@throw [OFInitializationFailedException newWithClass: c];
	}

	return self;
}

/* FIXME: Add dealloc! */
@end

@implementation OFMutex
+ mutex
{
	return [[[self alloc] init] autorelease];
}

- init
{
	self = [super init];


	if (!of_mutex_new(&mutex)) {
		Class c = isa;
		[self dealloc];
		@throw [OFInitializationFailedException newWithClass: c];
	}




	return self;
}

- lock
{

	/* FIXME: Add error-handling */
	of_mutex_lock(&mutex);




	return self;
}

- unlock
{

	/* FIXME: Add error-handling */
	of_mutex_unlock(&mutex);




	return self;
}

- (void)dealloc
{

	/* FIXME: Add error-handling */
	of_mutex_free(&mutex);




	[super dealloc];
}
@end

Modified src/objc_sync.m from [8a15b08565] to [441808ccaa].

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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
174
175
176
177
178
179
180
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243

244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#ifndef _WIN32
#include <pthread.h>
#endif

#import <objc/objc.h>

#ifdef _WIN32
#include <windows.h>
#endif

#import "OFMacros.h"

struct locks_s {
	id		 obj;
	size_t		 count;
	size_t		 recursion;
#ifndef _WIN32
	pthread_t	 thread;
	pthread_mutex_t	 mutex;
#else
	DWORD		 thread;
	CRITICAL_SECTION mutex;
#endif
};

#ifndef _WIN32
static pthread_mutex_t mutex;
#else
static CRITICAL_SECTION mutex;
#endif
static struct locks_s *locks = NULL;
static size_t num_locks = 0;

#ifndef _WIN32
static OF_INLINE BOOL
mutex_new(pthread_mutex_t *m)
{
	return (pthread_mutex_init(m, NULL) ? NO : YES);
}

static OF_INLINE BOOL
mutex_free(pthread_mutex_t *m)
{
	return (pthread_mutex_destroy(m) ? NO : YES);
}

static OF_INLINE BOOL
mutex_lock(pthread_mutex_t *m)
{
	return (pthread_mutex_lock(m) ? NO : YES);
}

static OF_INLINE BOOL
mutex_unlock(pthread_mutex_t *m)
{
	return (pthread_mutex_unlock(m) ? NO : YES);
}

#define thread_is_current(t) pthread_equal(t, pthread_self())
#define thread_current() pthread_self()
#else
static OF_INLINE BOOL
mutex_new(CRITICAL_SECTION *m)
{
	InitializeCriticalSection(m);
	return YES;
}

static OF_INLINE BOOL
mutex_free(CRITICAL_SECTION *m)
{
	DeleteCriticalSection(m);
	return YES;
}

static OF_INLINE BOOL
mutex_lock(CRITICAL_SECTION *m)
{
	EnterCriticalSection(m);
	return YES;
}

static OF_INLINE BOOL
mutex_unlock(CRITICAL_SECTION *m)
{
	LeaveCriticalSection(m);
	return YES;
}

#define thread_is_current(t) (t == GetCurrentThreadId())
#define thread_current() GetCurrentThreadId()
#endif

#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()
{
	return (mutex_new(&mutex) ? YES : NO);
}

int
objc_sync_enter(id obj)
{
	int i;

	if (obj == nil)
		return 0;

	if (!mutex_lock(&mutex))
		SYNC_ERR("mutex_lock(&mutex)");

	for (i = num_locks - 1; i >= 0; i--) {
		if (locks[i].obj == obj) {
			if (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 (!mutex_unlock(&mutex))
					SYNC_ERR("mutex_unlock(&mutex)");

				if (!mutex_lock(&locks[i].mutex)) {
					mutex_unlock(&mutex);

					SYNC_ERR("mutex_lock(&locks[i].mutex");
				}

				if (!mutex_lock(&mutex))
					SYNC_ERR("mutex_lock(&mutex)");

				assert(locks[i].recursion == 0);

				/* Update lock's active thread */
				locks[i].thread = thread_current();
			}

			if (!mutex_unlock(&mutex))
				SYNC_ERR("mutex_unlock(&mutex)");

			return 0;
		}
	}

	if (locks == NULL) {
		if ((locks = malloc(sizeof(struct locks_s))) == NULL) {
			mutex_unlock(&mutex);
			SYNC_ERR("malloc(...)");
		}
	} else {
		struct locks_s *new_locks;

		if ((new_locks = realloc(locks, (num_locks + 1) *
		    sizeof(struct locks_s))) == NULL) {
			mutex_unlock(&mutex);
			SYNC_ERR("realloc(...)");
		}

		locks = new_locks;
	}

	locks[num_locks].obj = obj;
	locks[num_locks].count = 1;
	locks[num_locks].recursion = 0;
	locks[num_locks].thread = thread_current();

	if (!mutex_new(&locks[num_locks].mutex)) {
		mutex_unlock(&mutex);
		SYNC_ERR("mutex_new(&locks[num_locks].mutex");
	}

	if (!mutex_lock(&locks[num_locks].mutex)) {
		mutex_unlock(&mutex);
		SYNC_ERR("mutex_lock(&locks[num_locks].mutex");
	}

	num_locks++;

	if (!mutex_unlock(&mutex))
		SYNC_ERR("mutex_unlock(&mutex)");

	return 0;
}

int
objc_sync_exit(id obj)
{
	int i;

	if (obj == nil)
		return 0;

	if (!mutex_lock(&mutex))
		SYNC_ERR("mutex_lock(&mutex)");

	for (i = num_locks - 1; i >= 0; i--) {
		if (locks[i].obj == obj) {
			if (locks[i].recursion > 0 &&
			    thread_is_current(locks[i].thread)) {
				locks[i].recursion--;

				if (!mutex_unlock(&mutex))
					SYNC_ERR("mutex_unlock(&mutex)");

				return 0;
			}

			if (!mutex_unlock(&locks[i].mutex)) {
				mutex_unlock(&mutex);
				SYNC_ERR("mutex_unlock(&locks[i].mutex)");
			}

			locks[i].count--;

			if (locks[i].count == 0) {
				struct locks_s *new_locks = NULL;

				if (!mutex_free(&locks[i].mutex)) {
					mutex_unlock(&mutex);

					SYNC_ERR("mutex_free(&locks[i].mutex");
				}

				num_locks--;
				locks[i] = locks[num_locks];

				if (num_locks == 0) {
					free(locks);
					new_locks = NULL;
				} else if ((new_locks = realloc(locks,
				    num_locks * sizeof(struct locks_s))) ==
				    NULL) {
					mutex_unlock(&mutex);
					SYNC_ERR("realloc(...)");
				}

				locks = new_locks;
			}

			if (!mutex_unlock(&mutex))
				SYNC_ERR("mutex_unlock(&mutex)");

			return 0;
		}
	}

	mutex_unlock(&mutex);
	SYNC_ERR("objc_sync_exit()");
}







<
<
<
<


<
<
<
<
|





<
|
|
<
<
<
<


<
|
<
<
<



<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<











|










|
|



|






|
|

|
|
>
|


|
|




|


|
|







|







|









|

|
|
|


|
|
|




|
|












|
|




|


|
|




|
|
|







|
|
>
|











|






|
|





|


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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>





#import <objc/objc.h>





#import "threading.h"

struct locks_s {
	id		 obj;
	size_t		 count;
	size_t		 recursion;

	of_thread_t	 thread;
	of_mutex_t	 mutex;




};


static of_mutex_t mutex;



static struct locks_s *locks = NULL;
static size_t num_locks = 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()
{
	return (of_mutex_new(&mutex) ? YES : NO);
}

int
objc_sync_enter(id obj)
{
	int i;

	if (obj == nil)
		return 0;

	if (!of_mutex_lock(&mutex))
		SYNC_ERR("of_mutex_lock(&mutex)");

	for (i = num_locks - 1; i >= 0; i--) {
		if (locks[i].obj == obj) {
			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 locks_s))) == NULL) {
			of_mutex_unlock(&mutex);
			SYNC_ERR("malloc(...)");
		}
	} else {
		struct locks_s *new_locks;

		if ((new_locks = realloc(locks, (num_locks + 1) *
		    sizeof(struct locks_s))) == NULL) {
			of_mutex_unlock(&mutex);
			SYNC_ERR("realloc(...)");
		}

		locks = new_locks;
	}

	locks[num_locks].obj = obj;
	locks[num_locks].count = 1;
	locks[num_locks].recursion = 0;
	locks[num_locks].thread = of_thread_current();

	if (!of_mutex_new(&locks[num_locks].mutex)) {
		of_mutex_unlock(&mutex);
		SYNC_ERR("of_mutex_new(&locks[num_locks].mutex");
	}

	if (!of_mutex_lock(&locks[num_locks].mutex)) {
		of_mutex_unlock(&mutex);
		SYNC_ERR("of_mutex_lock(&locks[num_locks].mutex");
	}

	num_locks++;

	if (!of_mutex_unlock(&mutex))
		SYNC_ERR("of_mutex_unlock(&mutex)");

	return 0;
}

int
objc_sync_exit(id obj)
{
	int i;

	if (obj == nil)
		return 0;

	if (!of_mutex_lock(&mutex))
		SYNC_ERR("of_mutex_lock(&mutex)");

	for (i = num_locks - 1; i >= 0; i--) {
		if (locks[i].obj == obj) {
			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 locks_s *new_locks = NULL;

				if (!of_mutex_free(&locks[i].mutex)) {
					of_mutex_unlock(&mutex);
					SYNC_ERR(
					    "of_mutex_free(&locks[i].mutex");
				}

				num_locks--;
				locks[i] = locks[num_locks];

				if (num_locks == 0) {
					free(locks);
					new_locks = NULL;
				} else if ((new_locks = realloc(locks,
				    num_locks * sizeof(struct locks_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()");
}

Added src/threading.h version [fc8a803188].











































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
 * Copyright (c) 2008 - 2009
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of libobjfw. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE included in
 * the packaging of this file.
 */

#import "OFMacros.h"

#ifndef _WIN32
#include <pthread.h>
typedef pthread_t of_thread_t;
typedef pthread_mutex_t of_mutex_t;
typedef pthread_key_t of_tlskey_t;
#else
#include <windows.h>
typedef HANDLE of_thread_t;
typedef CRITICAL_SECTION of_mutex_t;
typedef DWORD of_tlskey_t;
#endif

#ifndef _WIN32
#define of_thread_is_current(t) pthread_equal(t, pthread_self())
#define of_thread_current() pthread_self()
#else
#define of_thread_is_current(t) (t == GetCurrentThreadId())
#define of_thread_current() GetCurrentThreadId()
#endif

static OF_INLINE BOOL
of_thread_new(of_thread_t *thread, id (*main)(id), id data)
{
#ifndef _WIN32
	return (pthread_create(thread, NULL, (void*(*)(void*))main,
	    (void*)data) ? NO : YES);
#else
	*thread = CreateThread(NULL, 0, (void*(*)(void*))main,
	    (void*)data, 0, NULL);

	return (thread == NULL ? NO : YES);
#endif
}

static OF_INLINE BOOL
of_thread_join(of_thread_t thread)
{
#ifndef _WIN32
	void *ret;

	if (pthread_join(thread, &ret))
		return NO;

	/* FIXME: Do we need a way to differentiate? */
	return (ret != PTHREAD_CANCELED ? YES : NO);
#else
	if (WaitForSingleObject(thread, INFINITE))
		return NO;

	CloseHandle(thread);

	return YES;
#endif
}

static OF_INLINE BOOL
of_thread_cancel(of_thread_t thread)
{
#ifndef _WIN32
	return (pthread_cancel(thread) ? NO : YES);
#else
	if (thread != INVALID_HANDLE_VALUE) {
		TerminateThread(thread, 1);
		CloseHandle(thread);
	}

	return YES;
#endif
}

static OF_INLINE BOOL
of_mutex_new(of_mutex_t *mutex)
{
#ifndef _WIN32
	return (pthread_mutex_init(mutex, NULL) ? NO : YES);
#else
	InitializeCriticalSection(mutex);
	return YES;
#endif
}

static OF_INLINE BOOL
of_mutex_free(of_mutex_t *mutex)
{
#ifndef _WIN32
	return (pthread_mutex_destroy(mutex) ? NO : YES);
#else
	DeleteCriticalSection(mutex);
	return YES;
#endif
}

static OF_INLINE BOOL
of_mutex_lock(of_mutex_t *mutex)
{
#ifndef _WIN32
	return (pthread_mutex_lock(mutex) ? NO : YES);
#else
	EnterCriticalSection(mutex);
	return YES;
#endif
}

static OF_INLINE BOOL
of_mutex_unlock(of_mutex_t *mutex)
{
#ifndef _WIN32
	return (pthread_mutex_unlock(mutex) ? NO : YES);
#else
	LeaveCriticalSection(mutex);
	return YES;
#endif
}

static OF_INLINE BOOL
of_tlskey_new(of_tlskey_t *key, void (*destructor)(id))
{
#ifndef _WIN32
	return (pthread_key_create(key, (void(*)(void*))destructor) ? NO : YES);
#else
	/* FIXME: Call destructor */
	return ((*key = TlsAlloc()) == TLS_OUT_OF_INDEXES ? NO : YES);
#endif
}

static OF_INLINE id
of_tlskey_get(of_tlskey_t key)
{
#ifndef _WIN32
	void *ret = pthread_getspecific(key);
#else
	void *ret = TlsGetValue(key);
#endif

	/* NULL and nil might be different! */
	if (ret == NULL)
		return nil;

	return (id)ret;
}

static OF_INLINE BOOL
of_tlskey_set(of_tlskey_t key, id obj)
{
	void *p = (obj != nil ? (void*)obj : NULL);

#ifndef _WIN32
	return (pthread_setspecific(key, p) ? NO : YES);
#else
	return (TlsSetValue(key, p) ? YES : NO);
#endif
}