polyphony 0.43.10 → 0.43.11

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.
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