sleepy_penguin 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,13 @@
1
1
  #include "sleepy_penguin.h"
2
2
  #include <sys/epoll.h>
3
3
  #include <pthread.h>
4
+ #include "missing_epoll.h"
4
5
  #ifdef HAVE_RUBY_ST_H
5
6
  # include <ruby/st.h>
6
7
  #else
7
8
  # include <st.h>
8
9
  #endif
9
10
 
10
- #ifndef EPOLL_CLOEXEC
11
- # define EPOLL_CLOEXEC (int)(02000000)
12
- #endif
13
-
14
11
  #define EP_RECREATE (-2)
15
12
 
16
13
  static st_table *active;
@@ -49,33 +46,6 @@ static struct rb_epoll *ep_get(VALUE self)
49
46
  return ep;
50
47
  }
51
48
 
52
- #ifndef HAVE_EPOLL_CREATE1
53
- /*
54
- * fake epoll_create1() since some systems don't have it.
55
- * Don't worry about thread-safety since current Ruby 1.9 won't
56
- * call this without GVL.
57
- */
58
- static int my_epoll_create1(int flags)
59
- {
60
- int fd = epoll_create(1024); /* size ignored since 2.6.8 */
61
-
62
- if (fd < 0 || flags == 0)
63
- return fd;
64
-
65
- if ((flags & EPOLL_CLOEXEC) && (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1))
66
- goto err;
67
- return fd;
68
- err:
69
- {
70
- int saved_errno = errno;
71
- close(fd);
72
- errno = saved_errno;
73
- return -1;
74
- }
75
- }
76
- #define epoll_create1 my_epoll_create1
77
- #endif
78
-
79
49
  static void gcmark(void *ptr)
80
50
  {
81
51
  struct rb_epoll *ep = ptr;
@@ -149,31 +119,19 @@ static void ep_check(struct rb_epoll *ep)
149
119
  }
150
120
 
151
121
  /*
152
- * creates a new Epoll object with an optional +flags+ argument.
153
- * +flags+ may currently be Epoll::CLOEXEC or +0+ (or +nil+)
154
- * Epoll::CLOEXEC will be set by default if +nil+ or no
155
- * argument is passed.
122
+ * call-seq:
123
+ * SleepyPenguin::Epoll.new([flags]) -> Epoll object
124
+ *
125
+ * Creates a new Epoll object with an optional +flags+ argument.
126
+ * +flags+ may currently be +:CLOEXEC+ or +0+ (or +nil+).
156
127
  */
157
128
  static VALUE init(int argc, VALUE *argv, VALUE self)
