Class: Event::Backend::KQueue

Inherits:
Object
  • Object
show all
Defined in:
ext/event/backend/kqueue.c

Instance Method Summary collapse

Constructor Details

#initialize(loop) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'ext/event/backend/kqueue.c', line 87

VALUE Event_Backend_KQueue_initialize(VALUE self, VALUE loop) {
  struct Event_Backend_KQueue *data = NULL;
  TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
  
  data->loop = loop;
  int result = kqueue();
  
  if (result == -1) {
    rb_sys_fail("kqueue");
  } else {
    ioctl(result, FIOCLEX);
    data->descriptor = result;
    
    rb_update_max_fd(data->descriptor);
  }
  
  return self;
}

Instance Method Details

#closeObject



106
107
108
109
110
111
112
113
# File 'ext/event/backend/kqueue.c', line 106

VALUE Event_Backend_KQueue_close(VALUE self) {
  struct Event_Backend_KQueue *data = NULL;
  TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
  
  close_internal(data);
  
  return Qnil;
}

#io_wait(fiber, io, events) ⇒ Object



208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'ext/event/backend/kqueue.c', line 208

VALUE Event_Backend_KQueue_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE events) {
  struct Event_Backend_KQueue *data = NULL;
  TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
  
  int descriptor = NUM2INT(rb_funcall(io, id_fileno, 0));
  
  struct io_wait_arguments io_wait_arguments = {
    .events = io_add_filters(data->descriptor, descriptor, NUM2INT(events), fiber),
    .data = data,
    .descriptor = descriptor,
  };
  
  return rb_rescue(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_rescue, (VALUE)&io_wait_arguments);
}

#select(duration) ⇒ Object



291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'ext/event/backend/kqueue.c', line 291

VALUE Event_Backend_KQueue_select(VALUE self, VALUE duration) {
  struct Event_Backend_KQueue *data = NULL;
  TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
  
  struct select_arguments arguments = {
    .data = data,
    .count = KQUEUE_MAX_EVENTS,
    .storage = {
      .tv_sec = 0,
      .tv_nsec = 0
    }
  };
  
  // We break this implementation into two parts.
  // (1) count = kevent(..., timeout = 0)
  // (2) without gvl: kevent(..., timeout = 0) if count == 0 and timeout != 0
  // This allows us to avoid releasing and reacquiring the GVL.
  // Non-comprehensive testing shows this gives a 1.5x speedup.
  arguments.timeout = &arguments.storage;
  
  // First do the syscall with no timeout to get any immediately available events:
  select_internal_with_gvl(&arguments);
  
  // If there were no pending events, if we have a timeout, wait for more events:
  if (arguments.count == 0) {
    arguments.timeout = make_timeout(duration, &arguments.storage);
    
    if (!timeout_nonblocking(arguments.timeout)) {
      arguments.count = KQUEUE_MAX_EVENTS;
      
      select_internal_without_gvl(&arguments);
    }
  }
  
  for (int i = 0; i < arguments.count; i += 1) {
    VALUE fiber = (VALUE)arguments.events[i].udata;
    VALUE result = INT2NUM(arguments.events[i].filter);
    rb_funcall(fiber, id_transfer, 1, result);
  }
  
  return INT2NUM(arguments.count);
}