sleepy_penguin 1.4.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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();