ObjFW  Check-in [258b8a4944]

Overview
Comment:Fix a regression from the previous refactorization

kqueue and epoll were not updating _readObjects and _writeObjects
anymore, since this was done by the queue handling code, which they no
longer use after the refactorization.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 258b8a4944bd682c53f078cd5382575f3c973d4301460f6fc4e0e2b770e26467
User & Date: js on 2016-01-03 00:35:01
Other Links: manifest | tags
Context
2016-01-03
00:41
Update copyright check-in: 2a27cf3000 user: js tags: trunk
00:35
Fix a regression from the previous refactorization check-in: 258b8a4944 user: js tags: trunk
2015-12-29
21:33
Refactor OFKernelEventObserver check-in: e9b4700cb6 user: js tags: trunk
Changes

Modified src/OFKernelEventObserver.h from [4fe6de3289] to [72e7bbbce5].

18
19
20
21
22
23
24



25
26
27
28
29
30
31

#import "socket.h"

OF_ASSUME_NONNULL_BEGIN

@class OFMutableArray OF_GENERIC(ObjectType);
@class OFDate;




/*!
 * @protocol OFKernelEventObserverDelegate
 *	     OFKernelEventObserver.h ObjFW/OFKernelEventObserver.h
 *
 * @brief A protocol that needs to be implemented by delegates for
 *	  OFKernelEventObserver.







>
>
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

#import "socket.h"

OF_ASSUME_NONNULL_BEGIN

@class OFMutableArray OF_GENERIC(ObjectType);
@class OFDate;
#ifdef OF_HAVE_THREADS
@class OFMutex;
#endif

/*!
 * @protocol OFKernelEventObserverDelegate
 *	     OFKernelEventObserver.h ObjFW/OFKernelEventObserver.h
 *
 * @brief A protocol that needs to be implemented by delegates for
 *	  OFKernelEventObserver.
109
110
111
112
113
114
115



116
117
118
119
120
121
122
	    *_writeObjects;
	id <OFKernelEventObserverDelegate> _delegate;
#ifdef OF_HAVE_PIPE
	int _cancelFD[2];
#else
	of_socket_t _cancelFD[2];
	struct sockaddr_in _cancelAddr;



#endif
}

/*!
 * The delegate for the OFKernelEventObserver.
 */
@property OF_NULLABLE_PROPERTY (assign)







>
>
>







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
	    *_writeObjects;
	id <OFKernelEventObserverDelegate> _delegate;
#ifdef OF_HAVE_PIPE
	int _cancelFD[2];
#else
	of_socket_t _cancelFD[2];
	struct sockaddr_in _cancelAddr;
#endif
#ifdef OF_HAVE_THREADS
	OFMutex *_mutex;
#endif
}

/*!
 * The delegate for the OFKernelEventObserver.
 */
@property OF_NULLABLE_PROPERTY (assign)

Modified src/OFKernelEventObserver.m from [898e307ee4] to [952d94c390].

23
24
25
26
27
28
29



30
31
32
33
34
35
36
#import "OFArray.h"
#import "OFStream.h"
#import "OFStream+Private.h"
#ifndef OF_HAVE_PIPE
# import "OFStreamSocket.h"
#endif
#import "OFDate.h"




#ifdef HAVE_KQUEUE
# import "OFKernelEventObserver_kqueue.h"
#endif
#ifdef HAVE_EPOLL
# import "OFKernelEventObserver_epoll.h"
#endif







>
>
>







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#import "OFArray.h"
#import "OFStream.h"
#import "OFStream+Private.h"
#ifndef OF_HAVE_PIPE
# import "OFStreamSocket.h"
#endif
#import "OFDate.h"
#ifdef OF_HAVE_THREADS
# import "OFMutex.h"
#endif

#ifdef HAVE_KQUEUE
# import "OFKernelEventObserver_kqueue.h"
#endif
#ifdef HAVE_EPOLL
# import "OFKernelEventObserver_epoll.h"
#endif
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
		cancelAddrLen = sizeof(_cancelAddr);
		if (of_getsockname(_cancelFD[0], (struct sockaddr*)&_cancelAddr,
		    &cancelAddrLen) != 0)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
# endif
#endif




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

	return self;
}

- (void)dealloc
{
	close(_cancelFD[0]);
	if (_cancelFD[1] != _cancelFD[0])
		close(_cancelFD[1]);

#ifdef OF_WII
	of_socket_port_free(_cancelAddr.sin_port, SOCK_DGRAM);
#endif

	[_readObjects release];
	[_writeObjects release];





	[super dealloc];
}

