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
|
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
|
+
-
+
-
-
-
+
-
-
+
+
+
+
-
+
-
-
+
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
+
+
+
+
-
-
+
+
+
+
-
-
+
+
+
+
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
|
* LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
* file.
*/
#include "config.h"
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#import "OFStreamObserver_kqueue.h"
#import "OFDataArray.h"
#import "OFInitializationFailedException.h"
#import "OFOutOfMemoryException.h"
@interface OFStreamObserver_kqueue (addEventForFileDescriptor)
#define EVENTLIST_SIZE 64
- (void)_addEventForFileDescriptor: (int)fd
filter: (int16_t)filter;
@end
@implementation OFStreamObserver_kqueue
- init
{
self = [super init];
@try {
if ((kernelQueue = kqueue()) == -1)
@throw [OFInitializationFailedException
newWithClass: isa];
changeList = [[OFDataArray alloc] initWithItemSize:
[self _addEventForFileDescriptor: cancelFD[0]
filter: EVFILT_READ];
sizeof(struct kevent)];
[self _addFileDescriptorForReading: cancelFD[0]];
} @catch (id e) {
[self release];
@throw e;
}
return self;
}
- (void)dealloc
{
close(kernelQueue);
[changeList release];
[super dealloc];
}
- (void)_addEventForFileDescriptor: (int)fd
- (void)_addFileDescriptorForReading: (int)fd
filter: (int16_t)filter
{
struct kevent event, result;
struct kevent event;
eventList = [self resizeMemory: eventList
toNItems: FDs + 1
ofSize: sizeof(struct kevent)];
EV_SET(&event, fd, filter, EV_ADD | EV_RECEIPT, 0, 0, 0);
EV_SET(&event, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
[changeList addItem: &event];
if (kevent(kernelQueue, &event, 1, &result, 1, NULL) != 1 ||
result.data != 0)
/* FIXME: Find a better exception */
@throw [OFInitializationFailedException newWithClass: isa];
FDs++;
}
- (void)_removeEventForFileDescriptor: (int)fd
filter: (int16_t)filter
{
struct kevent event, result;
EV_SET(&event, fd, filter, EV_DELETE | EV_RECEIPT, 0, 0, 0);
if (kevent(kernelQueue, &event, 1, &result, 1, NULL) != 1)
/* FIXME: Find a better exception */
@throw [OFInitializationFailedException newWithClass: isa];
@try {
eventList = [self resizeMemory: eventList
toNItems: FDs - 1
ofSize: sizeof(struct kevent)];
} @catch (OFOutOfMemoryException *e) {
/* We don't care, as we only made it smaller */
[e release];
}
FDs--;
}
- (void)_addFileDescriptorForReading: (int)fd
{
[self _addEventForFileDescriptor: fd
filter: EVFILT_READ];
}
- (void)_addFileDescriptorForWriting: (int)fd
{
struct kevent event;
[self _addEventForFileDescriptor: fd
filter: EVFILT_WRITE];
EV_SET(&event, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
[changeList addItem: &event];
}
- (void)_removeFileDescriptorForReading: (int)fd
{
struct kevent event;
[self _removeEventForFileDescriptor: fd
filter: EVFILT_READ];
EV_SET(&event, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
[changeList addItem: &event];
}
- (void)_removeFileDescriptorForWriting: (int)fd
{
struct kevent event;
[self _removeEventForFileDescriptor: fd
filter: EVFILT_WRITE];
EV_SET(&event, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
[changeList addItem: &event];
}
- (BOOL)observeWithTimeout: (int)timeout
{
struct timespec timespec = { timeout, 0 };
struct kevent eventList[EVENTLIST_SIZE];
int i, events;
[self _processQueue];
if ([self _processCache])
return YES;
events = kevent(kernelQueue, NULL, 0, eventList, FDs,
events = kevent(kernelQueue, [changeList cArray],
(int)[changeList count], eventList, EVENTLIST_SIZE,
(timeout == -1 ? NULL : ×pec));
if (events == -1)
/* FIXME: Throw something */;
if (events == -1) {
switch (errno) {
case EINTR:
return NO;
case ENOMEM:
@throw [OFOutOfMemoryException newWithClass: isa];
default:
assert(0);
}
}
[changeList removeNItems: [changeList count]];
if (events == 0)
return NO;
for (i = 0; i < events; i++) {
if (eventList[i].ident == cancelFD[0]) {
char buffer;
|