event 0.2.2 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e032d8ef7daf3803999a2ac9cba5a72e95f6a3b6551f4724be451eb026b03e0
4
- data.tar.gz: 1cdb73bcd9a5f52483faa2da537c1033ebfaba64b41abc80734b475afbd1fd72
3
+ metadata.gz: 1adbb7e42901c2b8d7cd402e48ebf24fc763dd37a0c5e6da48262fd8bb33771a
4
+ data.tar.gz: 0a85f5629cadf9eb37813fcaabf16be2e459bdcaff72756640f6dc93f34e00f1
5
5
  SHA512:
6
- metadata.gz: 471fbc3ded644b8bfadbc4e1cca562f926bcd203141a59c6981e5ca85e225a9a1b09df4ed2f0792077272b2652ef50a81ea208c0fd44bd35b05158bfdb949c9b
7
- data.tar.gz: a22b2804acdc8ad4dc5bc300fb23aa5991a2d69db301c2d6d5d71016643848e13cb1d9392c6367eebf4f3b179357b60c86cdbcd5b2bad8053c0dd0e1b42f38f9
6
+ metadata.gz: c0f0fd8577bb468b2a093b5720c7651eb530f496867ace6caba28ace95abe8f7c45351c7e98feaa45443654521bdea43d8e157547be1d430f42af20232e011e6
7
+ data.tar.gz: 7b2230479a18b9d818c1fafa49589f8eea607da8e0283292a807e5d12d15d59f1aa84e6e1d5ac75197474807eeabb0982f15534c98e85cc81ad64c7f7f11dcc7
@@ -25,3 +25,5 @@ enum Event {
25
25
  ERROR = 8,
26
26
  HANGUP = 16
27
27
  };
28
+
29
+ #include <ruby/thread.h>
@@ -28,7 +28,7 @@
28
28
  static VALUE Event_Backend_EPoll = Qnil;
29
29
  static ID id_fileno, id_transfer;
30
30
 
31
- static const unsigned EPOLL_MAX_EVENTS = 64;
31
+ enum {EPOLL_MAX_EVENTS = 64};
32
32
 
33
33
  struct Event_Backend_EPoll {
34
34
  VALUE loop;
@@ -41,13 +41,19 @@ void Event_Backend_EPoll_Type_mark(void *_data)
41
41
  rb_gc_mark(data->loop);
42
42
  }
43
43
 
44
+ static
45
+ void close_internal(struct Event_Backend_EPoll *data) {
46
+ if (data->descriptor >= 0) {
47
+ close(data->descriptor);
48
+ data->descriptor = -1;
49
+ }
50
+ }
51
+
44
52
  void Event_Backend_EPoll_Type_free(void *_data)
45
53
  {
46
54
  struct Event_Backend_EPoll *data = _data;
47
55
 
48
- if (data->descriptor >= 0) {
49
- close(data->descriptor);
50
- }
56
+ close_internal(data);
51
57
 
52
58
  free(data);
53
59
  }
@@ -96,6 +102,15 @@ VALUE Event_Backend_EPoll_initialize(VALUE self, VALUE loop) {
96
102
  return self;
97
103
  }
98
104
 
105
+ VALUE Event_Backend_EPoll_close(VALUE self) {
106
+ struct Event_Backend_EPoll *data = NULL;
107
+ TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
108
+
109
+ close_internal(data);
110
+
111
+ return Qnil;
112
+ }
113
+
99
114
  static inline
