2 # The Scheduler provides an interface to the VM, allowing the VM to tell ruby
3 # when various operations have completed. The operation is performed in the
4 # background with respect to running ruby code.
6 # All methods of Scheduler return right away. When the operation has
7 # completed, the Channel is sent a value. Using this setup we can easily
8 # write thread aware code that doesn't block the entire process, only
9 # a single ruby Thread.
11 # == Where should I use calls to Scheduler?
13 # Rubinius uses green threads, so it must never perform a blocking C call as
14 # that will block all ruby threads.
16 # In the case of IO#read, the C read(2) will block until enough bytes are
17 # ready to be read. Instead of directly calling read(2), send_on_readable is
18 # called and waits in the VM until the file descriptor is ready to be read.
23 # In +microseconds+ send the +tag+ to +channel+. Returns an event id for
24 # use with #cancel. This is used to implement sleep. For example:
27 # Scheduler.send_in_microseconds chan, 1000, :hello
29 # # 1 second later :hello is printed
31 # The chan.receive appears to block the current thread, waking up when there
32 # is a value on the channel. To the caller of this code it appears that
33 # they have slept for 1 seconds.
35 def self.send_in_microseconds(channel, microseconds, tag)
36 Ruby.primitive :channel_send_in_microseconds
37 raise PrimitiveFailure, "primitive failed"
41 # Same as send_in_microseconds, but the 2nd argument is seconds, not
44 def self.send_in_seconds(chan, seconds, tag)
45 Ruby.primitive :channel_send_in_seconds
46 raise PrimitiveFailure, "primitive failed"
50 # Instructs the VM to send a value to +channel+ when the IO object +io+ is
51 # readable. +buffer+ and +nbytes+ are optional, and should be set to nil if
52 # you don't wish to use them. Returns an event id, for use with #cancel
54 # There are 2 modes of operation, depending on if +buffer+ is nil or not.
56 # If +buffer+ is nil the +channel+ is sent the file descriptor for +io+.
57 # This can be used to wait on multiple IO objects with one channel and
58 # figure out which IO object was ready given the return value of #receive3
60 # The second mode is when +buffer+ is an IO::Buffer object. In this mode
61 # when +io+ becomes readable +nbytes+ bytes are read from IO and stored into
62 # +buffer+. Note that this is done using the read(2) C function and thus
63 # +nbytes+ is the maximum number of bytes that will be read, not the actual
64 # number read. The value sent to the channel is the actual number of bytes
65 # read as a Fixnum object.
67 # If an error occurs while reading in the 2nd mode, the value sent to the
68 # channel is a SystemCallError representing the failure in read(2).
70 # See IO#sysread in kernel/core/io.rb for a simple example.
72 def self.send_on_readable(chan, io, buffer, nbytes)
73 Ruby.primitive :channel_send_on_readable
74 raise PrimitiveFailure, "primitive failed"
78 # Instructs the VM to send +nil+ to +channel+ when +io+ is writable.
79 # Returns an event id, for use with #cancel
81 def self.send_on_writable(chan, io)
82 Ruby.primitive :channel_send_on_readable
83 raise PrimitiveFailure, "primitive failed"
87 # Instructs the VM to send a Thread object to +chan+ when UNIX signal
88 # +signum+, a Fixnum, is received by the process. Returns an event id, for
91 # The Thread object that will be sent is the Thread object that was running
92 # when the signal was received by the process.
97 # Scheduler.send_on_signal chan, 2 # 2 is SIGINT
98 # thr = Thread.new { some_long_operation }
99 # val = chan.receive # blocks Thread.current until SIGINT is received
100 # # => #<Thread:0x....>
101 # p val == thr # => true
103 # Unlike all other +send_on+ methods, this one is persistant. Calling
104 # +send_on_signal+ once for SIGINT will cause all future SIGINTs to send a
107 def self.send_on_signal(channel, signum)
108 Ruby.primitive :channel_send_on_signal
109 raise PrimitiveFailure, "primitive failed"
113 # Wrapper for the primitive, use +send_on_stopped+
115 def self.send_on_stopped_prim(channel, pid, flags)
116 Ruby.primitive :channel_send_on_stopped
117 raise PrimitiveFailure, "primitive failed"
121 # Instructs the VM to send a value to +channel+ when process +pid+ is no
122 # longer running. This is used to implement Process.wait. Returns an event
123 # id for use with #cancel.
125 # Flags is a Fixnum and currently accepts only Process::WNOHANG to indicate
126 # send_on_stopped should send nil if the process is still running instead of
129 # The value sent to the channel is either:
130 # * A tuple containing +pid+ and +exit_status+
131 # * +false+ if there is no process +pid+
132 # * nil if flags indicated NOHANG
134 def self.send_on_stopped(channel, pid=-1, flags=0)
135 send_on_stopped_prim(channel, pid, flags)
139 # All +send_on+ methods return an event id for the registered event. That
140 # id can be passed to #cancel to inform the VM that we're not longer
141 # interested in the event. No value is sent to the channel that was
145 Ruby.primitive :scheduler_cancel
146 raise PrimitiveFailure, "primitive failed"