polyphony 0.43.10 → 0.43.11

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: b3000a280d995b187518c1e12f585939b4e67312db5458d105c6e6b40c784d5a
4
- data.tar.gz: 5a582fc77ae044238521619b1d5364a0dd2aac13ca8a6b82d006ec1f23284d2d
3
+ metadata.gz: 5d1eb9e2b1eef7f180107b3952fc6974e9c816268ebd8d2368ddfaac276d2086
4
+ data.tar.gz: dafb382dc7606b92b97fb98125b57abc72e1b1d6b07bb877abff608a41ee51a1
5
5
  SHA512:
6
- metadata.gz: 6d403109b1bbf55e1b0ab799d8c74752677784ca0c12cb5b1e21f62c9bdd244245966db8020b20a8d4ed988263a9535aef5a8aff24b50587c9583a67109d7677
7
- data.tar.gz: 205d6c9859ec8d12ddf7630cbd3893a13d3efb3537dd734e53f17efe31d52399488761da45684d0da7e5074ce950c47a7e51f4a1446577e36f7c3c7838604a7a
6
+ metadata.gz: 9f91b787b3eec2c19f6a02fd8a77469c8ae5d7a9302799c3e2a5957376b9f4b0135d2cd958ec7dcf326701e8ba81d85a28201a140ce5806ccc057cedafe907d5
7
+ data.tar.gz: df865277e2f37c0d7fde0ffd38f52fc466bf28033fb968bd012af7455df9e7805989152467e1e8e84719194f173c99c6290496987ad8a2b48fe26076e62c85bd
@@ -1,3 +1,11 @@
1
+ ## 0.43.11 2020-07-24
2
+
3
+ * Dump uncaught exception info for forked process (#36)
4
+ * Add additional socket config options (#37)
5
+ - :reuse_port (`SO_REUSEPORT`)
6
+ - :backlog (listen backlog, default `SOMAXCONN`)
7
+ * Fix possible race condition in Queue#shift (#34)
8
+
1
9
  ## 0.43.10 2020-07-23
2
10
 
3
11
  * Fix race condition when terminating fibers (#33)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.43.10)
4
+ polyphony (0.43.11)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/TODO.md CHANGED
@@ -1,5 +1,3 @@
1
- -- Add `Fiber#schedule_with_priority` method
2
-
3
1
  - Debugging
4
2
  - Eat your own dogfood: need a good tool to check what's going on when some
5
3
  test fails
@@ -13,25 +13,27 @@
13
13
  // VALUE LibevAgent_post_fork(VALUE self);
14
14
  // VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof);
15
15
  // VALUE LibevAgent_read_loop(VALUE self, VALUE io);
16
- // VALUE LibevAgent_ref(VALUE self);
17
16
  // VALUE LibevAgent_sleep(VALUE self, VALUE duration);
18
- // VALUE LibevAgent_unref(VALUE self);
19
17
  // VALUE LibevAgent_wait_io(VALUE self, VALUE io, VALUE write);
20
18
  // VALUE LibevAgent_wait_pid(VALUE self, VALUE pid);
21
19
  // VALUE LibevAgent_write(int argc, VALUE *argv, VALUE self);
22
20
 
23
21
  typedef VALUE (* agent_pending_count_t)(VALUE self);
24
22
  typedef VALUE (*agent_poll_t)(VALUE self, VALUE nowait, VALUE current_fiber, VALUE queue);
23
+ typedef VALUE (* agent_ref_t)(VALUE self);
25
24
  typedef int (* agent_ref_count_t)(VALUE self);
26
25
  typedef void (* agent_reset_ref_count_t)(VALUE self);
26
+ typedef VALUE (* agent_unref_t)(VALUE self);
27
27
  typedef VALUE (* agent_wait_event_t)(VALUE self, VALUE raise_on_exception);
28
28
  typedef VALUE (* agent_wakeup_t)(VALUE self);
29
29
 
30
30
  typedef struct agent_interface {
31
31
  agent_pending_count_t pending_count;
32
32
  agent_poll_t poll;
33
+ agent_ref_t ref;
33
34
  agent_ref_count_t ref_count;
34
35
  agent_reset_ref_count_t reset_ref_count;
36
+ agent_unref_t unref;
35
37
  agent_wait_event_t wait_event;
36
38
  agent_wakeup_t wakeup;
37
39
  } agent_interface_t;
@@ -11,16 +11,16 @@
11
11
 
12
12
  VALUE cTCPSocket;
13
13
 
14
- struct LibevAgent_t {
14
+ typedef struct LibevAgent_t {
15
15
  struct ev_loop *ev_loop;
16
16
  struct ev_async break_async;
17
17
  int running;
18
18
  int ref_count;
19
19
  int run_no_wait_count;
20
- };
20
+ } LibevAgent_t;
21
21
 
22
22
  static size_t LibevAgent_size(const void *ptr) {
23
- return sizeof(struct LibevAgent_t);
23
+ return sizeof(LibevAgent_t);
24
24
  }
25
25
 
26
26
  static const rb_data_type_t LibevAgent_type = {
@@ -30,13 +30,13 @@ static const rb_data_type_t LibevAgent_type = {
30
30
  };
31
31
 
32
32
  static VALUE LibevAgent_allocate(VALUE klass) {
33
- struct LibevAgent_t *agent = ALLOC(struct LibevAgent_t);
33
+ LibevAgent_t *agent = ALLOC(LibevAgent_t);
34
34
 
35
35
  return TypedData_Wrap_Struct(klass, &LibevAgent_type, agent);
36
36
  }
37
37
 
38
38
  #define GetLibevAgent(obj, agent) \
39
- TypedData_Get_Struct((obj), struct LibevAgent_t, &LibevAgent_type, (agent))
39
+ TypedData_Get_Struct((obj), LibevAgent_t, &LibevAgent_type, (agent))
40
40
 
41
41
  void break_async_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, int revents) {
42
42
  // This callback does nothing, the break async is used solely for breaking out
@@ -44,7 +44,7 @@ void break_async_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, in
44
44
  }
45
45
 
46
46
  static VALUE LibevAgent_initialize(VALUE self) {
47
- struct LibevAgent_t *agent;
47
+ LibevAgent_t *agent;
48
48
  VALUE thread = rb_thread_current();
49
49
  int is_main_thread = (thread == rb_thread_main());
50
50
 
@@ -63,7 +63,7 @@ static VALUE LibevAgent_initialize(VALUE self) {
63
63
  }
64
64
 
65
65
  VALUE LibevAgent_finalize(VALUE self) {
66
- struct LibevAgent_t *agent;
66
+ LibevAgent_t *agent;
67
67
  GetLibevAgent(self, agent);
68
68
 
69
69
  ev_async_stop(agent->ev_loop, &agent->break_async);
@@ -74,7 +74,7 @@ VALUE LibevAgent_finalize(VALUE self) {
74
74
  }
75
75
 
76
76
  VALUE LibevAgent_post_fork(VALUE self) {
77
- struct LibevAgent_t *agent;
77
+ LibevAgent_t *agent;
78
78
  GetLibevAgent(self, agent);
79
79
 
80
80
  if (!ev_is_default_loop(agent->ev_loop)) {
@@ -91,7 +91,7 @@ VALUE LibevAgent_post_fork(VALUE self) {
91
91
  }
92
92
 
93
93
  VALUE LibevAgent_ref(VALUE self) {
94
- struct LibevAgent_t *agent;
94
+ LibevAgent_t *agent;
95
95
  GetLibevAgent(self, agent);
96
96
 
97
97
  agent->ref_count++;
@@ -99,7 +99,7 @@ VALUE LibevAgent_ref(VALUE self) {
99
99
  }
100
100
 
101
101
  VALUE LibevAgent_unref(VALUE self) {
102
- struct LibevAgent_t *agent;
102
+ LibevAgent_t *agent;
103
103
  GetLibevAgent(self, agent);
104
104
 
105
105
  agent->ref_count--;
@@ -107,14 +107,14 @@ VALUE LibevAgent_unref(VALUE self) {
107
107
  }
108
108
 
109
109
  int LibevAgent_ref_count(VALUE self) {
110
- struct LibevAgent_t *agent;
110
+ LibevAgent_t *agent;
111
111
  GetLibevAgent(self, agent);
112
112
 
113
113
  return agent->ref_count;
114
114
  }
115
115
 
116
116
  void LibevAgent_reset_ref_count(VALUE self) {
117
- struct LibevAgent_t *agent;
117
+ LibevAgent_t *agent;
118
118
  GetLibevAgent(self, agent);
119
119
 
120
120
  agent->ref_count = 0;
@@ -122,7 +122,7 @@ void LibevAgent_reset_ref_count(VALUE self) {
122
122
 
123
123
  VALUE LibevAgent_pending_count(VALUE self) {
124
124
  int count;
125
- struct LibevAgent_t *agent;
125
+ LibevAgent_t *agent;
126
126
  GetLibevAgent(self, agent);
127
127
  count = ev_pending_count(agent->ev_loop);
128
128
  return INT2NUM(count);
@@ -130,7 +130,7 @@ VALUE LibevAgent_pending_count(VALUE self) {
130
130
 
131
131
  VALUE LibevAgent_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE queue) {
132
132
  int is_nowait = nowait == Qtrue;
133
- struct LibevAgent_t *agent;
133
+ LibevAgent_t *agent;
134
134
  GetLibevAgent(self, agent);
135
135
 
136
136
  if (is_nowait) {
@@ -152,7 +152,7 @@ VALUE LibevAgent_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE queue
152
152
  }
153
153
 
154
154
  VALUE LibevAgent_wakeup(VALUE self) {
155
- struct LibevAgent_t *agent;
155
+ LibevAgent_t *agent;
156
156
  GetLibevAgent(self, agent);
157
157
 
158
158
  if (agent->running) {
@@ -246,7 +246,7 @@ void LibevAgent_io_callback(EV_P_ ev_io *w, int revents)
246
246
  Fiber_make_runnable(watcher->fiber, Qnil);
247
247
  }
248
248
 
249
- inline VALUE libev_await(struct LibevAgent_t *agent) {
249
+ inline VALUE libev_await(LibevAgent_t *agent) {
250
250
  VALUE ret;
251
251
  agent->ref_count++;
252
252
  ret = Thread_switch_fiber(rb_thread_current());
@@ -256,12 +256,12 @@ inline VALUE libev_await(struct LibevAgent_t *agent) {
256
256
  }
257
257
 
258
258
  VALUE libev_agent_await(VALUE self) {
259
- struct LibevAgent_t *agent;
259
+ LibevAgent_t *agent;
260
260
  GetLibevAgent(self, agent);
261
261
  return libev_await(agent);
262
262
  }
263
263
 
264
- VALUE libev_io_wait(struct LibevAgent_t *agent, struct libev_io *watcher, rb_io_t *fptr, int flags) {
264
+ VALUE libev_io_wait(LibevAgent_t *agent, struct libev_io *watcher, rb_io_t *fptr, int flags) {
265
265
  VALUE switchpoint_result;
266
266
 
267
267
  if (watcher->fiber == Qnil) {
@@ -307,7 +307,7 @@ inline void io_set_nonblock(rb_io_t *fptr, VALUE io) {
307
307
  }
308
308
 
309
309
  VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof) {
310
- struct LibevAgent_t *agent;
310
+ LibevAgent_t *agent;
311
311
  struct libev_io watcher;
312
312
  rb_io_t *fptr;
313
313
  long dynamic_len = length == Qnil;
@@ -396,7 +396,7 @@ VALUE LibevAgent_read_loop(VALUE self, VALUE io) {
396
396
  PREPARE_STR(); \
397
397
  }
398
398
 
399
- struct LibevAgent_t *agent;
399
+ LibevAgent_t *agent;
400
400
  struct libev_io watcher;
401
401
  rb_io_t *fptr;
402
402
  VALUE str;
@@ -460,7 +460,7 @@ error:
460
460
  }
461
461
 
462
462
  VALUE LibevAgent_write(VALUE self, VALUE io, VALUE str) {
463
- struct LibevAgent_t *agent;
463
+ LibevAgent_t *agent;
464
464
  struct libev_io watcher;
465
465
  rb_io_t *fptr;
466
466
  VALUE switchpoint_result = Qnil;
@@ -504,7 +504,7 @@ error:
504
504
  }
505
505
 
506
506
  VALUE LibevAgent_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
507
- struct LibevAgent_t *agent;
507
+ LibevAgent_t *agent;
508
508
  struct libev_io watcher;
509
509
  rb_io_t *fptr;
510
510
  VALUE switchpoint_result = Qnil;
@@ -586,7 +586,7 @@ VALUE LibevAgent_write_m(int argc, VALUE *argv, VALUE self) {
586
586
  ///////////////////////////////////////////////////////////////////////////
587
587
 
588
588
  VALUE LibevAgent_accept(VALUE self, VALUE sock) {
589
- struct LibevAgent_t *agent;
589
+ LibevAgent_t *agent;
590
590
  struct libev_io watcher;
591
591
  rb_io_t *fptr;
592
592
  int fd;
@@ -640,7 +640,7 @@ error:
640
640
  }
641
641
 
642
642
  VALUE LibevAgent_accept_loop(VALUE self, VALUE sock) {
643
- struct LibevAgent_t *agent;
643
+ LibevAgent_t *agent;
644
644
  struct libev_io watcher;
645
645
  rb_io_t *fptr;
646
646
  int fd;
@@ -696,7 +696,7 @@ error:
696
696
  }
697
697
 
698
698
  VALUE LibevAgent_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
699
- struct LibevAgent_t *agent;
699
+ LibevAgent_t *agent;
700
700
  struct libev_io watcher;
701
701
  rb_io_t *fptr;
702
702
  struct sockaddr_in addr;
@@ -731,30 +731,33 @@ error:
731
731
  return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
732
732
  }
733
733
 
734
- VALUE LibevAgent_wait_io(VALUE self, VALUE io, VALUE write) {
735
- struct LibevAgent_t *agent;
734
+ VALUE libev_wait_fd(LibevAgent_t *agent, int fd, int events, int raise_exception) {
736
735
  struct libev_io watcher;
737
- rb_io_t *fptr;
738
736
  VALUE switchpoint_result = Qnil;
739
- int events = RTEST(write) ? EV_WRITE : EV_READ;
740
-
741
- VALUE underlying_io = rb_iv_get(io, "@io");
742
- GetLibevAgent(self, agent);
743
- if (underlying_io != Qnil) io = underlying_io;
744
- GetOpenFile(io, fptr);
745
737
 
746
738
  watcher.fiber = rb_fiber_current();
747
- ev_io_init(&watcher.io, LibevAgent_io_callback, fptr->fd, events);
739
+ ev_io_init(&watcher.io, LibevAgent_io_callback, fd, events);
748
740
  ev_io_start(agent->ev_loop, &watcher.io);
749
741
  switchpoint_result = libev_await(agent);
750
742
  ev_io_stop(agent->ev_loop, &watcher.io);
751
743
 
752
- TEST_RESUME_EXCEPTION(switchpoint_result);
753
- RB_GC_GUARD(watcher.fiber);
744
+ if (raise_exception) TEST_RESUME_EXCEPTION(switchpoint_result);
754
745
  RB_GC_GUARD(switchpoint_result);
755
746
  return switchpoint_result;
756
747
  }
757
748
 
749
+ VALUE LibevAgent_wait_io(VALUE self, VALUE io, VALUE write) {
750
+ LibevAgent_t *agent;
751
+ rb_io_t *fptr;
752
+ int events = RTEST(write) ? EV_WRITE : EV_READ;
753
+ VALUE underlying_io = rb_iv_get(io, "@io");
754
+ if (underlying_io != Qnil) io = underlying_io;
755
+ GetLibevAgent(self, agent);
756
+ GetOpenFile(io, fptr);
757
+
758
+ return libev_wait_fd(agent, fptr->fd, events, 1);
759
+ }
760
+
758
761
  struct libev_timer {
759
762
  struct ev_timer timer;
760
763
  VALUE fiber;
@@ -767,7 +770,7 @@ void LibevAgent_timer_callback(EV_P_ ev_timer *w, int revents)
767
770
  }
768
771
 
769
772
  VALUE LibevAgent_sleep(VALUE self, VALUE duration) {
770
- struct LibevAgent_t *agent;
773
+ LibevAgent_t *agent;
771
774
  struct libev_timer watcher;
772
775
  VALUE switchpoint_result = Qnil;
773
776
 
@@ -802,7 +805,7 @@ void LibevAgent_child_callback(EV_P_ ev_child *w, int revents)
802
805
  }
803
806
 
804
807
  VALUE LibevAgent_waitpid(VALUE self, VALUE pid) {
805
- struct LibevAgent_t *agent;
808
+ LibevAgent_t *agent;
806
809
  struct libev_child watcher;
807
810
  VALUE switchpoint_result = Qnil;
808
811
  GetLibevAgent(self, agent);
@@ -821,7 +824,7 @@ VALUE LibevAgent_waitpid(VALUE self, VALUE pid) {
821
824
  }
822
825
 
823
826
  struct ev_loop *LibevAgent_ev_loop(VALUE self) {
824
- struct LibevAgent_t *agent;
827
+ LibevAgent_t *agent;
825
828
  GetLibevAgent(self, agent);
826
829
  return agent->ev_loop;
827
830
  }
@@ -829,14 +832,14 @@ struct ev_loop *LibevAgent_ev_loop(VALUE self) {
829
832
  void LibevAgent_async_callback(EV_P_ ev_async *w, int revents) { }
830
833
 
831
834
  VALUE LibevAgent_wait_event(VALUE self, VALUE raise) {
832
- struct LibevAgent_t *agent;
833
- struct ev_async async;
835
+ LibevAgent_t *agent;
834
836
  VALUE switchpoint_result = Qnil;
835
837
  GetLibevAgent(self, agent);
836
838
 
839
+ struct ev_async async;
840
+
837
841
  ev_async_init(&async, LibevAgent_async_callback);
838
842
  ev_async_start(agent->ev_loop, &async);
839
-
840
843
  switchpoint_result = libev_await(agent);
841
844
  ev_async_stop(agent->ev_loop, &async);
842
845
 
@@ -876,10 +879,12 @@ void Init_LibevAgent() {
876
879
 
877
880
  ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
878
881
 
879
- __AGENT__.wakeup = LibevAgent_wakeup;
880
882
  __AGENT__.pending_count = LibevAgent_pending_count;
881
883
  __AGENT__.poll = LibevAgent_poll;
884
+ __AGENT__.ref = LibevAgent_ref;
882
885
  __AGENT__.ref_count = LibevAgent_ref_count;
883
886
  __AGENT__.reset_ref_count = LibevAgent_reset_ref_count;
887
+ __AGENT__.unref = LibevAgent_unref;
884
888
  __AGENT__.wait_event = LibevAgent_wait_event;
889
+ __AGENT__.wakeup = LibevAgent_wakeup;
885
890
  }
@@ -8,7 +8,7 @@
8
8
 
9
9
  // debugging
10
10
  #define OBJ_ID(obj) (NUM2LONG(rb_funcall(obj, rb_intern("object_id"), 0)))
11
- #define INSPECT(obj) { VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf("%s\n", StringValueCStr(s));}
11
+ #define INSPECT(str, obj) { printf(str); VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf("%s\n", StringValueCStr(s));}
12
12
  #define FIBER_TRACE(...) if (__tracing_enabled__) { \
13
13
  rb_funcall(rb_cObject, ID_fiber_trace, __VA_ARGS__); \
14
14
  }
@@ -20,11 +20,8 @@
20
20
  }
21
21
 
22
22
  extern agent_interface_t agent_interface;
23
- // #define __AGENT_PASTER__(call) (agent_interface ## . ## call)
24
- // #define __AGENT__(call) __AGENT_PASTER__(call)
25
23
  #define __AGENT__ (agent_interface)
26
24
 
27
-
28
25
  extern VALUE mPolyphony;
29
26
  extern VALUE cQueue;
30
27
  extern VALUE cEvent;
@@ -54,6 +54,7 @@ static VALUE Queue_initialize(VALUE self) {
54
54
  VALUE Queue_push(VALUE self, VALUE value) {
55
55
  Queue_t *queue;
56
56
  GetQueue(self, queue);
57
+
57
58
  if (queue->shift_queue.count > 0) {
58
59
  VALUE fiber = ring_buffer_shift(&queue->shift_queue);
59
60
  if (fiber != Qnil) Fiber_make_runnable(fiber, Qnil);
@@ -77,21 +78,26 @@ VALUE Queue_shift(VALUE self) {
77
78
  Queue_t *queue;
78
79
  GetQueue(self, queue);
79
80
 
80
- if (queue->values.count == 0) {
81
- VALUE agent = rb_ivar_get(rb_thread_current(), ID_ivar_agent);
82
- VALUE fiber = rb_fiber_current();
83
- VALUE switchpoint_result = Qnil;
81
+ VALUE fiber = rb_fiber_current();
82
+ VALUE thread = rb_thread_current();
83
+ VALUE agent = rb_ivar_get(thread, ID_ivar_agent);
84
+
85
+ while (1) {
84
86
  ring_buffer_push(&queue->shift_queue, fiber);
85
- switchpoint_result = __AGENT__.wait_event(agent, Qnil);
86
- if (RTEST(rb_obj_is_kind_of(switchpoint_result, rb_eException))) {
87
- ring_buffer_delete(&queue->shift_queue, fiber);
87
+ if (queue->values.count > 0) Fiber_make_runnable(fiber, Qnil);
88
+
89
+ VALUE switchpoint_result = __AGENT__.wait_event(agent, Qnil);
90
+ ring_buffer_delete(&queue->shift_queue, fiber);
91
+
92
+ if (RTEST(rb_obj_is_kind_of(switchpoint_result, rb_eException)))
88
93
  return rb_funcall(rb_mKernel, ID_raise, 1, switchpoint_result);
89
- }
90
- RB_GC_GUARD(agent);
91
94
  RB_GC_GUARD(switchpoint_result);
95
+
96
+ if (queue->values.count > 0)
97
+ return ring_buffer_shift(&queue->values);
92
98
  }
93
99
 
94
- return ring_buffer_shift(&queue->values);
100
+ return Qnil;
95
101
  }
96
102
 
97
103
  VALUE Queue_shift_no_wait(VALUE self) {
@@ -158,6 +164,13 @@ VALUE Queue_empty_p(VALUE self) {
158
164
  return (queue->values.count == 0) ? Qtrue : Qfalse;
159
165
  }
160
166
 
167
+ VALUE Queue_pending_p(VALUE self) {
168
+ Queue_t *queue;
169
+ GetQueue(self, queue);
170
+
171
+ return (queue->shift_queue.count > 0) ? Qtrue : Qfalse;
172
+ }
173
+
161
174
  VALUE Queue_size_m(VALUE self) {
162
175
  Queue_t *queue;
163
176
  GetQueue(self, queue);
@@ -190,5 +203,6 @@ void Init_Queue() {
190
203
  rb_define_method(cQueue, "shift_all", Queue_shift_all, 0);
191
204
  rb_define_method(cQueue, "flush_waiters", Queue_flush_waiters, 1);
192
205
  rb_define_method(cQueue, "empty?", Queue_empty_p, 0);
206
+ rb_define_method(cQueue, "pending?", Queue_pending_p, 0);
193
207
  rb_define_method(cQueue, "size", Queue_size_m, 0);
194
208
  }
@@ -57,7 +57,7 @@ module Polyphony
57
57
  rescue SystemExit
58
58
  # fall through to ensure
59
59
  rescue Exception => e
60
- e.full_message
60
+ warn e.full_message
61
61
  exit!
62
62
  ensure
63
63
  exit_forked_process
@@ -24,7 +24,7 @@ module Polyphony
24
24
  fiber = Fiber.current
25
25
  return @acquired_resources[fiber] if @acquired_resources[fiber]
26
26
 
27
- add_to_stock if @size < @limit && @stock.empty?
27
+ add_to_stock if (@stock.empty? || @stock.pending?) && @size < @limit
28
28
  resource = @stock.shift
29
29
  @acquired_resources[fiber] = resource
30
30
  yield resource
@@ -67,6 +67,10 @@ class ::Socket
67
67
  setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
68
68
  end
69
69
 
70
+ def reuse_port
71
+ setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEPORT, 1)
72
+ end
73
+
70
74
  class << self
71
75
  alias_method :orig_getaddrinfo, :getaddrinfo
72
76
  def getaddrinfo(*args)
@@ -120,6 +124,10 @@ class ::TCPSocket
120
124
  def reuse_addr
121
125
  setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, 1)
122
126
  end
127
+
128
+ def reuse_port
129
+ setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEPORT, 1)
130
+ end
123
131
  end
124
132
 
125
133
  # Override stock TCPServer code by encapsulating a Socket instance.
@@ -35,9 +35,10 @@ module Polyphony
35
35
  ::Socket.new(:INET, :STREAM).tap do |s|
36
36
  s.reuse_addr if opts[:reuse_addr]
37
37
  s.dont_linger if opts[:dont_linger]
38
+ s.reuse_port if opts[:reuse_port]
38
39
  addr = ::Socket.sockaddr_in(port, host)
39
40
  s.bind(addr)
40
- s.listen(0)
41
+ s.listen(opts[:backlog] || Socket::SOMAXCONN)
41
42
  end
42
43
  end
43
44
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.43.10'
4
+ VERSION = '0.43.11'
5
5
  end
@@ -692,7 +692,7 @@ class FiberTest < MiniTest::Test
692
692
 
693
693
  f.schedule
694
694
  f << 'bar'
695
- snooze
695
+ 2.times { snooze }
696
696
  assert_equal ['bar'], buffer
697
697
  end
698
698
  end
@@ -12,29 +12,19 @@ class ResourcePoolTest < MiniTest::Test
12
12
  assert_equal 0, pool.size
13
13
 
14
14
  results = []
15
- 4.times {
16
- spin {
17
- snooze
15
+ 4.times { |i|
16
+ spin(:"foo#{i}") {
18
17
  pool.acquire { |resource|
19
18
  results << resource
20
19
  snooze
21
20
  }
22
21
  }
23
22
  }
24
- 2.times { snooze }
25
- assert_equal 2, pool.limit
26
- assert_equal 0, pool.available
27
- assert_equal 2, pool.size
28
-
29
- 2.times { snooze }
30
-
31
- assert_equal ['a', 'b', 'a', 'b'], results
32
-
33
- 2.times { snooze }
34
-
23
+ Fiber.current.await_all_children
35
24
  assert_equal 2, pool.limit
36
25
  assert_equal 2, pool.available
37
26
  assert_equal 2, pool.size
27
+ assert_equal ['a', 'b', 'a', 'b'], results
38
28
  end
39
29
 
40
30
  def test_single_resource_limit
@@ -51,7 +41,7 @@ class ResourcePoolTest < MiniTest::Test
51
41
  }
52
42
  }
53
43
  }
54
- 20.times { snooze }
44
+ 21.times { snooze }
55
45
 
56
46
  assert_equal ['a'] * 10, results
57
47
  end
@@ -92,4 +82,23 @@ class ResourcePoolTest < MiniTest::Test
92
82
  end
93
83
  end
94
84
  end
85
+
86
+ def test_overloaded_resource_pool
87
+ pool = Polyphony::ResourcePool.new(limit: 1) { 1 }
88
+
89
+ buf = []
90
+ fibers = 2.times.map do |i|
91
+ spin(:"foo#{i}") do
92
+ 2.times do
93
+ pool.acquire do |r|
94
+ buf << r
95
+ snooze
96
+ end
97
+ end
98
+ end
99
+ end
100
+ Fiber.current.await_all_children
101
+
102
+ assert_equal [1, 1, 1, 1], buf
103
+ end
95
104
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polyphony
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.43.10
4
+ version: 0.43.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-23 00:00:00.000000000 Z
11
+ date: 2020-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -477,7 +477,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
477
477
  - !ruby/object:Gem::Version
478
478
  version: '0'
479
479
  requirements: []
480
- rubygems_version: 3.0.8
480
+ rubygems_version: 3.1.2
481
481
  signing_key:
482
482
  specification_version: 4
483
483
  summary: Fine grained concurrency for Ruby