class Polyphony::Timer

Implements a common timer for running multiple timeouts

Public Class Methods

new(tag = nil, resolution:) click to toggle source
# File lib/polyphony/core/timer.rb, line 6
def initialize(tag = nil, resolution:)
  @fiber = spin_loop(tag, interval: resolution) { update }
  @timeouts = {}
end

Public Instance Methods

after(interval, &block) click to toggle source
# File lib/polyphony/core/timer.rb, line 26
def after(interval, &block)
  spin do
    self.sleep interval
    block.()
  end
end
cancel_after(interval, with_exception: Polyphony::Cancel) { || ... } click to toggle source
# File lib/polyphony/core/timer.rb, line 48
def cancel_after(interval, with_exception: Polyphony::Cancel)
  fiber = Fiber.current
  @timeouts[fiber] = {
    interval: interval,
    target_stamp: now + interval,
    exception: with_exception
  }
  yield
ensure
  @timeouts.delete(fiber)
end
every(interval) { || ... } click to toggle source
# File lib/polyphony/core/timer.rb, line 33
def every(interval)
  fiber = Fiber.current
  @timeouts[fiber] = {
    interval: interval,
    target_stamp: now + interval,
    recurring: true
  }
  while true
    Polyphony.backend_wait_event(true)
    yield
  end
ensure
  @timeouts.delete(fiber)
end
move_on_after(interval, with_value: nil) { || ... } click to toggle source
# File lib/polyphony/core/timer.rb, line 60
def move_on_after(interval, with_value: nil)
  fiber = Fiber.current
  @timeouts[fiber] = {
    interval: interval,
    target_stamp: now + interval,
    exception: [Polyphony::MoveOn, with_value]
  }
  yield
rescue Polyphony::MoveOn => e
  e.value
ensure
  @timeouts.delete(fiber)
end
reset() click to toggle source
# File lib/polyphony/core/timer.rb, line 74
def reset
  record = @timeouts[Fiber.current]
  return unless record
  
  record[:target_stamp] = now + record[:interval]
end
sleep(duration) click to toggle source
# File lib/polyphony/core/timer.rb, line 15
def sleep(duration)
  fiber = Fiber.current
  @timeouts[fiber] = {
    interval: duration,
    target_stamp: now + duration
  }
  Polyphony.backend_wait_event(true)
ensure
  @timeouts.delete(fiber)
end
stop() click to toggle source
# File lib/polyphony/core/timer.rb, line 11
def stop
  @fiber.stop
end

Private Instance Methods

now() click to toggle source
# File lib/polyphony/core/timer.rb, line 83
def now
  ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
end
timeout_exception(record) click to toggle source
# File lib/polyphony/core/timer.rb, line 87
def timeout_exception(record)
  case (exception = record[:exception])
  when Array
    exception[0].new(exception[1])
  when Class
    exception.new
  else
    RuntimeError.new(exception)
  end
end
update() click to toggle source
# File lib/polyphony/core/timer.rb, line 98
def update
  return if @timeouts.empty?

  @timeouts.each do |fiber, record|
    next if record[:target_stamp] > now

    value = record[:exception] ? timeout_exception(record) : record[:value]
    fiber.schedule value

    next unless record[:recurring]

    while record[:target_stamp] <= now
      record[:target_stamp] += record[:interval]
    end
  end
end