ObjFW  Check-in [a4494ec477]

Overview
Comment:Add OFTimer and OFRunLoop.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: a4494ec477dcba57dbb2edc8a8666ee688e60f9e65348dfc403b3c4f0f24b56b
User & Date: js on 2012-09-11 16:48:49
Other Links: manifest | tags
Context
2012-09-12
06:00
OFStreamObserver: Take a double as timeout. check-in: 3c99aa51da user: js tags: trunk
2012-09-11
16:48
Add OFTimer and OFRunLoop. check-in: a4494ec477 user: js tags: trunk
14:20
Add missing abort to uncaught_exception_handler. check-in: e58bcdedb5 user: js tags: trunk
Changes

Modified src/Makefile from [964b921378] to [69b9e00272].

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
       OFMutableString.m		\
       OFNull.m				\
       OFNumber.m			\
       OFObject.m			\
       OFObject+Serialization.m		\
       ${OFPLUGIN_M}			\
       OFProcess.m			\

       OFSeekableStream.m		\
       OFSet.m				\
       OFSHA1Hash.m			\
       OFSortedList.m			\
       OFStream.m			\
       OFStreamObserver.m		\
       OFStreamSocket.m			\
       OFString.m			\
       OFString+Hashing.m		\
       OFString+JSONValue.m		\
       OFString+Serialization.m		\
       OFString+URLEncoding.m		\
       OFString+XMLEscaping.m		\
       OFString+XMLUnescaping.m		\
       OFTCPSocket.m			\
       ${OFTHREAD_M}			\
       OFThreadPool.m			\

       OFURL.m				\
       OFXMLAttribute.m			\
       OFXMLCDATA.m			\
       OFXMLCharacters.m		\
       OFXMLComment.m			\
       OFXMLElement.m			\
       OFXMLElement+Serialization.m	\







>

















>







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
       OFMutableString.m		\
       OFNull.m				\
       OFNumber.m			\
       OFObject.m			\
       OFObject+Serialization.m		\
       ${OFPLUGIN_M}			\
       OFProcess.m			\
       OFRunLoop.m			\
       OFSeekableStream.m		\
       OFSet.m				\
       OFSHA1Hash.m			\
       OFSortedList.m			\
       OFStream.m			\
       OFStreamObserver.m		\
       OFStreamSocket.m			\
       OFString.m			\
       OFString+Hashing.m		\
       OFString+JSONValue.m		\
       OFString+Serialization.m		\
       OFString+URLEncoding.m		\
       OFString+XMLEscaping.m		\
       OFString+XMLUnescaping.m		\
       OFTCPSocket.m			\
       ${OFTHREAD_M}			\
       OFThreadPool.m			\
       OFTimer.m			\
       OFURL.m				\
       OFXMLAttribute.m			\
       OFXMLCDATA.m			\
       OFXMLCharacters.m		\
       OFXMLComment.m			\
       OFXMLElement.m			\
       OFXMLElement+Serialization.m	\

Modified src/OFApplication.m from [6f344c5f2e] to [a2406ebb91].

25
26
27
28
29
30
31

32
33
34
35
36
37
38
#include <signal.h>

#import "OFApplication.h"
#import "OFString.h"
#import "OFArray.h"
#import "OFDictionary.h"
#import "OFThread.h"


#import "OFNotImplementedException.h"

#import "autorelease.h"

#if defined(__MACH__) && !defined(OF_IOS)
# include <crt_externs.h>







>







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <signal.h>

#import "OFApplication.h"
#import "OFString.h"
#import "OFArray.h"
#import "OFDictionary.h"
#import "OFThread.h"
#import "OFRunLoop.h"

#import "OFNotImplementedException.h"

#import "autorelease.h"

#if defined(__MACH__) && !defined(OF_IOS)
# include <crt_externs.h>
291
292
293
294
295
296
297


298


299
300
301
302
303
304
305
306
307
308
309
310
	REGISTER_SIGNAL(SIGUSR2)
#endif
#undef REGISTER_SIGNAL
}

