polyphony 0.40 → 0.43.2

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.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +11 -2
  3. data/.gitignore +2 -2
  4. data/.rubocop.yml +30 -0
  5. data/CHANGELOG.md +29 -2
  6. data/Gemfile.lock +13 -10
  7. data/README.md +0 -1
  8. data/Rakefile +3 -3
  9. data/TODO.md +27 -97
  10. data/docs/_config.yml +56 -7
  11. data/docs/_sass/custom/custom.scss +6 -26
  12. data/docs/_sass/overrides.scss +0 -46
  13. data/docs/{user-guide → _user-guide}/all-about-timers.md +0 -0
  14. data/docs/_user-guide/index.md +9 -0
  15. data/docs/{user-guide → _user-guide}/web-server.md +0 -0
  16. data/docs/api-reference/fiber.md +2 -2
  17. data/docs/api-reference/index.md +9 -0
  18. data/docs/api-reference/polyphony-process.md +1 -1
  19. data/docs/api-reference/thread.md +1 -1
  20. data/docs/faq.md +21 -11
  21. data/docs/favicon.ico +0 -0
  22. data/docs/getting-started/index.md +10 -0
  23. data/docs/getting-started/installing.md +2 -6
  24. data/docs/getting-started/overview.md +486 -0
  25. data/docs/getting-started/tutorial.md +27 -19
  26. data/docs/index.md +6 -2
  27. data/docs/main-concepts/concurrency.md +0 -5
  28. data/docs/main-concepts/design-principles.md +69 -21
  29. data/docs/main-concepts/extending.md +1 -1
  30. data/docs/main-concepts/index.md +9 -0
  31. data/docs/polyphony-logo.png +0 -0
  32. data/examples/adapters/redis_blpop.rb +12 -0
  33. data/examples/core/01-spinning-up-fibers.rb +1 -0
  34. data/examples/core/03-interrupting.rb +4 -1
  35. data/examples/core/04-handling-signals.rb +19 -0
  36. data/examples/core/xx-agent.rb +102 -0
  37. data/examples/core/xx-sleeping.rb +14 -6
  38. data/examples/io/xx-irb.rb +1 -1
  39. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +7 -6
  40. data/examples/performance/thread-vs-fiber/polyphony_server.rb +13 -36
  41. data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +58 -0
  42. data/examples/performance/xx-array.rb +11 -0
  43. data/examples/performance/xx-fiber-switch.rb +9 -0
  44. data/examples/performance/xx-snooze.rb +15 -0
  45. data/ext/{gyro → polyphony}/extconf.rb +2 -2
  46. data/ext/{gyro → polyphony}/fiber.c +15 -22
  47. data/ext/{gyro → polyphony}/libev.c +0 -0
  48. data/ext/{gyro → polyphony}/libev.h +0 -0
  49. data/ext/polyphony/libev_agent.c +725 -0
  50. data/ext/polyphony/libev_queue.c +217 -0
  51. data/ext/{gyro/gyro.c → polyphony/polyphony.c} +12 -37
  52. data/ext/polyphony/polyphony.h +90 -0
  53. data/ext/polyphony/polyphony_ext.c +21 -0
  54. data/ext/{gyro → polyphony}/thread.c +34 -151
  55. data/ext/{gyro → polyphony}/tracing.c +1 -1
  56. data/lib/polyphony.rb +19 -12
  57. data/lib/polyphony/adapters/irb.rb +1 -1
  58. data/lib/polyphony/adapters/postgres.rb +6 -5
  59. data/lib/polyphony/adapters/process.rb +5 -5
  60. data/lib/polyphony/adapters/redis.rb +3 -2
  61. data/lib/polyphony/adapters/trace.rb +28 -28
  62. data/lib/polyphony/core/channel.rb +3 -3
  63. data/lib/polyphony/core/exceptions.rb +1 -1
  64. data/lib/polyphony/core/global_api.rb +13 -11
  65. data/lib/polyphony/core/resource_pool.rb +3 -3
  66. data/lib/polyphony/core/sync.rb +2 -2
  67. data/lib/polyphony/core/thread_pool.rb +6 -6
  68. data/lib/polyphony/core/throttler.rb +13 -6
  69. data/lib/polyphony/event.rb +27 -0
  70. data/lib/polyphony/extensions/core.rb +22 -14
  71. data/lib/polyphony/extensions/fiber.rb +4 -4
  72. data/lib/polyphony/extensions/io.rb +59 -25
  73. data/lib/polyphony/extensions/openssl.rb +36 -16
  74. data/lib/polyphony/extensions/socket.rb +28 -10
  75. data/lib/polyphony/extensions/thread.rb +16 -9
  76. data/lib/polyphony/net.rb +9 -9
  77. data/lib/polyphony/version.rb +1 -1
  78. data/polyphony.gemspec +3 -3
  79. data/test/helper.rb +12 -1
  80. data/test/test_agent.rb +130 -0
  81. data/test/{test_async.rb → test_event.rb} +13 -7
  82. data/test/test_ext.rb +25 -4
  83. data/test/test_fiber.rb +19 -10
  84. data/test/test_global_api.rb +6 -6
  85. data/test/test_io.rb +46 -24
  86. data/test/test_queue.rb +74 -0
  87. data/test/test_signal.rb +3 -40
  88. data/test/test_socket.rb +34 -0
  89. data/test/test_thread.rb +37 -16
  90. data/test/test_trace.rb +6 -5
  91. metadata +39 -41
  92. data/docs/_includes/nav.html +0 -51
  93. data/docs/_includes/prevnext.html +0 -17
  94. data/docs/_layouts/default.html +0 -106
  95. data/docs/api-reference.md +0 -11
  96. data/docs/api-reference/gyro-async.md +0 -57
  97. data/docs/api-reference/gyro-child.md +0 -29
  98. data/docs/api-reference/gyro-queue.md +0 -44
  99. data/docs/api-reference/gyro-timer.md +0 -51
  100. data/docs/api-reference/gyro.md +0 -25
  101. data/docs/getting-started.md +0 -10
  102. data/docs/main-concepts.md +0 -10
  103. data/docs/user-guide.md +0 -10
  104. data/examples/core/forever_sleep.rb +0 -19
  105. data/ext/gyro/async.c +0 -132
  106. data/ext/gyro/child.c +0 -108
  107. data/ext/gyro/gyro.h +0 -158
  108. data/ext/gyro/gyro_ext.c +0 -33
  109. data/ext/gyro/io.c +0 -457
  110. data/ext/gyro/queue.c +0 -146
  111. data/ext/gyro/selector.c +0 -205
  112. data/ext/gyro/signal.c +0 -99
  113. data/ext/gyro/socket.c +0 -213
  114. data/ext/gyro/timer.c +0 -115
  115. data/test/test_timer.rb +0 -56