100
115
  uint32_t epoll_flags_from_events(int events) {
101
116
  uint32_t flags = 0;
@@ -212,28 +227,71 @@ int make_timeout(VALUE duration) {
212
227
  rb_raise(rb_eRuntimeError, "unable to convert timeout");
213
228
  }
214
229
 
230
+ struct select_arguments {
231
+ struct Event_Backend_EPoll *data;
232
+
233
+ int count;
234
+ struct epoll_event events[EPOLL_MAX_EVENTS];
235
+
236
+ int timeout;
237
+ };
238
+
239
+ static
240
+ void * select_internal(void *_arguments) {
241
+ struct select_arguments * arguments = (struct select_arguments *)_arguments;
242
+
243
+ arguments->count = epoll_wait(arguments->data->descriptor, arguments->events, EPOLL_MAX_EVENTS, arguments->timeout);
244
+
245
+ return NULL;
246
+ }
247
+
248
+ static
249
+ void select_internal_without_gvl(struct select_arguments *arguments) {
250
+ rb_thread_call_without_gvl(select_internal, (void *)arguments, RUBY_UBF_IO, 0);
251
+
252
+ if (arguments->count == -1) {
253
+ rb_sys_fail("select_internal_without_gvl:epoll_wait");
254
+ }
255
+ }
256
+
257
+ static
258
+ void select_internal_with_gvl(struct select_arguments *arguments) {
259
+ select_internal((void *)arguments);
260
+
261
+ if (arguments->count == -1) {
262
+ rb_sys_fail("select_internal_with_gvl:epoll_wait");
263
+ }
264
+ }
265
+
215
266
  VALUE Event_Backend_EPoll_select(VALUE self, VALUE duration) {
216
267
  struct Event_Backend_EPoll *data = NULL;
217
268
  TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
218
269
 
219
- struct epoll_event events[EPOLL_MAX_EVENTS];
270
+ struct select_arguments arguments = {
271
+ .data = data,
272
+ .timeout = 0
273
+ };
220
274
 
221
- int count = epoll_wait(data->descriptor, events, EPOLL_MAX_EVENTS, make_timeout(duration));
275
+ select_internal_with_gvl(&arguments);
222
276
 
223
- if (count == -1) {
224
- rb_sys_fail("epoll_wait");
277
+ if (arguments.count == 0) {
278
+ arguments.timeout = make_timeout(duration);
279
+
280
+ if (arguments.timeout != 0) {
281
+ select_internal_without_gvl(&arguments);
282
+ }
225
283
  }
226
284
 
227
- for (int i = 0; i < count; i += 1) {
228
- VALUE fiber = (VALUE)events[i].data.ptr;
229
- VALUE result = INT2NUM(events[i].events);
285
+ for (int i = 0; i < arguments.count; i += 1) {
286
+ VALUE fiber = (VALUE)arguments.events[i].data.ptr;
287
+ VALUE result = INT2NUM(arguments.events[i].events);
230
288
 
231
289
  // fprintf(stderr, "-> fiber=%p descriptor=%d\n", (void*)fiber, events[i].data.fd);
232
290
 
233
291
  rb_funcall(fiber, id_transfer, 1, result);
234
292
  }
235
293
 
236
- return INT2NUM(count);
294
+ return INT2NUM(arguments.count);
237
295
  }
238
296
 
239
297
  void Init_Event_Backend_EPoll(VALUE Event_Backend) {
@@ -244,6 +302,7 @@ void Init_Event_Backend_EPoll(VALUE Event_Backend) {
244
302
 
245
303
  rb_define_alloc_func(Event_Backend_EPoll, Event_Backend_EPoll_allocate);
246
304
  rb_define_method(Event_Backend_EPoll, "initialize", Event_Backend_EPoll_initialize, 1);
305
+ rb_define_method(Event_Backend_EPoll, "close", Event_Backend_EPoll_close, 0);
247
306
 
248
307
  rb_define_method(Event_Backend_EPoll, "io_wait", Event_Backend_EPoll_io_wait, 3);
249
308
  rb_define_method(Event_Backend_EPoll, "select", Event_Backend_EPoll_select, 1);
@@ -28,7 +28,7 @@
28
28
  static VALUE Event_Backend_KQueue = Qnil;
29
29
  static ID id_fileno, id_transfer;
30
30
 
31
- static const unsigned KQUEUE_MAX_EVENTS = 64;
31
+ enum {KQUEUE_MAX_EVENTS = 64};
32
32
 
33
33
  struct Event_Backend_KQueue {
34
34
  VALUE loop;
@@ -41,13 +41,19 @@ void Event_Backend_KQueue_Type_mark(void *_data)
41
41
  rb_gc_mark(data->loop);
42
42
  }
43
43
 
44
+ static
45
+ void close_internal(struct Event_Backend_KQueue *data) {
46
+ if (data->descriptor >= 0) {
47
+ close(data->descriptor);
48
+ data->descriptor = -1;
49
+ }
50
+ }
51
+
44
52
  void Event_Backend_KQueue_Type_free(void *_data)
45
53
  {
46
54
  struct Event_Backend_KQueue *data = _data;
47
55
 
48
- if (data->descriptor >= 0) {
49
- close(data->descriptor);
50
- }
56
+ close_internal(data);
51
57
 
52
58
  free(data);
53
59
  }
@@ -97,50 +103,121 @@ VALUE Event_Backend_KQueue_initialize(VALUE self, VALUE loop) {
97
103
  return self;
98
104
  }
99
105
 
100
- static inline
101
- u_short kqueue_filter_from_events(int events) {
102
- u_short filter = 0;
106
+ VALUE Event_Backend_KQueue_close(VALUE self) {
107
+ struct Event_Backend_KQueue *data = NULL;
108
+ TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
103
109
 
104
- if (events & READABLE) filter |= EVFILT_READ;
105
- if (events & PRIORITY) filter |= EV_OOBAND;
106
- if (events & WRITABLE) filter |= EVFILT_WRITE;
110
+ close_internal(data);
107
111
 
108
- return filter;
112
+ return Qnil;
109
113
  }
110
114
 
111
- static inline
112
- int events_from_kqueue_filter(u_short filter) {
113
- int events = 0;
115
+ static
116
+ int io_add_filters(int descriptor, int ident, int events, VALUE fiber) {
117
+ int count = 0;
118
+ struct kevent kevents[2] = {0};
119
+
120
+ if (events & READABLE) {
121
+ kevents[count].ident = ident;
122
+ kevents[count].filter = EVFILT_READ;
123
+ kevents[count].flags = EV_ADD | EV_ENABLE | EV_ONESHOT;
124
+ kevents[count].udata = (void*)fiber;
125
+
126
+ // #ifdef EV_OOBAND
127
+ // if (events & PRIORITY) {
128
+ // kevents[count].flags |= EV_OOBAND;
129
+ // }
130
+ // #endif
131
+
132
+ count++;
133
+ }
134
+
135
+ if (events & WRITABLE) {
136
+ kevents[count].ident = ident;
137
+ kevents[count].filter = EVFILT_WRITE;
138
+ kevents[count].flags = EV_ADD | EV_ENABLE | EV_ONESHOT;
139
+ kevents[count].udata = (void*)fiber;
140
+ count++;
141
+ }
142
+
143
+ int result = kevent(descriptor, kevents, count, NULL, 0, NULL);
114
144
 
115
- if (filter & EVFILT_READ) events |= READABLE;
116
- if (filter & EV_OOBAND) events |= PRIORITY;
117
- if (filter & EVFILT_WRITE) events |= WRITABLE;
145
+ if (result == -1) {
146
+ rb_sys_fail("kevent(register)");
147
+ }
118
148
 
119
- return INT2NUM(events);
149
+ return events;
120
150
  }
121
151
 
122
- VALUE Event_Backend_KQueue_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE events) {
123
- struct Event_Backend_KQueue *data = NULL;
124
- TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
152
+ static
153
+ void io_remove_filters(int descriptor, int ident, int events) {
154
+ int count = 0;
155
+ struct kevent kevents[2] = {0};
125
156
 
126
- struct kevent event = {0};
157
+ if (events & READABLE) {
158
+ kevents[count].ident = ident;
159
+ kevents[count].filter = EVFILT_READ;
160
+ kevents[count].flags = EV_DELETE;
161
+
162
+ count++;
163
+ }
127
164
 
128
- int descriptor = NUM2INT(rb_funcall(io, id_fileno, 0));
165
+ if (events & WRITABLE) {
166
+ kevents[count].ident = ident;
167
+ kevents[count].filter = EVFILT_WRITE;
168
+ kevents[count].flags = EV_DELETE;
169
+ count++;
170
+ }
129
171
 
130
- event.ident = descriptor;
131
- event.filter = kqueue_filters_from_events(events);
132
- event.flags = EV_ADD | EV_ENABLE | EV_ONESHOT;
133
- event.udata = (void*)fiber;
172
+ // Ignore the result.
173
+ kevent(descriptor, kevents, count, NULL, 0, NULL);
174
+ }
175
+
176
+ struct io_wait_arguments {
177
+ struct Event_Backend_KQueue *data;
178
+ int events;
179
+ int descriptor;
180
+ };
181
+
182
+ static
183
+ VALUE io_wait_rescue(VALUE _arguments, VALUE exception) {
184
+ struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
134
185
 
135
- // A better approach is to batch all changes:
136
- int result = kevent(data->descriptor, &event, 1, NULL, 0, NULL);
186
+ io_remove_filters(arguments->data->descriptor, arguments->descriptor, arguments->events);
137
187
 
138
- if (result == -1) {
139
- rb_sys_fail("kevent");
140
- }
188
+ rb_exc_raise(exception);
189
+ };
190
+
191
+ static inline
192
+ int events_from_kqueue_filter(int filter) {
193
+ if (filter == EVFILT_READ) return READABLE;
194
+ if (filter == EVFILT_WRITE) return WRITABLE;
195
+
196
+ return 0;
197
+ }
198
+
199
+ static
200
+ VALUE io_wait_transfer(VALUE _arguments) {
201
+ struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
202
+
203
+ VALUE result = rb_funcall(arguments->data->loop, id_transfer, 0);
141
204
 
142
- VALUE result = rb_funcall(data->loop, id_transfer, 0);
143
205
  return INT2NUM(events_from_kqueue_filter(NUM2INT(result)));
206
+ };
207
+
208
+ VALUE Event_Backend_KQueue_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE events) {
209
+ struct Event_Backend_KQueue *data = NULL;
210
+ TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
211
+
212
+ int descriptor = NUM2INT(rb_funcall(io, id_fileno, 0));
213
+
214
+ struct io_wait_arguments io_wait_arguments = {
215
+ .events = io_add_filters(data->descriptor, descriptor, NUM2INT(events), fiber),
216
+ .data = data,
217
+ .descriptor = descriptor,
218
+ };
219
+
220
+ return rb_rescue(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_rescue, (VALUE)&io_wait_arguments);
144
221
  }
145
222
 
146
223
  static
@@ -158,7 +235,7 @@ struct timespec * make_timeout(VALUE duration, struct timespec * storage) {
158
235
 
159
236
  else if (RB_FLOAT_TYPE_P(duration)) {
160
237
  double value = RFLOAT_VALUE(duration);
161
- time_t seconds = duration;
238
+ time_t seconds = value;
162
239
 
163
240
  storage->tv_sec = seconds;
164
241
  storage->tv_nsec = (value - seconds) * 1000000000L;
@@ -169,26 +246,89 @@ struct timespec * make_timeout(VALUE duration, struct timespec * storage) {
169
246
  rb_raise(rb_eRuntimeError, "unable to convert timeout");
170
247
  }
171
248
 
249
+ static
250
+ int timeout_nonblocking(struct timespec * timespec) {
251
+ return timespec && timespec->tv_sec == 0 && timespec->tv_nsec == 0;
252
+ }
253
+
254
+ struct select_arguments {
255
+ struct Event_Backend_KQueue *data;
256
+
257
+ int count;
258
+ struct kevent events[KQUEUE_MAX_EVENTS];
259
+
260
+ struct timespec storage;
261
+ struct timespec *timeout;
262
+ };
263
+
264
+ static
265
+ void * select_internal(void *_arguments) {
266
+ struct select_arguments * arguments = (struct select_arguments *)_arguments;
267
+
268
+ arguments->count = kevent(arguments->data->descriptor, NULL, 0, arguments->events, arguments->count, arguments->timeout);
269
+
270
+ return NULL;
271
+ }
272
+
273
+ static
274
+ void select_internal_without_gvl(struct select_arguments *arguments) {
275
+ rb_thread_call_without_gvl(select_internal, (void *)arguments, RUBY_UBF_IO, 0);
276
+
277
+ if (arguments->count == -1) {
278
+ rb_sys_fail("select_internal_without_gvl:kevent");
279
+ }
280
+ }
281
+
282
+ static
283
+ void select_internal_with_gvl(struct select_arguments *arguments) {
284
+ select_internal((void *)arguments);
285
+
286
+ if (arguments->count == -1) {
287
+ rb_sys_fail("select_internal_with_gvl:kevent");
288
+ }
289
+ }
290
+
172
291
  VALUE Event_Backend_KQueue_select(VALUE self, VALUE duration) {
173
292
  struct Event_Backend_KQueue *data = NULL;
174
293
  TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
175
294
 
176
- struct kevent events[KQUEUE_MAX_EVENTS];
177
- struct timespec storage;
295
+ struct select_arguments arguments = {
296
+ .data = data,
297
+ .count = KQUEUE_MAX_EVENTS,
298
+ .storage = {
299
+ .tv_sec = 0,
300
+ .tv_nsec = 0
301
+ }
302
+ };
178
303
 
179
- int count = kevent(data->descriptor, NULL, 0, events, KQUEUE_MAX_EVENTS, make_timeout(duration, &storage));
304
+ // We break this implementation into two parts.
305
+ // (1) count = kevent(..., timeout = 0)
306
+ // (2) without gvl: kevent(..., timeout = 0) if count == 0 and timeout != 0
307
+ // This allows us to avoid releasing and reacquiring the GVL.
308
+ // Non-comprehensive testing shows this gives a 1.5x speedup.
309
+ arguments.timeout = &arguments.storage;
180
310
 
181
- if (count == -1) {
182
- rb_sys_fail("kevent");
311
+ // First do the syscall with no timeout to get any immediately available events:
312
+ select_internal_with_gvl(&arguments);
313
+
314
+ // If there were no pending events, if we have a timeout, wait for more events:
315
+ if (arguments.count == 0) {
316
+ arguments.timeout = make_timeout(duration, &arguments.storage);
317
+
318
+ if (!timeout_nonblocking(arguments.timeout)) {
319
+ arguments.count = KQUEUE_MAX_EVENTS;
320
+
321
+ select_internal_without_gvl(&arguments);
322
+ }
183
323
  }
184
324
 
185
- for (int i = 0; i < count; i += 1) {
186
- VALUE fiber = (VALUE)events[i].udata;
187
- VALUE result = INT2NUM(events[i].filter);
325
+ for (int i = 0; i < arguments.count; i += 1) {
326
+ VALUE fiber = (VALUE)arguments.events[i].udata;
327
+ VALUE result = INT2NUM(arguments.events[i].filter);
188
328
  rb_funcall(fiber, id_transfer, 1, result);
189
329
  }
190
330
 
191
- return INT2NUM(count);
331
+ return INT2NUM(arguments.count);
192
332
  }
193
333
 
194
334
  void Init_Event_Backend_KQueue(VALUE Event_Backend) {
@@ -199,6 +339,7 @@ void Init_Event_Backend_KQueue(VALUE Event_Backend) {
199
339
 
200
340
  rb_define_alloc_func(Event_Backend_KQueue, Event_Backend_KQueue_allocate);
201
341
  rb_define_method(Event_Backend_KQueue, "initialize", Event_Backend_KQueue_initialize, 1);
342
+ rb_define_method(Event_Backend_KQueue, "close", Event_Backend_KQueue_close, 0);
202
343
 
203
344
  rb_define_method(Event_Backend_KQueue, "io_wait", Event_Backend_KQueue_io_wait, 3);
204
345
  rb_define_method(Event_Backend_KQueue, "select", Event_Backend_KQueue_select, 1);
@@ -28,8 +28,8 @@
28
28
  static VALUE Event_Backend_URing = Qnil;
29
29
  static ID id_fileno, id_transfer;
30
30
 
31
- static const int URING_ENTRIES = 64;
32
- static const int URING_MAX_EVENTS = 64;
31
+ enum {URING_ENTRIES = 128};
32
+ enum {URING_MAX_EVENTS = 128};
33
33
 
34
34
  struct Event_Backend_URing {
35
35
  VALUE loop;
@@ -42,14 +42,19 @@ void Event_Backend_URing_Type_mark(void *_data)
42
42
  rb_gc_mark(data->loop);
43
43
  }
44
44
 
45
- void Event_Backend_URing_Type_free(void *_data)
46
- {
47
- struct Event_Backend_URing *data = _data;
48
-
45
+ static
46
+ void close_internal(struct Event_Backend_URing *data) {
49
47
  if (data->ring.ring_fd >= 0) {
50
48
  io_uring_queue_exit(&data->ring);
51
49
  data->ring.ring_fd = -1;
52
50
  }
51
+ }
52
+
53
+ void Event_Backend_URing_Type_free(void *_data)
54
+ {
55
+ struct Event_Backend_URing *data = _data;
56
+
57
+ close_internal(data);
53
58
 
54
59
  free(data);
55
60
  }
@@ -97,6 +102,15 @@ VALUE Event_Backend_URing_initialize(VALUE self, VALUE loop) {
97
102
  return self;
98
103
  }
99
104
 
105
+ VALUE Event_Backend_URing_close(VALUE self) {
106
+ struct Event_Backend_URing *data = NULL;
107
+ TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
108
+
109
+ close_internal(data);
110
+
111
+ return Qnil;
112
+ }
113
+
100
114
  static inline
101
115
  short poll_flags_from_events(int events) {
102
116
  short flags = 0;
@@ -122,28 +136,75 @@ int events_from_poll_flags(short flags) {
122
136
  return events;
123
137
  }
124
138
 
139
+ struct io_wait_arguments {
140
+ struct Event_Backend_URing *data;
141
+ VALUE fiber;
142
+ short flags;
143
+ };
144
+
145
+ struct io_uring_sqe * io_get_sqe(struct Event_Backend_URing *data) {
146
+ struct io_uring_sqe *sqe = io_uring_get_sqe(&data->ring);
147
+
148
+ while (sqe == NULL) {
149
+ sqe = io_uring_get_sqe(&data->ring);
150
+ }
151
+
152
+ return sqe;
153
+ }
154
+
155
+ static
156
+ VALUE io_wait_rescue(VALUE _arguments, VALUE exception) {
157
+ struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
158
+ struct Event_Backend_URing *data = arguments->data;
159
+
160
+ struct io_uring_sqe *sqe = io_get_sqe(data);
161
+
162
+ // fprintf(stderr, "poll_remove(%p, %p)\n", sqe, (void*)arguments->fiber);
163
+
164
+ io_uring_prep_poll_remove(sqe, (void*)arguments->fiber);
165
+ io_uring_submit(&data->ring);
166
+
167
+ rb_exc_raise(exception);
168
+ };
169
+
170
+ static
171
+ VALUE io_wait_transfer(VALUE _arguments) {
172
+ struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
173
+ struct Event_Backend_URing *data = arguments->data;
174
+
175
+ VALUE result = rb_funcall(data->loop, id_transfer, 0);
176
+
177
+ // We explicitly filter the resulting events based on the requested events.
178
+ // In some cases, poll will report events we didn't ask for.
179
+ short flags = arguments->flags & NUM2INT(result);
180
+
181
+ return INT2NUM(events_from_poll_flags(flags));
182
+ };
183
+
125
184
  VALUE Event_Backend_URing_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE events) {
126
185
  struct Event_Backend_URing *data = NULL;
127
186
  TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
128
187
 
129
188
  int descriptor = NUM2INT(rb_funcall(io, id_fileno, 0));
130
- struct io_uring_sqe *sqe = io_uring_get_sqe(&data->ring);
189
+ struct io_uring_sqe *sqe = io_get_sqe(data);
190
+
191
+ if (!sqe) return INT2NUM(0);
131
192
 
132
193
  short flags = poll_flags_from_events(NUM2INT(events));
133
194
 
134
- // fprintf(stderr, "poll_add(%p, %d, %d)\n", sqe, descriptor, flags);
195
+ // fprintf(stderr, "poll_add(%p, %d, %d, %p)\n", sqe, descriptor, flags, (void*)fiber);
135
196
 
136
197
  io_uring_prep_poll_add(sqe, descriptor, flags);
137
198
  io_uring_sqe_set_data(sqe, (void*)fiber);
138
199
  io_uring_submit(&data->ring);
139
200
 
140
- VALUE result = rb_funcall(data->loop, id_transfer, 0);
141
-
142
- // We explicitly filter the resulting events based on the requested events.
143
- // In some cases, poll will report events we didn't ask for.
144
- flags &= NUM2INT(result);
201
+ struct io_wait_arguments io_wait_arguments = {
202
+ .data = data,
203
+ .fiber = fiber,
204
+ .flags = flags
205
+ };
145
206
 
146
- return INT2NUM(events_from_poll_flags(flags));
207
+ return rb_rescue(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_rescue, (VALUE)&io_wait_arguments);
147
208
  }
148
209
 
149
210
  inline static
@@ -176,7 +237,7 @@ VALUE Event_Backend_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffe
176
237
  resize_to_capacity(buffer, NUM2SIZET(offset), NUM2SIZET(length));
177
238
 
178
239
  int descriptor = NUM2INT(rb_funcall(io, id_fileno, 0));
179
- struct io_uring_sqe *sqe = io_uring_get_sqe(&data->ring);
240
+ struct io_uring_sqe *sqe = io_get_sqe(data);
180
241
 
181
242
  struct iovec iovecs[1];
182
243
  iovecs[0].iov_base = RSTRING_PTR(buffer) + NUM2SIZET(offset);
@@ -208,7 +269,7 @@ VALUE Event_Backend_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buff
208
269
  }
209
270
 
210
271
  int descriptor = NUM2INT(rb_funcall(io, id_fileno, 0));
211
- struct io_uring_sqe *sqe = io_uring_get_sqe(&data->ring);
272
+ struct io_uring_sqe *sqe = io_get_sqe(data);
212
273
 
213
274
  struct iovec iovecs[1];
214
275
  iovecs[0].iov_base = RSTRING_PTR(buffer) + NUM2SIZET(offset);
@@ -244,7 +305,7 @@ struct __kernel_timespec * make_timeout(VALUE duration, struct __kernel_timespec
244
305
 
245
306
  else if (RB_FLOAT_TYPE_P(duration)) {
246
307
  double value = RFLOAT_VALUE(duration);
247
- time_t seconds = duration;
308
+ time_t seconds = value;
248
309
 
249
310
  storage->tv_sec = seconds;
250
311
  storage->tv_nsec = (value - seconds) * 1000000000L;
@@ -255,36 +316,84 @@ struct __kernel_timespec * make_timeout(VALUE duration, struct __kernel_timespec
255
316
  rb_raise(rb_eRuntimeError, "unable to convert timeout");
256
317
  }
257
318
 
319
+ static
320
+ int timeout_nonblocking(struct __kernel_timespec *timespec) {
321
+ return timespec && timespec->tv_sec == 0 && timespec->tv_nsec == 0;
322
+ }
323
+
324
+ struct select_arguments {
325
+ struct Event_Backend_URing *data;
326
+
327
+ int count;
328
+ struct io_uring_cqe **cqes;
329
+
330
+ struct __kernel_timespec storage;
331
+ struct __kernel_timespec *timeout;
332
+ };
333
+
334
+ static
335
+ void * select_internal(void *_arguments) {
336
+ struct select_arguments * arguments = (struct select_arguments *)_arguments;
337
+
338
+ arguments->count = io_uring_wait_cqes(&arguments->data->ring, arguments->cqes, 1, arguments->timeout, NULL);
339
+
340
+ // If waiting resulted in a timeout, there are 0 events.
341
+ if (arguments->count == -ETIME) {
342
+ arguments->count = 0;
343
+ }
344
+
345
+ return NULL;
346
+ }
347
+
348
+ static
349
+ int select_internal_without_gvl(struct select_arguments *arguments) {
350
+ rb_thread_call_without_gvl(select_internal, (void *)arguments, RUBY_UBF_IO, 0);
351
+
352
+ if (arguments->count < 0) {
353
+ rb_syserr_fail(-arguments->count, "select_internal_without_gvl:io_uring_wait_cqes");
354
+ }
355
+
356
+ return arguments->count;
357
+ }
358
+
258
359
  VALUE Event_Backend_URing_select(VALUE self, VALUE duration) {
259
360
  struct Event_Backend_URing *data = NULL;
260
361
  TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
261
362
 
262
363
  struct io_uring_cqe *cqes[URING_MAX_EVENTS];
263
- struct __kernel_timespec storage;
264
364
 
365
+ // This is a non-blocking operation:
265
366
  int result = io_uring_peek_batch_cqe(&data->ring, cqes, URING_MAX_EVENTS);
266
367
 
267
- // fprintf(stderr, "result = %d\n", result);
268
-
269
368
  if (result < 0) {
270
369
  rb_syserr_fail(-result, strerror(-result));
271
- } else if (result == 0 && duration != Qnil) {
272
- result = io_uring_wait_cqes(&data->ring, cqes, 1, make_timeout(duration, &storage), NULL);
370
+ } else if (result == 0) {
371
+ // We might need to wait for events:
372
+ struct select_arguments arguments = {
373
+ .data = data,
374
+ .cqes = cqes,
375
+ .timeout = NULL,
376
+ };
273
377
 
274
- // fprintf(stderr, "result (timeout) = %d\n", result);
378
+ arguments.timeout = make_timeout(duration, &arguments.storage);
275
379
 
276
- if (result == -ETIME) {
277
- result = 0;
278
- } else if (result < 0) {
279
- rb_syserr_fail(-result, strerror(-result));
380
+ if (!timeout_nonblocking(arguments.timeout)) {
381
+ result = select_internal_without_gvl(&arguments);
280
382
  }
281
383
  }
282
384
 
385
+ // fprintf(stderr, "cqes count=%d\n", result);
386
+
283
387
  for (int i = 0; i < result; i += 1) {
388
+ // If the operation was cancelled, or the operation has no user data (fiber):
389
+ if (cqes[i]->res == -ECANCELED || cqes[i]->user_data == 0) {
390
+ continue;
391
+ }
392
+
284
393
  VALUE fiber = (VALUE)io_uring_cqe_get_data(cqes[i]);
285
394
  VALUE result = INT2NUM(cqes[i]->res);
286
395
 
287
- // fprintf(stderr, "cqes[i]->res = %d\n", cqes[i]->res);
396
+ // fprintf(stderr, "cqes[i] res=%d user_data=%p\n", cqes[i]->res, (void*)cqes[i]->user_data);
288
397
 
289
398
  io_uring_cqe_seen(&data->ring, cqes[i]);
290
399
 
@@ -302,6 +411,7 @@ void Init_Event_Backend_URing(VALUE Event_Backend) {
302
411
 
303
412
  rb_define_alloc_func(Event_Backend_URing, Event_Backend_URing_allocate);
304
413
  rb_define_method(Event_Backend_URing, "initialize", Event_Backend_URing_initialize, 1);
414
+ rb_define_method(Event_Backend_URing, "close", Event_Backend_URing_close, 0);
305
415
 
306
416
  rb_define_method(Event_Backend_URing, "io_wait", Event_Backend_URing_io_wait, 3);
307
417
  rb_define_method(Event_Backend_URing, "select", Event_Backend_URing_select, 1);
@@ -25,3 +25,4 @@
25
25
  #define EVENT_BACKEND_URING
26
26
 
27
27
  void Init_Event_Backend_URing(VALUE Event_Backend);
28
+ VALUE Event_Backend_URing_select(VALUE self, VALUE duration);
data/ext/event/extconf.rb CHANGED
@@ -28,6 +28,8 @@ extension_name = 'event'
28
28
  # The destination
29
29
  dir_config(extension_name)
30
30
 
31
+ $CFLAGS << " -Wall"
32
+
31
33
  $srcs = ["event.c"]
32
34
  $VPATH << "$(srcdir)/backend"
33
35
 
data/lib/event.rb CHANGED
@@ -19,7 +19,7 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require_relative 'event/version'
22
- require_relative 'event/backend/select'
22
+ require_relative 'event/backend'
23
23
 
24
24
  module Event
25
25
  # These constants are the same as those defined in IO.
@@ -0,0 +1,49 @@
1
+ # Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'backend/select'
22
+
23
+ module Event
24
+ module Backend
25
+ def self.default(env = ENV)
26
+ if backend = env['EVENT_BACKEND']&.to_sym
27
+ if Event::Backend.const_defined?(backend)
28
+ return Event::Backend.const_get(backend)
29
+ else
30
+ warn "Could not find EVENT_BACKEND=#{backend}!"
31
+ end
32
+ end
33
+
34
+ if self.const_defined?(:URing)
35
+ return Event::Backend::URing
36
+ elsif self.const_defined?(:KQueue)
37
+ return Event::Backend::KQueue
38
+ elsif self.const_defined?(:EPoll)
39
+ return Event::Backend::EPoll
40
+ else
41
+ return Event::Backend::Select
42
+ end
43
+ end
44
+
45
+ def self.new(...)
46
+ default.new(...)
47
+ end
48
+ end
49
+ end
@@ -28,16 +28,29 @@ module Event
28
28
  @writable = {}
29
29
  end
30
30
 
31
+ def close
32
+ @loop = nil
33
+ @readable = nil
34
+ @writable = nil
35
+ end
36
+
31
37
  def io_wait(fiber, io, events)
38
+ remove_readable = remove_writable = false
39
+
32
40
  if (events & READABLE) > 0 or (events & PRIORITY) > 0
33
41
  @readable[io] = fiber
42
+ remove_readable = true
34
43
  end
35
44
 
36
45
  if (events & WRITABLE) > 0
37
46
  @writable[io] = fiber
47
+ remove_writable = true
38
48
  end
39
49
 
40
50
  @loop.transfer
51
+ ensure
52
+ @readable.delete(io) if remove_readable
53
+ @writable.delete(io) if remove_writable
41
54
  end
42
55
 
43
56
  def select(duration = nil)
@@ -31,6 +31,15 @@ module Event
31
31
  @priority = {}
32
32
  end
33
33
 
34
+ def close
35
+ if @selector.nil?
36
+ raise "Selector already closed!"
37
+ end
38
+
39
+ @selector.close
40
+ @selector = nil
41
+ end
42
+
34
43
  def io_wait(fiber, io, events)
35
44
  register_readable(fiber, io, events)
36
45
  end
data/lib/event/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Event
2
- VERSION = "0.2.2"
2
+ VERSION = "0.4.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: event
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-28 00:00:00.000000000 Z
11
+ date: 2021-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bake
@@ -73,7 +73,6 @@ extensions:
73
73
  - ext/event/extconf.rb
74
74
  extra_rdoc_files: []
75
75
  files:
76
- - ext/event/Makefile
77
76
  - ext/event/backend/backend.h
78
77
  - ext/event/backend/epoll.c
79
78
  - ext/event/backend/epoll.h
@@ -85,6 +84,7 @@ files:
85
84
  - ext/event/event.h
86
85
  - ext/event/extconf.rb
87
86
  - lib/event.rb
87
+ - lib/event/backend.rb
88
88
  - lib/event/backend/select.rb
89
89
  - lib/event/debug/selector.rb
90
90
  - lib/event/selector.rb
@@ -108,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
108
  - !ruby/object:Gem::Version
109
109
  version: '0'
110
110
  requirements: []
111
- rubygems_version: 3.2.3
111
+ rubygems_version: 3.1.2
112
112
  signing_key:
113
113
  specification_version: 4
114
114
  summary: An event loop.
data/ext/event/Makefile DELETED
@@ -1,266 +0,0 @@
1
-
2
- SHELL = /bin/sh
3
-
4
- # V=0 quiet, V=1 verbose. other values don't work.
5
- V = 0
6
- Q1 = $(V:1=)
7
- Q = $(Q1:0=@)
8
- ECHO1 = $(V:1=@ :)
9
- ECHO = $(ECHO1:0=@ echo)
10
- NULLCMD = :
11
-
12
- #### Start of system configuration section. ####
13
-
14
- srcdir = .
15
- topdir = /home/samuel/.rubies/ruby-3.0.0/include/ruby-3.0.0
16
- hdrdir = $(topdir)
17
- arch_hdrdir = /home/samuel/.rubies/ruby-3.0.0/include/ruby-3.0.0/x86_64-linux
18
- PATH_SEPARATOR = :
19
- VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby:$(srcdir)/backend
20
- prefix = $(DESTDIR)/home/samuel/.rubies/ruby-3.0.0
21
- rubysitearchprefix = $(rubylibprefix)/$(sitearch)
22
- rubyarchprefix = $(rubylibprefix)/$(arch)
23
- rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
24
- exec_prefix = $(prefix)
25
- vendorarchhdrdir = $(vendorhdrdir)/$(sitearch)
26
- sitearchhdrdir = $(sitehdrdir)/$(sitearch)
27
- rubyarchhdrdir = $(rubyhdrdir)/$(arch)
28
- vendorhdrdir = $(rubyhdrdir)/vendor_ruby
29
- sitehdrdir = $(rubyhdrdir)/site_ruby
30
- rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME)
31
- vendorarchdir = $(vendorlibdir)/$(sitearch)
32
- vendorlibdir = $(vendordir)/$(ruby_version)
33
- vendordir = $(rubylibprefix)/vendor_ruby
34
- sitearchdir = $(sitelibdir)/$(sitearch)
35
- sitelibdir = $(sitedir)/$(ruby_version)
36
- sitedir = $(rubylibprefix)/site_ruby
37
- rubyarchdir = $(rubylibdir)/$(arch)
38
- rubylibdir = $(rubylibprefix)/$(ruby_version)
39
- sitearchincludedir = $(includedir)/$(sitearch)
40
- archincludedir = $(includedir)/$(arch)
41
- sitearchlibdir = $(libdir)/$(sitearch)
42
- archlibdir = $(libdir)/$(arch)
43
- ridir = $(datarootdir)/$(RI_BASE_NAME)
44
- mandir = $(datarootdir)/man
45
- localedir = $(datarootdir)/locale
46
- libdir = $(exec_prefix)/lib
47
- psdir = $(docdir)
48
- pdfdir = $(docdir)
49
- dvidir = $(docdir)
50
- htmldir = $(docdir)
51
- infodir = $(datarootdir)/info
52
- docdir = $(datarootdir)/doc/$(PACKAGE)
53
- oldincludedir = $(DESTDIR)/usr/include
54
- includedir = $(prefix)/include
55
- runstatedir = $(localstatedir)/run
56
- localstatedir = $(prefix)/var
57
- sharedstatedir = $(prefix)/com
58
- sysconfdir = $(prefix)/etc
59
- datadir = $(datarootdir)
60
- datarootdir = $(prefix)/share
61
- libexecdir = $(exec_prefix)/libexec
62
- sbindir = $(exec_prefix)/sbin
63
- bindir = $(exec_prefix)/bin
64
- archdir = $(rubyarchdir)
65
-
66
-
67
- CC_WRAPPER =
68
- CC = gcc
69
- CXX = g++
70
- LIBRUBY = $(LIBRUBY_A)
71
- LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
72
- LIBRUBYARG_SHARED = -Wl,-rpath,$(libdir) -L$(libdir)
73
- LIBRUBYARG_STATIC = -Wl,-rpath,$(libdir) -L$(libdir) -l$(RUBY_SO_NAME)-static $(MAINLIBS)
74
- empty =
75
- OUTFLAG = -o $(empty)
76
- COUTFLAG = -o $(empty)
77
- CSRCFLAG = $(empty)
78
-
79
- RUBY_EXTCONF_H = extconf.h
80
- cflags = $(optflags) $(debugflags) $(warnflags)
81
- cxxflags =
82
- optflags = -O3
83
- debugflags = -ggdb3
84
- warnflags = -Wall -Wextra -Wdeprecated-declarations -Wduplicated-cond -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wwrite-strings -Wimplicit-fallthrough=0 -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable
85
- cppflags =
86
- CCDLFLAGS = -fPIC
87
- CFLAGS = $(CCDLFLAGS) $(cflags) $(ARCH_FLAG)
88
- INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
89
- DEFS =
90
- CPPFLAGS = -DRUBY_EXTCONF_H=\"$(RUBY_EXTCONF_H)\" $(DEFS) $(cppflags)
91
- CXXFLAGS = $(CCDLFLAGS) $(ARCH_FLAG)
92
- ldflags = -L. -fstack-protector-strong -rdynamic -Wl,-export-dynamic
93
- dldflags = -Wl,--compress-debug-sections=zlib
94
- ARCH_FLAG =
95
- DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG)
96
- LDSHARED = $(CC) -shared
97
- LDSHAREDXX = $(CXX) -shared
98
- AR = gcc-ar
99
- EXEEXT =
100
-
101
- RUBY_INSTALL_NAME = $(RUBY_BASE_NAME)
102
- RUBY_SO_NAME = ruby
103
- RUBYW_INSTALL_NAME =
104
- RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version)
105
- RUBYW_BASE_NAME = rubyw
106
- RUBY_BASE_NAME = ruby
107
-
108
- arch = x86_64-linux
109
- sitearch = $(arch)
110
- ruby_version = 3.0.0
111
- ruby = $(bindir)/$(RUBY_BASE_NAME)
112
- RUBY = $(ruby)
113
- ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h $(RUBY_EXTCONF_H)
114
-
115
- RM = rm -f
116
- RM_RF = $(RUBY) -run -e rm -- -rf
117
- RMDIRS = rmdir --ignore-fail-on-non-empty -p
118
- MAKEDIRS = /usr/bin/mkdir -p
119
- INSTALL = /usr/bin/install -c
120
- INSTALL_PROG = $(INSTALL) -m 0755
121
- INSTALL_DATA = $(INSTALL) -m 644
122
- COPY = cp
123
- TOUCH = exit >
124
-
125
- #### End of system configuration section. ####
126
-
127
- preload =
128
- libpath = . $(libdir)
129
- LIBPATH = -L. -L$(libdir) -Wl,-rpath,$(libdir)
130
- DEFFILE =
131
-
132
- CLEANFILES = mkmf.log
133
- DISTCLEANFILES =
134
- DISTCLEANDIRS =
135
-
136
- extout =
137
- extout_prefix =
138
- target_prefix = /event
139
- LOCAL_LIBS =
140
- LIBS = -luring -lm -lc
141
- ORIG_SRCS = event.c
142
- SRCS = $(ORIG_SRCS) event.c uring.c epoll.c
143
- OBJS = event.o uring.o epoll.o
144
- HDRS = $(srcdir)/event.h $(srcdir)/extconf.h
145
- LOCAL_HDRS =
146
- TARGET = event
147
- TARGET_NAME = event
148
- TARGET_ENTRY = Init_$(TARGET_NAME)
149
- DLLIB = $(TARGET).so
150
- EXTSTATIC =
151
- STATIC_LIB =
152
-
153
- TIMESTAMP_DIR = .
154
- BINDIR = $(bindir)
155
- RUBYCOMMONDIR = $(sitedir)$(target_prefix)
156
- RUBYLIBDIR = $(sitelibdir)$(target_prefix)
157
- RUBYARCHDIR = $(sitearchdir)$(target_prefix)
158
- HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
159
- ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
160
- TARGET_SO_DIR =
161
- TARGET_SO = $(TARGET_SO_DIR)$(DLLIB)
162
- CLEANLIBS = $(TARGET_SO)
163
- CLEANOBJS = *.o *.bak
164
-
165
- all: $(DLLIB)
166
- static: $(STATIC_LIB)
167
- .PHONY: all install static install-so install-rb
168
- .PHONY: clean clean-so clean-static clean-rb
169
-
170
- clean-static::
171
- clean-rb-default::
172
- clean-rb::
173
- clean-so::
174
- clean: clean-so clean-static clean-rb-default clean-rb
175
- -$(Q)$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time
176
-
177
- distclean-rb-default::
178
- distclean-rb::
179
- distclean-so::
180
- distclean-static::
181
- distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb
182
- -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
183
- -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
184
- -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true
185
-
186
- realclean: distclean
187
- install: install-so install-rb
188
-
189
- install-so: $(DLLIB) $(TIMESTAMP_DIR)/.sitearchdir.-.event.time
190
- $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
191
- clean-static::
192
- -$(Q)$(RM) $(STATIC_LIB)
193
- install-rb: pre-install-rb do-install-rb install-rb-default
194
- install-rb-default: pre-install-rb-default do-install-rb-default
195
- pre-install-rb: Makefile
196
- pre-install-rb-default: Makefile
197
- do-install-rb:
198
- do-install-rb-default:
199
- pre-install-rb-default:
200
- @$(NULLCMD)
201
- $(TIMESTAMP_DIR)/.sitearchdir.-.event.time:
202
- $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR)
203
- $(Q) $(TOUCH) $@
204
-
205
- site-install: site-install-so site-install-rb
206
- site-install-so: install-so
207
- site-install-rb: install-rb
208
-
209
- .SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S
210
-
211
- .cc.o:
212
- $(ECHO) compiling $(<)
213
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
214
-
215
- .cc.S:
216
- $(ECHO) translating $(<)
217
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
218
-
219
- .mm.o:
220
- $(ECHO) compiling $(<)
221
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
222
-
223
- .mm.S:
224
- $(ECHO) translating $(<)
225
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
226
-
227
- .cxx.o:
228
- $(ECHO) compiling $(<)
229
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
230
-
231
- .cxx.S:
232
- $(ECHO) translating $(<)
233
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
234
-
235
- .cpp.o:
236
- $(ECHO) compiling $(<)
237
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
238
-
239
- .cpp.S:
240
- $(ECHO) translating $(<)
241
- $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
242
-
243
- .c.o:
244
- $(ECHO) compiling $(<)
245
- $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
246
-
247
- .c.S:
248
- $(ECHO) translating $(<)
249
- $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
250
-
251
- .m.o:
252
- $(ECHO) compiling $(<)
253
- $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
254
-
255
- .m.S:
256
- $(ECHO) translating $(<)
257
- $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
258
-
259
- $(TARGET_SO): $(OBJS) Makefile
260
- $(ECHO) linking shared-object event/$(DLLIB)
261
- -$(Q)$(RM) $(@)
262
- $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
263
-
264
-
265
-
266
- $(OBJS): $(HDRS) $(ruby_headers)