- (void)run
{


	[OFThread _createMainThread];



	[delegate applicationDidFinishLaunching];

	for (;;)
		[OFThread sleepForTimeInterval: 86400];
}

- (void)terminate
{
	exit(0);
}








>
>

>
>



|
<







292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307

308
309
310
311
312
313
314
	REGISTER_SIGNAL(SIGUSR2)
#endif
#undef REGISTER_SIGNAL
}

- (void)run
{
	OFRunLoop *runLoop;

	[OFThread _createMainThread];
	runLoop = [[[OFRunLoop alloc] init] autorelease];
	[OFRunLoop _setMainRunLoop: runLoop];

	[delegate applicationDidFinishLaunching];

	[runLoop run];

}

- (void)terminate
{
	exit(0);
}

Added src/OFRunLoop.h version [8d3f82ba8f].



















































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * 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.
 */

#import "OFObject.h"

@class OFSortedList;
@class OFTimer;

/**
 * \brief A class providing a run loop for the application and its processes.
 */
@interface OFRunLoop: OFObject
{
	OFSortedList *timersQueue;
}

/**
 * \brief Returns the main run loop.
 *
 * \return The main run loop
 */
+ (OFRunLoop*)mainRunLoop;

/**
 * \brief Returns the run loop for the current thread.
 *
 * \return The run loop for the current thread
 */
+ (OFRunLoop*)currentRunLoop;

+ (void)_setMainRunLoop: (OFRunLoop*)mainRunLoop;

/**
 * \brief Adds an OFTimer to the run loop.
 *
 * \param timer The timer to add
 */
- (void)addTimer: (OFTimer*)timer;

/**
 * \brief Starts the run loop.
 */
- (void)run;
@end

Added src/OFRunLoop.m version [b78dbdb727].



















































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * 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"

#import "OFRunLoop.h"
#import "OFThread.h"
#import "OFSortedList.h"
#import "OFTimer.h"
#import "OFDate.h"

static OFTLSKey *currentRunLoopKey;
static OFRunLoop *mainRunLoop;

@implementation OFRunLoop
+ (void)initialize
{
	if (self == [OFRunLoop class])
		currentRunLoopKey = [[OFTLSKey alloc] init];
}

+ (OFRunLoop*)mainRunLoop
{
	return [[mainRunLoop retain] autorelease];
}

+ (OFRunLoop*)currentRunLoop
{
	return [[[OFThread objectForTLSKey: currentRunLoopKey]
	    retain] autorelease];
}

+ (void)_setMainRunLoop: (OFRunLoop*)mainRunLoop_
{
	mainRunLoop = [mainRunLoop_ retain];
}

