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