Class: IO::Reactor

Inherits:
Object show all
Defined in:
lib/carat/io-reactor.rb

Overview

An object-oriented multiplexing asynchronous IO reactor class.

Constant Summary collapse

Version =

Class constants

/([\d\.]+)/.match( %q{$Revision: 1.13 $} )[1]
Rcsid =
%q$Id: reactor.rb,v 1.13 2003/08/04 23:56:14 deveiant Exp $
ValidEvents =
[:read, :write, :error]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeReactor

Create and return a new IO reactor object.



106
107
108
109
110
111
112
113
114
115
# File 'lib/carat/io-reactor.rb', line 106

def initialize
    @handles        = Hash::new {|hsh,key|
        hsh[ key ] = {
            :events        => [],
            :handler    => nil,
            :args        => [],
        }
    }
    @pendingEvents    = Hash::new {|hsh,key| hsh[ key ] = []}
end

Instance Attribute Details

#handlesObject (readonly)

The Hash of handles (instances of IO or its subclasses) associated with the reactor. The keys are the IO objects, and the values are a Hash of event/s => handler.



125
126
127
# File 'lib/carat/io-reactor.rb', line 125

def handles
  @handles
end

#pendingEventsObject (readonly)

The Hash of unhandled events which occurred in the last call to #poll, keyed by handle.



129
130
131
# File 'lib/carat/io-reactor.rb', line 129

def pendingEvents
  @pendingEvents
end

Instance Method Details

#clearObject

Clear all registered handles from the poll object. Returns the handles that were cleared.



236
237
238
239
240
241
242
243
# File 'lib/carat/io-reactor.rb', line 236

def clear
    rv = @handles.keys

    @pendingEvents.clear
    @handles.clear

    return rv
end

#disableEvents(io, *events) ⇒ Object

Remove the specified events from the list that will be polled for on the given io handle.

Raises:

  • (RuntimeError)


174
175
176
177
178
# File 'lib/carat/io-reactor.rb', line 174

def disableEvents( io, *events )
    raise RuntimeError, "Cannot disable the :error event" if
        events.include?( :error )
    @handles[ io ][:events] -= events
end

#empty?Boolean

Returns true if no handles are associated with the receiver.

Returns:

  • (Boolean)


305
306
307
# File 'lib/carat/io-reactor.rb', line 305

def empty?
    @handles.empty?
end

#enableEvents(io, *events) ⇒ Object

Add the specified events to the list that will be polled for on the given io handle.



167
168
169
# File 'lib/carat/io-reactor.rb', line 167

def enableEvents( io, *events )
    @handles[ io ][:events] |= events
end

#poll(timeout = -1 )) ⇒ Object

Poll the handles registered to the reactor for pending events. The following event types are defined:

:read

Data may be read from the handle without blocking.

:write

Data may be written to the handle without blocking.

:error

An error has occurred on the handle. This event type is always enabled, regardless of whether or not it is passed as one of the events.

Any handlers specified when the handles were registered are run for those handles with events. If a block is given, it will be invoked once for each handle which doesn’t have an explicit handler. If no block is given, events without explicit handlers are inserted into the reactor’s pendingEvents attribute.

The timeout argument is the number of floating-point seconds to wait for an event before returning (ie., fourth argument to the underlying select() call); negative timeout values will cause #poll to block until there is at least one event to report.

This method returns the number of handles on which one or more events occurred.



272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
# File 'lib/carat/io-reactor.rb', line 272

def poll( timeout=-1 ) # :yields: io, eventMask
    timeout = timeout.to_f
    @pendingEvents.clear
    count = 0

    unless @handles.empty?
        timeout = nil if timeout < 0
        eventedHandles = self.getPendingEvents( timeout )

        # For each event of each io that had an event happen, call any
        # associated callback, or any provided block, or failing both of
        # those, add the event to the hash of unhandled pending events.
        eventedHandles.each {|io,events|
            count += 1
            events.each {|ev|
                args = @handles[ io ][:args]

                if @handles[ io ][:handler]
                    @handles[ io ][:handler].call( io, ev, *args )
                elsif block_given?
                    yield( io, ev, *args )
                else
                    @pendingEvents[io].push( ev )
                end
            }
        }
    end

    return count
end

#register(io, *args, &handler) ⇒ Object Also known as: add

Register the specified IO object with the reactor for events given as args. The reactor will test the given io for the events specified whenever #poll is called. See the #poll method for a list of valid events. If no events are specified, only :error events will be polled for.

If a handler is specified, it will be called whenever the io has any of the specified events occur to it. It should take at least two parameters: the io and the event.

If args contains any objects except the Symbols ‘:read’, ‘:write’, or ‘:error’, and a handler is specified, they will be saved and passed to handler for each event.

Registering a handle will unregister any previously registered event/handler+arguments pairs associated with the handle.



148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/carat/io-reactor.rb', line 148

def register( io, *args, &handler )
    events = [:read, :write, :error] & args
    args -= events

    self.unregister( io )
    self.enableEvents( io, *events )
    if handler
        self.setHandler( io, *args, &handler )
    else
        self.setArgs( io, *args )
    end

    return self
end

#registered?(io) ⇒ Boolean

Returns true if the specified io is registered with the poll object.

Returns:

  • (Boolean)


229
230
231
# File 'lib/carat/io-reactor.rb', line 229

def registered?( io )
    return @handles.has_key?( io )
end

#removeArgs(io) ⇒ Object

Remove the arguments for the given handle to the given args.



212
213
214
# File 'lib/carat/io-reactor.rb', line 212

def removeArgs( io )
    return @handles[ io ][:args].clear
end

#removeHandler(io) ⇒ Object

Remove and return the handler for events on the given io handle.



194
195
196
197
198
199
# File 'lib/carat/io-reactor.rb', line 194

def removeHandler( io )
    rval = @handles[ io ][:handler]
    @handles[ io ][:handler] = nil
    self.removeArgs( io )
    return rval
end

#setArgs(io, *args) ⇒ Object

Set the additional arguments to pass to the handler for the given io handle on each event to the given args.



204
205
206
207
208
# File 'lib/carat/io-reactor.rb', line 204

def setArgs( io, *args )
    rval = @handles[ io ][:args]
    @handles[ io ][:args] = args
    return rval
end

#setHandler(io, *args, &handler) ⇒ Object

Set the handler for events on the given io handle to the specified handler. If any args are present, they will be passed as an exploded array to the handler for each event. Returns the previously-registered handler, if any.



185
186
187
188
189
190
# File 'lib/carat/io-reactor.rb', line 185

def setHandler( io, *args, &handler )
    rval = @handles[ io ][:handler]
    @handles[ io ][:handler] = handler
    self.setArgs( io, *args )
    return rval
end

#unregister(io) ⇒ Object Also known as: remove

Remove the specified io from the receiver’s list of registered handles, if present. Returns the handle if it was registered, or nil if it was not.



220
221
222
223
# File 'lib/carat/io-reactor.rb', line 220

def unregister( io )
    @pendingEvents.delete( io )
    @handles.delete( io )
end