- (void)addObjectForReading: (id <OFReadyForReadingObserving>)object
{
	OF_UNRECOGNIZED_SELECTOR







>
>
>
>




















>
>
>
>







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
		cancelAddrLen = sizeof(_cancelAddr);
		if (of_getsockname(_cancelFD[0], (struct sockaddr*)&_cancelAddr,
		    &cancelAddrLen) != 0)
			@throw [OFInitializationFailedException
			    exceptionWithClass: [self class]];
# endif
#endif

#ifdef OF_HAVE_THREADS
		_mutex = [[OFMutex alloc] init];
#endif
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	close(_cancelFD[0]);
	if (_cancelFD[1] != _cancelFD[0])
		close(_cancelFD[1]);

#ifdef OF_WII
	of_socket_port_free(_cancelAddr.sin_port, SOCK_DGRAM);
#endif

	[_readObjects release];
	[_writeObjects release];

#ifdef OF_HAVE_THREADS
	[_mutex release];
#endif

	[super dealloc];
}

- (void)addObjectForReading: (id <OFReadyForReadingObserving>)object
{
	OF_UNRECOGNIZED_SELECTOR

Modified src/OFKernelEventObserver_LockedQueue.h from [e60316af1b] to [e5e6d24907].

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

#import "OFKernelEventObserver.h"

OF_ASSUME_NONNULL_BEGIN

@class OFMutableArray OF_GENERIC(ObjectType);
@class OFDataArray;
#ifdef OF_HAVE_THREADS
@class OFMutex;
#endif

@interface OFKernelEventObserver_LockedQueue: OFKernelEventObserver
{
	OFDataArray *_queueActions, *_queueFDs;
	OFMutableArray *_queueObjects;
#ifdef OF_HAVE_THREADS
	OFMutex *_mutex;
#endif
}

- (void)OF_addObjectForReading: (id)object
		fileDescriptor: (int)fd;
- (void)OF_addObjectForWriting: (id)object
		fileDescriptor: (int)fd;
- (void)OF_removeObjectForReading: (id)object







<
<
<





<
<
<







16
17
18
19
20
21
22



23
24
25
26
27



28
29
30
31
32
33
34

#import "OFKernelEventObserver.h"

OF_ASSUME_NONNULL_BEGIN

@class OFMutableArray OF_GENERIC(ObjectType);
@class OFDataArray;




@interface OFKernelEventObserver_LockedQueue: OFKernelEventObserver
{
	OFDataArray *_queueActions, *_queueFDs;
	OFMutableArray *_queueObjects;



}

- (void)OF_addObjectForReading: (id)object
		fileDescriptor: (int)fd;
- (void)OF_addObjectForWriting: (id)object
		fileDescriptor: (int)fd;
- (void)OF_removeObjectForReading: (id)object

Modified src/OFKernelEventObserver_LockedQueue.m from [dc0778aa90] to [bec31b0210].

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
	self = [super init];

	@try {
		_queueActions = [[OFDataArray alloc]
		    initWithItemSize: sizeof(int)];
		_queueFDs = [[OFDataArray alloc] initWithItemSize: sizeof(int)];
		_queueObjects = [[OFMutableArray alloc] init];

#ifdef OF_HAVE_THREADS
		_mutex = [[OFMutex alloc] init];
#endif
	} @catch (id e) {
		@throw [OFInitializationFailedException
		    exceptionWithClass: [self class]];
	}

	return self;
}

- (void)dealloc
{
	[_queueActions release];
	[_queueFDs release];
	[_queueObjects release];
#ifdef OF_HAVE_THREADS
	[_mutex release];
#endif

	[super dealloc];
}

- (void)addObjectForReading: (id <OFReadyForReadingObserving>)object
{
#ifdef OF_HAVE_THREADS







<
<
<
<













<
<
<







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
	self = [super init];

	@try {
		_queueActions = [[OFDataArray alloc]
		    initWithItemSize: sizeof(int)];
		_queueFDs = [[OFDataArray alloc] initWithItemSize: sizeof(int)];
		_queueObjects = [[OFMutableArray alloc] init];




	} @catch (id e) {
		@throw [OFInitializationFailedException
		    exceptionWithClass: [self class]];
	}

	return self;
}

- (void)dealloc
{
	[_queueActions release];
	[_queueFDs release];
	[_queueObjects release];




	[super dealloc];
}

