polyphony 0.57.0 → 0.58

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: e350937221c476548465a2881e64689042137eab59571a0940f63236a249563f
4
- data.tar.gz: 14870d9e38e7aa9f300d09cdfa0693929edb59756e0d17e7b3e7ae2d4a9dab0d
3
+ metadata.gz: e8002b8c0e03afa8e915b5ed67d64c1fc288a5fa220dfb2c32d3966a78046eee
4
+ data.tar.gz: c3a46eeae1f048f4adee9d3130f5dd3593936e843c1874d928f742d1fa83053f
5
5
  SHA512:
6
- metadata.gz: 8087b84c7a583c8f3905c20d06aa4ad119fd2901be2594e66f56b577c1fa141f9e203971aedd27ad7c57b9c184adad1b97d0fbe4024702bfe3ef6bdaa861ac92
7
- data.tar.gz: 6943231ef2b29dac3e33cfee865dbc6b3b35549c62e04dd1ed08d40fbd90a5c179417baf3b27b965e80c3ee7e137cbe167be9e8187dff46d89892978beb8a40d
6
+ metadata.gz: e6681155761daee35b73c9674e69aa505786e576814db0c909028cb576d8609f99bccc79f80b7d06d90c7658747bc2589c9837d3bdb3419782147e573d39f278
7
+ data.tar.gz: 90197a8db54405ca37492a54a20adf00c85f142af606cad26ad823161825ccf6bd9a414adcbbf3e27eaf93eea1d94a7cbc50a2fb5982ee4ce48969d4378400cd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.58 2021-06-25
2
+
3
+ - Implement `Thread#idle_gc_period`, `#on_idle` (#56)
4
+ - Implement `Backend#idle_block=` (#56)
5
+
1
6
  ## 0.57.0 2021-06-23
2
7
 
3
8
  - Implement `Backend#splice_chunks` method for both libev and io_uring backends
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.57.0)
4
+ polyphony (0.58)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -5,6 +5,14 @@
5
5
  #include "polyphony.h"
6
6
  #include "backend_common.h"
7
7
 
8
+ inline void initialize_backend_base(struct Backend_base *base) {
9
+ base->currently_polling = 0;
10
+ base->pending_count = 0;
11
+ base->idle_gc_period = 0;
12
+ base->idle_gc_last_time = 0;
13
+ base->idle_block = Qnil;
14
+ }
15
+
8
16
  #ifdef POLYPHONY_USE_PIDFD_OPEN
9
17
  #ifndef __NR_pidfd_open
10
18
  #define __NR_pidfd_open 434 /* System call # on most architectures */
@@ -174,6 +182,9 @@ inline void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking) {
174
182
  }
175
183
 
