ÿØÿà JFIF ÿÛ „ ( %!1!%*+...983,7(-.-
PK ]SM M
raise-i.rinu [ U:RDoc::AnyMethod[iI"
raise:ETI"Fiber#raise;TF:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [
I"ERaises an exception in the fiber at the point at which the last ;TI"H+Fiber.yield+ was called. If the fiber has not been started or has ;TI"Ealready run to completion, raises +FiberError+. If the fiber is ;TI"Myielding, it is resumed. If it is transferring, it is transferred into. ;TI"0But if it is resuming, raises +FiberError+.;To:RDoc::Markup::BlankLine o;
; [
I"HWith no arguments, raises a +RuntimeError+. With a single +String+ ;TI"Qargument, raises a +RuntimeError+ with the string as a message. Otherwise, ;TI"Kthe first parameter should be the name of an +Exception+ class (or an ;TI"Hobject that returns an +Exception+ object when sent an +exception+ ;TI"Nmessage). The optional second parameter sets the message associated with ;TI"Qthe exception, and the third parameter is an array of callback information. ;TI"NExceptions are caught by the +rescue+ clause of begin...end ;TI"blocks.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"fiber.raise -> obj
fiber.raise(string) -> obj
fiber.raise(exception [, string [, array]]) -> obj
;T0[ I"(*args);T@FI"
Fiber;TcRDoc::NormalClass00PK ]Ѿ8
alive%3f-i.rinu [ U:RDoc::AnyMethod[iI"alive?:ETI"Fiber#alive?;TF:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [I"DReturns true if the fiber can still be resumed (or transferred ;TI"Hto). After finishing execution of the fiber block this method will ;TI"always return +false+.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"#fiber.alive? -> true or false
;T0[ I"();T@FI"
Fiber;TcRDoc::NormalClass00PK ]qw w resume-i.rinu [ U:RDoc::AnyMethod[iI"resume:ETI"Fiber#resume;TF:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [
I"HResumes the fiber from the point at which the last Fiber.yield was ;TI"=called, or starts running it if it is the first call to ;TI"B#resume. Arguments passed to resume will be the value of the ;TI"EFiber.yield expression or will be passed as block parameters to ;TI"4the fiber's block if this is the first #resume.;To:RDoc::Markup::BlankLine o;
; [ I"OAlternatively, when resume is called it evaluates to the arguments passed ;TI"@to the next Fiber.yield statement inside the fiber's block ;TI"@or to the block value if it runs to completion without any ;TI"Fiber.yield;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"$fiber.resume(args, ...) -> obj
;T0[ I"(*args);T@FI"
Fiber;TcRDoc::NormalClass00PK ]l m m cdesc-Fiber.rinu [ U:RDoc::NormalClass[iI"
Fiber:ET@I"Object;To:RDoc::Markup::Document:@parts[o;;[$o:RDoc::Markup::Paragraph;[
I"EFibers are primitives for implementing light weight cooperative ;TI"Mconcurrency in Ruby. Basically they are a means of creating code blocks ;TI"Lthat can be paused and resumed, much like threads. The main difference ;TI"Nis that they are never preempted and that the scheduling must be done by ;TI"#the programmer and not the VM.;To:RDoc::Markup::BlankLine o; ;[ I"OAs opposed to other stackless light weight concurrency models, each fiber ;TI"Jcomes with a stack. This enables the fiber to be paused from deeply ;TI"Dnested function calls within the fiber block. See the ruby(1) ;TI"9manpage to configure the size of the fiber stack(s).;T@o; ;[
I"KWhen a fiber is created it will not run automatically. Rather it must ;TI"?be explicitly asked to run using the Fiber#resume method. ;TI"FThe code running inside the fiber can give up control by calling ;TI"EFiber.yield in which case it yields control back to caller (the ;TI"!caller of the Fiber#resume).;T@o; ;[I"JUpon yielding or termination the Fiber returns the value of the last ;TI"executed expression;T@o; ;[I"For instance:;T@o:RDoc::Markup::Verbatim;[
I"fiber = Fiber.new do
;TI" Fiber.yield 1
;TI" 2
;TI" end
;TI"
;TI"puts fiber.resume
;TI"puts fiber.resume
;TI"puts fiber.resume
;T:@format0o; ;[I"produces;T@o;;[I"1
;TI"2
;TI"#FiberError: dead fiber called
;T;0o; ;[ I"HThe Fiber#resume method accepts an arbitrary number of parameters, ;TI"Dif it is the first call to #resume then they will be passed as ;TI"Eblock arguments. Otherwise they will be the return value of the ;TI"call to Fiber.yield;T@o; ;[I"
Example:;T@o;;[I""fiber = Fiber.new do |first|
;TI"& second = Fiber.yield first + 2
;TI" end
;TI"
;TI"puts fiber.resume 10
;TI"!puts fiber.resume 1_000_000
;TI"Kputs fiber.resume "The fiber will be dead before I can cause trouble"
;T;0o; ;[I"produces;T@o;;[I"12
;TI"
1000000
;TI"#FiberError: dead fiber called
;T;0S:RDoc::Markup::Heading:
leveli: textI"Non-blocking Fibers;T@o; ;[
I"LThe concept of non-blocking fiber was introduced in Ruby 3.0. ;TI"OA non-blocking fiber, when reaching a operation that would normally block ;TI"Mthe fiber (like sleep, or wait for another process or I/O) ;TI"Lwill yield control to other fibers and allow the scheduler to ;TI"Mhandle blocking and waking up (resuming) this fiber when it can proceed.;T@o; ;[ I"TFor a Fiber to behave as non-blocking, it need to be created in Fiber.new with ;TI"Jblocking: false (which is the default), and Fiber.scheduler ;TI"Nshould be set with Fiber.set_scheduler. If Fiber.scheduler is not set in ;TI"Qthe current thread, blocking and non-blocking fibers' behavior is identical.;T@o; ;[I"QRuby doesn't provide a scheduler class: it is expected to be implemented by ;TI":the user and correspond to Fiber::SchedulerInterface.;T@o; ;[I"SThere is also Fiber.schedule method, which is expected to immediately perform ;TI"Rthe given block in a non-blocking manner. Its actual implementation is up to ;TI"the scheduler.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0;0;0[ [ [ [[I"
class;T[[:public[ [:protected[ [:private[
[I"blocking?;TI"cont.c;T[I"current;T@}[I"current_scheduler;T@}[I"new;T@}[I"
schedule;T@}[I"scheduler;T@}[I"set_scheduler;T@}[I"
yield;T@}[I"
instance;T[[;[ [;[ [;[[I"alive?;T@}[I"backtrace;T@}[I"backtrace_locations;T@}[I"blocking?;T@}[I"inspect;T@}[I"
raise;T@}[I"resume;T@}[I" to_s;T@}[I"
transfer;T@}[ [U:RDoc::Context::Section[i 0o;;[ ;0;0[I"cont.c;T@mcRDoc::TopLevelPK ]: inspect-i.rinu [ U:RDoc::AnyMethod[iI"inspect:ETI"Fiber#inspect;TF:privateo:RDoc::Markup::Document:@parts[ :
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below000[ I"();T@FI"
Fiber;TcRDoc::NormalClass0[@FI" to_s;TPK ]|y current-c.rinu [ U:RDoc::AnyMethod[iI"current:ETI"Fiber::current;TT:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [I"IReturns the current fiber. If you are not running in the context of ;TI"4a fiber this method will return the root fiber.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"Fiber.current -> fiber
;T0[ I"();T@FI"
Fiber;TcRDoc::NormalClass00PK ]c`af f new-c.rinu [ U:RDoc::AnyMethod[iI"new:ETI"Fiber::new;TT:privateo:RDoc::Markup::Document:@parts[ o:RDoc::Markup::Paragraph; [I"TCreates new Fiber. Initially, the fiber is not running and can be resumed with ;TI"N#resume. Arguments to the first #resume call will be passed to the block:;To:RDoc::Markup::BlankLine o:RDoc::Markup::Verbatim; [I" f = Fiber.new do |initial|
;TI" current = initial
;TI" loop do
;TI"- puts "current: #{current.inspect}"
;TI" current = Fiber.yield
;TI" end
;TI" end
;TI".f.resume(100) # prints: current: 100
;TI"4f.resume(1, 2, 3) # prints: current: [1, 2, 3]
;TI".f.resume # prints: current: nil
;TI"# ... and so on ...
;T:@format0o;
; [I"WIf blocking: false is passed to Fiber.new, _and_ current thread ;TI"Vhas a Fiber.scheduler defined, the Fiber becomes non-blocking (see "Non-blocking ;TI"$Fibers" section in class docs).;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"9Fiber.new(blocking: false) { |*args| ... } -> fiber
;T0[ I"(*args);T@"FI"
Fiber;TcRDoc::NormalClass00PK ]-xY Y backtrace-i.rinu [ U:RDoc::AnyMethod[iI"backtrace:ETI"Fiber#backtrace;TF:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [I"XReturns the current execution stack of the fiber. +start+, +count+ and +end+ allow ;TI"+to select only parts of the backtrace.;To:RDoc::Markup::BlankLine o:RDoc::Markup::Verbatim; ['I"def level3
;TI" Fiber.yield
;TI" end
;TI"
;TI"def level2
;TI" level3
;TI" end
;TI"
;TI"def level1
;TI" level2
;TI" end
;TI"
;TI"f = Fiber.new { level1 }
;TI"
;TI",# It is empty before the fiber started
;TI"f.backtrace
;TI"#=> []
;TI"
;TI"f.resume
;TI"
;TI"f.backtrace
;TI"#=> ["test.rb:2:in `yield'", "test.rb:2:in `level3'", "test.rb:6:in `level2'", "test.rb:10:in `level1'", "test.rb:13:in `block in '"]
;TI".p f.backtrace(1) # start from the item 1
;TI"y#=> ["test.rb:2:in `level3'", "test.rb:6:in `level2'", "test.rb:10:in `level1'", "test.rb:13:in `block in '"]
;TI"5p f.backtrace(2, 2) # start from item 2, take 2
;TI"=#=> ["test.rb:6:in `level2'", "test.rb:10:in `level1'"]
;TI"2p f.backtrace(1..3) # take items from 1 to 3
;TI"V#=> ["test.rb:2:in `level3'", "test.rb:6:in `level2'", "test.rb:10:in `level1'"]
;TI"
;TI"f.resume
;TI"
;TI"-# It is nil after the fiber is finished
;TI"f.backtrace
;TI"#=> nil;T:@format0:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"fiber.backtrace -> array
fiber.backtrace(start) -> array
fiber.backtrace(start, count) -> array
fiber.backtrace(start..end) -> array
;T0[ I"(*args);T@4FI"
Fiber;TcRDoc::NormalClass00PK ];Zh h
yield-c.rinu [ U:RDoc::AnyMethod[iI"
yield:ETI"Fiber::yield;TT:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [
I"HYields control back to the context that resumed the fiber, passing ;TI"Galong any arguments that were passed to it. The fiber will resume ;TI";processing at this point when #resume is called next. ;TI"EAny arguments passed to the next #resume will be the value that ;TI".this Fiber.yield expression evaluates to.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"#Fiber.yield(args, ...) -> obj
;T0[ I"(*args);T@FI"
Fiber;TcRDoc::NormalClass00PK ] to_s-i.rinu [ U:RDoc::AnyMethod[iI" to_s:ETI"Fiber#to_s;TF:privateo:RDoc::Markup::Document:@parts[ :
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below000[[I"inspect;T@ I"();T@FI"
Fiber;TcRDoc::NormalClass00PK ] blocking%3f-c.rinu [ U:RDoc::AnyMethod[iI"blocking?:ETI"Fiber::blocking?;TT:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [I";Returns +false+ if the current fiber is non-blocking. ;TI"RFiber is non-blocking if it was created via passing blocking: false ;TI")to Fiber.new, or via Fiber.schedule.;To:RDoc::Markup::BlankLine o;
; [I"=If the current Fiber is blocking, the method returns 1. ;TI"HFuture developments may allow for situations where larger integers ;TI"could be returned.;T@o;
; [I"NNote that, even if the method returns +false+, Fiber behaves differently ;TI":only if Fiber.scheduler is set in the current thread.;T@o;
; [I"ESee the "Non-blocking fibers" section in class docs for details.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"#Fiber.blocking? -> false or 1
;T0[ I"();T@FI"
Fiber;TcRDoc::NormalClass00PK ]
transfer-i.rinu [ U:RDoc::AnyMethod[iI"
transfer:ETI"Fiber#transfer;TF:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [ I"GTransfer control to another fiber, resuming it from where it last ;TI"Fstopped or starting it if it was not resumed before. The calling ;TI"4fiber will be suspended much like in a call to ;TI"Fiber.yield.;To:RDoc::Markup::BlankLine o;
; [I"DThe fiber which receives the transfer call treats it much like ;TI"Ha resume call. Arguments passed to transfer are treated like those ;TI"passed to resume.;T@o;
; [I"LThe two style of control passing to and from fiber (one is #resume and ;TI"KFiber::yield, another is #transfer to and from fiber) can't be freely ;TI"mixed.;T@o:RDoc::Markup::List:
@type:BULLET:@items[o:RDoc::Markup::ListItem:@label0; [o;
; [ I"GIf the Fiber's lifecycle had started with transfer, it will never ;TI":be able to yield or be resumed control passing, only ;TI"Efinish or transfer back. (It still can resume other fibers that ;TI" are allowed to be resumed.);To;;0; [o;
; [I"DIf the Fiber's lifecycle had started with resume, it can yield ;TI"Eor transfer to another Fiber, but can receive control back only ;TI"Bthe way compatible with the way it was given away: if it had ;TI"Atransferred, it only can be transferred back, and if it had ;TI"Dyielded, it only can be resumed back. After that, it again can ;TI"transfer or yield.;T@o;
; [I"4If those rules are broken FiberError is raised.;T@o;
; [
I"CFor an individual Fiber design, yield/resume is easier to use ;TI"B(the Fiber just gives away control, it doesn't need to think ;TI"Iabout who the control is given to), while transfer is more flexible ;TI"Efor complex cases, allowing to build arbitrary graphs of Fibers ;TI"dependent on each other.;T@o;
; [I"
Example:;T@o:RDoc::Markup::Verbatim; [#I"Emanager = nil # For local var to be visible inside worker block
;TI"
;TI"1# This fiber would be started with transfer
;TI",# It can't yield, and can't be resumed
;TI"!worker = Fiber.new { |work|
;TI" puts "Worker: starts"
;TI"C puts "Worker: Performed #{work.inspect}, transferring back"
;TI"` # Fiber.yield # this would raise FiberError: attempt to yield on a not resumed fiber
;TI"j # manager.resume # this would raise FiberError: attempt to resume a resumed fiber (double resume)
;TI") manager.transfer(work.capitalize)
;TI"}
;TI"
;TI"/# This fiber would be started with resume
;TI"8# It can yield or transfer, and can be transferred
;TI"# back or resumed
;TI"manager = Fiber.new {
;TI" puts "Manager: starts"
;TI": puts "Manager: transferring 'something' to worker"
;TI"- result = worker.transfer('something')
;TI"9 puts "Manager: worker returned #{result.inspect}"
;TI"` # worker.resume # this would raise FiberError: attempt to resume a transferring fiber
;TI"\ Fiber.yield # this is OK, the fiber transferred from and to, now it can yield
;TI" puts "Manager: finished"
;TI"}
;TI"
;TI"!puts "Starting the manager"
;TI"manager.resume
;TI"!puts "Resuming the manager"
;TI"`# manager.transfer # this would raise FiberError: attempt to transfer to a yielding fiber
;TI"manager.resume
;T:@format0o;
; [I"produces;T@o;; [
I"Starting the manager
;TI"Manager: starts
;TI"1Manager: transferring 'something' to worker
;TI"Worker: starts
;TI"6Worker: Performed "something", transferring back
;TI"*Manager: worker returned "Something"
;TI"Resuming the manager
;TI"Manager: finished;T;0:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"&fiber.transfer(args, ...) -> obj
;T0[ I"(*args);T@jFI"
Fiber;TcRDoc::NormalClass00PK ]Yn
schedule-c.rinu [ U:RDoc::AnyMethod[iI"
schedule:ETI"Fiber::schedule;TT:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [I"XThe method is expected to immediately run the provided block of code in a ;TI"!separate non-blocking fiber.;To:RDoc::Markup::BlankLine o:RDoc::Markup::Verbatim; [I"puts "Go to sleep!"
;TI"
;TI"*Fiber.set_scheduler(MyScheduler.new)
;TI"
;TI"Fiber.schedule do
;TI" puts "Going to sleep"
;TI" sleep(1)
;TI" puts "I slept well"
;TI" end
;TI"
;TI"$puts "Wakey-wakey, sleepyhead"
;T:@format0o;
; [I"MAssuming MyScheduler is properly implemented, this program will produce:;T@o;; [
I"Go to sleep!
;TI"Going to sleep
;TI"Wakey-wakey, sleepyhead
;TI"...1 sec pause here...
;TI"I slept well
;T;
0o;
; [ I"S...e.g. on the first blocking operation inside the Fiber (sleep(1)), ;TI"Qthe control is yielded to the outside code (main fiber), and at the end ;TI"Sof that execution, the scheduler takes care of properly resuming all the ;TI"blocked fibers.;T@o;
; [ I"SNote that the behavior described above is how the method is expected ;TI"Sto behave, actual behavior is up to the current scheduler's implementation of ;TI"QFiber::SchedulerInterface#fiber method. Ruby doesn't enforce this method to ;TI""behave in any particular way.;T@o;
; [I"4If the scheduler is not set, the method raises ;TI"8RuntimeError (No scheduler is available!).;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"-Fiber.schedule { |*args| ... } -> fiber
;T0[ I"(*args);T@7FI"
Fiber;TcRDoc::NormalClass00PK ]S^ current_scheduler-c.rinu [ U:RDoc::AnyMethod[iI"current_scheduler:ETI"Fiber::current_scheduler;TT:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [I"dReturns the Fiber scheduler, that was last set for the current thread with Fiber.set_scheduler ;TI"6if and only if the current fiber is non-blocking.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"+Fiber.current_scheduler -> obj or nil
;T0[ I"();T@FI"
Fiber;TcRDoc::NormalClass00PK ] scheduler-c.rinu [ U:RDoc::AnyMethod[iI"scheduler:ETI"Fiber::scheduler;TT:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Verbatim; [I"eReturns the Fiber scheduler, that was last set for the current thread with Fiber.set_scheduler.
;TI"[Returns +nil+ if no scheduler is set (which is the default), and non-blocking fibers'
;T:@format0o:RDoc::Markup::Paragraph; [I")# behavior is the same as blocking.;To;
; [I"_(see "Non-blocking fibers" section in class docs for details about the scheduler concept).;T;0:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"#Fiber.scheduler -> obj or nil
;T0[ I"();T@FI"
Fiber;TcRDoc::NormalClass00PK ]t& SchedulerInterface/fiber-i.rinu [ U:RDoc::AnyMethod[iI"
fiber:ETI"$Fiber::SchedulerInterface#fiber;TF:privateo:RDoc::Markup::Document:@parts[
o:RDoc::Markup::Paragraph; [I"ZImplementation of the Fiber.schedule. The method is expected to immediately ;TI"\run the given block of code in a separate non-blocking fiber, and to return that Fiber.;To:RDoc::Markup::BlankLine o;
; [I")Minimal suggested implementation is:;T@o:RDoc::Markup::Verbatim; [
I"def fiber(&block)
;TI"2 fiber = Fiber.new(blocking: false, &block)
;TI" fiber.resume
;TI"
fiber
;TI"end;T:@format0:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"fiber(&block)
;T0[ I"();T@FI"SchedulerInterface;TcRDoc::NormalClass00PK ]t _zi i $ SchedulerInterface/process_wait-i.rinu [ U:RDoc::AnyMethod[iI"process_wait:ETI"+Fiber::SchedulerInterface#process_wait;TF:privateo:RDoc::Markup::Document:@parts[
o:RDoc::Markup::Paragraph; [I"OInvoked by Process::Status.wait in order to wait for a specified process. ;TI";See that method description for arguments description.;To:RDoc::Markup::BlankLine o;
; [I"&Suggested minimal implementation:;T@o:RDoc::Markup::Verbatim; [I"Thread.new do
;TI"( Process::Status.wait(pid, flags)
;TI"end.value
;T:@format0o;
; [I"KThis hook is optional: if it is not present in the current scheduler, ;TI";Process::Status.wait will behave as a blocking method.;T@o;
; [I"3Expected to return a Process::Status instance.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"process_wait(pid, flags)
;T0[ I"();T@FI"SchedulerInterface;TcRDoc::NormalClass00PK ]}P SchedulerInterface/io_write-i.rinu [ U:RDoc::AnyMethod[iI"
io_write:ETI"'Fiber::SchedulerInterface#io_write;TF:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [I">Invoked by IO#write to write +length+ bytes to +io+ from ;TI"0from a specified +buffer+ (see IO::Buffer).;To:RDoc::Markup::BlankLine o;
; [
I"DThe +length+ argument is the "(minimum) length to be written". ;TI"OIf the IO buffer size is 8KiB, but the +length+ specified is 1024 (1KiB), ;TI">at most 8KiB will be written, but at least 1KiB will be. ;TI"RGenerally, the only case where less data than +length+ will be written is if ;TI"(there is an error writing the data.;T@o;
; [I"NSpecifying a +length+ of 0 is valid and means try writing at least once, ;TI"as much data as possible.;T@o;
; [I"LSuggested implementation should try to write to +io+ in a non-blocking ;TI"Qmanner and call #io_wait if the +io+ is not ready (which will yield control ;TI"to other fibers).;T@o;
; [I"SSee IO::Buffer for an interface available to get data from buffer efficiently.;T@o;
; [I"ZExpected to return number of bytes written, or, in case of an error, -errno ;TI";(negated number corresponding to system's error code).;T@o;
; [I"4The method should be considered _experimental_.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I">io_write(io, buffer, length) -> written length or -errno
;T0[ I"();T@*FI"SchedulerInterface;TcRDoc::NormalClass00PK ]mo
. SchedulerInterface/cdesc-SchedulerInterface.rinu [ U:RDoc::NormalClass[iI"SchedulerInterface:ETI"Fiber::SchedulerInterface;TI"Object;To:RDoc::Markup::Document:@parts[o;;[o:RDoc::Markup::Paragraph;[ I"VThis is not an existing class, but documentation of the interface that Scheduler ;TI"hobject should comply to in order to be used as argument to Fiber.scheduler and handle non-blocking ;TI"]fibers. See also the "Non-blocking fibers" section in Fiber class docs for explanations ;TI"of some concepts.;To:RDoc::Markup::BlankLine o; ;[I"BScheduler's behavior and usage are expected to be as follows:;T@o:RDoc::Markup::List:
@type:BULLET:@items[ o:RDoc::Markup::ListItem:@label0;[o; ;[I"XWhen the execution in the non-blocking Fiber reaches some blocking operation (like ;TI"Vsleep, wait for a process, or a non-ready I/O), it calls some of the scheduler's ;TI" hook methods, listed below.;To;;0;[o; ;[I"ZScheduler somehow registers what the current fiber is waiting on, and yields control ;TI"[to other fibers with Fiber.yield (so the fiber would be suspended while expecting its ;TI"Bwait to end, and other fibers in the same thread can perform);To;;0;[o; ;[I"XAt the end of the current thread execution, the scheduler's method #close is called;To;;0;[o; ;[I"XThe scheduler runs into a wait loop, checking all the blocked fibers (which it has ;TI"Tregistered on hook calls) and resuming them when the awaited resource is ready ;TI",(e.g. I/O ready or sleep time elapsed).;T@o; ;[I"VA typical implementation would probably rely for this closing loop on a gem like ;TI"CEventMachine[https://github.com/eventmachine/eventmachine] or ;TI".Async[https://github.com/socketry/async].;T@o; ;[I"LThis way concurrent execution will be achieved transparently for every ;TI"individual Fiber's code.;T@o; ;[I"Hook methods are:;T@o;;;
;[o;;0;[o; ;[I"io_wait, #io_read, and #io_write;To;;0;[o; ;[I"#process_wait;To;;0;[o; ;[I"#kernel_sleep;To;;0;[o; ;[I"#timeout_after;To;;0;[o; ;[I"#address_resolve;To;;0;[o; ;[I"#block and #unblock;To;;0;[o; ;[I"Z(the list is expanded as Ruby developers make more methods having non-blocking calls);T@o; ;[
I"[When not specified otherwise, the hook implementations are mandatory: if they are not ;TI"`implemented, the methods trying to call hook will fail. To provide backward compatibility, ;TI"]in the future hooks will be optional (if they are not implemented, due to the scheduler ;TI"]being created for the older Ruby version, the code which needs this hook will not fail, ;TI"1and will just behave in a blocking fashion).;T@o; ;[I"_It is also strongly recommended that the scheduler implements the #fiber method, which is ;TI"$delegated to by Fiber.schedule.;T@o; ;[I"RSample _toy_ implementation of the scheduler can be found in Ruby's code, in ;TI"%test/fiber/scheduler.rb;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0;0;0[ [ [ [[I"
class;T[[:public[ [:protected[ [:private[ [I"
instance;T[[;[ [;[ [;[[I"address_resolve;TI"cont.c;T[I"
block;T@[I"
close;T@[I"
fiber;T@[I"io_read;T@[I"io_wait;T@[I"
io_write;T@[I"kernel_sleep;T@[I"process_wait;T@[I"timeout_after;T@[I"unblock;T@[ [U:RDoc::Context::Section[i 0o;;[ ;0;0[I"cont.c;TI"
Fiber;TcRDoc::NormalClassPK ]g ' SchedulerInterface/address_resolve-i.rinu [ U:RDoc::AnyMethod[iI"address_resolve:ETI".Fiber::SchedulerInterface#address_resolve;TF:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [I"LInvoked by any method that performs a non-reverse DNS lookup. The most ;TI"Fnotable method is Addrinfo.getaddrinfo, but there are many other.;To:RDoc::Markup::BlankLine o;
; [I"NThe method is expected to return an array of strings corresponding to ip ;TI"Qaddresses the +hostname+ is resolved to, or +nil+ if it can not be resolved.;T@o;
; [I"7Fairly exhaustive list of all possible call-sites:;T@o:RDoc::Markup::List:
@type:BULLET:@items[o:RDoc::Markup::ListItem:@label0; [o;
; [I"Addrinfo.getaddrinfo;To;;0; [o;
; [I"Addrinfo.tcp;To;;0; [o;
; [I"Addrinfo.udp;To;;0; [o;
; [I"Addrinfo.ip;To;;0; [o;
; [I"Addrinfo.new;To;;0; [o;
; [I"Addrinfo.marshal_load;To;;0; [o;
; [I"SOCKSSocket.new;To;;0; [o;
; [I"TCPServer.new;To;;0; [o;
; [I"TCPSocket.new;To;;0; [o;
; [I"IPSocket.getaddress;To;;0; [o;
; [I"TCPSocket.gethostbyname;To;;0; [o;
; [I"UDPSocket#connect;To;;0; [o;
; [I"UDPSocket#bind;To;;0; [o;
; [I"UDPSocket#send;To;;0; [o;
; [I"Socket.getaddrinfo;To;;0; [o;
; [I"Socket.gethostbyname;To;;0; [o;
; [I"Socket.pack_sockaddr_in;To;;0; [o;
; [I"Socket.sockaddr_in;To;;0; [o;
; [I"Socket.unpack_sockaddr_in;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I":address_resolve(hostname) -> array_of_strings or nil
;T0[ I"();T@xFI"SchedulerInterface;TcRDoc::NormalClass00PK ]v9 9 SchedulerInterface/close-i.rinu [ U:RDoc::AnyMethod[iI"
close:ETI"$Fiber::SchedulerInterface#close;TF:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [I"WCalled when the current thread exits. The scheduler is expected to implement this ;TI"Mmethod in order to allow all waiting fibers to finalize their execution.;To:RDoc::Markup::BlankLine o;
; [I"TThe suggested pattern is to implement the main event loop in the #close method.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below000[ I"();T@FI"SchedulerInterface;TcRDoc::NormalClass00PK ]:) SchedulerInterface/unblock-i.rinu [ U:RDoc::AnyMethod[iI"unblock:ETI"&Fiber::SchedulerInterface#unblock;TF:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [I"VInvoked to wake up Fiber previously blocked with #block (for example, Mutex#lock ;TI"Mcalls #block and Mutex#unlock calls #unblock). The scheduler should use ;TI"Bthe +fiber+ parameter to understand which fiber is unblocked.;To:RDoc::Markup::BlankLine o;
; [I"T+blocker+ is what was awaited for, but it is informational only (for debugging ;TI"Vand logging), and it is not guaranteed to be the same value as the +blocker+ for ;TI"#block.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"unblock(blocker, fiber)
;T0[ I"();T@FI"SchedulerInterface;TcRDoc::NormalClass00PK ]ՈW % SchedulerInterface/timeout_after-i.rinu [ U:RDoc::AnyMethod[iI"timeout_after:ETI",Fiber::SchedulerInterface#timeout_after;TF:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [I"NInvoked by Timeout.timeout to execute the given +block+ within the given ;TI"O+duration+. It can also be invoked directly by the scheduler or user code.;To:RDoc::Markup::BlankLine o;
; [
I"IAttempt to limit the execution time of a given +block+ to the given ;TI"P+duration+ if possible. When a non-blocking operation causes the +block+'s ;TI"Jexecution time to exceed the specified +duration+, that non-blocking ;TI"Poperation should be interrupted by raising the specified +exception_class+ ;TI"6constructed with the given +exception_arguments+.;T@o;
; [
I"PGeneral execution timeouts are often considered risky. This implementation ;TI"Qwill only interrupt non-blocking operations. This is by design because it's ;TI"Eexpected that non-blocking operations can fail for a variety of ;TI"Qunpredictable reasons, so applications should already be robust in handling ;TI"2these conditions and by implication timeouts.;T@o;
; [ I"MHowever, as a result of this design, if the +block+ does not invoke any ;TI"Lnon-blocking operations, it will be impossible to interrupt it. If you ;TI"Hdesire to provide predictable points for timeouts, consider adding ;TI"+sleep(0)+.;T@o;
; [I"HIf the block is executed successfully, its result will be returned.;T@o;
; [I">The exception will typically be raised using Fiber#raise.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"_timeout_after(duration, exception_class, *exception_arguments, &block) -> result of block
;T0[ I"();T@*FI"SchedulerInterface;TcRDoc::NormalClass00PK ] SchedulerInterface/block-i.rinu [ U:RDoc::AnyMethod[iI"
block:ETI"$Fiber::SchedulerInterface#block;TF:privateo:RDoc::Markup::Document:@parts[
o:RDoc::Markup::Paragraph; [I"PInvoked by methods like Thread.join, and by Mutex, to signify that current ;TI"RFiber is blocked until further notice (e.g. #unblock) or until +timeout+ has ;TI"
elapsed.;To:RDoc::Markup::BlankLine o;
; [I"P+blocker+ is what we are waiting on, informational only (for debugging and ;TI"6logging). There are no guarantee about its value.;T@o;
; [I"OExpected to return boolean, specifying whether the blocking operation was ;TI"successful or not.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"#block(blocker, timeout = nil)
;T0[ I"();T@FI"SchedulerInterface;TcRDoc::NormalClass00PK ]0r SchedulerInterface/io_read-i.rinu [ U:RDoc::AnyMethod[iI"io_read:ETI"&Fiber::SchedulerInterface#io_read;TF:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [I"JInvoked by IO#read to read +length+ bytes from +io+ into a specified ;TI"+buffer+ (see IO::Buffer).;To:RDoc::Markup::BlankLine o;
; [
I"?The +length+ argument is the "minimum length to be read". ;TI"MIf the IO buffer size is 8KiB, but the +length+ is +1024+ (1KiB), up to ;TI"48KiB might be read, but at least 1KiB will be. ;TI"OGenerally, the only case where less data than +length+ will be read is if ;TI"(there is an error reading the data.;T@o;
; [I"MSpecifying a +length+ of 0 is valid and means try reading at least once ;TI"#and return any available data.;T@o;
; [I"MSuggested implementation should try to read from +io+ in a non-blocking ;TI"Qmanner and call #io_wait if the +io+ is not ready (which will yield control ;TI"to other fibers).;T@o;
; [I">See IO::Buffer for an interface available to return data.;T@o;
; [I"WExpected to return number of bytes read, or, in case of an error, -errno ;TI";(negated number corresponding to system's error code).;T@o;
; [I"4The method should be considered _experimental_.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I":io_read(io, buffer, length) -> read length or -errno
;T0[ I"();T@*FI"SchedulerInterface;TcRDoc::NormalClass00PK ]V $ SchedulerInterface/kernel_sleep-i.rinu [ U:RDoc::AnyMethod[iI"kernel_sleep:ETI"+Fiber::SchedulerInterface#kernel_sleep;TF:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [
I"HInvoked by Kernel#sleep and Mutex#sleep and is expected to provide ;TI"Oan implementation of sleeping in a non-blocking way. Implementation might ;TI"Mregister the current fiber in some list of "which fiber wait until what ;TI"Jmoment", call Fiber.yield to pass control, and then in #close resume ;TI".the fibers whose wait period has elapsed.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I""kernel_sleep(duration = nil)
;T0[ I"();T@FI"SchedulerInterface;TcRDoc::NormalClass00PK ]4 SchedulerInterface/io_wait-i.rinu [ U:RDoc::AnyMethod[iI"io_wait:ETI"&Fiber::SchedulerInterface#io_wait;TF:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [I"OInvoked by IO#wait, IO#wait_readable, IO#wait_writable to ask whether the ;TI"?specified descriptor is ready for specified events within ;TI"the specified +timeout+.;To:RDoc::Markup::BlankLine o;
; [I"Q+events+ is a bit mask of IO::READABLE, IO::WRITABLE, and ;TI"IO::PRIORITY.;T@o;
; [ I"OSuggested implementation should register which Fiber is waiting for which ;TI"Lresources and immediately calling Fiber.yield to pass control to other ;TI"Nfibers. Then, in the #close method, the scheduler might dispatch all the ;TI",I/O resources to fibers waiting for it.;T@o;
; [I"HExpected to return the subset of events that are ready immediately.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I""io_wait(io, events, timeout)
;T0[ I"();T@FI"SchedulerInterface;TcRDoc::NormalClass00PK ]X blocking%3f-i.rinu [ U:RDoc::AnyMethod[iI"blocking?:ETI"Fiber#blocking?;TF:privateo:RDoc::Markup::Document:@parts[
o:RDoc::Markup::Paragraph; [I"BReturns +true+ if +fiber+ is blocking and +false+ otherwise. ;TI"RFiber is non-blocking if it was created via passing blocking: false ;TI")to Fiber.new, or via Fiber.schedule.;To:RDoc::Markup::BlankLine o;
; [I"RNote that, even if the method returns +false+, the fiber behaves differently ;TI":only if Fiber.scheduler is set in the current thread.;T@o;
; [I"ESee the "Non-blocking fibers" section in class docs for details.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"&fiber.blocking? -> true or false
;T0[ I"();T@FI"
Fiber;TcRDoc::NormalClass00PK ]RF set_scheduler-c.rinu [ U:RDoc::AnyMethod[iI"set_scheduler:ETI"Fiber::set_scheduler;TT:privateo:RDoc::Markup::Document:@parts[
o:RDoc::Markup::Paragraph; [
I"\Sets the Fiber scheduler for the current thread. If the scheduler is set, non-blocking ;TI"Wfibers (created by Fiber.new with blocking: false, or by Fiber.schedule) ;TI"\call that scheduler's hook methods on potentially blocking operations, and the current ;TI"\thread will call scheduler's +close+ method on finalization (allowing the scheduler to ;TI".properly manage all non-finished fibers).;To:RDoc::Markup::BlankLine o;
; [I"_+scheduler+ can be an object of any class corresponding to Fiber::SchedulerInterface. Its ;TI"&implementation is up to the user.;T@o;
; [I">See also the "Non-blocking fibers" section in class docs.;T:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"1Fiber.set_scheduler(scheduler) -> scheduler
;T0[ I" (p1);T@FI"
Fiber;TcRDoc::NormalClass00PK ]&Y Y backtrace_locations-i.rinu [ U:RDoc::AnyMethod[iI"backtrace_locations:ETI"Fiber#backtrace_locations;TF:privateo:RDoc::Markup::Document:@parts[o:RDoc::Markup::Paragraph; [I"HLike #backtrace, but returns each line of the execution stack as a ;TI"KThread::Backtrace::Location. Accepts the same arguments as #backtrace.;To:RDoc::Markup::BlankLine o:RDoc::Markup::Verbatim; [I"#f = Fiber.new { Fiber.yield }
;TI"f.resume
;TI"'loc = f.backtrace_locations.first
;TI"loc.label #=> "yield"
;TI"loc.path #=> "test.rb"
;TI"loc.lineno #=> 1;T:@format0:
@fileI"cont.c;T:0@omit_headings_from_table_of_contents_below0I"fiber.backtrace_locations -> array
fiber.backtrace_locations(start) -> array
fiber.backtrace_locations(start, count) -> array
fiber.backtrace_locations(start..end) -> array
;T0[ I"(*args);T@FI"
Fiber;TcRDoc::NormalClass00PK ]SM M
raise-i.rinu [ PK ]Ѿ8
alive%3f-i.rinu [ PK ]qw w resume-i.rinu [ PK ]l m m @ cdesc-Fiber.rinu [ PK ]: inspect-i.rinu [ PK ]|y current-c.rinu [ PK ]c`af f new-c.rinu [ PK ]-xY Y " backtrace-i.rinu [ PK ];Zh h
) yield-c.rinu [ PK ] + to_s-i.rinu [ PK ] , blocking%3f-c.rinu [ PK ]
0 transfer-i.rinu [ PK ]Yn
? schedule-c.rinu [ PK ]S^ xF current_scheduler-c.rinu [ PK ] H scheduler-c.rinu [ PK ]t& }K SchedulerInterface/fiber-i.rinu [ PK ]t _zi i $ N SchedulerInterface/process_wait-i.rinu [ PK ]}P aR SchedulerInterface/io_write-i.rinu [ PK ]mo
. wX SchedulerInterface/cdesc-SchedulerInterface.rinu [ PK ]g ' f SchedulerInterface/address_resolve-i.rinu [ PK ]v9 9 Ym SchedulerInterface/close-i.rinu [ PK ]:) o SchedulerInterface/unblock-i.rinu [ PK ]ՈW % 2s SchedulerInterface/timeout_after-i.rinu [ PK ] dz SchedulerInterface/block-i.rinu [ PK ]0r } SchedulerInterface/io_read-i.rinu [ PK ]V $ SchedulerInterface/kernel_sleep-i.rinu [ PK ]4 SchedulerInterface/io_wait-i.rinu [ PK ]X blocking%3f-i.rinu [ PK ]RF # set_scheduler-c.rinu [ PK ]&Y Y : backtrace_locations-i.rinu [ PK
ە