2020-08-19 21:51:45 -04:00
/**********************************************************************
scheduler . c
$ Author $
Copyright ( C ) 2020 Samuel Grant Dawson Williams
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-10-15 21:25:58 -04:00
# include "vm_core.h"
2020-08-19 21:51:45 -04:00
# include "internal/scheduler.h"
# include "ruby/io.h"
2020-09-19 19:34:02 -04:00
static ID id_close ;
2020-09-17 08:30:40 -04:00
static ID id_block ;
static ID id_unblock ;
2020-09-19 19:34:02 -04:00
static ID id_kernel_sleep ;
2020-12-07 15:29:09 -05:00
static ID id_process_wait ;
2020-09-19 19:34:02 -04:00
2020-08-19 21:51:45 -04:00
static ID id_io_read ;
static ID id_io_write ;
static ID id_io_wait ;
void
Init_Scheduler ( void )
{
2020-09-19 19:34:02 -04:00
id_close = rb_intern_const ( " close " ) ;
2020-09-17 08:30:40 -04:00
id_block = rb_intern_const ( " block " ) ;
id_unblock = rb_intern_const ( " unblock " ) ;
2020-09-19 19:34:02 -04:00
id_kernel_sleep = rb_intern_const ( " kernel_sleep " ) ;
2020-12-07 15:29:09 -05:00
id_process_wait = rb_intern_const ( " process_wait " ) ;
2020-09-19 19:34:02 -04:00
2020-08-19 21:51:45 -04:00
id_io_read = rb_intern_const ( " io_read " ) ;
id_io_write = rb_intern_const ( " io_write " ) ;
id_io_wait = rb_intern_const ( " io_wait " ) ;
}
2020-10-15 21:25:58 -04:00
VALUE
2020-12-05 00:46:34 -05:00
rb_scheduler_get ( void )
2020-10-15 21:25:58 -04:00
{
rb_thread_t * thread = GET_THREAD ( ) ;
VM_ASSERT ( thread ) ;
return thread - > scheduler ;
}
VALUE
rb_scheduler_set ( VALUE scheduler )
{
rb_thread_t * thread = GET_THREAD ( ) ;
VM_ASSERT ( thread ) ;
// 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.
if ( thread - > scheduler ! = Qnil ) {
rb_scheduler_close ( thread - > scheduler ) ;
}
thread - > scheduler = scheduler ;
return thread - > scheduler ;
}
static VALUE
rb_threadptr_scheduler_current ( rb_thread_t * thread )
{
VM_ASSERT ( thread ) ;
if ( thread - > blocking = = 0 ) {
return thread - > scheduler ;
} else {
return Qnil ;
}
}
VALUE
2020-12-05 00:46:34 -05:00
rb_scheduler_current ( void )
2020-10-15 21:25:58 -04:00
{
return rb_threadptr_scheduler_current ( GET_THREAD ( ) ) ;
}
VALUE rb_thread_scheduler_current ( VALUE thread )
{
return rb_threadptr_scheduler_current ( rb_thread_ptr ( thread ) ) ;
}
2020-10-01 00:44:29 -04:00
VALUE
rb_scheduler_close ( VALUE scheduler )
2020-09-19 19:34:02 -04:00
{
2020-09-30 20:42:58 -04:00
if ( rb_respond_to ( scheduler , id_close ) ) {
return rb_funcall ( scheduler , id_close , 0 ) ;
}
2020-10-01 00:45:50 -04:00
return Qnil ;
2020-09-19 19:34:02 -04:00
}
2020-08-19 21:51:45 -04:00
VALUE
2020-10-01 00:44:29 -04:00
rb_scheduler_timeout ( struct timeval * timeout )
{
2020-08-19 21:51:45 -04:00
if ( timeout ) {
return rb_float_new ( ( double ) timeout - > tv_sec + ( 0.000001f * timeout - > tv_usec ) ) ;
}
return Qnil ;
}
2020-10-01 00:44:29 -04:00
VALUE
rb_scheduler_kernel_sleep ( VALUE scheduler , VALUE timeout )
2020-08-19 21:51:45 -04:00
{
return rb_funcall ( scheduler , id_kernel_sleep , 1 , timeout ) ;
}
2020-10-01 00:44:29 -04:00
VALUE
rb_scheduler_kernel_sleepv ( VALUE scheduler , int argc , VALUE * argv )
2020-08-19 21:51:45 -04:00
{
return rb_funcallv ( scheduler , id_kernel_sleep , argc , argv ) ;
}
2020-12-07 15:29:09 -05:00
int
rb_scheduler_supports_process_wait ( VALUE scheduler )
{
return rb_respond_to ( scheduler , id_process_wait ) ;
}
VALUE
rb_scheduler_process_wait ( VALUE scheduler , rb_pid_t pid , int flags )
{
return rb_funcall ( scheduler , id_process_wait , 2 , PIDT2NUM ( pid ) , RB_INT2NUM ( flags ) ) ;
}
2020-10-01 00:44:29 -04:00
VALUE
rb_scheduler_block ( VALUE scheduler , VALUE blocker , VALUE timeout )
2020-09-05 00:26:24 -04:00
{
2020-09-20 17:54:08 -04:00
return rb_funcall ( scheduler , id_block , 2 , blocker , timeout ) ;
2020-09-05 00:26:24 -04:00
}
2020-10-01 00:44:29 -04:00
VALUE
rb_scheduler_unblock ( VALUE scheduler , VALUE blocker , VALUE fiber )
2020-09-05 00:26:24 -04:00
{
2020-09-17 08:30:40 -04:00
return rb_funcall ( scheduler , id_unblock , 2 , blocker , fiber ) ;
2020-09-05 00:26:24 -04:00
}
2020-10-01 00:44:29 -04:00
VALUE
rb_scheduler_io_wait ( VALUE scheduler , VALUE io , VALUE events , VALUE timeout )
2020-08-19 21:51:45 -04:00
{
return rb_funcall ( scheduler , id_io_wait , 3 , io , events , timeout ) ;
}
2020-10-01 00:44:29 -04:00
VALUE
rb_scheduler_io_wait_readable ( VALUE scheduler , VALUE io )
2020-08-19 21:51:45 -04:00
{
return rb_scheduler_io_wait ( scheduler , io , RB_UINT2NUM ( RUBY_IO_READABLE ) , Qnil ) ;
}
2020-10-01 00:44:29 -04:00
VALUE
rb_scheduler_io_wait_writable ( VALUE scheduler , VALUE io )
2020-08-19 21:51:45 -04:00
{
return rb_scheduler_io_wait ( scheduler , io , RB_UINT2NUM ( RUBY_IO_WRITABLE ) , Qnil ) ;
}
2020-10-01 00:44:29 -04:00
int
rb_scheduler_supports_io_read ( VALUE scheduler )
2020-08-19 21:51:45 -04:00
{
2020-08-20 08:53:08 -04:00
return rb_respond_to ( scheduler , id_io_read ) ;
2020-08-19 21:51:45 -04:00
}
2020-10-01 00:44:29 -04:00
VALUE
rb_scheduler_io_read ( VALUE scheduler , VALUE io , VALUE buffer , size_t offset , size_t length )
2020-08-20 08:53:08 -04:00
{
return rb_funcall ( scheduler , id_io_read , 4 , io , buffer , SIZET2NUM ( offset ) , SIZET2NUM ( length ) ) ;
}
2020-10-01 00:44:29 -04:00
int
rb_scheduler_supports_io_write ( VALUE scheduler )
2020-08-20 08:53:08 -04:00
{
return rb_respond_to ( scheduler , id_io_write ) ;
}
2020-10-01 00:44:29 -04:00
VALUE
rb_scheduler_io_write ( VALUE scheduler , VALUE io , VALUE buffer , size_t offset , size_t length )
2020-08-19 21:51:45 -04:00
{
// We should ensure string has capacity to receive data, and then resize it afterwards.
2020-08-20 08:53:08 -04:00
return rb_funcall ( scheduler , id_io_write , 4 , io , buffer , SIZET2NUM ( offset ) , SIZET2NUM ( length ) ) ;
2020-08-19 21:51:45 -04:00
}