@@ -1,213 +0,0 @@
1
- #include "gyro.h"
2
- #include <sys/socket.h>
3
-
4
- static VALUE cTCPSocket;
5
-
6
- ///////////////////////////////////////////////////////////////////////////
7
-
8
- struct rsock_send_arg {
9
- int fd, flags;
10
- VALUE mesg;
11
- struct sockaddr *to;
12
- socklen_t tolen;
13
- };
14
-
15
- #define StringValue(v) rb_string_value(&(v))
16
- #define IS_ADDRINFO(obj) rb_typeddata_is_kind_of((obj), &addrinfo_type)
17
-
18
- VALUE
19
- rsock_sockaddr_string_value(volatile VALUE *v)
20
- {
21
- // VALUE val = *v;
22
- // if (IS_ADDRINFO(val)) {
23
- // *v = addrinfo_to_sockaddr(val);
24
- // }
25
- StringValue(*v);
26
- return *v;
27
- }
28
-
29
- #define SockAddrStringValue(v) rsock_sockaddr_string_value(&(v))
30
- #define RSTRING_LENINT(str) rb_long2int(RSTRING_LEN(str))
31
- #ifndef RSTRING_SOCKLEN
32
- # define RSTRING_SOCKLEN (socklen_t)RSTRING_LENINT
33
- #endif
34
-
35
- #if defined __APPLE__
36
- # define do_write_retry(code) do {ret = code;} while (ret == -1 && errno == EPROTOTYPE)
37
- #else
38
- # define do_write_retry(code) ret = code
39
- #endif
40
-
41
- VALUE
42
- rsock_sendto_blocking(void *data)
43
- {
44
- struct rsock_send_arg *arg = data;
45
- VALUE mesg = arg->mesg;
46
- ssize_t ret;
47
- do_write_retry(sendto(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
48
- arg->flags, arg->to, arg->tolen));
49
- return (VALUE)ret;
50
- }
51
-
52
- VALUE
53
- rsock_send_blocking(void *data)
54
- {
55
- struct rsock_send_arg *arg = data;
56
- VALUE mesg = arg->mesg;
57
- ssize_t ret;
58
- do_write_retry(send(arg->fd, RSTRING_PTR(mesg), RSTRING_LEN(mesg),
59
- arg->flags));
60
- return (VALUE)ret;
61
- }
62
-
63
- ///////////////////////////////////////////////////////////////////////////
64
-
65
- static VALUE BasicSocket_send(int argc, VALUE *argv, VALUE sock) {
66
- VALUE underlying_socket = rb_iv_get(sock, "@io");
67
- if (!NIL_P(underlying_socket)) sock = underlying_socket;
68
- struct rsock_send_arg arg;
69
- VALUE flags, to;
70
- rb_io_t *fptr;
71
- ssize_t n;
72
- rb_blocking_function_t *func;
73
- const char *funcname;
74
- VALUE write_watcher = Qnil;
75
-
76
- rb_scan_args(argc, argv, "21", &arg.mesg, &flags, &to);
77
-
78
- StringValue(arg.mesg);
79
-
80
- if (!NIL_P(to)) {
81
- SockAddrStringValue(to);
82
- to = rb_str_new4(to);
83
- arg.to = (struct sockaddr *)RSTRING_PTR(to);
84
- arg.tolen = RSTRING_SOCKLEN(to);
85
- func = rsock_sendto_blocking;
86
- funcname = "sendto(2)";
87
- }
88
- else {
89
- func = rsock_send_blocking;
90
- funcname = "send(2)";
91
- }
92
- GetOpenFile(sock, fptr);
93
- rb_io_set_nonblock(fptr);
94
- arg.fd = fptr->fd;
95
- arg.flags = NUM2INT(flags);
96
- while ((n = (ssize_t)func(&arg)) < 0) {
97
- if (NIL_P(write_watcher))
98
- write_watcher = Gyro_IO_auto_io(fptr->fd, EV_WRITE);
99
- Gyro_IO_await(write_watcher);
100
- }
101
- return SSIZET2NUM(n);
102
- }
103
-
104
- static VALUE BasicSocket_recv(int argc, VALUE *argv, VALUE sock) {
105
- VALUE underlying_socket = rb_iv_get(sock, "@io");
106
- if (!NIL_P(underlying_socket)) sock = underlying_socket;
107
- long len = argc >= 1 ? NUM2LONG(argv[0]) : 8192;
108
- if (len < 0) {
109
- rb_raise(rb_eArgError, "negative length %ld given", len);
110
- }
111
-
112
- rb_io_t *fptr;
113
- long n;
114
- int shrinkable;
115
- VALUE read_watcher = Qnil;
116
-
117
-
118
- VALUE str = argc >= 3 ? argv[2] : Qnil;
119
-
120
- shrinkable = io_setstrbuf(&str, len);
121
- OBJ_TAINT(str);
122
- GetOpenFile(sock, fptr);
123
- // rb_io_set_nonblock(fptr);
124
- rb_io_check_byte_readable(fptr);
125
-
126
- if (len == 0)
127
- return str;
128
-
129
- while (1) {
130
- n = recv(fptr->fd, RSTRING_PTR(str), len, MSG_DONTWAIT);
131
- if (n < 0) {
132
- int e = errno;
133
- if (e == EWOULDBLOCK || e == EAGAIN) {
134
- if (NIL_P(read_watcher))
135
- read_watcher = Gyro_IO_auto_io(fptr->fd, EV_READ);
136
- Gyro_IO_await(read_watcher);
137
- }
138
- else
139
- rb_syserr_fail(e, strerror(e));
140
- // rb_syserr_fail_path(e, fptr->pathv);
141
- }
142
- else
143
- break;
144
- }
145
-
146
- io_set_read_length(str, n, shrinkable);
147
- io_enc_str(str, fptr);
148
-
149
- if (n == 0)
150
- return Qnil;
151
-
152
- return str;
153
- }
154
-
155
- static VALUE Socket_accept(VALUE sock) {
156
- rb_io_t *fptr;
157
- int fd;
158
- struct sockaddr addr;
159
- socklen_t len = (socklen_t)sizeof addr;
160
- VALUE read_watcher = Qnil;
161
-
162
- GetOpenFile(sock, fptr);
163
- rb_io_set_nonblock(fptr);
164
-
165
- while (1) {
166
- fd = accept(fptr->fd, &addr, &len);
167
-
168
- if (fd < 0) {
169
- int e = errno;
170
- if (e == EWOULDBLOCK || e == EAGAIN) {
171
- if (NIL_P(read_watcher))
172
- read_watcher = Gyro_IO_auto_io(fptr->fd, EV_READ);
173
- Gyro_IO_await(read_watcher);
174
- }
175
- else
176
- rb_syserr_fail(e, strerror(e));
177
- // rb_syserr_fail_path(e, fptr->pathv);
178
- }
179
- else {
180
- VALUE connection = rb_obj_alloc(cTCPSocket);
181
- rb_io_t *fp;
182
- MakeOpenFile(connection, fp);
183
- rb_update_max_fd(fd);
184
- fp->fd = fd;
185
- fp->mode = FMODE_READWRITE | FMODE_DUPLEX;
186
- rb_io_ascii8bit_binmode(connection);
187
- rb_io_set_nonblock(fp);
188
- rb_io_synchronized(fp);
189
- // if (rsock_do_not_reverse_lookup) {
190
- // fp->mode |= FMODE_NOREVLOOKUP;
191
- // }
192
-
193
- return connection;
194
- }
195
- }
196
- }
197
-
198
- void Init_Socket() {
199
- VALUE cBasicSocket;
200
- VALUE cSocket;
201
-
202
- rb_require("socket");
203
- cBasicSocket = rb_const_get(rb_cObject, rb_intern("BasicSocket"));
204
-
205
- rb_define_method(cBasicSocket, "send", BasicSocket_send, -1);
206
- rb_define_method(cBasicSocket, "recv", BasicSocket_recv, -1);
207
-
208
- cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
209
-
210
- rb_define_method(cSocket, "accept", Socket_accept, 0);
211
-
212
- cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
213
- }
@@ -1,115 +0,0 @@
1
- #include "gyro.h"
2
-
3
- struct Gyro_Timer {
4
- GYRO_WATCHER_DECL(ev_timer);
5
- double after;
6
- double repeat;
7
- };
8
-
9
- VALUE cGyro_Timer = Qnil;
10
-
11
- static void Gyro_Timer_mark(void *ptr) {
12
- struct Gyro_Timer *timer = ptr;
13
- GYRO_WATCHER_MARK(timer);
14
- }
15
-
16
- static void Gyro_Timer_free(void *ptr) {
17
- struct Gyro_Timer *timer = ptr;
18
- GYRO_WATCHER_FREE(timer);
19
- }
20
-
21
- static size_t Gyro_Timer_size(const void *ptr) {
22
- return sizeof(struct Gyro_Timer);
23
- }
24
-
25
- static const rb_data_type_t Gyro_Timer_type = {
26
- "Gyro_Timer",
27
- {Gyro_Timer_mark, Gyro_Timer_free, Gyro_Timer_size,},
28
- 0, 0, 0
29
- };
30
-
31
- static VALUE Gyro_Timer_allocate(VALUE klass) {
32
- struct Gyro_Timer *timer = ALLOC(struct Gyro_Timer);
33
- return TypedData_Wrap_Struct(klass, &Gyro_Timer_type, timer);
34
- }
35
-
36
- #define GetGyro_Timer(obj, timer) \
37
- TypedData_Get_Struct((obj), struct Gyro_Timer, &Gyro_Timer_type, (timer))
38
-
39
- inline void timer_activate(struct Gyro_Timer *timer) {
40
- timer->fiber = rb_fiber_current();
41
- timer->selector = Thread_current_event_selector();
42
- timer->ev_loop = Gyro_Selector_ev_loop(timer->selector);
43
-
44
- if (timer->active) return;
45
-
46
- timer->active = 1;
47
- Gyro_Selector_add_active_watcher(timer->selector, timer->self);
48
- ev_timer_start(timer->ev_loop, &timer->ev_timer);
49
- }
50
-
51
- inline void timer_deactivate(struct Gyro_Timer *timer, int non_recurring_only) {
52
- if (!timer->active) return;
53
-
54
- if (!timer->repeat || !non_recurring_only) {
55
- ev_timer_stop(timer->ev_loop, &timer->ev_timer);
56
- if (RTEST(timer->selector)) {
57
- Gyro_Selector_remove_active_watcher(timer->selector, timer->self);
58
- timer->selector = Qnil;
59
- }
60
- timer->ev_loop = 0;
61
- timer->active = 0;
62
- }
63
-
64
- timer->fiber = Qnil;
65
- }
66
-
67
- void Gyro_Timer_callback(struct ev_loop *ev_loop, struct ev_timer *ev_timer, int revents) {
68
- struct Gyro_Timer *timer = (struct Gyro_Timer*)ev_timer;
69
-
70
- Fiber_make_runnable(timer->fiber, DBL2NUM(timer->after));
71
- timer_deactivate(timer, 1);
72
- }
73
-
74
- static VALUE Gyro_Timer_initialize(VALUE self, VALUE after, VALUE repeat) {
75
- struct Gyro_Timer *timer;
76
-
77
- GetGyro_Timer(self, timer);
78
- GYRO_WATCHER_INITIALIZE(timer, self);
79
- timer->after = NUM2DBL(after);
80
- timer->repeat = NUM2DBL(repeat);
81
- ev_timer_init(&timer->ev_timer, Gyro_Timer_callback, timer->after, timer->repeat);
82
-
83
- return Qnil;
84
- }
85
-
86
- VALUE Gyro_Timer_stop(VALUE self) {
87
- struct Gyro_Timer *timer;
88
- GetGyro_Timer(self, timer);
89
-
90
- timer_deactivate(timer, 0);
91
- return self;
92
- }
93
-
94
- VALUE Gyro_Timer_await(VALUE self) {
95
- struct Gyro_Timer *timer;
96
- VALUE ret;
97
- GetGyro_Timer(self, timer);
98
-
99
- timer_activate(timer);
100
- ret = Gyro_switchpoint();
101
- timer_deactivate(timer, 1);
102
-
103
- TEST_RESUME_EXCEPTION(ret);
104
- RB_GC_GUARD(ret);
105
- return ret;
106
- }
107
-
108
- void Init_Gyro_Timer() {
109
- cGyro_Timer = rb_define_class_under(mGyro, "Timer", rb_cData);
110
- rb_define_alloc_func(cGyro_Timer, Gyro_Timer_allocate);
111
-
112
- rb_define_method(cGyro_Timer, "initialize", Gyro_Timer_initialize, 2);
113
- rb_define_method(cGyro_Timer, "await", Gyro_Timer_await, 0);
114
- rb_define_method(cGyro_Timer, "stop", Gyro_Timer_stop, 0);
115
- }
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'helper'
4
-
5
- class TimerTest < MiniTest::Test
6
- def test_that_one_shot_timer_works
7
- count = 0
8
- t = Gyro::Timer.new(0.01, 0)
9
- spin {
10
- t.await
11
- count += 1
12
- }
13
- suspend
14
- assert_equal 1, count
15
- end
16
-
17
- def test_that_repeating_timer_works
18
- count = 0
19
- t = Gyro::Timer.new(0.001, 0.001)
20
- spin {
21
- loop {
22
- t.await
23
- count += 1
24
- break if count >= 3
25
- }
26
- }
27
- suspend
28
- assert_equal 3, count
29
- ensure
30
- t.stop
31
- end
32
-
33
- def test_that_repeating_timer_compensates_for_drift
34
- count = 0
35
- t = Gyro::Timer.new(0.1, 0.1)
36
- deltas = []
37
- last = nil
38
- spin {
39
- last = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
40
- loop {
41
- t.await
42
- now = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
43
- elapsed = (now - last)
44
- deltas << elapsed
45
- last = now
46
- count += 1
47
- sleep 0.05
48
- break if count >= 3
49
- }
50
- }
51
- suspend
52
- assert_equal 0, deltas[1..-1].filter { |d| (d - 0.1).abs >= 0.05 }.size
53
- ensure
54
- t.stop
55
- end
56
- end