158
129
  {
159
- int flags;
160
130
  struct rb_epoll *ep = ep_get(self);
161
131
  VALUE fl;
162
132
 
163
133
  rb_scan_args(argc, argv, "01", &fl);
164
- if (NIL_P(fl)) {
165
- flags = 0;
166
- } else {
167
- switch (TYPE(fl)) {
168
- case T_FIXNUM:
169
- case T_BIGNUM:
170
- flags = NUM2INT(fl);
171
- break;
172
- default:
173
- rb_raise(rb_eArgError, "flags must be an integer");
174
- }
175
- }
176
- ep->flags = flags;
134
+ ep->flags = rb_sp_get_flags(self, fl);
177
135
  my_epoll_create(ep);
178
136
 
179
137
  return self;
@@ -183,11 +141,11 @@ static VALUE ctl(VALUE self, VALUE io, VALUE flags, int op)
183
141
  {
184
142
  struct epoll_event event;
185
143
  struct rb_epoll *ep = ep_get(self);
186
- int fd = my_fileno(io);
144
+ int fd = rb_sp_fileno(io);
187
145
  int rv;
188
146
 
189
147
  ep_check(ep);
190
- event.events = NUM2UINT(flags);
148
+ event.events = rb_sp_get_uflags(self, flags);
191
149
  pack_event_data(&event, io);
192
150
 
193
151
  rv = epoll_ctl(ep->fd, op, fd, &event);
@@ -204,6 +162,7 @@ static VALUE ctl(VALUE self, VALUE io, VALUE flags, int op)
204
162
  rb_ary_store(ep->marks, fd, io);
205
163
  /* fall-through */
206
164
  case EPOLL_CTL_MOD:
165
+ flags = UINT2NUM(event.events);
207
166
  rb_ary_store(ep->flag_cache, fd, flags);
208
167
  break;
209
168
  case EPOLL_CTL_DEL:
@@ -215,19 +174,30 @@ static VALUE ctl(VALUE self, VALUE io, VALUE flags, int op)
215
174
  }
216
175
 
217
176
  /*
218
- * used to avoid exceptions when your app is too lazy to check
219
- * what state a descriptor is in
177
+ * call-seq:
178
+ * ep.set(io, flags) -> 0
179
+ *
180
+ * Used to avoid exceptions when your app is too lazy to check
181
+ * what state a descriptor is in, this sets the epoll descriptor
182
+ * to watch an +io+ with the given +flags+
183
+ *
184
+ * +flags+ may be an array of symbols or an unsigned Integer bit mask:
185
+ *
186
+ * - flags = [ :IN, :ET ]
187
+ * - flags = SleepyPenguin::Epoll::IN | SleepyPenguin::Epoll::ET
188
+ *
189
+ * See constants in Epoll for more information.
220
190
  */
221
191
  static VALUE set(VALUE self, VALUE io, VALUE flags)
222
192
  {
223
193
  struct epoll_event event;
224
194
  struct rb_epoll *ep = ep_get(self);
225
- int fd = my_fileno(io);
195
+ int fd = rb_sp_fileno(io);
226
196
  int rv;
227
197
  VALUE cur_io = rb_ary_entry(ep->marks, fd);
228
198
 
229
199
  ep_check(ep);
230
- event.events = NUM2UINT(flags);
200
+ event.events = rb_sp_get_uflags(self, flags);
231
201
  pack_event_data(&event, io);
232
202
 
233
203
  if (cur_io == io) {
@@ -261,30 +231,34 @@ fallback_add:
261
231
  }
262
232
  rb_ary_store(ep->marks, fd, io);
263
233
  }
234
+ flags = UINT2NUM(event.events);
264
235
  rb_ary_store(ep->flag_cache, fd, flags);
265
236
 
266
237
  return INT2NUM(rv);
267
238
  }
268
239
 
269
240
  /*
270
- * Deletes an +io+ from an epoll set, but returns nil
271
- * on ENOENT instead of raising an error. This is useful
272
- * for apps that do not care to track the status of an
241
+ * call-seq:
242
+ * epoll.delete(io) -> io or nil
243
+ *
244
+ * Stops an +io+ object from being monitored. This is like Epoll#del
245
+ * but returns +nil+ on ENOENT instead of raising an error. This is
246
+ * useful for apps that do not care to track the status of an
273
247
  * epoll object itself.
274
248
  */
275
249
  static VALUE delete(VALUE self, VALUE io)
