Class: LightIO::Core::IOloop

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/lightio/core/ioloop.rb

Overview

IOloop like a per-threaded EventMachine (cause fiber cannot resume cross threads)

IOloop handle io waiting and schedule beams, user do not supposed to directly use this class

Constant Summary collapse

THREAD_PROXY =
::LightIO::RawProxy.new(::Thread,
methods: [:current],
instance_methods: [:thread_variable_get, :thread_variable_set, :thread_variable?])

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeIOloop

Returns a new instance of IOloop.



10
11
12
13
# File 'lib/lightio/core/ioloop.rb', line 10

def initialize
  @fiber = Fiber.new {run}
  @backend = Backend::NIO.new
end

Class Method Details

.currentObject

return current ioloop or create new one



55
56
57
58
59
60
61
62
# File 'lib/lightio/core/ioloop.rb', line 55

def current
  key = :"lightio.ioloop"
  current_thread = THREAD_PROXY.send(:current)
  unless THREAD_PROXY.instance_send(current_thread, :thread_variable?, key)
    THREAD_PROXY.instance_send(current_thread, :thread_variable_set, key, IOloop.new)
  end
  THREAD_PROXY.instance_send(current_thread, :thread_variable_get, key)
end

Instance Method Details

#transferObject



45
46
47
# File 'lib/lightio/core/ioloop.rb', line 45

def transfer
  @fiber.transfer
end

#wait(watcher) ⇒ Object

Wait a watcher, watcher can be a timer or socket. see LightIO::Watchers module for detail



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/lightio/core/ioloop.rb', line 21

def wait(watcher)
  future = Future.new
  # add watcher to loop
  id = Object.new
  watcher.set_callback {|err| future.transfer([id, err])}
  watcher.start(self)
  # trigger a fiber switch
  # wait until watcher is ok
  # then do work
  response_id, err = future.value
  current_beam = LightIO::Core::Beam.current
  if response_id != id
    raise LightIO::InvalidTransferError, "expect #{id}, but get #{response_id}"
  elsif err
    # if future return a err
    # simulate Thread#raise to Beam , that we can shutdown beam blocking by socket accepting
    # transfer back to which beam occur this err
    # not sure this is a right way to do it
    current_beam.raise(err) if current_beam.is_a?(LightIO::Core::Beam)
  end
  # check beam error after wait
  current_beam.send(:check_and_raise_error) if current_beam.is_a?(LightIO::Core::Beam)
end