ÿØÿà JFIF    ÿÛ „ ( %!1!%*+...983,7(-.- PK]SMM 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::BlankLineo; ; [ 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]qww 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::BlankLineo; ; [ 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 mmcdesc-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::BlankLineo; ;[ 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[i0o;;[;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`affnew-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::BlankLineo: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]-xYYbacktrace-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::BlankLineo: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];Zhh 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::BlankLineo; ; [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::BlankLineo; ; [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::BlankLineo: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::BlankLineo; ; [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 _zii$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::BlankLineo; ; [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::BlankLineo; ; [ 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::BlankLineo; ;[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[i0o;;[;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::BlankLineo; ; [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]v99SchedulerInterface/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::BlankLineo; ; [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::BlankLineo; ; [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::BlankLineo; ; [ 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::BlankLineo; ; [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] 0rSchedulerInterface/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::BlankLineo; ; [ 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]4SchedulerInterface/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::BlankLineo; ; [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]Xblocking%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::BlankLineo; ; [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]RFset_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::BlankLineo; ; [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]&YYbacktrace_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::BlankLineo: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]SMM raise-i.rinu[PK]Ѿ8 alive%3f-i.rinu[PK]qww resume-i.rinu[PK]l mm@ cdesc-Fiber.rinu[PK]: inspect-i.rinu[PK]|y current-c.rinu[PK]c`affnew-c.rinu[PK]-xYY"backtrace-i.rinu[PK];Zhh )yield-c.rinu[PK] +to_s-i.rinu[PK],blocking%3f-c.rinu[PK] 0transfer-i.rinu[PK]Yn ?schedule-c.rinu[PK]S^xFcurrent_scheduler-c.rinu[PK]Hscheduler-c.rinu[PK]t&}KSchedulerInterface/fiber-i.rinu[PK]t _zii$NSchedulerInterface/process_wait-i.rinu[PK]}P aRSchedulerInterface/io_write-i.rinu[PK]mo .wXSchedulerInterface/cdesc-SchedulerInterface.rinu[PK]g'fSchedulerInterface/address_resolve-i.rinu[PK]v99YmSchedulerInterface/close-i.rinu[PK]:)oSchedulerInterface/unblock-i.rinu[PK]ՈW%2sSchedulerInterface/timeout_after-i.rinu[PK]dzSchedulerInterface/block-i.rinu[PK] 0r}SchedulerInterface/io_read-i.rinu[PK]V$SchedulerInterface/kernel_sleep-i.rinu[PK]4SchedulerInterface/io_wait-i.rinu[PK]Xblocking%3f-i.rinu[PK]RF#set_scheduler-c.rinu[PK]&YY:backtrace_locations-i.rinu[PK ە