Class: EventLoop

Inherits:
Object show all
Includes:
SignalEmitter
Defined in:
lib/puppet/external/event-loop/event-loop.rb

Defined Under Namespace

Modules: Watchable Classes: Timer

Constant Summary collapse

IO_STATES =
[:readable, :writable, :exceptional]

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SignalEmitter

#__maybe_initialize_signal_emitter, #__signal__, #add_signal_handler, included, #remove_signal_handler

Constructor Details

#initializeEventLoop

Returns a new instance of EventLoop.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/puppet/external/event-loop/event-loop.rb', line 64

def initialize
  @running = false
  @awake = false
  @wakeup_time = nil
  @timers = []

  @io_arrays = [[], [], []]
  @ios = Hash.new do |h, k| raise ArgumentError,
    "invalid IO event: #{k}", caller(2) end
  IO_STATES.each_with_index { |x, i| @ios[x] = @io_arrays[i] }

  @notify_src, @notify_snk = IO.pipe

  # prevent file descriptor leaks
  if @notify_src.respond_to?(:fcntl) and defined?(Fcntl) and defined?(Fcntl::F_SETFD) and defined?(Fcntl::FD_CLOEXEC)
    @notify_src.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
    @notify_snk.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
  end

  @notify_src.will_block = false
  @notify_snk.will_block = false

  # Each time a byte is sent through the notification pipe
  # we need to read it, or IO.select will keep returning.
  monitor_io(@notify_src, :readable)
  @notify_src.extend(Watchable)
  @notify_src.on_readable do
    begin
      @notify_src.sysread(256)
    rescue Errno::EAGAIN
      # The pipe wasn't readable after all.
    end
  end
end

Class Method Details

.currentObject



34
35
# File 'lib/puppet/external/event-loop/event-loop.rb', line 34

def current
Thread.current["event-loop::current"] || default end

.current=(x) ⇒ Object



36
37
# File 'lib/puppet/external/event-loop/event-loop.rb', line 36

def current= x
Thread.current["event-loop::current"] = x end

.defaultObject



31
# File 'lib/puppet/external/event-loop/event-loop.rb', line 31

def default ; @default ||= new end

.default=(x) ⇒ Object



32
# File 'lib/puppet/external/event-loop/event-loop.rb', line 32

def default= x ; @default = x end

.method_missing(name, *args, &block) ⇒ Object



53
54
55
56
57
58
59
# File 'lib/puppet/external/event-loop/event-loop.rb', line 53

def method_missing (name, *args, &block)
  if current.respond_to? name
    current.__send__(name, *args, &block)
  else
    super
  end
end

.with_current(new) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/puppet/external/event-loop/event-loop.rb', line 39

def with_current (new)
  if current == new
    yield
  else
    begin
      old = self.current
      self.current = new
      yield
    ensure
      self.current = old
    end
  end
end

Instance Method Details

#check_timer(timer) ⇒ Object



154
155
156
# File 'lib/puppet/external/event-loop/event-loop.rb', line 154

def check_timer (timer)
  wake_up if timer.end_time < @wakeup_time
end

#ignore_io(io, *events) ⇒ Object



158
159
160
161
162
163
# File 'lib/puppet/external/event-loop/event-loop.rb', line 158

def ignore_io (io, *events)
  events = IO_STATES if events.empty?
  for event in events do
    wake_up if @ios[event].delete(io)
  end
end

#ignore_timer(timer) ⇒ Object



165
166
167
168
# File 'lib/puppet/external/event-loop/event-loop.rb', line 165

def ignore_timer (timer)
  # Don't need to wake up for this.
  @timers.delete(timer)
end

#iterate(user_timeout = nil) ⇒ Object



115
116
117
118
119
120
121
# File 'lib/puppet/external/event-loop/event-loop.rb', line 115

def iterate (user_timeout=nil)
  t1, t2 = user_timeout, max_timeout
  timeout = t1 && t2 ? [t1, t2].min : t1 || t2
  select(timeout).zip(IO_STATES) do |ios, state|
    ios.each { |x| x.signal(state) } if ios
  end
end

#max_timeoutObject



170
171
172
173
# File 'lib/puppet/external/event-loop/event-loop.rb', line 170

def max_timeout
  return nil if @timers.empty?
  [@timers.collect { |x| x.time_left }.min, 0].max
end

#monitor_io(io, *events) ⇒ Object



144
145
146
147
148
# File 'lib/puppet/external/event-loop/event-loop.rb', line 144

def monitor_io (io, *events)
  for event in events do
    @ios[event] << io ; wake_up unless monitoring_io?(io, event)
  end
end

#monitor_timer(timer) ⇒ Object



150
151
152
# File 'lib/puppet/external/event-loop/event-loop.rb', line 150

def monitor_timer (timer)
  @timers << timer unless monitoring_timer? timer
end

#monitoring_io?(io, event) ⇒ Boolean

Returns:

  • (Boolean)


139
140
# File 'lib/puppet/external/event-loop/event-loop.rb', line 139

def monitoring_io? (io, event)
@ios[event].include? io end

#monitoring_timer?(timer) ⇒ Boolean

Returns:

  • (Boolean)


141
142
# File 'lib/puppet/external/event-loop/event-loop.rb', line 141

def monitoring_timer? (timer)
@timers.include? timer end

#quitObject



137
# File 'lib/puppet/external/event-loop/event-loop.rb', line 137

def quit ; stopped! ; wake_up ; self end

#runObject



103
104
105
106
107
108
109
110
111
112
113
# File 'lib/puppet/external/event-loop/event-loop.rb', line 103

def run
  if block_given?
    thread = Thread.new { run }
    yield ; quit ; thread.join
  else
    running!
    iterate while running?
  end
ensure
  quit
end

#wake_upObject



175
176
177
# File 'lib/puppet/external/event-loop/event-loop.rb', line 175

def wake_up
  @notify_snk.write('.') if sleeping?
end