- (void)addObjectForReading: (id <OFReadyForReadingObserving>)object
{
#ifdef OF_HAVE_THREADS

Modified src/OFKernelEventObserver_epoll.m from [02fb70080b] to [e19549d9cb].

23
24
25
26
27
28
29

30
31



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

#include <sys/epoll.h>

#import "OFKernelEventObserver.h"
#import "OFKernelEventObserver+Private.h"
#import "OFKernelEventObserver_epoll.h"

#import "OFMapTable.h"
#import "OFNull.h"




#import "OFInitializationFailedException.h"
#import "OFObserveFailedException.h"

#define EVENTLIST_SIZE 64

static const of_map_table_functions_t mapFunctions = { NULL };







>


>
>
>







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <unistd.h>

#include <sys/epoll.h>

#import "OFKernelEventObserver.h"
#import "OFKernelEventObserver+Private.h"
#import "OFKernelEventObserver_epoll.h"
#import "OFArray.h"
#import "OFMapTable.h"
#import "OFNull.h"
#ifdef OF_HAVE_THREADS
# import "OFMutex.h"
#endif

#import "OFInitializationFailedException.h"
#import "OFObserveFailedException.h"

#define EVENTLIST_SIZE 64

static const of_map_table_functions_t mapFunctions = { NULL };
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

	[super dealloc];
}

- (void)OF_addObject: (id)object
      fileDescriptor: (int)fd
	      events: (int)addEvents

{
	intptr_t events;

	events = (intptr_t)[_FDToEvents valueForKey: (void*)(intptr_t)fd];

	if (events == 0) {
		struct epoll_event event;

		memset(&event, 0, sizeof(event));
		event.events = addEvents;
		event.data.ptr = object;

		if (epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &event) == -1)
			@throw [OFObserveFailedException
			    exceptionWithObserver: self
					    errNo: errno];

		[_FDToEvents setValue: (void*)(intptr_t)addEvents
			       forKey: (void*)(intptr_t)fd];
	} else {
		struct epoll_event event;

		memset(&event, 0, sizeof(event));
		event.events = (int)events | addEvents;
		event.data.ptr = object;



		if (epoll_ctl(_epfd, EPOLL_CTL_MOD, fd, &event) == -1)



			@throw [OFObserveFailedException
			    exceptionWithObserver: self
					    errNo: errno];


		[_FDToEvents setValue: (void*)(events | addEvents)
			       forKey: (void*)(intptr_t)fd];



	}

}

- (void)OF_removeObject: (id)object
	 fileDescriptor: (int)fd
		 events: (int)removeEvents

{




	intptr_t events;

	events = (intptr_t)[_FDToEvents valueForKey: (void*)(intptr_t)fd];

	events &= ~removeEvents;

	if (events == 0) {
		if (epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, NULL) == -1)
			@throw [OFObserveFailedException
			    exceptionWithObserver: self
					    errNo: errno];

		[_FDToEvents removeValueForKey: (void*)(intptr_t)fd];
	} else {
		struct epoll_event event;

		memset(&event, 0, sizeof(event));
		event.events = (int)events;
		event.data.ptr = object;

		if (epoll_ctl(_epfd, EPOLL_CTL_MOD, fd, &event) == -1)
			@throw [OFObserveFailedException
			    exceptionWithObserver: self
					    errNo: errno];

		[_FDToEvents setValue: (void*)events
			       forKey: (void*)(intptr_t)fd];
	}







}

- (void)addObjectForReading: (id <OFReadyForReadingObserving>)object
{
	[self OF_addObject: object
	    fileDescriptor: [object fileDescriptorForReading]
		    events: EPOLLIN];

}

- (void)addObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	[self OF_addObject: object
	    fileDescriptor: [object fileDescriptorForWriting]
		    events: EPOLLOUT];

}

- (void)removeObjectForReading: (id <OFReadyForReadingObserving>)object
{
	[self OF_removeObject: object
	       fileDescriptor: [object fileDescriptorForReading]
		       events: EPOLLIN];

}

- (void)removeObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	[self OF_removeObject: object
	       fileDescriptor: [object fileDescriptorForWriting]
		       events: EPOLLOUT];

}

- (void)observeForTimeInterval: (of_time_interval_t)timeInterval
{
	OFNull *nullObject = [OFNull null];
	void *pool = objc_autoreleasePoolPush();
	struct epoll_event eventList[EVENTLIST_SIZE];







>

<
|
|
>
|

|
<
<
<

<
<
<
<
|
<
|
<
<





>
>
|
>
>
>



>



>
>
>

>





>

>
>
>
>
|

|
>
|

|
|
|
|
|

|
|
|

|
|
|

|
|
|
|

|
|
|
>
>
>
>
>
>
>






|
>






|
>






|
>






|
>







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

	[super dealloc];
}

