Class: Eventbox
- Inherits:
-
Object
- Object
- Eventbox
- Extended by:
- Boxable
- Defined in:
- lib/eventbox.rb,
lib/eventbox/timer.rb,
lib/eventbox/boxable.rb,
lib/eventbox/version.rb,
lib/eventbox/sanitizer.rb,
lib/eventbox/event_loop.rb,
lib/eventbox/thread_pool.rb,
lib/eventbox/call_context.rb,
lib/eventbox/object_registry.rb,
lib/eventbox/argument_wrapper.rb
Direct Known Subclasses
Defined Under Namespace
Modules: ArgumentWrapper, Boxable, CallContext, Sanitizer, Timer Classes: AbortAction, Action, ActionCallContext, AsyncProc, BlockingExternalCallContext, CompletionProc, ExternalObject, ExternalProc, InternalProc, InvalidAccess, MultipleResults, ObjectRegistry, SyncProc, Thread, ThreadPool, WrappedException, WrappedObject, WrappedProc, YieldProc
Constant Summary collapse
- VERSION =
"1.0.0"
Class Method Summary collapse
-
.eventbox_options ⇒ Hash
Retrieves the Eventbox options of this class.
-
.with_options(**options) ⇒ Object
Create a new derived class with the given options.
Instance Method Summary collapse
-
#async_proc(name = nil, &block) ⇒ Object
private
Create a proc object for asynchronous (fire-and-forget) calls similar to Boxable#async_call.
-
#call_context ⇒ Object
private
Get the context of the waiting external call within a yield or sync method or closure.
-
#init(*args) ⇒ Object
private
Initialize a new Eventbox instance.
-
#new_action_call_context ⇒ Object
private
Starts a new action dedicated to call external objects.
-
#shared_object(object) ⇒ Object
Mark an object as to be shared instead of copied.
-
#shutdown!(&completion_block) ⇒ Object
Force stop of all action threads spawned by this Eventbox instance.
-
#sync_proc(name = nil, &block) ⇒ Object
private
Create a Proc object for synchronous calls similar to Boxable#sync_call.
- #with_call_context(ctx, &block) ⇒ Object private
-
#yield_proc(name = nil, &block) ⇒ Object
private
Create a Proc object for calls with deferred result similar to Boxable#yield_call.
- #€(object) ⇒ Object
Methods included from Boxable
action, async_call, attr_accessor, attr_reader, attr_writer, sync_call, yield_call
Class Method Details
.eventbox_options ⇒ Hash
Retrieves the Eventbox options of this class.
47 48 49 50 51 52 53 |
# File 'lib/eventbox.rb', line 47 def self. { threadpool: Thread, guard_time: 0.5, gc_actions: false, } end |
.with_options(**options) ⇒ Object
Create a new derived class with the given options.
The options are merged with the options of the base class. The following options are available:
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/eventbox.rb', line 71 def self.(**) Class.new(self) do define_singleton_method(:eventbox_options) do super().merge() end def self.inspect klazz = self until name=klazz.name klazz = klazz.superclass end "#{name}#{}" end end end |
Instance Method Details
#async_proc(name = nil, &block) ⇒ Object (private)
Create a proc object for asynchronous (fire-and-forget) calls similar to Eventbox::Boxable#async_call.
It can be passed to external scope and called from there like so:
class MyBox < Eventbox
sync_call def print(p1)
async_proc do |p2|
puts "#{p1} #{p2}"
end
end
end
MyBox.new.print("Hello").call("world") # Prints "Hello world"
The created object can be safely called from any thread. All block arguments are passed through the Sanitizer. The block itself might not do any blocking calls or expensive computations - this would impair responsiveness of the Eventbox instance. Instead use Eventbox::Boxable#action in these cases.
The block always returns self
to the caller.
182 183 184 |
# File 'lib/eventbox.rb', line 182 def async_proc(name=nil, &block) @__event_loop__.new_async_proc(name=nil, &block) end |
#call_context ⇒ Object (private)
Get the context of the waiting external call within a yield or sync method or closure.
Callable within the event scope only.
Usable as first parameter to ExternalProc.call and Eventbox::ExternalObject#send.
292 293 294 295 296 297 298 |
# File 'lib/eventbox.rb', line 292 private def call_context if @__event_loop__.event_scope? @__event_loop__._latest_call_context else raise InvalidAccess, "not in event scope" end end |
#init(*args) ⇒ Object (private)
Initialize a new Eventbox instance.
This method is executed for initialization of a Eventbox instance. This method receives all arguments given to Eventbox.new
after they have passed the Sanitizer. It can be used like initialize
in ordinary ruby classes including super
to initialize included modules or base classes.
#init can be defined as either Eventbox::Boxable#sync_call or Eventbox::Boxable#async_call with no difference. #init can also be defined as Eventbox::Boxable#yield_call, so that the new
call is blocked until the result is yielded. #init can even be defined as Eventbox::Boxable#action, so that each instance of the class immediately starts a new thread.
160 161 |
# File 'lib/eventbox.rb', line 160 def init(*args) end |
#new_action_call_context ⇒ Object (private)
Starts a new action dedicated to call external objects.
It returns a CallContext which can be used with Eventbox::ExternalObject#send and Eventbox::ExternalProc#call.
280 281 282 |
# File 'lib/eventbox.rb', line 280 private def new_action_call_context ActionCallContext.new(@__event_loop__) end |
#shared_object(object) ⇒ Object
Mark an object as to be shared instead of copied.
A marked object is never passed as copy, but passed as reference. The object is therefore wrapped as WrappedObject or ExternalObject when used in an unsafe scope. Objects marked within the event scope are wrapped as WrappedObject, which denies access from external/action scope or the event scope of a different Eventbox instance. Objects marked in external/action scope are wrapped as ExternalObject which allows asynchronous calls from event scope. In all cases the object can be passed as reference and is automatically unwrapped when passed back to the original scope. It can therefore be used to modify the original object even after traversing the boundaries.
The mark is stored for the lifetime of the object, so that it’s enough to mark only once at object creation.
Due to Sanitizer dissection of non-marshalable objects, wrapping and unwrapping works even if the shared object is stored within another object as instance variable or within a collection class. This is in contrast to €-variables which can only wrap the argument object as a whole when entering the event scope. See the difference here:
A = Struct.new(:a)
class Bo < Eventbox
sync_call def go(struct, €struct)
p struct # prints #<struct A a=#<Eventbox::ExternalObject @object="abc" @name=:a>>
p €struct # prints #<Eventbox::ExternalObject @object=#<struct A a="abc"> @name=:€struct>
[struct, €struct]
end
end
e = Bo.new
o = A.new(e.shared_object("abc"))
e.go(o, o) # => [#<struct A a="abc">, #<struct A a="abc">]
267 268 269 |
# File 'lib/eventbox.rb', line 267 public def shared_object(object) @__event_loop__.shared_object(object) end |
#shutdown!(&completion_block) ⇒ Object
Force stop of all action threads spawned by this Eventbox instance.
It is possible to enable automatic cleanup of action threads by the garbage collector through with_options. However in some cases automatic garbage collection doesn’t remove all instances due to running action threads. Calling shutdown! when the work of the instance is done, ensures that it is GC’ed in all cases.
If #shutdown! is called externally, it blocks until all actions threads have terminated.
If #shutdown! is called in the event scope, it just triggers the termination of all action threads and returns afterwards. Optionally #shutdown! can be called with a block. It is called when all actions threads terminated.
319 320 321 |
# File 'lib/eventbox.rb', line 319 public def shutdown!(&completion_block) @__event_loop__.shutdown(&completion_block) end |
#sync_proc(name = nil, &block) ⇒ Object (private)
Create a Proc object for synchronous calls similar to Eventbox::Boxable#sync_call.
It can be passed to external scope and called from there like so:
class MyBox < Eventbox
sync_call def print(p1)
sync_proc do |p2|
"#{p1} #{p2}"
end
end
end
puts MyBox.new.print("Hello").call("world") # Prints "Hello world"
The created object can be safely called from any thread. All block arguments as well as the result value are passed through the Sanitizer. The block itself might not do any blocking calls or expensive computations - this would impair responsiveness of the Eventbox instance. Instead use Eventbox::Boxable#action in these cases.
This Proc is simular to #async_proc, but when the block is invoked, it is executed and it’s return value is returned to the caller. Since all processing within the event scope of an Eventbox instance must not execute blocking operations, sync procs can only return immediate values. For deferred results use #yield_proc instead.
207 208 209 |
# File 'lib/eventbox.rb', line 207 def sync_proc(name=nil, &block) @__event_loop__.new_sync_proc(name=nil, &block) end |
#with_call_context(ctx, &block) ⇒ Object (private)
300 301 302 303 304 305 306 |
# File 'lib/eventbox.rb', line 300 private def with_call_context(ctx, &block) if @__event_loop__.event_scope? @__event_loop__.with_call_context(ctx, &block) else raise InvalidAccess, "not in event scope" end end |
#yield_proc(name = nil, &block) ⇒ Object (private)
Create a Proc object for calls with deferred result similar to Eventbox::Boxable#yield_call.
It can be passed to external scope and called from there like so:
class MyBox < Eventbox
sync_call def print(p1)
yield_proc do |p2, result|
result.yield "#{p1} #{p2}"
end
end
end
puts MyBox.new.print("Hello").call("world") # Prints "Hello world"
This proc type is simular to #sync_proc, however it’s not the result of the block that is returned. Instead the block is called with one additional argument in the event scope, which is used to yield a result value. The result value can be yielded within the called block, but it can also be called by any other event scope or external method, leading to a deferred proc return. The external thread calling this proc is suspended until a result is yielded. However the Eventbox object keeps responsive to calls from other threads.
The created object can be safely called from any thread. If yield procs are called in the event scope, they must get a Proc object as the last argument. It is called when a result was yielded.
All block arguments as well as the result value are passed through the Sanitizer. The block itself might not do any blocking calls or expensive computations - this would impair responsiveness of the Eventbox instance. Instead use Eventbox::Boxable#action in these cases.
237 238 239 |
# File 'lib/eventbox.rb', line 237 def yield_proc(name=nil, &block) @__event_loop__.new_yield_proc(name=nil, &block) end |
#€(object) ⇒ Object
271 272 273 |
# File 'lib/eventbox.rb', line 271 public def €(object) @__event_loop__.€(object) end |