polyphony 0.59.1 → 0.60
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/Gemfile.lock +15 -29
- data/examples/core/message_based_supervision.rb +51 -0
- data/ext/polyphony/backend_common.c +18 -15
- data/ext/polyphony/backend_common.h +0 -1
- data/ext/polyphony/backend_io_uring.c +41 -19
- data/ext/polyphony/backend_io_uring_context.c +10 -1
- data/ext/polyphony/backend_io_uring_context.h +5 -3
- data/ext/polyphony/backend_libev.c +20 -15
- data/ext/polyphony/extconf.rb +2 -2
- data/ext/polyphony/fiber.c +1 -32
- data/ext/polyphony/polyphony.c +12 -12
- data/ext/polyphony/polyphony.h +4 -4
- data/ext/polyphony/queue.c +12 -12
- data/ext/polyphony/runqueue.c +0 -3
- data/lib/polyphony/extensions/fiber.rb +100 -80
- data/lib/polyphony/extensions/io.rb +10 -9
- data/lib/polyphony/extensions/openssl.rb +14 -4
- data/lib/polyphony/extensions/socket.rb +15 -15
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +0 -7
- data/test/test_backend.rb +42 -5
- data/test/test_ext.rb +1 -1
- data/test/test_fiber.rb +106 -18
- data/test/test_global_api.rb +1 -1
- data/test/test_io.rb +29 -0
- data/test/test_supervise.rb +100 -100
- data/test/test_thread_pool.rb +1 -1
- data/test/test_trace.rb +5 -4
- metadata +3 -106
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 515e9a5686bb0eedb02ad626e491b3e8acb350a765a468029e0b5357673f443c
|
4
|
+
data.tar.gz: 94fd7eaedd37c01f1ebc33ba78ffb00d3e8fc42f4a0266bf63ba8eedb83d008c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a546bcf43f556dc7d6bbc3c04b9448141a539e91d2d893441a161eecf9246ff516a54cf94cae476ef9358470e5475c98577c807fd1cef1f712f342337d3c8cc8
|
7
|
+
data.tar.gz: e0bb07cc0028c3205f3c2d87a59699e35e3d4d0e797eff63258892475548086125ed40e63152c56253a1c596b680eacc7080bf08f7d152576c34dc57df0206ab
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
## 0.60 2021-07-15
|
2
|
+
|
3
|
+
|
4
|
+
- Fix linux version detection (for kernel version > 5.9)
|
5
|
+
- Fix op ctx leak in io_uring backend (when polling for I/O readiness)
|
6
|
+
- Add support for appending to buffer in `Backend#read`, `Backend#recv` methods
|
7
|
+
- Improve anti-event starvation mechanism
|
8
|
+
- Redesign fiber monitoring mechanism
|
9
|
+
- Implement `Fiber#attach`
|
10
|
+
- Add optional maxlen argument to `IO#read_loop`, `Socket#recv_loop` (#60)
|
11
|
+
- Implement `Fiber#detach` (#52)
|
12
|
+
|
1
13
|
## 0.59.1 2021-06-28
|
2
14
|
|
3
15
|
- Accept fiber tag in `Polyphony::Timer.new`
|
data/Gemfile.lock
CHANGED
@@ -1,27 +1,25 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
polyphony (0.59.
|
4
|
+
polyphony (0.59.2)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
ansi (1.5.0)
|
10
|
-
ast (2.4.
|
10
|
+
ast (2.4.2)
|
11
11
|
builder (3.2.4)
|
12
12
|
coderay (1.1.3)
|
13
|
-
docile (1.
|
14
|
-
hiredis (0.6.3)
|
15
|
-
http_parser.rb (0.6.0)
|
13
|
+
docile (1.4.0)
|
16
14
|
httparty (0.17.1)
|
17
15
|
mime-types (~> 3.0)
|
18
16
|
multi_xml (>= 0.5.2)
|
19
|
-
json (2.
|
17
|
+
json (2.5.1)
|
20
18
|
localhost (1.1.8)
|
21
19
|
method_source (1.0.0)
|
22
20
|
mime-types (3.3.1)
|
23
21
|
mime-types-data (~> 3.2015)
|
24
|
-
mime-types-data (3.
|
22
|
+
mime-types-data (3.2021.0704)
|
25
23
|
minitest (5.14.4)
|
26
24
|
minitest-reporters (1.4.2)
|
27
25
|
ansi
|
@@ -30,22 +28,18 @@ GEM
|
|
30
28
|
ruby-progressbar
|
31
29
|
msgpack (1.4.2)
|
32
30
|
multi_xml (0.6.0)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
ast (~> 2.4.0)
|
37
|
-
pg (1.1.4)
|
31
|
+
parallel (1.20.1)
|
32
|
+
parser (3.0.2.0)
|
33
|
+
ast (~> 2.4.1)
|
38
34
|
pry (0.13.1)
|
39
35
|
coderay (~> 1.1)
|
40
36
|
method_source (~> 1.0)
|
41
|
-
rack (2.2.3)
|
42
37
|
rainbow (3.0.0)
|
43
|
-
rake (13.0.
|
38
|
+
rake (13.0.6)
|
44
39
|
rake-compiler (1.1.1)
|
45
40
|
rake
|
46
|
-
|
47
|
-
|
48
|
-
rexml (3.2.4)
|
41
|
+
regexp_parser (2.1.1)
|
42
|
+
rexml (3.2.5)
|
49
43
|
rubocop (0.85.1)
|
50
44
|
parallel (~> 1.10)
|
51
45
|
parser (>= 2.7.0.1)
|
@@ -55,37 +49,29 @@ GEM
|
|
55
49
|
rubocop-ast (>= 0.0.3)
|
56
50
|
ruby-progressbar (~> 1.7)
|
57
51
|
unicode-display_width (>= 1.4.0, < 2.0)
|
58
|
-
rubocop-ast (
|
59
|
-
parser (>=
|
60
|
-
ruby-progressbar (1.
|
61
|
-
sequel (5.34.0)
|
52
|
+
rubocop-ast (1.8.0)
|
53
|
+
parser (>= 3.0.1.1)
|
54
|
+
ruby-progressbar (1.11.0)
|
62
55
|
simplecov (0.17.1)
|
63
56
|
docile (~> 1.1)
|
64
57
|
json (>= 1.8, < 3)
|
65
58
|
simplecov-html (~> 0.10.0)
|
66
59
|
simplecov-html (0.10.2)
|
67
|
-
unicode-display_width (1.
|
60
|
+
unicode-display_width (1.7.0)
|
68
61
|
|
69
62
|
PLATFORMS
|
70
63
|
ruby
|
71
64
|
|
72
65
|
DEPENDENCIES
|
73
|
-
hiredis (= 0.6.3)
|
74
|
-
http_parser.rb (~> 0.6.0)
|
75
66
|
httparty (= 0.17.1)
|
76
67
|
localhost (~> 1.1.4)
|
77
68
|
minitest (= 5.14.4)
|
78
69
|
minitest-reporters (= 1.4.2)
|
79
70
|
msgpack (= 1.4.2)
|
80
|
-
mysql2 (= 0.5.3)
|
81
|
-
pg (= 1.1.4)
|
82
71
|
polyphony!
|
83
72
|
pry (= 0.13.1)
|
84
|
-
rack (>= 2.0.8, < 2.3.0)
|
85
73
|
rake-compiler (= 1.1.1)
|
86
|
-
redis (= 4.1.0)
|
87
74
|
rubocop (= 0.85.1)
|
88
|
-
sequel (= 5.34.0)
|
89
75
|
simplecov (= 0.17.1)
|
90
76
|
|
91
77
|
BUNDLED WITH
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
class Supervisor
|
7
|
+
def initialize(*fibers)
|
8
|
+
@fiber = spin { do_supervise }
|
9
|
+
@fiber.message_on_child_termination = true
|
10
|
+
fibers.each { |f| add(f) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def await
|
14
|
+
@fiber.await
|
15
|
+
end
|
16
|
+
|
17
|
+
def spin(tag = nil, &block)
|
18
|
+
@fiber.spin(tag, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def add(fiber)
|
22
|
+
fiber.attach(@fiber)
|
23
|
+
end
|
24
|
+
|
25
|
+
def do_supervise
|
26
|
+
loop do
|
27
|
+
msg = receive
|
28
|
+
# puts "Supervisor received #{msg.inspect}"
|
29
|
+
f, r = msg
|
30
|
+
puts "Fiber #{f.tag} terminated with #{r.inspect}, restarting..."
|
31
|
+
f.restart
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def supervise(*fibers)
|
37
|
+
supervisor = Supervisor.new(*fibers)
|
38
|
+
supervisor.await
|
39
|
+
end
|
40
|
+
|
41
|
+
def start_worker(id)
|
42
|
+
spin_loop(:"worker#{id}") do
|
43
|
+
duration = rand(0.5..1.0)
|
44
|
+
puts "Worker #{id} sleeping for #{duration} seconds"
|
45
|
+
sleep duration
|
46
|
+
raise 'foo' if rand > 0.7
|
47
|
+
break if rand > 0.6
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
supervise(start_worker(1), start_worker(2))
|
@@ -25,6 +25,11 @@ inline void backend_base_mark(struct Backend_base *base) {
|
|
25
25
|
runqueue_mark(&base->runqueue);
|
26
26
|
}
|
27
27
|
|
28
|
+
inline void conditional_nonblocking_poll(VALUE backend, struct Backend_base *base, VALUE current, VALUE next) {
|
29
|
+
if (runqueue_should_poll_nonblocking(&base->runqueue) || next == current)
|
30
|
+
Backend_poll(backend, Qnil);
|
31
|
+
}
|
32
|
+
|
28
33
|
VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base) {
|
29
34
|
VALUE current_fiber = rb_fiber_current();
|
30
35
|
runqueue_entry next;
|
@@ -32,26 +37,22 @@ VALUE backend_base_switch_fiber(VALUE backend, struct Backend_base *base) {
|
|
32
37
|
unsigned int backend_was_polled = 0;
|
33
38
|
unsigned int idle_tasks_run_count = 0;
|
34
39
|
|
35
|
-
|
36
|
-
TRACE(base, 2, SYM_fiber_switchpoint, current_fiber);
|
40
|
+
COND_TRACE(base, 2, SYM_fiber_switchpoint, current_fiber);
|
37
41
|
|
38
42
|
while (1) {
|
39
43
|
next = runqueue_shift(&base->runqueue);
|
40
44
|
if (next.fiber != Qnil) {
|
41
45
|
// Polling for I/O op completion is normally done when the run queue is
|
42
46
|
// empty, but if the runqueue never empties, we'll never get to process
|
43
|
-
// any event completions. In order to prevent this, an anti-
|
47
|
+
// any event completions. In order to prevent this, an anti-starvation
|
44
48
|
// mechanism is employed, under the following conditions:
|
45
49
|
// - a blocking poll was not yet performed
|
46
50
|
// - there are pending blocking operations
|
47
|
-
// - the runqueue has
|
48
|
-
//
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
// this prevents event starvation in case the run queue never empties
|
53
|
-
Backend_poll(backend, Qnil);
|
54
|
-
}
|
51
|
+
// - the runqueue shift count has reached a fixed threshold (currently 64), or
|
52
|
+
// - the next fiber is the same as the current fiber (a single fiber is snoozing)
|
53
|
+
if (!backend_was_polled && pending_ops_count)
|
54
|
+
conditional_nonblocking_poll(backend, base, current_fiber, next.fiber);
|
55
|
+
|
55
56
|
break;
|
56
57
|
}
|
57
58
|
|
@@ -82,7 +83,8 @@ void backend_base_schedule_fiber(VALUE thread, VALUE backend, struct Backend_bas
|
|
82
83
|
if (rb_fiber_alive_p(fiber) != Qtrue) return;
|
83
84
|
already_runnable = rb_ivar_get(fiber, ID_ivar_runnable) != Qnil;
|
84
85
|
|
85
|
-
COND_TRACE(base,
|
86
|
+
COND_TRACE(base, 4, SYM_fiber_schedule, fiber, value, prioritize ? Qtrue : Qfalse);
|
87
|
+
|
86
88
|
(prioritize ? runqueue_unshift : runqueue_push)(&base->runqueue, fiber, value, already_runnable);
|
87
89
|
if (!already_runnable) {
|
88
90
|
rb_ivar_set(fiber, ID_ivar_runnable, Qtrue);
|
@@ -171,7 +173,7 @@ inline VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
|
|
171
173
|
//////////////////////////////////////////////////////////////////////
|
172
174
|
//////////////////////////////////////////////////////////////////////
|
173
175
|
|
174
|
-
VALUE backend_await(struct Backend_base *backend) {
|
176
|
+
inline VALUE backend_await(struct Backend_base *backend) {
|
175
177
|
VALUE ret;
|
176
178
|
backend->pending_count++;
|
177
179
|
ret = Thread_switch_fiber(rb_thread_current());
|
@@ -180,9 +182,10 @@ VALUE backend_await(struct Backend_base *backend) {
|
|
180
182
|
return ret;
|
181
183
|
}
|
182
184
|
|
183
|
-
VALUE backend_snooze() {
|
185
|
+
inline VALUE backend_snooze() {
|
186
|
+
VALUE ret;
|
184
187
|
Fiber_make_runnable(rb_fiber_current(), Qnil);
|
185
|
-
|
188
|
+
ret = Thread_switch_fiber(rb_thread_current());
|
186
189
|
return ret;
|
187
190
|
}
|
188
191
|
|
@@ -197,6 +197,15 @@ inline VALUE Backend_poll(VALUE self, VALUE blocking) {
|
|
197
197
|
}
|
198
198
|
|
199
199
|
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_enter, rb_fiber_current());
|
200
|
+
// if (SHOULD_TRACE(&backend->base))
|
201
|
+
// printf(
|
202
|
+
// "io_uring_poll(blocking_mode: %d, pending: %d, taken: %d, available: %d, runqueue: %d\n",
|
203
|
+
// is_blocking,
|
204
|
+
// backend->base.pending_count,
|
205
|
+
// backend->store.taken_count,
|
206
|
+
// backend->store.available_count,
|
207
|
+
// backend->base.runqueue.entries.count
|
208
|
+
// );
|
200
209
|
if (is_blocking) io_uring_backend_poll(backend);
|
201
210
|
io_uring_backend_handle_ready_cqes(backend);
|
202
211
|
COND_TRACE(&backend->base, 2, SYM_fiber_event_poll_leave, rb_fiber_current());
|
@@ -231,7 +240,6 @@ inline struct backend_stats Backend_stats(VALUE self) {
|
|
231
240
|
|
232
241
|
return (struct backend_stats){
|
233
242
|
.scheduled_fibers = runqueue_len(&backend->base.runqueue),
|
234
|
-
.waiting_fibers = 0,
|
235
243
|
.pending_ops = backend->base.pending_count
|
236
244
|
};
|
237
245
|
}
|
@@ -302,17 +310,25 @@ VALUE io_uring_backend_wait_fd(Backend_t *backend, int fd, int write) {
|
|
302
310
|
io_uring_prep_poll_add(sqe, fd, write ? POLLOUT : POLLIN);
|
303
311
|
|
304
312
|
io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resumed_value);
|
313
|
+
context_store_release(&backend->store, ctx);
|
314
|
+
|
305
315
|
RB_GC_GUARD(resumed_value);
|
306
316
|
return resumed_value;
|
307
317
|
}
|
308
318
|
|
309
|
-
VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof) {
|
319
|
+
VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof, VALUE pos) {
|
310
320
|
Backend_t *backend;
|
311
321
|
rb_io_t *fptr;
|
312
322
|
long dynamic_len = length == Qnil;
|
313
323
|
long buffer_size = dynamic_len ? 4096 : NUM2INT(length);
|
314
|
-
|
315
|
-
|
324
|
+
long buf_pos = NUM2INT(pos);
|
325
|
+
if (str != Qnil) {
|
326
|
+
int current_len = RSTRING_LEN(str);
|
327
|
+
if (buf_pos < 0 || buf_pos > current_len) buf_pos = current_len;
|
328
|
+
}
|
329
|
+
else buf_pos = 0;
|
330
|
+
int shrinkable = io_setstrbuf(&str, buf_pos + buffer_size);
|
331
|
+
char *buf = RSTRING_PTR(str) + buf_pos;
|
316
332
|
long total = 0;
|
317
333
|
int read_to_eof = RTEST(to_eof);
|
318
334
|
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
@@ -349,9 +365,9 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
|
|
349
365
|
if (!dynamic_len) break;
|
350
366
|
|
351
367
|
// resize buffer
|
352
|
-
rb_str_resize(str, total);
|
368
|
+
rb_str_resize(str, buf_pos + total);
|
353
369
|
rb_str_modify_expand(str, buffer_size);
|
354
|
-
buf = RSTRING_PTR(str) + total;
|
370
|
+
buf = RSTRING_PTR(str) + buf_pos + total;
|
355
371
|
shrinkable = 0;
|
356
372
|
buffer_size += buffer_size;
|
357
373
|
}
|
@@ -359,7 +375,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
|
|
359
375
|
}
|
360
376
|
}
|
361
377
|
|
362
|
-
io_set_read_length(str, total, shrinkable);
|
378
|
+
io_set_read_length(str, buf_pos + total, shrinkable);
|
363
379
|
io_enc_str(str, fptr);
|
364
380
|
|
365
381
|
if (!total) return Qnil;
|
@@ -367,12 +383,12 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
|
|
367
383
|
return str;
|
368
384
|
}
|
369
385
|
|
370
|
-
VALUE Backend_read_loop(VALUE self, VALUE io) {
|
386
|
+
VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
371
387
|
Backend_t *backend;
|
372
388
|
rb_io_t *fptr;
|
373
389
|
VALUE str;
|
374
390
|
long total;
|
375
|
-
long len =
|
391
|
+
long len = NUM2INT(maxlen);
|
376
392
|
int shrinkable;
|
377
393
|
char *buf;
|
378
394
|
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
@@ -580,13 +596,19 @@ VALUE Backend_write_m(int argc, VALUE *argv, VALUE self) {
|
|
580
596
|
Backend_writev(self, argv[0], argc - 1, argv + 1);
|
581
597
|
}
|
582
598
|
|
583
|
-
VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length) {
|
599
|
+
VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
|
584
600
|
Backend_t *backend;
|
585
601
|
rb_io_t *fptr;
|
586
602
|
long dynamic_len = length == Qnil;
|
587
603
|
long len = dynamic_len ? 4096 : NUM2INT(length);
|
588
|
-
|
589
|
-
|
604
|
+
long buf_pos = NUM2INT(pos);
|
605
|
+
if (str != Qnil) {
|
606
|
+
int current_len = RSTRING_LEN(str);
|
607
|
+
if (buf_pos < 0 || buf_pos > current_len) buf_pos = current_len;
|
608
|
+
}
|
609
|
+
else buf_pos = 0;
|
610
|
+
int shrinkable = io_setstrbuf(&str, buf_pos + len);
|
611
|
+
char *buf = RSTRING_PTR(str) + buf_pos;
|
590
612
|
long total = 0;
|
591
613
|
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
592
614
|
|
@@ -618,7 +640,7 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length) {
|
|
618
640
|
}
|
619
641
|
}
|
620
642
|
|
621
|
-
io_set_read_length(str, total, shrinkable);
|
643
|
+
io_set_read_length(str, buf_pos + total, shrinkable);
|
622
644
|
io_enc_str(str, fptr);
|
623
645
|
|
624
646
|
if (!total) return Qnil;
|
@@ -626,12 +648,12 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length) {
|
|
626
648
|
return str;
|
627
649
|
}
|
628
650
|
|
629
|
-
VALUE Backend_recv_loop(VALUE self, VALUE io) {
|
651
|
+
VALUE Backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
|
630
652
|
Backend_t *backend;
|
631
653
|
rb_io_t *fptr;
|
632
654
|
VALUE str;
|
633
655
|
long total;
|
634
|
-
long len =
|
656
|
+
long len = NUM2INT(maxlen);
|
635
657
|
int shrinkable;
|
636
658
|
char *buf;
|
637
659
|
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
@@ -1421,11 +1443,11 @@ void Init_Backend() {
|
|
1421
1443
|
rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
|
1422
1444
|
rb_define_method(cBackend, "connect", Backend_connect, 3);
|
1423
1445
|
rb_define_method(cBackend, "feed_loop", Backend_feed_loop, 3);
|
1424
|
-
rb_define_method(cBackend, "read", Backend_read,
|
1425
|
-
rb_define_method(cBackend, "read_loop", Backend_read_loop,
|
1426
|
-
rb_define_method(cBackend, "recv", Backend_recv,
|
1446
|
+
rb_define_method(cBackend, "read", Backend_read, 5);
|
1447
|
+
rb_define_method(cBackend, "read_loop", Backend_read_loop, 2);
|
1448
|
+
rb_define_method(cBackend, "recv", Backend_recv, 4);
|
1427
1449
|
rb_define_method(cBackend, "recv_feed_loop", Backend_recv_feed_loop, 3);
|
1428
|
-
rb_define_method(cBackend, "recv_loop", Backend_recv_loop,
|
1450
|
+
rb_define_method(cBackend, "recv_loop", Backend_recv_loop, 2);
|
1429
1451
|
rb_define_method(cBackend, "send", Backend_send, 3);
|
1430
1452
|
rb_define_method(cBackend, "sendv", Backend_sendv, 3);
|
1431
1453
|
rb_define_method(cBackend, "sleep", Backend_sleep, 1);
|
@@ -25,6 +25,8 @@ void context_store_initialize(op_context_store_t *store) {
|
|
25
25
|
store->last_id = 0;
|
26
26
|
store->available = NULL;
|
27
27
|
store->taken = NULL;
|
28
|
+
store->available_count = 0;
|
29
|
+
store->taken_count = 0;
|
28
30
|
}
|
29
31
|
|
30
32
|
inline op_context_t *context_store_acquire(op_context_store_t *store, enum op_type type) {
|
@@ -32,12 +34,12 @@ inline op_context_t *context_store_acquire(op_context_store_t *store, enum op_ty
|
|
32
34
|
if (ctx) {
|
33
35
|
if (ctx->next) ctx->next->prev = NULL;
|
34
36
|
store->available = ctx->next;
|
37
|
+
store->available_count--;
|
35
38
|
}
|
36
39
|
else {
|
37
40
|
ctx = malloc(sizeof(op_context_t));
|
38
41
|
}
|
39
42
|
ctx->id = (++store->last_id);
|
40
|
-
// printf("acquire %p %d (%s)\n", ctx, ctx->id, op_type_to_str(type));
|
41
43
|
ctx->prev = NULL;
|
42
44
|
ctx->next = store->taken;
|
43
45
|
if (store->taken) store->taken->prev = ctx;
|
@@ -49,6 +51,10 @@ inline op_context_t *context_store_acquire(op_context_store_t *store, enum op_ty
|
|
49
51
|
ctx->ref_count = 2;
|
50
52
|
ctx->result = 0;
|
51
53
|
|
54
|
+
store->taken_count++;
|
55
|
+
|
56
|
+
// printf("acquire %p %d (%s, ref_count: %d) taken: %d\n", ctx, ctx->id, op_type_to_str(type), ctx->ref_count, store->taken_count);
|
57
|
+
|
52
58
|
return ctx;
|
53
59
|
}
|
54
60
|
|
@@ -61,6 +67,9 @@ inline int context_store_release(op_context_store_t *store, op_context_t *ctx) {
|
|
61
67
|
ctx->ref_count--;
|
62
68
|
if (ctx->ref_count) return 0;
|
63
69
|
|
70
|
+
store->taken_count--;
|
71
|
+
store->available_count++;
|
72
|
+
|
64
73
|
if (ctx->next) ctx->next->prev = ctx->prev;
|
65
74
|
if (ctx->prev) ctx->prev->next = ctx->next;
|
66
75
|
if (store->taken == ctx) store->taken = ctx->next;
|