- (void)OF_addObject: (id)object
      fileDescriptor: (int)fd
	      events: (int)addEvents
	objectsArray: (OFMutableArray*)objectsArray
{

#ifdef OF_HAVE_THREADS
	[_mutex lock];
	@try {
#endif
		struct epoll_event event;
		intptr_t events;








		events = (intptr_t)[_FDToEvents

		    valueForKey: (void*)(intptr_t)fd];



		memset(&event, 0, sizeof(event));
		event.events = (int)events | addEvents;
		event.data.ptr = object;

		[objectsArray addObject: object];

		if (epoll_ctl(_epfd,
		    (events == 0 ? EPOLL_CTL_ADD : EPOLL_CTL_MOD),
		    fd, &event) == -1) {
			[objectsArray removeObjectIdenticalTo: object];
			@throw [OFObserveFailedException
			    exceptionWithObserver: self
					    errNo: errno];
		}

		[_FDToEvents setValue: (void*)(events | addEvents)
			       forKey: (void*)(intptr_t)fd];
#ifdef OF_HAVE_THREADS
	} @finally {
		[_mutex unlock];
	}
#endif
}

- (void)OF_removeObject: (id)object
	 fileDescriptor: (int)fd
		 events: (int)removeEvents
	   objectsArray: (OFMutableArray*)objectsArray
{
#ifdef OF_HAVE_THREADS
	[_mutex lock];
	@try {
#endif
		intptr_t events;

		events = (intptr_t)[_FDToEvents
		    valueForKey: (void*)(intptr_t)fd];
		events &= ~removeEvents;

		if (events == 0) {
			if (epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, NULL) == -1)
				@throw [OFObserveFailedException
				    exceptionWithObserver: self
						    errNo: errno];

			[_FDToEvents removeValueForKey: (void*)(intptr_t)fd];
		} else {
			struct epoll_event event;

			memset(&event, 0, sizeof(event));
			event.events = (int)events;
			event.data.ptr = object;

			if (epoll_ctl(_epfd, EPOLL_CTL_MOD, fd, &event) == -1)
				@throw [OFObserveFailedException
				    exceptionWithObserver: self
						    errNo: errno];

			[_FDToEvents setValue: (void*)events
				       forKey: (void*)(intptr_t)fd];
		}

		[objectsArray removeObjectIdenticalTo: object];
#ifdef OF_HAVE_THREADS
	} @finally {
		[_mutex unlock];
	}
#endif
}

- (void)addObjectForReading: (id <OFReadyForReadingObserving>)object
{
	[self OF_addObject: object
	    fileDescriptor: [object fileDescriptorForReading]
		    events: EPOLLIN
	      objectsArray: _readObjects];
}

- (void)addObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	[self OF_addObject: object
	    fileDescriptor: [object fileDescriptorForWriting]
		    events: EPOLLOUT
	      objectsArray: _writeObjects];
}

- (void)removeObjectForReading: (id <OFReadyForReadingObserving>)object
{
	[self OF_removeObject: object
	       fileDescriptor: [object fileDescriptorForReading]
		       events: EPOLLIN
		 objectsArray: _readObjects];
}

- (void)removeObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	[self OF_removeObject: object
	       fileDescriptor: [object fileDescriptorForWriting]
		       events: EPOLLOUT
		 objectsArray: _writeObjects];
}

- (void)observeForTimeInterval: (of_time_interval_t)timeInterval
{
	OFNull *nullObject = [OFNull null];
	void *pool = objc_autoreleasePoolPush();
	struct epoll_event eventList[EVENTLIST_SIZE];

Modified src/OFKernelEventObserver_kqueue.m from [3ad5dffb1b] to [8f67672c8e].

28
29
30
31
32
33
34



35
36
37
38
39
40
41
#include <sys/time.h>

#import "OFKernelEventObserver.h"
#import "OFKernelEventObserver+Private.h"
#import "OFKernelEventObserver_kqueue.h"
#import "OFDataArray.h"
#import "OFArray.h"




#import "OFInitializationFailedException.h"
#import "OFObserveFailedException.h"
#import "OFOutOfRangeException.h"

#define EVENTLIST_SIZE 64








>
>
>







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <sys/time.h>

#import "OFKernelEventObserver.h"
#import "OFKernelEventObserver+Private.h"
#import "OFKernelEventObserver_kqueue.h"
#import "OFDataArray.h"
#import "OFArray.h"
#ifdef OF_HAVE_THREADS
# import "OFMutex.h"
#endif

#import "OFInitializationFailedException.h"
#import "OFObserveFailedException.h"
#import "OFOutOfRangeException.h"

#define EVENTLIST_SIZE 64

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
	event.flags = EV_ADD;
#ifndef OF_NETBSD
	event.udata = object;
#else
	event.udata = (intptr_t)object;
#endif







	if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0)

		@throw [OFObserveFailedException
		    exceptionWithObserver: self
				    errNo: errno];






}

