farce 0.3.0-x86_64-linux-gnu → 0.4.1-x86_64-linux-gnu
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 +50 -0
- data/README.md +117 -1489
- data/docs/compatibility.md +74 -0
- data/docs/concurrency.md +151 -0
- data/docs/data-structures.md +313 -0
- data/docs/installation.md +63 -0
- data/docs/integrations.md +124 -0
- data/docs/introduction.md +266 -0
- data/docs/scheduling.md +176 -0
- data/docs/sharing.md +211 -0
- data/docs/shims.md +144 -0
- data/docs/utilities.md +93 -0
- data/docs/variants-and-scopes.md +92 -0
- data/ext/farce/LIBURING-LICENSE +20 -0
- data/ext/farce/atom.c +23 -66
- data/ext/farce/counter.c +1 -1
- data/ext/farce/depend +15 -7
- data/ext/farce/drivers.c +44 -2
- data/ext/farce/exchanger.c +1 -1
- data/ext/farce/extconf.rb +45 -2
- data/ext/farce/farce.c +8 -0
- data/ext/farce/flag.c +1 -1
- data/ext/farce/futex.c +76 -0
- data/ext/farce/futex.h +31 -0
- data/ext/farce/lock.c +16 -62
- data/ext/farce/map.c +10 -54
- data/ext/farce/native_wait.c +139 -0
- data/ext/farce/native_wait.h +37 -0
- data/ext/farce/priority_queue.c +16 -58
- data/ext/farce/queue.c +1 -1
- data/ext/farce/reactor.c +100 -11
- data/ext/farce/reactor.h +6 -2
- data/ext/farce/signal.c +17 -64
- data/ext/farce/tree_map.c +15 -54
- data/ext/farce/unshareable.c +1 -1
- data/ext/farce/unsupported.c +13 -1
- data/ext/farce/vector.c +13 -60
- data/ext/farce/weak_map.c +1 -1
- data/lib/farce/abstract/flag.rb +6 -0
- data/lib/farce/backports.rb +274 -0
- data/lib/farce/engine/jruby/fiber_scheduler.rb +3 -0
- data/lib/farce/engine/jruby/scheduler_synchronization.rb +87 -0
- data/lib/farce/engine/ruby/3.4/farce.so +0 -0
- data/lib/farce/engine/ruby/3.4/null_port.rb +21 -0
- data/lib/farce/engine/ruby/3.4/patch.rb +67 -0
- data/lib/farce/engine/ruby/3.4/port.rb +13 -12
- data/lib/farce/engine/ruby/3.4/ractor_methods.rb +0 -1
- data/lib/farce/engine/ruby/4.0/farce.so +0 -0
- data/lib/farce/engine/ruby/4.0/null_port.rb +36 -0
- data/lib/farce/engine/ruby/4.0/port.rb +1 -2
- data/lib/farce/engine/ruby/4.1/null_port.rb +5 -0
- data/lib/farce/engine/ruby.rb +7 -0
- data/lib/farce/engine/shared/null_port.rb +18 -0
- data/lib/farce/engine/shared/port.rb +41 -3
- data/lib/farce/engine/shared/queue.rb +4 -4
- data/lib/farce/engine/shared/ractor_methods.rb +2 -2
- data/lib/farce/engine/shared/ractor_selector.rb +73 -0
- data/lib/farce/extension.rb +150 -0
- data/lib/farce/integrations/ractor_tmvar.rb +4 -1
- data/lib/farce/internal/fake_ractor.rb +10 -2
- data/lib/farce/internal/scheduler_lifecycle.rb +7 -4
- data/lib/farce/null_port.rb +12 -0
- data/lib/farce/system.rb +10 -2
- data/lib/farce/version.rb +1 -1
- data/lib/farce.rb +1 -1
- metadata +27 -1
data/ext/farce/signal.c
CHANGED
|
@@ -1,21 +1,16 @@
|
|
|
1
1
|
#include "containers.h"
|
|
2
|
-
#include "
|
|
2
|
+
#include "native_wait.h"
|
|
3
3
|
|
|
4
|
-
#include <errno.h>
|
|
5
|
-
#include <fcntl.h>
|
|
6
4
|
#include <math.h>
|
|
7
5
|
#include <stdint.h>
|
|
8
6
|
#include <time.h>
|
|
9
|
-
#include <unistd.h>
|
|
10
7
|
|
|
11
8
|
static VALUE cSignal;
|
|
12
9
|
|
|
13
10
|
typedef struct containers_signal_waiter containers_signal_waiter_t;
|
|
14
11
|
|
|
15
12
|
struct containers_signal_waiter {
|
|
16
|
-
|
|
17
|
-
int write_fd;
|
|
18
|
-
bool notified;
|
|
13
|
+
containers_waiter_t notification;
|
|
19
14
|
containers_signal_waiter_t *next;
|
|
20
15
|
};
|
|
21
16
|
|
|
@@ -66,34 +61,13 @@ containers_signal_parse_timeout(VALUE value)
|
|
|
66
61
|
return timeout;
|
|
67
62
|
}
|
|
68
63
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
{
|
|
72
|
-
#ifdef _WIN32
|
|
73
|
-
(void)fd;
|
|
74
|
-
#else
|
|
75
|
-
int flags = fcntl(fd, F_GETFL, 0);
|
|
76
|
-
if (flags >= 0) (void)fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
77
|
-
flags = fcntl(fd, F_GETFD, 0);
|
|
78
|
-
if (flags >= 0) (void)fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
|
|
79
|
-
#endif
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/* Called with signal->lock held. Each waiter has a separate descriptor, so a
|
|
83
|
-
* single broadcast makes every scheduled Fiber or native thread runnable. */
|
|
64
|
+
/* Called with signal->lock held. The notification remains latched while
|
|
65
|
+
* the waiting caller selects its parking backend outside the state mutex. */
|
|
84
66
|
static void
|
|
85
67
|
containers_signal_notify_waiters_locked(containers_signal_t *signal)
|
|
86
68
|
{
|
|
87
|
-
unsigned char byte = 1;
|
|
88
69
|
for (containers_signal_waiter_t *waiter = signal->waiters; waiter; waiter = waiter->next) {
|
|
89
|
-
|
|
90
|
-
ssize_t result;
|
|
91
|
-
do {
|
|
92
|
-
result = write(waiter->write_fd, &byte, 1);
|
|
93
|
-
} while (result < 0 && errno == EINTR);
|
|
94
|
-
if (result == 1 || (result < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))) {
|
|
95
|
-
waiter->notified = true;
|
|
96
|
-
}
|
|
70
|
+
(void)containers_waiter_notify(&waiter->notification);
|
|
97
71
|
}
|
|
98
72
|
}
|
|
99
73
|
|
|
@@ -112,7 +86,7 @@ containers_signal_memsize(const void *pointer)
|
|
|
112
86
|
}
|
|
113
87
|
|
|
114
88
|
static const rb_data_type_t containers_signal_type = {
|
|
115
|
-
.wrap_struct_name = "
|
|
89
|
+
.wrap_struct_name = "Farce::Internal::Signal",
|
|
116
90
|
.function = {
|
|
117
91
|
.dmark = NULL,
|
|
118
92
|
.dfree = containers_signal_free,
|
|
@@ -184,26 +158,14 @@ containers_signal_new(void)
|
|
|
184
158
|
return containers_signal_initialize(signal);
|
|
185
159
|
}
|
|
186
160
|
|
|
187
|
-
static bool
|
|
188
|
-
containers_signal_wait_for_descriptor(int fd, containers_signal_timeout_t *timeout)
|
|
189
|
-
{
|
|
190
|
-
VALUE wait_timeout = Qnil;
|
|
191
|
-
if (timeout->finite) {
|
|
192
|
-
double remaining = timeout->deadline - containers_signal_monotonic_now();
|
|
193
|
-
if (remaining <= 0) return false;
|
|
194
|
-
wait_timeout = DBL2NUM(remaining);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return containers_wait_for_readable(fd, wait_timeout);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
161
|
static VALUE
|
|
201
162
|
containers_signal_wait_body(VALUE opaque)
|
|
202
163
|
{
|
|
203
164
|
containers_signal_wait_context_t *context = (containers_signal_wait_context_t *)opaque;
|
|
204
|
-
return
|
|
205
|
-
|
|
206
|
-
|
|
165
|
+
return containers_waiter_wait(
|
|
166
|
+
&context->waiter.notification, &context->signal->lock,
|
|
167
|
+
context->timeout->finite, context->timeout->deadline, NULL
|
|
168
|
+
) ? Qtrue : Qfalse;
|
|
207
169
|
}
|
|
208
170
|
|
|
209
171
|
static VALUE
|
|
@@ -220,8 +182,7 @@ containers_signal_wait_cleanup(VALUE opaque)
|
|
|
220
182
|
}
|
|
221
183
|
}
|
|
222
184
|
pthread_mutex_unlock(&context->signal->lock);
|
|
223
|
-
|
|
224
|
-
close(context->waiter.write_fd);
|
|
185
|
+
containers_waiter_close(&context->waiter.notification);
|
|
225
186
|
return Qnil;
|
|
226
187
|
}
|
|
227
188
|
|
|
@@ -232,24 +193,12 @@ containers_signal_wait_once(
|
|
|
232
193
|
containers_signal_timeout_t *timeout
|
|
233
194
|
)
|
|
234
195
|
{
|
|
235
|
-
int descriptors[2];
|
|
236
|
-
if (pipe(descriptors) != 0) {
|
|
237
|
-
pthread_mutex_unlock(&signal->lock);
|
|
238
|
-
rb_sys_fail("pipe");
|
|
239
|
-
}
|
|
240
|
-
containers_signal_set_fd_flags(descriptors[0]);
|
|
241
|
-
containers_signal_set_fd_flags(descriptors[1]);
|
|
242
|
-
|
|
243
196
|
containers_signal_wait_context_t context = {
|
|
244
197
|
.signal = signal,
|
|
245
|
-
.waiter = {
|
|
246
|
-
.read_fd = descriptors[0],
|
|
247
|
-
.write_fd = descriptors[1],
|
|
248
|
-
.notified = false,
|
|
249
|
-
.next = signal->waiters,
|
|
250
|
-
},
|
|
198
|
+
.waiter = {.next = signal->waiters},
|
|
251
199
|
.timeout = timeout,
|
|
252
200
|
};
|
|
201
|
+
containers_waiter_init(&context.waiter.notification);
|
|
253
202
|
signal->waiters = &context.waiter;
|
|
254
203
|
pthread_mutex_unlock(&signal->lock);
|
|
255
204
|
return RTEST(rb_ensure(
|
|
@@ -330,6 +279,10 @@ containers_signal_wait(int argc, VALUE *argv, VALUE self)
|
|
|
330
279
|
pthread_mutex_unlock(&signal->lock);
|
|
331
280
|
return ULL2NUM(generation);
|
|
332
281
|
}
|
|
282
|
+
if (timeout.finite && timeout.deadline <= containers_signal_monotonic_now()) {
|
|
283
|
+
pthread_mutex_unlock(&signal->lock);
|
|
284
|
+
return containers_signal_timeout_result();
|
|
285
|
+
}
|
|
333
286
|
bool awakened = containers_signal_wait_once(signal, &timeout);
|
|
334
287
|
pthread_mutex_lock(&signal->lock);
|
|
335
288
|
if (!awakened && signal->generation == observed) {
|
data/ext/farce/tree_map.c
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include "containers.h"
|
|
2
|
+
#include "native_wait.h"
|
|
2
3
|
#include "transaction.h"
|
|
3
4
|
#include <ruby/atomic.h>
|
|
4
5
|
#include <ruby/fiber/scheduler.h>
|
|
@@ -558,9 +559,7 @@ tc_map_store_unlocked(VALUE self, tc_map *map, VALUE key, VALUE value,
|
|
|
558
559
|
typedef struct tc_core_map_waiter tc_core_map_waiter;
|
|
559
560
|
|
|
560
561
|
struct tc_core_map_waiter {
|
|
561
|
-
|
|
562
|
-
int write_fd;
|
|
563
|
-
bool notified;
|
|
562
|
+
containers_waiter_t notification;
|
|
564
563
|
tc_core_map_waiter *next;
|
|
565
564
|
};
|
|
566
565
|
|
|
@@ -787,40 +786,14 @@ typedef struct {
|
|
|
787
786
|
tc_core_map_waiter waiter;
|
|
788
787
|
} tc_core_map_fiber_wait;
|
|
789
788
|
|
|
790
|
-
static void
|
|
791
|
-
tc_core_map_set_fd_flags(int fd)
|
|
792
|
-
{
|
|
793
|
-
#ifdef _WIN32
|
|
794
|
-
(void)fd;
|
|
795
|
-
#else
|
|
796
|
-
int flags = fcntl(fd, F_GETFL, 0);
|
|
797
|
-
if (flags >= 0) (void)fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
798
|
-
flags = fcntl(fd, F_GETFD, 0);
|
|
799
|
-
if (flags >= 0) (void)fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
|
|
800
|
-
#endif
|
|
801
|
-
}
|
|
802
|
-
|
|
803
789
|
/* Called with core->lock held. The waiter remains linked until its ensure
|
|
804
790
|
* cleanup so an interrupt cannot leave a dangling stack pointer behind. */
|
|
805
791
|
static void
|
|
806
792
|
tc_core_map_notify_one_locked(tc_core_map *core)
|
|
807
793
|
{
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
waiter != NULL;
|
|
812
|
-
waiter = waiter->next) {
|
|
813
|
-
ssize_t result;
|
|
814
|
-
|
|
815
|
-
if (waiter->notified) continue;
|
|
816
|
-
do {
|
|
817
|
-
result = write(waiter->write_fd, &byte, 1);
|
|
818
|
-
} while (result < 0 && errno == EINTR);
|
|
819
|
-
if (result == 1 ||
|
|
820
|
-
(result < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))) {
|
|
821
|
-
waiter->notified = true;
|
|
822
|
-
return;
|
|
823
|
-
}
|
|
794
|
+
for (tc_core_map_waiter *waiter = core->waiters; waiter; waiter = waiter->next) {
|
|
795
|
+
if (waiter->notification.notified) continue;
|
|
796
|
+
if (containers_waiter_notify(&waiter->notification)) return;
|
|
824
797
|
}
|
|
825
798
|
}
|
|
826
799
|
|
|
@@ -828,7 +801,9 @@ static VALUE
|
|
|
828
801
|
tc_core_map_fiber_wait_body(VALUE opaque)
|
|
829
802
|
{
|
|
830
803
|
tc_core_map_fiber_wait *wait = (tc_core_map_fiber_wait *)opaque;
|
|
831
|
-
return
|
|
804
|
+
return containers_waiter_wait(
|
|
805
|
+
&wait->waiter.notification, &wait->core->lock, false, 0, NULL
|
|
806
|
+
) ? Qtrue : Qfalse;
|
|
832
807
|
}
|
|
833
808
|
|
|
834
809
|
static VALUE
|
|
@@ -851,9 +826,9 @@ tc_core_map_fiber_wait_cleanup(VALUE opaque)
|
|
|
851
826
|
}
|
|
852
827
|
/* Notification makes a waiter runnable, but does not reserve ownership.
|
|
853
828
|
* Always pass the baton if a notified waiter leaves while ownerless,
|
|
854
|
-
* including cancellation after
|
|
829
|
+
* including cancellation after a wait returned but before the lock
|
|
855
830
|
* acquisition loop claimed ownership. */
|
|
856
|
-
if (wait->waiter.notified &&
|
|
831
|
+
if (wait->waiter.notification.notified &&
|
|
857
832
|
NIL_P(wait->core->owner_fiber) &&
|
|
858
833
|
!tc_core_map_publication_busy(
|
|
859
834
|
RUBY_ATOMIC_LOAD(wait->core->publication_state)
|
|
@@ -862,8 +837,7 @@ tc_core_map_fiber_wait_cleanup(VALUE opaque)
|
|
|
862
837
|
}
|
|
863
838
|
pthread_mutex_unlock(&wait->core->lock);
|
|
864
839
|
|
|
865
|
-
|
|
866
|
-
close(wait->waiter.write_fd);
|
|
840
|
+
containers_waiter_close(&wait->waiter.notification);
|
|
867
841
|
return Qnil;
|
|
868
842
|
}
|
|
869
843
|
|
|
@@ -871,24 +845,11 @@ tc_core_map_fiber_wait_cleanup(VALUE opaque)
|
|
|
871
845
|
static void
|
|
872
846
|
tc_core_map_wait_once(tc_core_map *core)
|
|
873
847
|
{
|
|
874
|
-
int descriptors[2];
|
|
875
|
-
|
|
876
|
-
if (pipe(descriptors) != 0) {
|
|
877
|
-
pthread_mutex_unlock(&core->lock);
|
|
878
|
-
rb_sys_fail("pipe");
|
|
879
|
-
}
|
|
880
|
-
tc_core_map_set_fd_flags(descriptors[0]);
|
|
881
|
-
tc_core_map_set_fd_flags(descriptors[1]);
|
|
882
|
-
|
|
883
848
|
tc_core_map_fiber_wait wait = {
|
|
884
849
|
.core = core,
|
|
885
|
-
.waiter = {
|
|
886
|
-
.read_fd = descriptors[0],
|
|
887
|
-
.write_fd = descriptors[1],
|
|
888
|
-
.notified = false,
|
|
889
|
-
.next = NULL,
|
|
890
|
-
},
|
|
850
|
+
.waiter = {.next = NULL},
|
|
891
851
|
};
|
|
852
|
+
containers_waiter_init(&wait.waiter.notification);
|
|
892
853
|
|
|
893
854
|
if (core->last_waiter != NULL) core->last_waiter->next = &wait.waiter;
|
|
894
855
|
else core->waiters = &wait.waiter;
|
|
@@ -904,8 +865,8 @@ tc_core_map_wait_once(tc_core_map *core)
|
|
|
904
865
|
}
|
|
905
866
|
|
|
906
867
|
/* CRuby needs logical Fiber ownership rather than pthread ownership: multiple
|
|
907
|
-
* scheduled Fibers can contend on the same native thread.
|
|
908
|
-
*
|
|
868
|
+
* scheduled Fibers can contend on the same native thread. Native notifications
|
|
869
|
+
* park only the current Fiber while its owner resumes. */
|
|
909
870
|
static void
|
|
910
871
|
tc_core_map_lock(VALUE self, tc_core_map *core)
|
|
911
872
|
{
|
data/ext/farce/unshareable.c
CHANGED
|
@@ -40,7 +40,7 @@ containers_marker_size(const void *pointer)
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
static const rb_data_type_t containers_pin_marker_type = {
|
|
43
|
-
.wrap_struct_name = "
|
|
43
|
+
.wrap_struct_name = "Farce pin marker",
|
|
44
44
|
.function = {
|
|
45
45
|
.dmark = containers_marker_mark,
|
|
46
46
|
.dfree = RUBY_TYPED_DEFAULT_FREE,
|
data/ext/farce/unsupported.c
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
#include "
|
|
1
|
+
#include "futex.h"
|
|
2
2
|
|
|
3
3
|
void farce_init_fiber_scheduler(VALUE internal) {
|
|
4
4
|
(void)internal;
|
|
5
5
|
rb_raise(rb_eLoadError, "native Farce fiber scheduling requires epoll or kqueue; use the select implementation");
|
|
6
6
|
}
|
|
7
|
+
|
|
8
|
+
bool containers_futex_scheduler_supported(VALUE scheduler) {
|
|
9
|
+
(void)scheduler;
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
bool containers_futex_scheduler_wait(VALUE scheduler, containers_futex_t *word, VALUE timeout) {
|
|
14
|
+
(void)scheduler;
|
|
15
|
+
(void)word;
|
|
16
|
+
(void)timeout;
|
|
17
|
+
return true;
|
|
18
|
+
}
|
data/ext/farce/vector.c
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
#include "containers.h"
|
|
2
|
+
#include "native_wait.h"
|
|
2
3
|
#include "transaction.h"
|
|
3
|
-
#include "ruby/io.h"
|
|
4
4
|
#include "ruby/fiber/scheduler.h"
|
|
5
5
|
|
|
6
6
|
#include <errno.h>
|
|
7
|
-
#include <fcntl.h>
|
|
8
7
|
#include <math.h>
|
|
9
8
|
#include <stdint.h>
|
|
10
9
|
#include <stdlib.h>
|
|
11
10
|
#include <time.h>
|
|
12
|
-
#include <unistd.h>
|
|
13
11
|
|
|
14
12
|
#define VECTOR_INITIAL_CAPACITY 16
|
|
15
13
|
static VALUE cVector;
|
|
@@ -19,9 +17,7 @@ static VALUE vector_transaction_marker;
|
|
|
19
17
|
typedef struct vector_waiter vector_waiter_t;
|
|
20
18
|
|
|
21
19
|
struct vector_waiter {
|
|
22
|
-
|
|
23
|
-
int write_fd;
|
|
24
|
-
bool notified;
|
|
20
|
+
containers_waiter_t notification;
|
|
25
21
|
vector_waiter_t *next;
|
|
26
22
|
};
|
|
27
23
|
|
|
@@ -85,7 +81,7 @@ vector_memsize(const void *pointer)
|
|
|
85
81
|
}
|
|
86
82
|
|
|
87
83
|
static const rb_data_type_t vector_type = {
|
|
88
|
-
.wrap_struct_name = "
|
|
84
|
+
.wrap_struct_name = "Farce::Internal::Vector",
|
|
89
85
|
.function = {
|
|
90
86
|
.dmark = vector_mark,
|
|
91
87
|
.dfree = vector_free,
|
|
@@ -214,35 +210,14 @@ vector_timeout_keyword(VALUE keywords)
|
|
|
214
210
|
return timeout;
|
|
215
211
|
}
|
|
216
212
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
{
|
|
220
|
-
#ifdef _WIN32
|
|
221
|
-
(void)fd;
|
|
222
|
-
#else
|
|
223
|
-
int flags = fcntl(fd, F_GETFL, 0);
|
|
224
|
-
if (flags >= 0) (void)fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
225
|
-
flags = fcntl(fd, F_GETFD, 0);
|
|
226
|
-
if (flags >= 0) (void)fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
|
|
227
|
-
#endif
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/* Called with vector->lock held. Each waiter has an independent pipe, so a
|
|
231
|
-
* transition wakes every waiting thread or scheduled fiber. */
|
|
213
|
+
/* Called with vector->lock held. A transition wakes every registered
|
|
214
|
+
* thread or fiber without sharing a consumable notification. */
|
|
232
215
|
static void
|
|
233
216
|
vector_notify_waiters_locked(vector_t *vector)
|
|
234
217
|
{
|
|
235
|
-
unsigned char byte = 1;
|
|
236
218
|
vector->generation++;
|
|
237
219
|
for (vector_waiter_t *waiter = vector->waiters; waiter; waiter = waiter->next) {
|
|
238
|
-
|
|
239
|
-
ssize_t result;
|
|
240
|
-
do {
|
|
241
|
-
result = write(waiter->write_fd, &byte, 1);
|
|
242
|
-
} while (result < 0 && errno == EINTR);
|
|
243
|
-
if (result == 1 || (result < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))) {
|
|
244
|
-
waiter->notified = true;
|
|
245
|
-
}
|
|
220
|
+
(void)containers_waiter_notify(&waiter->notification);
|
|
246
221
|
}
|
|
247
222
|
}
|
|
248
223
|
|
|
@@ -259,23 +234,14 @@ typedef struct {
|
|
|
259
234
|
vector_timeout_t *timeout;
|
|
260
235
|
} vector_wait_context_t;
|
|
261
236
|
|
|
262
|
-
static bool
|
|
263
|
-
vector_wait_for_descriptor(int fd, vector_timeout_t *timeout)
|
|
264
|
-
{
|
|
265
|
-
VALUE wait_timeout = Qnil;
|
|
266
|
-
if (timeout->finite) {
|
|
267
|
-
double remaining = timeout->deadline - vector_monotonic_now();
|
|
268
|
-
if (remaining <= 0) return false;
|
|
269
|
-
wait_timeout = DBL2NUM(remaining);
|
|
270
|
-
}
|
|
271
|
-
return containers_wait_for_readable(fd, wait_timeout);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
237
|
static VALUE
|
|
275
238
|
vector_wait_body(VALUE opaque)
|
|
276
239
|
{
|
|
277
240
|
vector_wait_context_t *context = (vector_wait_context_t *)opaque;
|
|
278
|
-
return
|
|
241
|
+
return containers_waiter_wait(
|
|
242
|
+
&context->waiter.notification, &context->vector->lock,
|
|
243
|
+
context->timeout->finite, context->timeout->deadline, NULL
|
|
244
|
+
) ? Qtrue : Qfalse;
|
|
279
245
|
}
|
|
280
246
|
|
|
281
247
|
static VALUE
|
|
@@ -292,8 +258,7 @@ vector_wait_cleanup(VALUE opaque)
|
|
|
292
258
|
}
|
|
293
259
|
}
|
|
294
260
|
pthread_mutex_unlock(&context->vector->lock);
|
|
295
|
-
|
|
296
|
-
close(context->waiter.write_fd);
|
|
261
|
+
containers_waiter_close(&context->waiter.notification);
|
|
297
262
|
return Qnil;
|
|
298
263
|
}
|
|
299
264
|
|
|
@@ -303,24 +268,12 @@ vector_wait_cleanup(VALUE opaque)
|
|
|
303
268
|
static bool
|
|
304
269
|
vector_wait_once(vector_t *vector, vector_timeout_t *timeout)
|
|
305
270
|
{
|
|
306
|
-
int descriptors[2];
|
|
307
|
-
if (pipe(descriptors) != 0) {
|
|
308
|
-
pthread_mutex_unlock(&vector->lock);
|
|
309
|
-
rb_sys_fail("pipe");
|
|
310
|
-
}
|
|
311
|
-
vector_set_fd_flags(descriptors[0]);
|
|
312
|
-
vector_set_fd_flags(descriptors[1]);
|
|
313
|
-
|
|
314
271
|
vector_wait_context_t context = {
|
|
315
272
|
.vector = vector,
|
|
316
|
-
.waiter = {
|
|
317
|
-
.read_fd = descriptors[0],
|
|
318
|
-
.write_fd = descriptors[1],
|
|
319
|
-
.notified = false,
|
|
320
|
-
.next = vector->waiters,
|
|
321
|
-
},
|
|
273
|
+
.waiter = {.next = vector->waiters},
|
|
322
274
|
.timeout = timeout,
|
|
323
275
|
};
|
|
276
|
+
containers_waiter_init(&context.waiter.notification);
|
|
324
277
|
vector->waiters = &context.waiter;
|
|
325
278
|
pthread_mutex_unlock(&vector->lock);
|
|
326
279
|
return RTEST(rb_ensure(vector_wait_body, (VALUE)&context, vector_wait_cleanup, (VALUE)&context));
|
data/ext/farce/weak_map.c
CHANGED
|
@@ -250,7 +250,7 @@ weak_map_memsize(const void *pointer)
|
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
static const rb_data_type_t weak_map_type = {
|
|
253
|
-
.wrap_struct_name = "
|
|
253
|
+
.wrap_struct_name = "Farce::Internal::WeakMap",
|
|
254
254
|
.function = {
|
|
255
255
|
.dmark = weak_map_mark,
|
|
256
256
|
.dfree = weak_map_free,
|
data/lib/farce/abstract/flag.rb
CHANGED
|
@@ -59,6 +59,12 @@ module Farce
|
|
|
59
59
|
include Internal::ValueSerialization
|
|
60
60
|
include Internal::Inspect
|
|
61
61
|
|
|
62
|
+
# @return [Boolean] whether the flag is set
|
|
63
|
+
def set? = value
|
|
64
|
+
|
|
65
|
+
# @return [Boolean] whether the flag is unset
|
|
66
|
+
def unset? = !value
|
|
67
|
+
|
|
62
68
|
# Wait until the flag becomes true.
|
|
63
69
|
# @param timeout [Numeric, nil] the total seconds available
|
|
64
70
|
# @yield called when the timeout expires
|