Class: IO::Event::Debug::Selector

Inherits:
Object
  • Object
show all
Defined in:
lib/io/event/debug/selector.rb

Overview

Enforces the selector interface and delegates operations to a wrapped selector instance.

You can enable this in the default selector by setting the ‘IO_EVENT_DEBUG_SELECTOR` environment variable. In addition, you can log all selector operations to a file by setting the `IO_EVENT_DEBUG_SELECTOR_LOG` environment variable. This is useful for debugging and understanding the behavior of the event loop.

Defined Under Namespace

Modules: Forwarders

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(selector, log: nil) ⇒ Selector

Initialize the debug selector with the given selector and optional log.



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/io/event/debug/selector.rb', line 42

def initialize(selector, log: nil)
	@selector = selector
	
	@readable = {}
	@writable = {}
	@priority = {}
	
	unless Fiber.current == selector.loop
		Kernel::raise "Selector must be initialized on event loop fiber!"
	end
	
	@log = log
	
	install_optional_forwarders(selector)
end

Class Method Details

.wrap(selector, env = ENV) ⇒ Object

Wrap the given selector with debugging.



28
29
30
31
32
33
34
35
36
# File 'lib/io/event/debug/selector.rb', line 28

def self.wrap(selector, env = ENV)
	log = nil
	
	if log_path = env["IO_EVENT_DEBUG_SELECTOR_LOG"]
		log = File.open(log_path, "w")
	end
	
	return self.new(selector, log: log)
end

Instance Method Details

#blocking_operation_wait(operation) ⇒ Object

Run the given blocking operation and wait for its completion.



157
158
159
160
# File 'lib/io/event/debug/selector.rb', line 157

def blocking_operation_wait(operation)
	log("Waiting for blocking operation #{operation.inspect}")
	@selector.blocking_operation_wait(operation)
end

#closeObject

Close the selector.



101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/io/event/debug/selector.rb', line 101

def close
	log("Closing selector")
	
	if @selector.nil?
		Kernel::raise "Selector already closed!"
	end
	
	@selector.close
	@selector = nil
	
	@log&.flush
end

#idle_durationObject

The idle duration of the underlying selector.



73
74
75
# File 'lib/io/event/debug/selector.rb', line 73

def idle_duration
	@selector.idle_duration
end

#io_read(fiber, io, buffer, length, offset = 0) ⇒ Object

Read from the given IO, forwarded to the underlying selector.



175
176
177
178
# File 'lib/io/event/debug/selector.rb', line 175

def io_read(fiber, io, buffer, length, offset = 0)
	log("Reading from IO #{io.inspect} with buffer #{buffer}; length #{length} offset #{offset}")
	@selector.io_read(fiber, io, buffer, length, offset)
end

#io_wait(fiber, io, events) ⇒ Object

Wait for the given IO, forwarded to the underlying selector.



169
170
171
172
# File 'lib/io/event/debug/selector.rb', line 169

def io_wait(fiber, io, events)
	log("Waiting for IO #{io.inspect} for events #{events.inspect}")
	@selector.io_wait(fiber, io, events)
end

#io_write(fiber, io, buffer, length, offset = 0) ⇒ Object

Write to the given IO, forwarded to the underlying selector.



181
182
183
184
# File 'lib/io/event/debug/selector.rb', line 181

def io_write(fiber, io, buffer, length, offset = 0)
	log("Writing to IO #{io.inspect} with buffer #{buffer}; length #{length} offset #{offset}")
	@selector.io_write(fiber, io, buffer, length, offset)
end

#log(message) ⇒ Object

Log the given message.



87
88
89
90
91
92
93
# File 'lib/io/event/debug/selector.rb', line 87

def log(message)
	return unless @log
	
	Fiber.blocking do
		@log.puts("T+%10.1f; %s" % [now, message])
	end
end

#nowObject

The current time.



80
81
82
# File 'lib/io/event/debug/selector.rb', line 80

def now
	Process.clock_gettime(Process::CLOCK_MONOTONIC)
end

#process_wait(*arguments) ⇒ Object

Wait for the given process, forwarded to the underlying selector.



163
164
165
166
# File 'lib/io/event/debug/selector.rb', line 163

def process_wait(*arguments)
	log("Waiting for process with #{arguments.inspect}")
	@selector.process_wait(*arguments)
end

#push(fiber) ⇒ Object

Push the given fiber to the selector ready list, such that it will be resumed on the next call to #select.



135
136
137
138
# File 'lib/io/event/debug/selector.rb', line 135

def push(fiber)
	log("Pushing fiber #{fiber.inspect} to ready list")
	@selector.push(fiber)
end

#raise(fiber, *arguments, **options) ⇒ Object

Raise the given exception on the given fiber.



144
145
146
147
# File 'lib/io/event/debug/selector.rb', line 144

def raise(fiber, *arguments, **options)
	log("Raising exception on fiber #{fiber.inspect} with #{arguments.inspect}")
	@selector.raise(fiber, *arguments, **options)
end

#ready?Boolean

Check if the selector is ready.

Returns:

  • (Boolean)


152
153
154
# File 'lib/io/event/debug/selector.rb', line 152

def ready?
	@selector.ready?
end

#respond_to?(name, include_private = false) ⇒ Boolean

Forward the given method to the underlying selector.

Returns:

  • (Boolean)


187
188
189
# File 'lib/io/event/debug/selector.rb', line 187

def respond_to?(name, include_private = false)
	@selector.respond_to?(name, include_private)
end

#resume(*arguments) ⇒ Object

Resume the given fiber with the given arguments.



121
122
123
124
# File 'lib/io/event/debug/selector.rb', line 121

def resume(*arguments)
	log("Resuming fiber with #{arguments.inspect}")
	@selector.resume(*arguments)
end

#select(duration = nil) ⇒ Object

Select for the given duration, forwarded to the underlying selector.



192
193
194
195
196
197
198
199
# File 'lib/io/event/debug/selector.rb', line 192

def select(duration = nil)
	log("Selecting for #{duration.inspect}")
	unless Fiber.current == @selector.loop
		Kernel::raise "Selector must be run on event loop fiber!"
	end
	
	@selector.select(duration)
end

#transferObject

Transfer from the calling fiber to the selector.



115
116
117
118
# File 'lib/io/event/debug/selector.rb', line 115

def transfer
	log("Transfering to event loop")
	@selector.transfer
end

#wakeupObject

Wakeup the the selector.



96
97
98
# File 'lib/io/event/debug/selector.rb', line 96

def wakeup
	@selector.wakeup
end

#yieldObject

Yield to the selector.



127
128
129
130
# File 'lib/io/event/debug/selector.rb', line 127

def yield
	log("Yielding to event loop")
	@selector.yield
end