- (void)addObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	struct kevent event;

	memset(&event, 0, sizeof(event));
	event.ident = [object fileDescriptorForWriting];
	event.filter = EVFILT_WRITE;
	event.flags = EV_ADD;
#ifndef OF_NETBSD
	event.udata = object;
#else
	event.udata = (intptr_t)object;
#endif







	if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0)

		@throw [OFObserveFailedException
		    exceptionWithObserver: self
				    errNo: errno];






}

- (void)removeObjectForReading: (id <OFReadyForReadingObserving>)object
{
	struct kevent event;

	memset(&event, 0, sizeof(event));
	event.ident = [object fileDescriptorForReading];
	event.filter = EVFILT_READ;
	event.flags = EV_DELETE;





	if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0)
		@throw [OFObserveFailedException
		    exceptionWithObserver: self
				    errNo: errno];







}

- (void)removeObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	struct kevent event;

	memset(&event, 0, sizeof(event));
	event.ident = [object fileDescriptorForWriting];
	event.filter = EVFILT_WRITE;
	event.flags = EV_DELETE;





	if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0)
		@throw [OFObserveFailedException
		    exceptionWithObserver: self
				    errNo: errno];







}

- (void)observeForTimeInterval: (of_time_interval_t)timeInterval
{
	void *pool = objc_autoreleasePoolPush();
	struct timespec timeout;
	struct kevent eventList[EVENTLIST_SIZE];







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
















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











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











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







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
	event.flags = EV_ADD;
#ifndef OF_NETBSD
	event.udata = object;
#else
	event.udata = (intptr_t)object;
#endif

#ifdef OF_HAVE_THREADS
	[_mutex lock];
	@try {
#endif
		[_readObjects addObject: object];

		if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0) {
			[_readObjects removeObjectIdenticalTo: object];
			@throw [OFObserveFailedException
			    exceptionWithObserver: self
					    errNo: errno];
		}
#ifdef OF_HAVE_THREADS
	} @finally {
		[_mutex unlock];
	}
#endif
}

- (void)addObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	struct kevent event;

	memset(&event, 0, sizeof(event));
	event.ident = [object fileDescriptorForWriting];
	event.filter = EVFILT_WRITE;
	event.flags = EV_ADD;
#ifndef OF_NETBSD
	event.udata = object;
#else
	event.udata = (intptr_t)object;
#endif

#ifdef OF_HAVE_THREADS
	[_mutex lock];
	@try {
#endif
		[_writeObjects addObject: object];

		if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0) {
			[_writeObjects removeObjectIdenticalTo: object];
			@throw [OFObserveFailedException
			    exceptionWithObserver: self
					    errNo: errno];
		}
#ifdef OF_HAVE_THREADS
	} @finally {
		[_mutex unlock];
	}
#endif
}

- (void)removeObjectForReading: (id <OFReadyForReadingObserving>)object
{
	struct kevent event;

	memset(&event, 0, sizeof(event));
	event.ident = [object fileDescriptorForReading];
	event.filter = EVFILT_READ;
	event.flags = EV_DELETE;

#ifdef OF_HAVE_THREADS
	[_mutex lock];
	@try {
#endif
		if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0)
			@throw [OFObserveFailedException
			    exceptionWithObserver: self
					    errNo: errno];

		[_readObjects removeObjectIdenticalTo: object];
#ifdef OF_HAVE_THREADS
	} @finally {
		[_mutex unlock];
	}
#endif
}

- (void)removeObjectForWriting: (id <OFReadyForWritingObserving>)object
{
	struct kevent event;

	memset(&event, 0, sizeof(event));
	event.ident = [object fileDescriptorForWriting];
	event.filter = EVFILT_WRITE;
	event.flags = EV_DELETE;

#ifdef OF_HAVE_THREADS
	[_mutex lock];
	@try {
#endif
		if (kevent(_kernelQueue, &event, 1, NULL, 0, NULL) != 0)
			@throw [OFObserveFailedException
			    exceptionWithObserver: self
					    errNo: errno];

		[_writeObjects removeObjectIdenticalTo: object];
#ifdef OF_HAVE_THREADS
	} @finally {
		[_mutex unlock];
	}
#endif
}

- (void)observeForTimeInterval: (of_time_interval_t)timeInterval
{
	void *pool = objc_autoreleasePoolPush();
	struct timespec timeout;
	struct kevent eventList[EVENTLIST_SIZE];