176
184
  inline void backend_run_idle_tasks(struct Backend_base *base) {
185
+ if (base->idle_block != Qnil)
186
+ rb_funcall(base->idle_block, ID_call, 0);
187
+
177
188
  if (base->idle_gc_period == 0) return;
178
189
 
179
190
  double now = current_time();
@@ -9,8 +9,11 @@ struct Backend_base {
9
9
  unsigned int pending_count;
10
10
  double idle_gc_period;
11
11
  double idle_gc_last_time;
12
+ VALUE idle_block;
12
13
  };
13
14
 
15
+ void initialize_backend_base(struct Backend_base *base);
16
+
14
17
  #ifdef POLYPHONY_USE_PIDFD_OPEN
15
18
  int pidfd_open(pid_t pid, unsigned int flags);
16
19
  #endif
@@ -42,13 +42,19 @@ typedef struct Backend_t {
42
42
  int event_fd;
43
43
  } Backend_t;
44
44
 
45
+ static void Backend_mark(void *ptr) {
46
+ Backend_t *backend = ptr;
47
+ if (backend->base.idle_block != Qnil)
48
+ rb_gc_mark(backend->base.idle_block);
49
+ }
50
+
45
51
  static size_t Backend_size(const void *ptr) {
46
52
  return sizeof(Backend_t);
47
53
  }
48
54
 
49
55
  static const rb_data_type_t Backend_type = {
50
56
  "IOUringBackend",
51
- {0, 0, Backend_size,},
57
+ {Backend_mark, 0, Backend_size,},
52
58
  0, 0, RUBY_TYPED_FREE_IMMEDIATELY
53
59
  };
54
60
 
@@ -65,11 +71,7 @@ static VALUE Backend_initialize(VALUE self) {
65
71
  Backend_t *backend;
66
72
  GetBackend(self, backend);
67
73
 
68
- backend->base.currently_polling = 0;
69
- backend->base.pending_count = 0;
70
- backend->base.idle_gc_period = 0;
71
- backend->base.idle_gc_last_time = 0;
72
-
74
+ initialize_backend_base(&backend->base);
73
75
  backend->pending_sqes = 0;
74
76
  backend->prepared_limit = 2048;
75
77
 
@@ -134,6 +136,7 @@ static inline void io_uring_backend_handle_completion(struct io_uring_cqe *cqe,
134
136
  op_context_t *ctx = io_uring_cqe_get_data(cqe);
135
137
  if (!ctx) return;
136
138
 
139
+ // printf("cqe ctx %p id: %d result: %d (%s, ref_count: %d)\n", ctx, ctx->id, cqe->res, op_type_to_str(ctx->type), ctx->ref_count);
137
140
  ctx->result = cqe->res;
138
141
  if (ctx->ref_count == 2 && ctx->result != -ECANCELED && ctx->fiber)
139
142
  Fiber_make_runnable(ctx->fiber, ctx->resume_value);
@@ -908,7 +911,6 @@ int io_uring_backend_submit_timeout_and_await(Backend_t *backend, double duratio
908
911
 
909
912
  op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
910
913
  io_uring_prep_timeout(sqe, &ts, 0, 0);
911
-
912
914
  io_uring_backend_defer_submit_and_await(backend, sqe, ctx, resume_value);
913
915
  return context_store_release(&backend->store, ctx);
914
916
  }
@@ -1185,6 +1187,13 @@ VALUE Backend_idle_gc_period_set(VALUE self, VALUE period) {
1185
1187
  return self;
1186
1188
  }
1187
1189
 
1190
+ VALUE Backend_idle_block_set(VALUE self, VALUE block) {
1191
+ Backend_t *backend;
1192
+ GetBackend(self, backend);
1193
+ backend->base.idle_block = block;
1194
+ return self;
1195
+ }
1196
+
1188
1197
  inline VALUE Backend_run_idle_tasks(VALUE self) {
1189
1198
  Backend_t *backend;
1190
1199
  GetBackend(self, backend);
@@ -1359,6 +1368,7 @@ void Init_Backend() {
1359
1368
  rb_define_method(cBackend, "kind", Backend_kind, 0);
1360
1369
  rb_define_method(cBackend, "chain", Backend_chain, -1);
1361
1370
  rb_define_method(cBackend, "idle_gc_period=", Backend_idle_gc_period_set, 1);
1371
+ rb_define_method(cBackend, "idle_block=", Backend_idle_block_set, 1);
1362
1372
  rb_define_method(cBackend, "splice_chunks", Backend_splice_chunks, 7);
1363
1373
 
1364
1374
  rb_define_method(cBackend, "accept", Backend_accept, 2);
@@ -37,8 +37,7 @@ inline op_context_t *context_store_acquire(op_context_store_t *store, enum op_ty
37
37
  ctx = malloc(sizeof(op_context_t));
38
38
  }
39
39
  ctx->id = (++store->last_id);
40
- // printf("acquire %d (%s)\n", ctx->id, op_type_to_str(type));
41
-
40
+ // printf("acquire %p %d (%s)\n", ctx, ctx->id, op_type_to_str(type));
42
41
  ctx->prev = NULL;
43
42
  ctx->next = store->taken;
44
43
  if (store->taken) store->taken->prev = ctx;
@@ -55,7 +54,7 @@ inline op_context_t *context_store_acquire(op_context_store_t *store, enum op_ty
55
54
 
56
55
  // returns true if ctx was released
57
56
  inline int context_store_release(op_context_store_t *store, op_context_t *ctx) {
58
- // printf("release %d (%s, ref_count: %d)\n", ctx->id, op_type_to_str(ctx->type), ctx->ref_count);
57
+ // printf("release %p %d (%s, ref_count: %d)\n", ctx, ctx->id, op_type_to_str(ctx->type), ctx->ref_count);
59
58
 
60
59
  assert(ctx->ref_count);
61
60
 
@@ -73,13 +73,19 @@ typedef struct Backend_t {
73
73
  struct ev_async break_async;
74
74
  } Backend_t;
75
75
 
76
+ static void Backend_mark(void *ptr) {
77
+ Backend_t *backend = ptr;
78
+ if (backend->base.idle_block != Qnil)
79
+ rb_gc_mark(backend->base.idle_block);
80
+ }
81
+
76
82
  static size_t Backend_size(const void *ptr) {
77
83
  return sizeof(Backend_t);
78
84
  }
79
85
 
80
86
  static const rb_data_type_t Backend_type = {
81
87
  "LibevBackend",
82
- {0, 0, Backend_size,},
88
+ {Backend_mark, 0, Backend_size,},
83
89
  0, 0, RUBY_TYPED_FREE_IMMEDIATELY
84
90
  };
85
91
 
@@ -110,6 +116,8 @@ static VALUE Backend_initialize(VALUE self) {
110
116
  Backend_t *backend;
111
117
 
112
118
  GetBackend(self, backend);
119
+
120
+ initialize_backend_base(&backend->base);
113
121
  backend->ev_loop = libev_new_loop();
114
122
 
115
123
  // start async watcher used for breaking a poll op (from another thread)
@@ -119,11 +127,6 @@ static VALUE Backend_initialize(VALUE self) {
119
127
  // block when no other watcher is active
120
128
  ev_unref(backend->ev_loop);
121
129
 
122
- backend->base.currently_polling = 0;
123
- backend->base.pending_count = 0;
124
- backend->base.idle_gc_period = 0;
125
- backend->base.idle_gc_last_time = 0;
126
-
127
130
  return Qnil;
128
131
  }
129
132
 
@@ -1290,6 +1293,13 @@ VALUE Backend_idle_gc_period_set(VALUE self, VALUE period) {
1290
1293
  return self;
1291
1294
  }
1292
1295
 
1296
+ VALUE Backend_idle_block_set(VALUE self, VALUE block) {
1297
+ Backend_t *backend;
1298
+ GetBackend(self, backend);
1299
+ backend->base.idle_block = block;
1300
+ return self;
1301
+ }
1302
+
1293
1303
  inline VALUE Backend_run_idle_tasks(VALUE self) {
1294
1304
  Backend_t *backend;
1295
1305
  GetBackend(self, backend);
@@ -1448,6 +1458,7 @@ void Init_Backend() {
1448
1458
  rb_define_method(cBackend, "kind", Backend_kind, 0);
1449
1459
  rb_define_method(cBackend, "chain", Backend_chain, -1);
1450
1460
  rb_define_method(cBackend, "idle_gc_period=", Backend_idle_gc_period_set, 1);
1461
+ rb_define_method(cBackend, "idle_block=", Backend_idle_block_set, 1);
1451
1462
  rb_define_method(cBackend, "splice_chunks", Backend_splice_chunks, 7);
1452
1463
 
1453
1464
  rb_define_method(cBackend, "accept", Backend_accept, 2);
@@ -105,4 +105,12 @@ class ::Thread
105
105
  main_fiber << value
106
106
  end
107
107
  alias_method :send, :<<
108
+
109
+ def idle_gc_period=(period)
110
+ backend.idle_gc_period = period
111
+ end
112
+
113
+ def on_idle(&block)
114
+ backend.idle_block = block
115
+ end
108
116
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.57.0'
4
+ VERSION = '0.58'
5
5
  end
data/test/test_backend.rb CHANGED
@@ -340,9 +340,38 @@ class BackendTest < MiniTest::Test
340
340
  # GC period.
341
341
  sleep 0.05
342
342
  assert_equal count + 1, GC.count
343
+
344
+ @backend.idle_gc_period = 0
345
+ count = GC.count
346
+ sleep 0.001
347
+ sleep 0.002
348
+ sleep 0.003
349
+ assert_equal count, GC.count
343
350
  ensure
344
351
  GC.enable
345
352
  end
353
+
354
+ def test_idle_block
355
+ counter = 0
356
+
357
+ @backend.idle_block = proc { counter += 1 }
358
+
359
+ 3.times { snooze }
360
+ assert_equal 0, counter
361
+
362
+ sleep 0.01
363
+ assert_equal 1, counter
364
+ sleep 0.01
365
+ assert_equal 2, counter
366
+
367
+ assert_equal 2, counter
368
+ 3.times { snooze }
369
+ assert_equal 2, counter
370
+
371
+ @backend.idle_block = nil
372
+ sleep 0.01
373
+ assert_equal 2, counter
374
+ end
346
375
  end
347
376
 
348
377
  class BackendChainTest < MiniTest::Test
data/test/test_thread.rb CHANGED
@@ -171,4 +171,56 @@ class ThreadTest < MiniTest::Test
171
171
  t&.kill
172
172
  t&.join
173
173
  end
174
+
175
+ def test_idle_gc
176
+ GC.disable
177
+
178
+ count = GC.count
179
+ snooze
180
+ assert_equal count, GC.count
181
+ sleep 0.01
182
+ assert_equal count, GC.count
183
+
184
+ Thread.current.idle_gc_period = 0.1
185
+ snooze
186
+ assert_equal count, GC.count
187
+ sleep 0.05
188
+ assert_equal count, GC.count
189
+ # The idle tasks are ran at most once per fiber switch, before the backend
190
+ # is polled. Therefore, the second sleep will not have triggered a GC, since
191
+ # only 0.05s have passed since the gc period was set.
192
+ sleep 0.07
193
+ assert_equal count, GC.count
194
+ # Upon the third sleep the GC should be triggered, at 0.12s post setting the
195
+ # GC period.
196
+ sleep 0.05
197
+ assert_equal count + 1, GC.count
198
+
199
+ Thread.current.idle_gc_period = 0
200
+ count = GC.count
201
+ sleep 0.001
202
+ sleep 0.002
203
+ sleep 0.003
204
+ assert_equal count, GC.count
205
+ ensure
206
+ GC.enable
207
+ end
208
+
209
+ def test_on_idle
210
+ counter = 0
211
+
212
+ Thread.current.on_idle { counter += 1 }
213
+
214
+ 3.times { snooze }
215
+ assert_equal 0, counter
216
+
217
+ sleep 0.01
218
+ assert_equal 1, counter
219
+ sleep 0.01
220
+ assert_equal 2, counter
221
+
222
+ assert_equal 2, counter
223
+ 3.times { snooze }
224
+ assert_equal 2, counter
225
+ end
174
226
  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.57.0
4
+ version: '0.58'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-23 00:00:00.000000000 Z
11
+ date: 2021-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler