Ruby: scheduler.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

scheduler.c
Go to the documentation of this file.
1/**********************************************************************
2
3 scheduler.c
4
5 $Author$
6
7 Copyright (C) 2020 Samuel Grant Dawson Williams
8
9**********************************************************************/
10
11#include "vm_core.h"
12#include "internal/scheduler.h"
13#include "ruby/io.h"
14
15static ID id_close;
16
17static ID id_block;
18static ID id_unblock;
19
20static ID id_kernel_sleep;
21static ID id_process_wait;
22
23static ID id_io_read;
24static ID id_io_write;
25static ID id_io_wait;
26
27void
28Init_Scheduler(void)
29{
30 id_close = rb_intern_const("close");
31
32 id_block = rb_intern_const("block");
33 id_unblock = rb_intern_const("unblock");
34
35 id_kernel_sleep = rb_intern_const("kernel_sleep");
36 id_process_wait = rb_intern_const("process_wait");
37
38 id_io_read = rb_intern_const("io_read");
39 id_io_write = rb_intern_const("io_write");
40 id_io_wait = rb_intern_const("io_wait");
41}
42
43 VALUE
44 rb_scheduler_get(void)
45{
46 rb_thread_t *thread = GET_THREAD();
47 VM_ASSERT(thread);
48
49 return thread->scheduler;
50}
51
52static void
53verify_interface(VALUE scheduler)
54{
55 if (!rb_respond_to(scheduler, id_block)) {
56 rb_raise(rb_eArgError, "Scheduler must implement #block!");
57 }
58
59 if (!rb_respond_to(scheduler, id_unblock)) {
60 rb_raise(rb_eArgError, "Scheduler must implement #unblock!");
61 }
62
63 if (!rb_respond_to(scheduler, id_kernel_sleep)) {
64 rb_raise(rb_eArgError, "Scheduler must implement #kernel_sleep!");
65 }
66
67 if (!rb_respond_to(scheduler, id_io_wait)) {
68 rb_raise(rb_eArgError, "Scheduler must implement #io_wait!");
69 }
70}
71
72 VALUE
73 rb_scheduler_set(VALUE scheduler)
74{
75 rb_thread_t *thread = GET_THREAD();
76 VM_ASSERT(thread);
77
78 if (scheduler != Qnil) {
79 verify_interface(scheduler);
80 }
81
82 // We invoke Scheduler#close when setting it to something else, to ensure the previous scheduler runs to completion before changing the scheduler. That way, we do not need to consider interactions, e.g., of a Fiber from the previous scheduler with the new scheduler.
83 if (thread->scheduler != Qnil) {
84 rb_scheduler_close(thread->scheduler);
85 }
86
87 thread->scheduler = scheduler;
88
89 return thread->scheduler;
90}
91
92static VALUE
93rb_threadptr_scheduler_current(rb_thread_t *thread)
94{
95 VM_ASSERT(thread);
96
97 if (thread->blocking == 0) {
98 return thread->scheduler;
99 } else {
100 return Qnil;
101 }
102}
103
104 VALUE
105 rb_scheduler_current(void)
106{
107 return rb_threadptr_scheduler_current(GET_THREAD());
108}
109
110 VALUE rb_thread_scheduler_current(VALUE thread)
111{
112 return rb_threadptr_scheduler_current(rb_thread_ptr(thread));
113}
114
115 VALUE
116 rb_scheduler_close(VALUE scheduler)
117{
118 if (rb_respond_to(scheduler, id_close)) {
119 return rb_funcall(scheduler, id_close, 0);
120 }
121
122 return Qnil;
123}
124
125 VALUE
126 rb_scheduler_timeout(struct timeval *timeout)
127{
128 if (timeout) {
129 return rb_float_new((double)timeout->tv_sec + (0.000001f * timeout->tv_usec));
130 }
131
132 return Qnil;
133}
134
135 VALUE
136 rb_scheduler_kernel_sleep(VALUE scheduler, VALUE timeout)
137{
138 return rb_funcall(scheduler, id_kernel_sleep, 1, timeout);
139}
140
141 VALUE
142 rb_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE * argv)
143{
144 return rb_funcallv(scheduler, id_kernel_sleep, argc, argv);
145}
146
147int
148 rb_scheduler_supports_process_wait(VALUE scheduler)
149{
150 return rb_respond_to(scheduler, id_process_wait);
151}
152
153 VALUE
154 rb_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags)
155{
156 return rb_funcall(scheduler, id_process_wait, 2, PIDT2NUM(pid), RB_INT2NUM(flags));
157}
158
159 VALUE
160 rb_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout)
161{
162 return rb_funcall(scheduler, id_block, 2, blocker, timeout);
163}
164
165 VALUE
166 rb_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber)
167{
168 return rb_funcall(scheduler, id_unblock, 2, blocker, fiber);
169}
170
171 VALUE
172 rb_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
173{
174 return rb_funcall(scheduler, id_io_wait, 3, io, events, timeout);
175}
176
177 VALUE
178 rb_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
179{
180 return rb_scheduler_io_wait(scheduler, io, RB_UINT2NUM(RUBY_IO_READABLE), Qnil);
181}
182
183 VALUE
184 rb_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
185{
186 return rb_scheduler_io_wait(scheduler, io, RB_UINT2NUM(RUBY_IO_WRITABLE), Qnil);
187}
188
189int
190 rb_scheduler_supports_io_read(VALUE scheduler)
191{
192 return rb_respond_to(scheduler, id_io_read);
193}
194
195 VALUE
196 rb_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length)
197{
198 return rb_funcall(scheduler, id_io_read, 4, io, buffer, SIZET2NUM(offset), SIZET2NUM(length));
199}
200
201int
202 rb_scheduler_supports_io_write(VALUE scheduler)
203{
204 return rb_respond_to(scheduler, id_io_write);
205}
206
207 VALUE
208 rb_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length)
209{
210 // We should ensure string has capacity to receive data, and then resize it afterwards.
211 return rb_funcall(scheduler, id_io_write, 4, io, buffer, SIZET2NUM(offset), SIZET2NUM(length));
212}
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
rb_eArgError
VALUE rb_eArgError
Definition: error.c:1058
rb_funcall
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:1077
rb_respond_to
int rb_respond_to(VALUE, ID)
Definition: vm_method.c:2561
io.h
RUBY_IO_READABLE
@ RUBY_IO_READABLE
Definition: io.h:45
RUBY_IO_WRITABLE
@ RUBY_IO_WRITABLE
Definition: io.h:46
RB_UINT2NUM
#define RB_UINT2NUM
Definition: int.h:39
RB_INT2NUM
#define RB_INT2NUM
Definition: int.h:37
rb_float_new
#define rb_float_new
Definition: numeric.h:95
rb_funcallv
#define rb_funcallv(...)
Definition: internal.h:77
offset
voidpf uLong offset
Definition: ioapi.h:144
PIDT2NUM
#define PIDT2NUM
Definition: pid_t.h:27
argc
int argc
Definition: ruby.c:240
argv
char ** argv
Definition: ruby.c:241
rb_scheduler_io_wait_writable
VALUE rb_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Definition: scheduler.c:184
rb_scheduler_kernel_sleep
VALUE rb_scheduler_kernel_sleep(VALUE scheduler, VALUE timeout)
Definition: scheduler.c:136
rb_scheduler_current
VALUE rb_scheduler_current(void)
Definition: scheduler.c:105
rb_scheduler_io_wait
VALUE rb_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Definition: scheduler.c:172
rb_scheduler_block
VALUE rb_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout)
Definition: scheduler.c:160
rb_scheduler_kernel_sleepv
VALUE rb_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE *argv)
Definition: scheduler.c:142
rb_scheduler_process_wait
VALUE rb_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags)
Definition: scheduler.c:154
Init_Scheduler
void Init_Scheduler(void)
Definition: scheduler.c:28
rb_scheduler_timeout
VALUE rb_scheduler_timeout(struct timeval *timeout)
Definition: scheduler.c:126
rb_scheduler_get
VALUE rb_scheduler_get(void)
Definition: scheduler.c:44
rb_scheduler_supports_process_wait
int rb_scheduler_supports_process_wait(VALUE scheduler)
Definition: scheduler.c:148
rb_scheduler_supports_io_read
int rb_scheduler_supports_io_read(VALUE scheduler)
Definition: scheduler.c:190
rb_scheduler_io_wait_readable
VALUE rb_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Definition: scheduler.c:178
rb_thread_scheduler_current
VALUE rb_thread_scheduler_current(VALUE thread)
Definition: scheduler.c:110
rb_scheduler_unblock
VALUE rb_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber)
Definition: scheduler.c:166
rb_scheduler_supports_io_write
int rb_scheduler_supports_io_write(VALUE scheduler)
Definition: scheduler.c:202
rb_scheduler_close
VALUE rb_scheduler_close(VALUE scheduler)
Definition: scheduler.c:116
rb_scheduler_io_read
VALUE rb_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length)
Definition: scheduler.c:196
rb_scheduler_io_write
VALUE rb_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length)
Definition: scheduler.c:208
rb_scheduler_set
VALUE rb_scheduler_set(VALUE scheduler)
Definition: scheduler.c:73
scheduler.h
Internal header for Scheduler.
SIZET2NUM
#define SIZET2NUM
Definition: size_t.h:52
Qnil
#define Qnil
Definition: special_consts.h:51
rb_thread_struct
Definition: vm_core.h:935
rb_thread_struct::scheduler
VALUE scheduler
Definition: vm_core.h:1015
rb_thread_struct::blocking
unsigned blocking
Definition: vm_core.h:1016
timeval
Definition: missing.h:51
timeval::tv_usec
long tv_usec
Definition: missing.h:53
timeval::tv_sec
time_t tv_sec
Definition: missing.h:52
VALUE
unsigned long VALUE
Definition: value.h:38
ID
unsigned long ID
Definition: value.h:39
vm_core.h
VM_ASSERT
#define VM_ASSERT(expr)
Definition: vm_core.h:61