[ruby/win32ole] Undefine allocator of WIN32OLE_VARIABLE to get rid of warning
[ruby-80x24.org.git] / scheduler.c
blob06658356b176e9012f1127daf9293adc6b89f3bb
1 /**********************************************************************
3 scheduler.c
5 $Author$
7 Copyright (C) 2020 Samuel Grant Dawson Williams
9 **********************************************************************/
11 #include "vm_core.h"
12 #include "ruby/fiber/scheduler.h"
13 #include "ruby/io.h"
14 #include "ruby/io/buffer.h"
16 #include "internal/thread.h"
18 static ID id_close;
19 static ID id_scheduler_close;
21 static ID id_block;
22 static ID id_unblock;
24 static ID id_timeout_after;
25 static ID id_kernel_sleep;
26 static ID id_process_wait;
28 static ID id_io_read, id_io_pread;
29 static ID id_io_write, id_io_pwrite;
30 static ID id_io_wait;
31 static ID id_io_close;
33 static ID id_address_resolve;
35 void
36 Init_Fiber_Scheduler(void)
38 id_close = rb_intern_const("close");
39 id_scheduler_close = rb_intern_const("scheduler_close");
41 id_block = rb_intern_const("block");
42 id_unblock = rb_intern_const("unblock");
44 id_timeout_after = rb_intern_const("timeout_after");
45 id_kernel_sleep = rb_intern_const("kernel_sleep");
46 id_process_wait = rb_intern_const("process_wait");
48 id_io_read = rb_intern_const("io_read");
49 id_io_pread = rb_intern_const("io_pread");
50 id_io_write = rb_intern_const("io_write");
51 id_io_pwrite = rb_intern_const("io_pwrite");
53 id_io_wait = rb_intern_const("io_wait");
54 id_io_close = rb_intern_const("io_close");
56 id_address_resolve = rb_intern_const("address_resolve");
59 VALUE
60 rb_fiber_scheduler_get(void)
62 VM_ASSERT(ruby_thread_has_gvl_p());
64 rb_thread_t *thread = GET_THREAD();
65 VM_ASSERT(thread);
67 return thread->scheduler;
70 static void
71 verify_interface(VALUE scheduler)
73 if (!rb_respond_to(scheduler, id_block)) {
74 rb_raise(rb_eArgError, "Scheduler must implement #block");
77 if (!rb_respond_to(scheduler, id_unblock)) {
78 rb_raise(rb_eArgError, "Scheduler must implement #unblock");
81 if (!rb_respond_to(scheduler, id_kernel_sleep)) {
82 rb_raise(rb_eArgError, "Scheduler must implement #kernel_sleep");
85 if (!rb_respond_to(scheduler, id_io_wait)) {
86 rb_raise(rb_eArgError, "Scheduler must implement #io_wait");
90 VALUE
91 rb_fiber_scheduler_set(VALUE scheduler)
93 VM_ASSERT(ruby_thread_has_gvl_p());
95 rb_thread_t *thread = GET_THREAD();
96 VM_ASSERT(thread);
98 if (scheduler != Qnil) {
99 verify_interface(scheduler);
102 // 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.
103 if (thread->scheduler != Qnil) {
104 rb_fiber_scheduler_close(thread->scheduler);
107 thread->scheduler = scheduler;
109 return thread->scheduler;
112 static VALUE
113 rb_fiber_scheduler_current_for_threadptr(rb_thread_t *thread)
115 VM_ASSERT(thread);
117 if (thread->blocking == 0) {
118 return thread->scheduler;
120 else {
121 return Qnil;
125 VALUE
126 rb_fiber_scheduler_current(void)
128 return rb_fiber_scheduler_current_for_threadptr(GET_THREAD());
131 VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
133 return rb_fiber_scheduler_current_for_threadptr(rb_thread_ptr(thread));
136 VALUE
137 rb_fiber_scheduler_close(VALUE scheduler)
139 VM_ASSERT(ruby_thread_has_gvl_p());
141 VALUE result;
143 result = rb_check_funcall(scheduler, id_scheduler_close, 0, NULL);
144 if (result != Qundef) return result;
146 result = rb_check_funcall(scheduler, id_close, 0, NULL);
147 if (result != Qundef) return result;
149 return Qnil;
152 VALUE
153 rb_fiber_scheduler_make_timeout(struct timeval *timeout)
155 if (timeout) {
156 return rb_float_new((double)timeout->tv_sec + (0.000001f * timeout->tv_usec));
159 return Qnil;
162 VALUE
163 rb_fiber_scheduler_kernel_sleep(VALUE scheduler, VALUE timeout)
165 return rb_funcall(scheduler, id_kernel_sleep, 1, timeout);
168 VALUE
169 rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE * argv)
171 return rb_funcallv(scheduler, id_kernel_sleep, argc, argv);
174 #if 0
175 VALUE
176 rb_fiber_scheduler_timeout_after(VALUE scheduler, VALUE timeout, VALUE exception, VALUE message)
178 VALUE arguments[] = {
179 timeout, exception, message
182 return rb_check_funcall(scheduler, id_timeout_after, 3, arguments);
185 VALUE
186 rb_fiber_scheduler_timeout_afterv(VALUE scheduler, int argc, VALUE * argv)
188 return rb_check_funcall(scheduler, id_timeout_after, argc, argv);
190 #endif
192 VALUE
193 rb_fiber_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags)
195 VALUE arguments[] = {
196 PIDT2NUM(pid), RB_INT2NUM(flags)
199 return rb_check_funcall(scheduler, id_process_wait, 2, arguments);
202 VALUE
203 rb_fiber_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout)
205 return rb_funcall(scheduler, id_block, 2, blocker, timeout);
208 VALUE
209 rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber)
211 VM_ASSERT(rb_obj_is_fiber(fiber));
213 return rb_funcall(scheduler, id_unblock, 2, blocker, fiber);
216 VALUE
217 rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
219 return rb_funcall(scheduler, id_io_wait, 3, io, events, timeout);
222 VALUE
223 rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
225 return rb_fiber_scheduler_io_wait(scheduler, io, RB_UINT2NUM(RUBY_IO_READABLE), Qnil);
228 VALUE
229 rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
231 return rb_fiber_scheduler_io_wait(scheduler, io, RB_UINT2NUM(RUBY_IO_WRITABLE), Qnil);
234 VALUE
235 rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t length)
237 VALUE arguments[] = {
238 io, buffer, SIZET2NUM(length)
241 return rb_check_funcall(scheduler, id_io_read, 3, arguments);
244 VALUE
245 rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, VALUE buffer, size_t length, off_t offset)
247 VALUE arguments[] = {
248 io, buffer, SIZET2NUM(length), OFFT2NUM(offset)
251 return rb_check_funcall(scheduler, id_io_pread, 4, arguments);
254 VALUE
255 rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t length)
257 VALUE arguments[] = {
258 io, buffer, SIZET2NUM(length)
261 return rb_check_funcall(scheduler, id_io_write, 3, arguments);
264 VALUE
265 rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, VALUE buffer, size_t length, off_t offset)
267 VALUE arguments[] = {
268 io, buffer, SIZET2NUM(length), OFFT2NUM(offset)
271 return rb_check_funcall(scheduler, id_io_pwrite, 4, arguments);
274 VALUE
275 rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
277 VALUE buffer = rb_io_buffer_new(base, size, RB_IO_BUFFER_LOCKED);
279 VALUE result = rb_fiber_scheduler_io_read(scheduler, io, buffer, length);
281 rb_io_buffer_unlock(buffer);
282 rb_io_buffer_free(buffer);
284 return result;
287 VALUE
288 rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
290 VALUE buffer = rb_io_buffer_new((void*)base, size, RB_IO_BUFFER_LOCKED|RB_IO_BUFFER_READONLY);
292 VALUE result = rb_fiber_scheduler_io_write(scheduler, io, buffer, length);
294 rb_io_buffer_unlock(buffer);
295 rb_io_buffer_free(buffer);
297 return result;
300 VALUE
301 rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
303 VALUE arguments[] = {io};
305 return rb_check_funcall(scheduler, id_io_close, 1, arguments);
308 VALUE
309 rb_fiber_scheduler_address_resolve(VALUE scheduler, VALUE hostname)
311 VALUE arguments[] = {
312 hostname
315 return rb_check_funcall(scheduler, id_address_resolve, 1, arguments);