276
250
  {
277
251
  struct rb_epoll *ep = ep_get(self);
278
- int fd = my_fileno(io);
252
+ int fd = rb_sp_fileno(io);
279
253
  int rv;
280
254
  VALUE cur_io;
281
255
 
282
256
  ep_check(ep);
283
- if (my_io_closed(io))
257
+ if (rb_sp_io_closed(io))
284
258
  goto out;
285
259
 
286
260
  cur_io = rb_ary_entry(ep->marks, fd);
287
- if (NIL_P(cur_io) || my_io_closed(cur_io))
261
+ if (NIL_P(cur_io) || rb_sp_io_closed(cur_io))
288
262
  return Qnil;
289
263
 
290
264
  rv = epoll_ctl(ep->fd, EPOLL_CTL_DEL, fd, NULL);
@@ -340,7 +314,7 @@ static VALUE nogvl_wait(void *args)
340
314
 
341
315
  static VALUE real_epwait(struct rb_epoll *ep)
342
316
  {
343
- int n = (int)rb_thread_blocking_region(nogvl_wait, ep, RUBY_UBF_IO, 0);
317
+ int n = (int)rb_sp_io_region(nogvl_wait, ep);
344
318
 
345
319
  return epwait_result(ep, n);
346
320
  }
@@ -438,11 +412,14 @@ static VALUE real_epwait(struct rb_epoll *ep)
438
412
  #endif /* 1.8 Green thread compatibility code */
439
413
 
440
414
  /*
441
- * Calls epoll_wait(2) and yields
415
+ * call-seq:
416
+ * epoll.wait([maxevents[, timeout]]) { |flags, io| ... }
442
417
  *
443
- * :call-seq:
444
- *
445
- * epoll.wait(64, 1000) { |flags, obj| ... }
418
+ * Calls epoll_wait(2) and yields Integer +flags+ and IO objects watched
419
+ * for. +maxevents+ is the maximum number of events to process at once,
420
+ * lower numbers may prevent starvation when used by dup-ed Epoll objects
421
+ * in multiple threads. +timeout+ is specified in milliseconds, +nil+
422
+ * (the default) meaning it will block and wait indefinitely.
446
423
  */
447
424
  static VALUE epwait(int argc, VALUE *argv, VALUE self)
448
425
  {
@@ -464,23 +441,51 @@ static VALUE epwait(int argc, VALUE *argv, VALUE self)
464
441
  return real_epwait(ep);
465
442
  }
466
443
 
467
- /* adds +io+ object the +self+ with +flags+ */
444
+ /*
445
+ * call-seq:
446
+ * epoll.add(io, flags) -> 0
447
+ *
448
+ * Starts watching a given +io+ object with +flags+ which may be an Integer
449
+ * bitmask or Array representing arrays to watch for. Consider Epoll#set
450
+ * instead as it is easier to use.
451
+ */
468
452
  static VALUE add(VALUE self, VALUE io, VALUE flags)
469
453
  {
470
454
  return ctl(self, io, flags, EPOLL_CTL_ADD);
471
455
  }
472
456
 
473
- /* adds +io+ object the +self+ with +flags+ */
457
+ /*
458
+ * call-seq:
459
+ * epoll.del(io) -> 0
460
+ *
461
+ * Disables an IO object from being watched. Consider Epoll#delete as
462
+ * it is easier to use.
463
+ */
474
464
  static VALUE del(VALUE self, VALUE io)
475
465
  {
476
- return ctl(self, io, INT2NUM(0), EPOLL_CTL_DEL);
466
+ return ctl(self, io, INT2FIX(0), EPOLL_CTL_DEL);
477
467
  }
478
468
 
469
+ /*
470
+ * call-seq:
471
+ * epoll.mod(io, flags) -> 0
472
+ *
473
+ * Changes the watch for an existing IO object based on +flags+.
474
+ * Consider Epoll#set instead as it is easier to use.
475
+ */
479
476
  static VALUE mod(VALUE self, VALUE io, VALUE flags)
480
477
  {
481
478
  return ctl(self, io, flags, EPOLL_CTL_MOD);
482
479
  }
483
480
 
481
+ /*
482
+ * call-seq:
483
+ * epoll.to_io -> Epoll::IO object
484
+ *
485
+ * Used to expose the given Epoll object as an Epoll::IO object for IO.select
486
+ * or IO#stat. This is unlikely to be useful directly, but is used internally
487
+ * by IO.select.
488
+ */
484
489
  static VALUE to_io(VALUE self)
485
490
  {
486
491
  struct rb_epoll *ep = ep_get(self);
@@ -493,6 +498,13 @@ static VALUE to_io(VALUE self)
493
498
  return ep->io;
494
499
  }
495
500
 
501
+ /*
502
+ * call-seq:
503
+ * epoll.close -> nil
504
+ *
505
+ * Closes an existing Epoll object and returns memory back to the kernel.
506
+ * Raises IOError if object is already closed.
507
+ */
496
508
  static VALUE epclose(VALUE self)
497
509
  {
498
510
  struct rb_epoll *ep = ep_get(self);
@@ -522,6 +534,12 @@ static VALUE epclose(VALUE self)
522
534
  return Qnil;
523
535
  }
524
536
 
537
+ /*
538
+ * call-seq:
539
+ * epoll.closed? -> true or false
540
+ *
541
+ * Returns whether or not an Epoll object is closed.
542
+ */
525
543
  static VALUE epclosed(VALUE self)
526
544
  {
527
545
  struct rb_epoll *ep = ep_get(self);
@@ -534,7 +552,7 @@ static int cloexec_dup(struct rb_epoll *ep)
534
552
  #ifdef F_DUPFD_CLOEXEC
535
553
  int flags = ep->flags & EPOLL_CLOEXEC ? F_DUPFD_CLOEXEC : F_DUPFD;
536
554
  int fd = fcntl(ep->fd, flags, 0);
537
- #else
555
+ #else /* potentially racy on GVL-free systems: */
538
556
  int fd = dup(ep->fd);
539
557
  if (fd >= 0)
540
558
  (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
@@ -542,6 +560,15 @@ static int cloexec_dup(struct rb_epoll *ep)
542
560
  return fd;
543
561
  }
544
562
 
563
+ /*
564
+ * call-seq:
565
+ * epoll.dup -> another Epoll object
566
+ *
567
+ * Duplicates an Epoll object and userspace buffers related to this library.
568
+ * This allows the same epoll object in the Linux kernel to be safely used
569
+ * across multiple native threads as long as there is one SleepyPenguin::Epoll
570
+ * object per-thread.
571
+ */
545
572
  static VALUE init_copy(VALUE copy, VALUE orig)
546
573
  {
547
574
  struct rb_epoll *a = ep_get(orig);
@@ -572,30 +599,37 @@ static VALUE init_copy(VALUE copy, VALUE orig)
572
599
  return copy;
573
600
  }
574
601
 
602
+ /*
603
+ * call-seq:
604
+ * epoll.io_for(io) -> object
605
+ *
606
+ * Returns the given IO object currently being watched for. Different
607
+ * IO objects may internally refer to the same process file descriptor.
608
+ * Mostly used for debugging.
609
+ */
575
610
  static VALUE io_for(VALUE self, VALUE obj)
576
611
  {
577
612
  struct rb_epoll *ep = ep_get(self);
578
613
 
579
- return rb_ary_entry(ep->marks, my_fileno(obj));
614
+ return rb_ary_entry(ep->marks, rb_sp_fileno(obj));
580
615
  }
581
616
 
582
617
  /*
583
- * :call-seq:
584
- *
585
- * epoll.flags_for(io) => Integer
618
+ * call-seq:
619
+ * epoll.flags_for(io) -> Integer
586
620
  *
587
621
  * Returns the flags currently watched for in current Epoll object.
622
+ * Mostly used for debugging.
588
623
  */
589
624
  static VALUE flags_for(VALUE self, VALUE obj)
590
625
  {
591
626
  struct rb_epoll *ep = ep_get(self);
592
627
 
593
- return rb_ary_entry(ep->flag_cache, my_fileno(obj));
628
+ return rb_ary_entry(ep->flag_cache, rb_sp_fileno(obj));
594
629
  }
595
630
 
596
631
  /*
597
- * :call-seq:
598
- *
632
+ * call-seq:
599
633
  * epoll.include?(io) => true or false
600
634
  *
601
635
  * Returns whether or not a given IO is watched and prevented from being
@@ -606,7 +640,7 @@ static VALUE include_p(VALUE self, VALUE obj)
606
640
  {
607
641
  struct rb_epoll *ep = ep_get(self);
608
642
 
609
- return NIL_P(rb_ary_entry(ep->marks, my_fileno(obj))) ? Qfalse : Qtrue;
643
+ return NIL_P(rb_ary_entry(ep->marks, rb_sp_fileno(obj))) ? Qfalse : Qtrue;
610
644
  }
611
645
 
612
646
  /*
@@ -641,8 +675,47 @@ void sleepy_penguin_init_epoll(void)
641
675
  {
642
676
  VALUE mSleepyPenguin, cEpoll;
643
677
 
678
+ /*
679
+ * Document-module: SleepyPenguin
680
+ *
681
+ * require "sleepy_penguin"
682
+ * include SleepyPenguin
683
+ *
684
+ * The SleepyPenguin namespace includes the Epoll, Inotify, SignalFD,
685
+ * TimerFD, EventFD classes in its top level and no other constants.
686
+ *
687
+ * If you are uncomfortable including SleepyPenguin, you may also
688
+ * use the "SP" alias if it doesn't conflict with existing code:
689
+ *
690
+ * require "sleepy_penguin/sp"
691
+ *
692
+ * And then access classes via:
693
+ *
694
+ * - SP::Epoll
695
+ * - SP::EventFD
696
+ * - SP::Inotify
697
+ * - SP::SignalFD
698
+ * - SP::TimerFD
699
+ */
644
700
  mSleepyPenguin = rb_define_module("SleepyPenguin");
701
+
702
+ /*
703
+ * Document-class: SleepyPenguin::Epoll
704
+ *
705
+ * The Epoll class provides access to epoll(7) functionality in the
706
+ * Linux 2.6 kernel. It provides fork and GC-safety for Ruby
707
+ * objects stored within the IO object and may be passed as an
708
+ * argument to IO.select.
709
+ */
645
710
  cEpoll = rb_define_class_under(mSleepyPenguin, "Epoll", rb_cObject);
711
+
712
+ /*
713
+ * Document-class: SleepyPenguin::Epoll::IO
714
+ *
715
+ * Epoll::IO is an internal class. Its only purpose is to be
716
+ * compatible with IO.select and related methods and should not
717
+ * be used directly, use Epoll instead.
718
+ */
646
719
  cEpoll_IO = rb_define_class_under(cEpoll, "IO", rb_cIO);
647
720
  rb_define_method(cEpoll, "initialize", init, -1);
648
721
  rb_define_method(cEpoll, "initialize_copy", init_copy, 1);
@@ -660,39 +733,43 @@ void sleepy_penguin_init_epoll(void)
660
733
  rb_define_method(cEpoll, "set", set, 2);
661
734
  rb_define_method(cEpoll, "wait", epwait, -1);
662
735
 
663
- /* specifies wheter close-on-exec flag is set for Epoll.new */
736
+ /* specifies whether close-on-exec flag is set for Epoll.new */
664
737
  rb_define_const(cEpoll, "CLOEXEC", INT2NUM(EPOLL_CLOEXEC));
665
738
 
666
739
  /* watch for read/recv operations */
667
- rb_define_const(cEpoll, "IN", INT2NUM(EPOLLIN));
740
+ rb_define_const(cEpoll, "IN", UINT2NUM(EPOLLIN));
668
741
 
669
742
  /* watch for write/send operations */
670
- rb_define_const(cEpoll, "OUT", INT2NUM(EPOLLOUT));
743
+ rb_define_const(cEpoll, "OUT", UINT2NUM(EPOLLOUT));
671
744
 
672
745
  #ifdef EPOLLRDHUP
673
- /* watch a specified IO for shutdown(SHUT_WR) on the remote-end */
674
- rb_define_const(cEpoll, "RDHUP", INT2NUM(EPOLLRDHUP));
746
+ /*
747
+ * Watch a specified io for shutdown(SHUT_WR) on the remote-end.
748
+ * Available since Linux 2.6.17.
749
+ */
750
+ rb_define_const(cEpoll, "RDHUP", UINT2NUM(EPOLLRDHUP));
675
751
  #endif
752
+
676
753
  /* watch for urgent read(2) data */
677
- rb_define_const(cEpoll, "PRI", INT2NUM(EPOLLPRI));
754
+ rb_define_const(cEpoll, "PRI", UINT2NUM(EPOLLPRI));
678
755
 
679
756
  /*
680
757
  * watch for errors, there is no need to specify this,
681
758
  * it is always monitored when an IO is watched
682
759
  */
683
- rb_define_const(cEpoll, "ERR", INT2NUM(EPOLLERR));
760
+ rb_define_const(cEpoll, "ERR", UINT2NUM(EPOLLERR));
684
761
 
685
762
  /*
686
763
  * watch for hangups, there is no need to specify this,
687
764
  * it is always monitored when an IO is watched
688
765
  */
689
- rb_define_const(cEpoll, "HUP", INT2NUM(EPOLLHUP));
766
+ rb_define_const(cEpoll, "HUP", UINT2NUM(EPOLLHUP));
690
767
 
691
768
  /* notifications are only Edge Triggered, see epoll(7) */
692
- rb_define_const(cEpoll, "ET", INT2NUM(EPOLLET));
769
+ rb_define_const(cEpoll, "ET", UINT2NUM((uint32_t)EPOLLET));
693
770
 
694
771
  /* unwatch the descriptor once any event has fired */
695
- rb_define_const(cEpoll, "ONESHOT", INT2NUM(EPOLLONESHOT));
772
+ rb_define_const(cEpoll, "ONESHOT", UINT2NUM(EPOLLONESHOT));
696
773
 
697
774
  id_for_fd = rb_intern("for_fd");
698
775
  active = st_init_numtable();