- init
{
	self = [super init];

	@try {
		void *pool = objc_autoreleasePoolPush();

		timersQueue = [[[OFThread currentThread] _timersQueue] retain];
		[OFThread setObject: self
			  forTLSKey: currentRunLoopKey];

		objc_autoreleasePoolPop(pool);
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[timersQueue release];

	[super dealloc];
}

- (void)addTimer: (OFTimer*)timer
{
	@synchronized (timersQueue) {
		[timersQueue addObject: timer];
	}
}

- (void)run
{
	for (;;) {
		void *pool = objc_autoreleasePoolPush();
		OFDate *now = [OFDate date];

		@synchronized (timersQueue) {
			of_list_object_t *iter, *next;

			for (iter = [timersQueue firstListObject];
			    iter != NULL; iter = next) {
				/*
				 * If a timer is in the future, we can
				 * stop now as it is sorted.
				 */
				if ([[iter->object fireDate] compare: now] ==
				    OF_ORDERED_DESCENDING)
					break;

				[iter->object fire];

				next = iter->next;
				[timersQueue removeListObject: iter];
			}

			/* Sleep until we reach the next timer */
			if (iter != NULL)
				[OFThread sleepUntilDate:
				    [iter->object fireDate]];
			else {
				/*
				 * FIXME:
				 * Theoretically, another thread could add
				 * something to the run loop. This means we
				 * would need a way to block the thread until
				 * another event is added. The most easy way to
				 * achieve that would be if a run loop also
				 * handles streams: An OFStreamObserver could
				 * be called instead of sleepUntilDate above
				 * and get a timeout. If no timers are left,
				 * it could be called without a timeout and
				 * would automatically stop blocking once a new
				 * stream is added. This could also be used to
				 * stop blocking once a new timer is added.
				 */
				[OFThread sleepForTimeInterval: 24 * 3600];
			}
		}

		objc_autoreleasePoolPop(pool);
	}
}
@end

Modified src/OFThread.h from [82f143b8db] to [2e194b355b].

16
17
18
19
20
21
22

23
24
25
26
27
28
29

#import "OFObject.h"
#import "OFList.h"

#import "threading.h"

@class OFDate;


#ifdef OF_HAVE_BLOCKS
typedef id (^of_thread_block_t)(id object);
#endif

/**
 * \brief A class for Thread Local Storage keys.







>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

#import "OFObject.h"
#import "OFList.h"

#import "threading.h"

@class OFDate;
@class OFSortedList;

#ifdef OF_HAVE_BLOCKS
typedef id (^of_thread_block_t)(id object);
#endif

/**
 * \brief A class for Thread Local Storage keys.
90
91
92
93
94
95
96






97
98
99
100
101
102
103
		OF_THREAD_RUNNING,
		OF_THREAD_WAITING_FOR_JOIN
	} running;
#ifdef OF_HAVE_BLOCKS
	of_thread_block_t block;
#endif
	id returnValue;






}

#if defined(OF_HAVE_PROPERTIES) && defined(OF_HAVE_BLOCKS)
@property (copy) of_thread_block_t block;
#endif

/**







>
>
>
>
>
>







91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
		OF_THREAD_RUNNING,
		OF_THREAD_WAITING_FOR_JOIN
	} running;
#ifdef OF_HAVE_BLOCKS
	of_thread_block_t block;
#endif
	id returnValue;
#ifdef OF_THREAD_M
@protected
#else
@private
#endif
	OFSortedList *timersQueue;
}

#if defined(OF_HAVE_PROPERTIES) && defined(OF_HAVE_BLOCKS)
@property (copy) of_thread_block_t block;
#endif

/**
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
 * \return The object the join method should return when called for this thread
 */
- (id)main;

/**
 * \brief This routine is exectued when the thread's main method has finished
 *	  executing or terminate has been called.


 */
- (void)handleTermination;

/**
 * \brief Starts the thread.
 */
- (void)start;

/**
 * \brief Joins a thread.
 *
 * \return The object returned by the main method of the thread.
 */
- (id)join;


@end

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







>
>














>
>







252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
 * \return The object the join method should return when called for this thread
 */
- (id)main;

/**
 * \brief This routine is exectued when the thread's main method has finished
 *	  executing or terminate has been called.
 *
 * \note Be sure to call [super handleTermination]!
 */
- (void)handleTermination;

/**
 * \brief Starts the thread.
 */
- (void)start;

/**
 * \brief Joins a thread.
 *
 * \return The object returned by the main method of the thread.
 */
- (id)join;

- (OFSortedList*)_timersQueue;
@end

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

Modified src/OFThread.m from [e9c62791d8] to [984a3e9ddd].

26
27
28
29
30
31
32

33
34
35
36
37
38
39
# include <unistd.h>
# include <sched.h>
#endif

#import "OFThread.h"
#import "OFList.h"
#import "OFDate.h"

#import "OFAutoreleasePool.h"

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

#import "OFConditionBroadcastFailedException.h"







>







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# include <unistd.h>
# include <sched.h>
#endif

#import "OFThread.h"
#import "OFList.h"
#import "OFDate.h"
#import "OFSortedList.h"
#import "OFAutoreleasePool.h"

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

#import "OFConditionBroadcastFailedException.h"
255
256
257
258
259
260
261

262
263




264
265
266
267
268
269
270
271
272
273
274
275
276
277
278







279
280
281
282
283
284
285
}

- initWithBlock: (of_thread_block_t)block_
	 object: (id)object_
{
	self = [super init];


	block = [block_ copy];
	object = [object_ retain];





