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



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

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



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

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_read(fiber, io, buffer, _offset, _length) ⇒ Object



355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
# File 'ext/event/backend/kqueue.c', line 355

VALUE Event_Backend_KQueue_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _offset, VALUE _length) {
  struct Event_Backend_KQueue *data = NULL;
  TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
  
  int descriptor = RB_NUM2INT(rb_funcall(io, id_fileno, 0));
  
  size_t offset = NUM2SIZET(_offset);
  size_t length = NUM2SIZET(_length);
  
  struct io_read_arguments io_read_arguments = {
    .self = self,
    .fiber = fiber,
    .io = io,
    
    .flags = Event_Backend_nonblock_set(descriptor),
    .descriptor = descriptor,
    .buffer = buffer,
    .offset = offset,
    .length = length,
  };
  
  return rb_ensure(io_read_loop, (VALUE)&io_read_arguments, io_read_ensure, (VALUE)&io_read_arguments);
}

#io_wait(fiber, io, events) ⇒ Object



289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'ext/event/backend/kqueue.c', line 289

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 = RB_NUM2INT(rb_funcall(io, id_fileno, 0));
  
  struct io_wait_arguments io_wait_arguments = {
    .events = io_add_filters(data->descriptor, descriptor, RB_NUM2INT(events), fiber),
    .data = data,
    .descriptor = descriptor,
  };
  
  return rb_rescue(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_rescue, (VALUE)&io_wait_arguments);
}

#io_write(fiber, io, buffer, _offset, _length) ⇒ Object



428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
# File 'ext/event/backend/kqueue.c', line 428

VALUE Event_Backend_KQueue_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _offset, VALUE _length) {
  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));
  
  size_t offset = NUM2SIZET(_offset);
  size_t length = NUM2SIZET(_length);
  
  struct io_write_arguments io_write_arguments = {
    .self = self,
    .fiber = fiber,
    .io = io,
    
    .flags = Event_Backend_nonblock_set(descriptor),
    .descriptor = descriptor,
    .buffer = buffer,
    .offset = offset,
    .length = length,
  };
  
  return rb_ensure(io_write_loop, (VALUE)&io_write_arguments, io_write_ensure, (VALUE)&io_write_arguments);
}

#process_wait(fiber, pid, flags) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'ext/event/backend/kqueue.c', line 177

VALUE Event_Backend_KQueue_process_wait(VALUE self, VALUE fiber, VALUE pid, VALUE flags) {
  struct Event_Backend_KQueue *data = NULL;
  TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
  
  struct process_wait_arguments process_wait_arguments = {
    .data = data,
    .pid = NUM2PIDT(pid),
    .flags = RB_NUM2INT(flags),
  };
  
  int waiting = process_add_filters(data->descriptor, process_wait_arguments.pid, fiber);
  
  if (waiting) {
    return rb_rescue(process_wait_transfer, (VALUE)&process_wait_arguments, process_wait_rescue, (VALUE)&process_wait_arguments);
  } else {
    return Event_Backend_process_status_wait(process_wait_arguments.pid);
  }
}

#select(duration) ⇒ Object



520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
# File 'ext/event/backend/kqueue.c', line 520

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);
    
    Event_Backend_transfer_result(fiber, result);
  }
  
  return INT2NUM(arguments.count);
}