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 +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +1 -1
- data/TODO.md +0 -2
- data/ext/polyphony/agent.h +4 -2
- data/ext/polyphony/libev_agent.c +49 -44
- data/ext/polyphony/polyphony.h +1 -4
- data/ext/polyphony/queue.c +24 -10
- data/lib/polyphony.rb +1 -1
- data/lib/polyphony/core/resource_pool.rb +1 -1
- data/lib/polyphony/extensions/socket.rb +8 -0
- data/lib/polyphony/net.rb +2 -1
- data/lib/polyphony/version.rb +1 -1
- data/test/test_fiber.rb +1 -1
- data/test/test_resource_pool.rb +24 -15
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d1eb9e2b1eef7f180107b3952fc6974e9c816268ebd8d2368ddfaac276d2086
|
4
|
+
data.tar.gz: dafb382dc7606b92b97fb98125b57abc72e1b1d6b07bb877abff608a41ee51a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f91b787b3eec2c19f6a02fd8a77469c8ae5d7a9302799c3e2a5957376b9f4b0135d2cd958ec7dcf326701e8ba81d85a28201a140ce5806ccc057cedafe907d5
|
7
|
+
data.tar.gz: df865277e2f37c0d7fde0ffd38f52fc466bf28033fb968bd012af7455df9e7805989152467e1e8e84719194f173c99c6290496987ad8a2b48fe26076e62c85bd
|
data/CHANGELOG.md
CHANGED
@@ -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)
|
data/Gemfile.lock
CHANGED
data/TODO.md
CHANGED
data/ext/polyphony/agent.h
CHANGED
@@ -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;
|
data/ext/polyphony/libev_agent.c
CHANGED
@@ -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(
|
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
|
-
|
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),
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
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
|
-
|
259
|
+
LibevAgent_t *agent;
|
260
260
|
GetLibevAgent(self, agent);
|
261
261
|
return libev_await(agent);
|
262
262
|
}
|
263
263
|
|
264
|
-
VALUE libev_io_wait(
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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,
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
}
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -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;
|
data/ext/polyphony/queue.c
CHANGED
@@ -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
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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
|
-
|
86
|
-
|
87
|
-
|
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
|
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
|
}
|
data/lib/polyphony.rb
CHANGED
@@ -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
|
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.
|
data/lib/polyphony/net.rb
CHANGED
@@ -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(
|
41
|
+
s.listen(opts[:backlog] || Socket::SOMAXCONN)
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
data/lib/polyphony/version.rb
CHANGED
data/test/test_fiber.rb
CHANGED
data/test/test_resource_pool.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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.
|
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-
|
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.
|
480
|
+
rubygems_version: 3.1.2
|
481
481
|
signing_key:
|
482
482
|
specification_version: 4
|
483
483
|
summary: Fine grained concurrency for Ruby
|