	return self;
}
#endif

- (id)main
{
	@throw [OFNotImplementedException exceptionWithClass: [self class]
						    selector: _cmd];

	return nil;
}

- (void)handleTermination
{







}

- (void)start
{
	if (running == OF_THREAD_RUNNING)
		@throw [OFThreadStillRunningException
		    exceptionWithClass: [self class]







>
|
|
>
>
>
>















>
>
>
>
>
>
>







256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
}

- initWithBlock: (of_thread_block_t)block_
	 object: (id)object_
{
	self = [super init];

	@try {
		block = [block_ copy];
		object = [object_ retain];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
#endif

- (id)main
{
	@throw [OFNotImplementedException exceptionWithClass: [self class]
						    selector: _cmd];

	return nil;
}

- (void)handleTermination
{
	@synchronized (timersQueue) {
		/*
		 * Make sure we don't run old timers when the thread is
		 * restarted.
		 */
		[timersQueue removeAllObjects];
	}
}

- (void)start
{
	if (running == OF_THREAD_RUNNING)
		@throw [OFThreadStillRunningException
		    exceptionWithClass: [self class]
309
310
311
312
313
314
315












316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332

333
334
335
336
337
338
339
		    exceptionWithClass: [self class]
				thread: self];

	running = OF_THREAD_NOT_RUNNING;

	return returnValue;
}













- (void)dealloc
{
	if (running == OF_THREAD_RUNNING)
		@throw [OFThreadStillRunningException
		    exceptionWithClass: [self class]
				thread: self];

	/*
	 * We should not be running anymore, but call detach in order to free
	 * the resources.
	 */
	if (running == OF_THREAD_WAITING_FOR_JOIN)
		of_thread_detach(thread);

	[object release];
	[returnValue release];


	[super dealloc];
}
@end

@implementation OFTLSKey
+ (void)initialize







>
>
>
>
>
>
>
>
>
>
>
>

















>







322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
		    exceptionWithClass: [self class]
				thread: self];

	running = OF_THREAD_NOT_RUNNING;

	return returnValue;
}

- (OFSortedList*)_timersQueue
{
	if (timersQueue == nil) {
		OFSortedList *tmp = [[OFSortedList alloc] init];

		if (!of_atomic_cmpswap_ptr((void**)&timersQueue, nil, tmp))
			[tmp release];
	}

	return [[timersQueue retain] autorelease];
}

- (void)dealloc
{
	if (running == OF_THREAD_RUNNING)
		@throw [OFThreadStillRunningException
		    exceptionWithClass: [self class]
				thread: self];

	/*
	 * We should not be running anymore, but call detach in order to free
	 * the resources.
	 */
	if (running == OF_THREAD_WAITING_FOR_JOIN)
		of_thread_detach(thread);

	[object release];
	[returnValue release];
	[timersQueue release];

	[super dealloc];
}
@end

@implementation OFTLSKey
+ (void)initialize

Added src/OFTimer.h version [1d5be3d2a6].





































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
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
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * 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.
 */

#import "OFObject.h"

@class OFDate;

/**
 * \brief A class for creating and firing timers.
 */
@interface OFTimer: OFObject <OFComparing>
{
	OFDate *fireDate;
	double interval;
	id target, object1, object2;
	SEL selector;
	uint8_t arguments;
	BOOL repeats;
}

/**
 * \brief Creates and schedules a new timer with the specified time interval.
 *
 * \param interval The time interval after which the timer should be executed
 *		   when fired
 * \param target The target on which to call the selector
 * \param selector The selector to call on the target
 * \param repeats Whether the timer repeats after it has been executed
 * \return A new, autoreleased timer
 */
+ scheduledTimerWithTimeInterval: (double)interval
			  target: (id)target
			selector: (SEL)selector
			 repeats: (BOOL)repeats;

/**
 * \brief Creates and schedules a new timer with the specified time interval.
 *
 * \param interval The time interval after which the timer should be executed
 *		   when fired
 * \param target The target on which to call the selector
 * \param selector The selector to call on the target
 * \param object An object to pass when calling the selector on the target
 * \param repeats Whether the timer repeats after it has been executed
 * \return A new, autoreleased timer
 */
+ scheduledTimerWithTimeInterval: (double)interval
			  target: (id)target
			selector: (SEL)selector
			  object: (id)object
			 repeats: (BOOL)repeats;

/**
 * \brief Creates and schedules a new timer with the specified time interval.
 *
 * \param interval The time interval after which the timer should be executed
 *		   when fired
 * \param target The target on which to call the selector
 * \param selector The selector to call on the target
 * \param object1 The first object to pass when calling the selector on the
 *		  target
 * \param object2 The second object to pass when calling the selector on the
 *		  target
 * \param repeats Whether the timer repeats after it has been executed
 * \return A new, autoreleased timer
 */
+ scheduledTimerWithTimeInterval: (double)interval
			  target: (id)target
			selector: (SEL)selector
			  object: (id)object1
			  object: (id)object2
			 repeats: (BOOL)repeats;

/**
 * \brief Creates a new timer with the specified time interval.
 *
 * \param interval The time interval after which the timer should be executed
 *		   when fired
 * \param target The target on which to call the selector
 * \param selector The selector to call on the target
 * \param repeats Whether the timer repeats after it has been executed
 * \return A new, autoreleased timer
 */
+ timerWithTimeInterval: (double)interval
		 target: (id)target
	       selector: (SEL)selector
		repeats: (BOOL)repeats;

/**
 * \brief Creates a new timer with the specified time interval.
 *
 * \param interval The time interval after which the timer should be executed
 *		   when fired
 * \param target The target on which to call the selector
 * \param selector The selector to call on the target
 * \param object An object to pass when calling the selector on the target
 * \param repeats Whether the timer repeats after it has been executed
 * \return A new, autoreleased timer
 */
+ timerWithTimeInterval: (double)interval
		 target: (id)target
	       selector: (SEL)selector
		 object: (id)object
		repeats: (BOOL)repeats;

/**
 * \brief Creates a new timer with the specified time interval.
 *
 * \param interval The time interval after which the timer should be executed
 *		   when fired
 * \param target The target on which to call the selector
 * \param selector The selector to call on the target
 * \param object1 The first object to pass when calling the selector on the
 *		  target
 * \param object2 The second object to pass when calling the selector on the
 *		  target
 * \param repeats Whether the timer repeats after it has been executed
 * \return A new, autoreleased timer
 */
+ timerWithTimeInterval: (double)interval
		 target: (id)target
	       selector: (SEL)selector
		 object: (id)object1
		 object: (id)object2
		repeats: (BOOL)repeats;

/**
 * \brief Initializes an already allocated timer with the specified time
 *	  interval.
 *
 * \param fireDate The date at which the timer should fire
 * \param interval The time interval after which to repeat the timer, if it is
 *		   a repeating timer
 * \param target The target on which to call the selector
 * \param selector The selector to call on the target
 * \param repeats Whether the timer repeats after it has been executed
 * \return An initialized timer
 */
- initWithFireDate: (OFDate*)fireDate
	  interval: (double)interval
	    target: (id)target
	  selector: (SEL)selector
	   repeats: (BOOL)repeats;

/**
 * \brief Initializes an already allocated timer with the specified time
 *	  interval.
 *
 * \param fireDate The date at which the timer should fire
 * \param interval The time interval after which to repeat the timer, if it is
 *		   a repeating timer
 * \param target The target on which to call the selector
 * \param selector The selector to call on the target
 * \param object An object to pass when calling the selector on the target
 * \param repeats Whether the timer repeats after it has been executed
 * \return An initialized timer
 */
- initWithFireDate: (OFDate*)fireDate
	  interval: (double)interval
	    target: (id)target
	  selector: (SEL)selector
	    object: (id)object1
	   repeats: (BOOL)repeats;

/**
 * \brief Initializes an already allocated timer with the specified time
 *	  interval.
 *
 * \param fireDate The date at which the timer should fire
 * \param interval The time interval after which to repeat the timer, if it is
 *		   a repeating timer
 * \param target The target on which to call the selector
 * \param selector The selector to call on the target
 * \param repeats Whether the timer repeats after it has been executed
 * \return An initialized timer
 */
- initWithFireDate: (OFDate*)fireDate
	  interval: (double)interval
	    target: (id)target
	  selector: (SEL)selector
	    object: (id)object1
	    object: (id)object2
	   repeats: (BOOL)repeats;

/**
 * \brief Fires the timer, meaning it will execute the specified selector on the
 *	  target.
 */
- (void)fire;

/**
 * \brief Returns the next date at which the timer will fire.
 *
 * \return The next date at which the timer will fire
 */
- (OFDate*)fireDate;
@end

Added src/OFTimer.m version [70767b5be1].



















































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
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
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * 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"

#import "OFTimer.h"
#import "OFDate.h"
#import "OFRunLoop.h"

#import "OFInvalidArgumentException.h"

#import "autorelease.h"
#import "macros.h"

@implementation OFTimer
+ scheduledTimerWithTimeInterval: (double)interval
			  target: (id)target
			selector: (SEL)selector
			 repeats: (BOOL)repeats
{
	void *pool = objc_autoreleasePoolPush();
	OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: interval];
	id timer = [[[self alloc] initWithFireDate: fireDate
					  interval: interval
					    target: target
					  selector: selector
					   repeats: repeats] autorelease];

	[[OFRunLoop currentRunLoop] addTimer: timer];

	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

+ scheduledTimerWithTimeInterval: (double)interval
			  target: (id)target
			selector: (SEL)selector
			  object: (id)object
			 repeats: (BOOL)repeats
{
	void *pool = objc_autoreleasePoolPush();
	OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: interval];
	id timer = [[[self alloc] initWithFireDate: fireDate
					  interval: interval
					    target: target
					  selector: selector
					    object: object
					   repeats: repeats] autorelease];

	[[OFRunLoop currentRunLoop] addTimer: timer];

	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

+ scheduledTimerWithTimeInterval: (double)interval
			  target: (id)target
			selector: (SEL)selector
			  object: (id)object1
			  object: (id)object2
			 repeats: (BOOL)repeats
{
	void *pool = objc_autoreleasePoolPush();
	OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: interval];
	id timer = [[[self alloc] initWithFireDate: fireDate
					  interval: interval
					    target: target
					  selector: selector
					    object: object1
					    object: object2
					   repeats: repeats] autorelease];

	[[OFRunLoop currentRunLoop] addTimer: timer];

	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

+ timerWithTimeInterval: (double)interval
		 target: (id)target
	       selector: (SEL)selector
		repeats: (BOOL)repeats
{
	void *pool = objc_autoreleasePoolPush();
	OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: interval];
	id timer = [[[self alloc] initWithFireDate: fireDate
					  interval: interval
					    target: target
					  selector: selector
					   repeats: repeats] autorelease];

	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

+ timerWithTimeInterval: (double)interval
		 target: (id)target
	       selector: (SEL)selector
		 object: (id)object
		repeats: (BOOL)repeats
{
	void *pool = objc_autoreleasePoolPush();
	OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: interval];
	id timer = [[[self alloc] initWithFireDate: fireDate
					  interval: interval
					    target: target
					  selector: selector
					    object: object
					   repeats: repeats] autorelease];

	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

+ timerWithTimeInterval: (double)interval
		 target: (id)target
	       selector: (SEL)selector
		 object: (id)object1
		 object: (id)object2
		repeats: (BOOL)repeats
{
	void *pool = objc_autoreleasePoolPush();
	OFDate *fireDate = [OFDate dateWithTimeIntervalSinceNow: interval];
	id timer = [[[self alloc] initWithFireDate: fireDate
					  interval: interval
					    target: target
					  selector: selector
					    object: object1
					    object: object2
					   repeats: repeats] autorelease];

	[timer retain];
	objc_autoreleasePoolPop(pool);

	return [timer autorelease];
}

- _initWithFireDate: (OFDate*)fireDate_
	   interval: (double)interval_
	     target: (id)target_
	   selector: (SEL)selector_
	     object: (id)object1_
	     object: (id)object2_
	  arguments: (uint8_t)arguments_
	    repeats: (BOOL)repeats_
{
	self = [super init];

	@try {
		fireDate = [fireDate_ retain];
		interval = interval_;
		target = [target_ retain];
		selector = selector_;
		object1 = [object1_ retain];
		object2 = [object2_ retain];
		arguments = arguments_;
		repeats = repeats_;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- initWithFireDate: (OFDate*)fireDate_
	  interval: (double)interval_
	    target: (id)target_
	  selector: (SEL)selector_
	   repeats: (BOOL)repeats_
{
	return [self _initWithFireDate: fireDate_
			      interval: interval_
				target: target_
			      selector: selector_
				object: nil
				object: nil
			     arguments: 0
			       repeats: repeats_];
}

- initWithFireDate: (OFDate*)fireDate_
	  interval: (double)interval_
	    target: (id)target_
	  selector: (SEL)selector_
	    object: (id)object
	   repeats: (BOOL)repeats_
{
	return [self _initWithFireDate: fireDate_
			      interval: interval_
				target: target_
			      selector: selector_
				object: object
				object: nil
			     arguments: 1
			       repeats: repeats_];
}

- initWithFireDate: (OFDate*)fireDate_
	  interval: (double)interval_
	    target: (id)target_
	  selector: (SEL)selector_
	    object: (id)object1_
	    object: (id)object2_
	   repeats: (BOOL)repeats_
{
	return [self _initWithFireDate: fireDate_
			      interval: interval_
				target: target_
			      selector: selector_
				object: object1_
				object: object2_
			     arguments: 2
			       repeats: repeats_];
}

- (void)dealloc
{
	[fireDate release];
	[target release];
	[object1 release];
	[object2 release];

	[super dealloc];
}

- (of_comparison_result_t)compare: (id <OFComparing>)object_
{
	OFTimer *otherTimer;

	if (![object_ isKindOfClass: [OFTimer class]])
		@throw[OFInvalidArgumentException
		    exceptionWithClass: [self class]
			      selector: _cmd];

	otherTimer = (OFTimer*)object_;

	return [fireDate compare: otherTimer->fireDate];
}

- (void)fire
{
	OF_ENSURE(arguments >= 0 && arguments <= 2);

	switch (arguments) {
	case 0:
		[target performSelector: selector];
		break;
	case 1:
		[target performSelector: selector
			     withObject: object1];
		break;
	case 2:
		[target performSelector: selector
			     withObject: object1
			     withObject: object2];
		break;
	}

	if (repeats) {
		OFDate *old = fireDate;
		fireDate = [[OFDate alloc]
		    initWithTimeIntervalSinceNow: interval];
		[old release];

		[[OFRunLoop currentRunLoop] addTimer: self];
	}
}

- (OFDate*)fireDate
{
	return [[fireDate retain] autorelease];
}
@end

Modified src/ObjFW.h from [0edf98a084] to [2fc0f8109d].

66
67
68
69
70
71
72


73
74
75
76
77
78
79
#import "OFXMLProcessingInstructions.h"
#import "OFXMLParser.h"
#import "OFXMLElementBuilder.h"

#import "OFSerialization.h"

#import "OFApplication.h"



#import "OFAllocFailedException.h"
#import "OFException.h"
#import "OFAcceptFailedException.h"
#import "OFAddressTranslationFailedException.h"
#import "OFAlreadyConnectedException.h"
#import "OFBindFailedException.h"







>
>







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#import "OFXMLProcessingInstructions.h"
#import "OFXMLParser.h"
#import "OFXMLElementBuilder.h"

#import "OFSerialization.h"

#import "OFApplication.h"
#import "OFTimer.h"
#import "OFRunLoop.h"

#import "OFAllocFailedException.h"
#import "OFException.h"
#import "OFAcceptFailedException.h"
#import "OFAddressTranslationFailedException.h"
#import "OFAlreadyConnectedException.h"
#import "OFBindFailedException.h"