rb-kqueue 0.0.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
- data/lib/rb-kqueue/event.rb +1 -1
- data/lib/rb-kqueue/native/flags.rb +22 -13
- data/lib/rb-kqueue/native.rb +3 -0
- data/lib/rb-kqueue/queue.rb +68 -5
- data/lib/rb-kqueue/watcher/file.rb +36 -1
- data/lib/rb-kqueue/watcher/read_write.rb +12 -0
- data/lib/rb-kqueue/watcher/signal.rb +32 -0
- data/lib/rb-kqueue/watcher/socket_read_write.rb +5 -0
- data/lib/rb-kqueue/watcher/timer.rb +30 -0
- data/lib/rb-kqueue/watcher.rb +1 -1
- data/lib/rb-kqueue.rb +1 -1
- data/rb-kqueue.gemspec +3 -1
- metadata +3 -1
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.0
|
|
1
|
+
0.1.0
|
data/lib/rb-kqueue/event.rb
CHANGED
|
@@ -39,7 +39,7 @@ module KQueue
|
|
|
39
39
|
#
|
|
40
40
|
# @return [Array<Symbol>]
|
|
41
41
|
def flags
|
|
42
|
-
@fflags ||= Native::Flags.from_mask("
|
|
42
|
+
@fflags ||= Native::Flags.from_mask("NOTE_#{filter.to_s.upcase}", @native[:fflags])
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
# Returns whether the end-of-file flag has been set for this event.
|
|
@@ -37,23 +37,32 @@ module KQueue
|
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
# For `EVFILT_{READ,WRITE}`
|
|
40
|
-
|
|
40
|
+
NOTE_READ_LOWAT = NOTE_WRITE_LOWAT = 0x00000001 # Low water mark
|
|
41
41
|
|
|
42
42
|
# For `EVFILT_VNODE`
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
NOTE_VNODE_DELETE = 0x00000001 # Vnode was removed
|
|
44
|
+
NOTE_VNODE_WRITE = 0x00000002 # Data contents changed
|
|
45
|
+
NOTE_VNODE_EXTEND = 0x00000004 # Size increased
|
|
46
|
+
NOTE_VNODE_ATTRIB = 0x00000008 # Attributes changed
|
|
47
|
+
NOTE_VNODE_LINK = 0x00000010 # Link count changed
|
|
48
|
+
NOTE_VNODE_RENAME = 0x00000020 # Vnode was renamed
|
|
49
|
+
NOTE_VNODE_REVOKE = 0x00000040 # Vnode access was revoked
|
|
50
50
|
|
|
51
51
|
# For `EVFILT_PROC`
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
NOTE_PROC_EXIT = 0x80000000 # Process exited
|
|
53
|
+
NOTE_PROC_FORK = 0x40000000 # Process forked
|
|
54
|
+
NOTE_PROC_EXEC = 0x20000000 # Process exec'd
|
|
55
|
+
NOTE_PROC_REAP = 0x10000000 # Process reaped
|
|
56
|
+
NOTE_PROC_SIGNAL = 0x08000000 # Received signal
|
|
57
|
+
NOTE_PROC_TRACK = 0x00000001 # follow across forks
|
|
58
|
+
NOTE_PROC_TRACKERR = 0x00000002 # could not track child
|
|
59
|
+
NOTE_PROC_CHILD = 0x00000004 # am a child process
|
|
60
|
+
|
|
61
|
+
# For `EVFILT_TIMER`
|
|
62
|
+
NOTE_TIMER_SECONDS = 0x00000001 # data is seconds
|
|
63
|
+
NOTE_TIMER_USECONDS = 0x00000002 # data is microseconds
|
|
64
|
+
NOTE_TIMER_NSECONDS = 0x00000004 # data is nanoseconds
|
|
65
|
+
NOTE_TIMER_ABSOLUTE = 0x00000008 # absolute timeout
|
|
57
66
|
|
|
58
67
|
|
|
59
68
|
# Converts a list of flags to the bitmask that the C API expects.
|
data/lib/rb-kqueue/native.rb
CHANGED
data/lib/rb-kqueue/queue.rb
CHANGED
|
@@ -55,7 +55,7 @@ module KQueue
|
|
|
55
55
|
|
|
56
56
|
# Watches a stream and produces an event when there's data available to read.
|
|
57
57
|
#
|
|
58
|
-
# This can watch files, pipes, and
|
|
58
|
+
# This can watch files, pipes, fifos, and BPF devices.
|
|
59
59
|
# For files, an event is fired whenever the file pointer
|
|
60
60
|
# is not at the end of the file,
|
|
61
61
|
# and the {Event#data} field is set to the offset
|
|
@@ -66,6 +66,17 @@ module KQueue
|
|
|
66
66
|
# The {Event#data} field is set to the number of bytes available.
|
|
67
67
|
# When the last writer disconnects, {Event#eof?} will be set.
|
|
68
68
|
#
|
|
69
|
+
# For BPF devices (not supported under Darwin/OS X),
|
|
70
|
+
# an event is fired when the BPF buffer is full,
|
|
71
|
+
# the BPF timeout has expired,
|
|
72
|
+
# or when the BPF has "immediate mode" enabled
|
|
73
|
+
# and there is data to read.
|
|
74
|
+
# The {Event#data} field is set to the number of bytes available.
|
|
75
|
+
#
|
|
76
|
+
# Note that this isn't compatible with JRuby
|
|
77
|
+
# unless a native-code file descriptor is passed in.
|
|
78
|
+
# This means the file descriptor must be returned by an FFI-wrapped C function.
|
|
79
|
+
#
|
|
69
80
|
# @param fd [IO, Fixnum] A Ruby IO stream, or the file descriptor
|
|
70
81
|
# for a native IO stream.
|
|
71
82
|
# @yield [event] A block that will be run when the specified stream
|
|
@@ -75,7 +86,6 @@ module KQueue
|
|
|
75
86
|
# @return [Watcher] The Watcher for this event.
|
|
76
87
|
# @raise [SystemCallError] If something goes wrong when registering the Watcher.
|
|
77
88
|
def watch_stream_for_read(fd, &callback)
|
|
78
|
-
fd = fd.fileno if fd.respond_to?(:fileno)
|
|
79
89
|
Watcher::ReadWrite.new(self, fd, :read, callback)
|
|
80
90
|
end
|
|
81
91
|
|
|
@@ -97,6 +107,10 @@ module KQueue
|
|
|
97
107
|
# It's possible for {Event#eof?} to be set while there's still
|
|
98
108
|
# data pending in the socket buffer.
|
|
99
109
|
#
|
|
110
|
+
# Note that this isn't compatible with JRuby
|
|
111
|
+
# unless a native-code file descriptor is passed in.
|
|
112
|
+
# This means the file descriptor must be returned by an FFI-wrapped C function.
|
|
113
|
+
#
|
|
100
114
|
# @param fd [Socket, Fixnum] A Ruby Socket, or the file descriptor
|
|
101
115
|
# for a native Socket.
|
|
102
116
|
# @param low_water [Fixnum] The low-water mark for new data.
|
|
@@ -107,7 +121,6 @@ module KQueue
|
|
|
107
121
|
# @return [Watcher] The Watcher for this event.
|
|
108
122
|
# @raise [SystemCallError] If something goes wrong when registering the Watcher.
|
|
109
123
|
def watch_socket_for_read(fd, low_water = nil, &callback)
|
|
110
|
-
fd = fd.fileno if fd.respond_to?(:fileno)
|
|
111
124
|
Watcher::SocketReadWrite.new(self, fd, :read, low_water, callback)
|
|
112
125
|
end
|
|
113
126
|
|
|
@@ -119,6 +132,10 @@ module KQueue
|
|
|
119
132
|
# remaining in the write buffer.
|
|
120
133
|
# When the reader disconnects, {Event#eof?} will be set.
|
|
121
134
|
#
|
|
135
|
+
# Note that this isn't compatible with JRuby
|
|
136
|
+
# unless a native-code file descriptor is passed in.
|
|
137
|
+
# This means the file descriptor must be returned by an FFI-wrapped C function.
|
|
138
|
+
#
|
|
122
139
|
# @param fd [IO, Fixnum] A Ruby IO stream, or the file descriptor
|
|
123
140
|
# for a native IO stream.
|
|
124
141
|
# @yield [event] A block that will be run when the specified stream
|
|
@@ -128,7 +145,6 @@ module KQueue
|
|
|
128
145
|
# @return [Watcher] The Watcher for this event.
|
|
129
146
|
# @raise [SystemCallError] If something goes wrong when registering the Watcher.
|
|
130
147
|
def watch_stream_for_write(fd, &callback)
|
|
131
|
-
fd = fd.fileno if fd.respond_to?(:fileno)
|
|
132
148
|
Watcher::ReadWrite.new(self, fd, :write, callback)
|
|
133
149
|
end
|
|
134
150
|
|
|
@@ -146,6 +162,10 @@ module KQueue
|
|
|
146
162
|
# It's possible for {Event#eof?} to be set while there's still
|
|
147
163
|
# data pending in the socket buffer.
|
|
148
164
|
#
|
|
165
|
+
# Note that this isn't compatible with JRuby
|
|
166
|
+
# unless a native-code file descriptor is passed in.
|
|
167
|
+
# This means the file descriptor must be returned by an FFI-wrapped C function.
|
|
168
|
+
#
|
|
149
169
|
# @param fd [Socket, Fixnum] A Ruby Socket, or the file descriptor
|
|
150
170
|
# for a native Socket.
|
|
151
171
|
# @param low_water [Fixnum] The low-water mark for new data.
|
|
@@ -156,7 +176,6 @@ module KQueue
|
|
|
156
176
|
# @return [Watcher] The Watcher for this event.
|
|
157
177
|
# @raise [SystemCallError] If something goes wrong when registering the Watcher.
|
|
158
178
|
def watch_socket_for_write(fd, low_water = nil, &callback)
|
|
159
|
-
fd = fd.fileno if fd.respond_to?(:fileno)
|
|
160
179
|
Watcher::SocketReadWrite.new(self, fd, :write, low_water, callback)
|
|
161
180
|
end
|
|
162
181
|
|
|
@@ -228,9 +247,19 @@ module KQueue
|
|
|
228
247
|
#
|
|
229
248
|
# `:signal`
|
|
230
249
|
# : The process was sent a signal.
|
|
250
|
+
# This is only supported under Darwin/OS X.
|
|
231
251
|
#
|
|
232
252
|
# `:reap`
|
|
233
253
|
# : The process was reaped by the parent via `wait(2)` or similar.
|
|
254
|
+
# This is only supported under Darwin/OS X.
|
|
255
|
+
#
|
|
256
|
+
# `:track`
|
|
257
|
+
# : Follow the process across `fork(2)` calls.
|
|
258
|
+
# {Event#flags} for the parent process will contain `:fork`,
|
|
259
|
+
# while {Event#flags} for the child process will contain `:child`.
|
|
260
|
+
# If the system was unable to attach an event to the child process,
|
|
261
|
+
# {Event#flags} will contain `:trackerr`.
|
|
262
|
+
# This is not supported under Darwin/OS X.
|
|
234
263
|
#
|
|
235
264
|
# @param pid [Fixnum] The id of the process.
|
|
236
265
|
# @param flags [Array<Symbol>] Which events to watch for.
|
|
@@ -243,6 +272,40 @@ module KQueue
|
|
|
243
272
|
Watcher::Process.new(self, path, flags, callback)
|
|
244
273
|
end
|
|
245
274
|
|
|
275
|
+
# Watches for signals to this process.
|
|
276
|
+
# This coexists with other signal facilities, and has lower precedence.
|
|
277
|
+
# Only signals sent to the process, not to a particular thread, will fire events.
|
|
278
|
+
# Event notification happens before normal signal delivery processing.
|
|
279
|
+
#
|
|
280
|
+
# The {Event#data} field contains the number of times the signal has been generated
|
|
281
|
+
# since the last time the event was fired.
|
|
282
|
+
#
|
|
283
|
+
# @param signal [String, Fixnum] The name of number of the signal.
|
|
284
|
+
# @yield [event] A block that will be run when the signal is received.
|
|
285
|
+
# @yieldparam event [Event] The Event object containing information
|
|
286
|
+
# about the event that occurred.
|
|
287
|
+
# @return [Watcher] The Watcher for this event.
|
|
288
|
+
# @raise [SystemCallError] If something goes wrong when registering the Watcher.
|
|
289
|
+
def watch_for_signal(signal, &callback)
|
|
290
|
+
Watcher::Signal.new(self, signal, callback)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Sets up a watcher that fires an event
|
|
294
|
+
# once every specified interval.
|
|
295
|
+
#
|
|
296
|
+
# The {Event#data} field contains the number of times the interval has passed
|
|
297
|
+
# since the last time the event was fired.
|
|
298
|
+
#
|
|
299
|
+
# @param time [Number] The interval, in seconds.
|
|
300
|
+
# @yield [event] A block that will be run when the interval passes.
|
|
301
|
+
# @yieldparam event [Event] The Event object containing information
|
|
302
|
+
# about the event that occurred.
|
|
303
|
+
# @return [Watcher] The Watcher for this event.
|
|
304
|
+
# @raise [SystemCallError] If something goes wrong when registering the Watcher.
|
|
305
|
+
def watch_timer(time, &callback)
|
|
306
|
+
Watcher::Timer.new(self, time, callback)
|
|
307
|
+
end
|
|
308
|
+
|
|
246
309
|
# Starts the queue watching for events.
|
|
247
310
|
# Blocks until \{#stop} is called.
|
|
248
311
|
#
|
|
@@ -13,7 +13,42 @@ module KQueue
|
|
|
13
13
|
# @private
|
|
14
14
|
def initialize(queue, path, flags, callback)
|
|
15
15
|
@path = path
|
|
16
|
-
@
|
|
16
|
+
@fd = Native.open(path, 0) # 0 means "read only"
|
|
17
|
+
|
|
18
|
+
if @fd < 0
|
|
19
|
+
raise SystemCallError.new(
|
|
20
|
+
"Failed to open file #{path}" +
|
|
21
|
+
case FFI.errno
|
|
22
|
+
when Errno::EACCES::Errno; ": Permission denied."
|
|
23
|
+
when Errno::EAGAIN::Errno; ": Slave side of a locked pseudo-terminal device."
|
|
24
|
+
when Errno::EFAULT::Errno; ": Outside the process's allocated address space."
|
|
25
|
+
when Errno::EINTR::Errno; ": Interrupted."
|
|
26
|
+
when Errno::ELOOP::Errno; ": Too many symbolic links (possible loop)."
|
|
27
|
+
when Errno::EMFILE::Errno; ": Too many open files."
|
|
28
|
+
when Errno::ENAMETOOLONG::Errno; ": Name too long."
|
|
29
|
+
when Errno::ENFILE::Errno; ": System file table is full."
|
|
30
|
+
when Errno::ENOENT::Errno; ": File doesn't exist."
|
|
31
|
+
when Errno::ENOTDIR::Errno; ": A component of the path prefix is not a directory."
|
|
32
|
+
when Errno::ENXIO::Errno; ": The device associated with this file doesn't exist."
|
|
33
|
+
when Errno::EOPNOTSUPP::Errno; ": File type not supported."
|
|
34
|
+
when Errno::EOVERFLOW::Errno; ": File too big."
|
|
35
|
+
else; ""
|
|
36
|
+
end,
|
|
37
|
+
FFI.errno)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
ObjectSpace.define_finalizer(self, lambda do
|
|
41
|
+
next unless Native.close(@fd) < 0
|
|
42
|
+
raise SystemCallError.new(
|
|
43
|
+
"Failed to close file #{path}" +
|
|
44
|
+
case FFI.errno
|
|
45
|
+
when Errno::EBADF::Errno; ": Invalid file descriptor."
|
|
46
|
+
when Errno::EINTR::Errno; ": Closing interrupted."
|
|
47
|
+
when Errno::EIO::Errno; ": IO error."
|
|
48
|
+
else; ""
|
|
49
|
+
end,
|
|
50
|
+
FFI.errno)
|
|
51
|
+
end)
|
|
17
52
|
super(queue, @file.fileno, :vnode, flags, nil, callback)
|
|
18
53
|
end
|
|
19
54
|
end
|
|
@@ -9,6 +9,13 @@ module KQueue
|
|
|
9
9
|
# Note that read and write events for sockets
|
|
10
10
|
# use the {SocketReadWrite} class.
|
|
11
11
|
class ReadWrite < Watcher
|
|
12
|
+
# The Ruby IO object from which the file descriptor was extracted.
|
|
13
|
+
# This is only set if an IO object was used to construct this watcher.
|
|
14
|
+
# Otherwise, it's `nil`.
|
|
15
|
+
#
|
|
16
|
+
# @return [IO, nil]
|
|
17
|
+
attr_reader :io
|
|
18
|
+
|
|
12
19
|
# The file descriptor for the stream being watched.
|
|
13
20
|
#
|
|
14
21
|
# @return [Fixnum]
|
|
@@ -23,6 +30,11 @@ module KQueue
|
|
|
23
30
|
#
|
|
24
31
|
# @private
|
|
25
32
|
def initialize(queue, fd, type, callback)
|
|
33
|
+
if fd.is_a?(IO)
|
|
34
|
+
@io = fd
|
|
35
|
+
fd = fd.fileno
|
|
36
|
+
end
|
|
37
|
+
|
|
26
38
|
@fd = fd
|
|
27
39
|
@type = type
|
|
28
40
|
super(queue, @fd, type, [], nil, callback)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module KQueue
|
|
2
|
+
class Watcher
|
|
3
|
+
# The {Watcher} subclass for events fired when a signal is received.
|
|
4
|
+
# Signal events are watched via {Queue#watch_for_signal}.
|
|
5
|
+
class Signal < Watcher
|
|
6
|
+
# The name of the signal, e.g. "KILL" for SIGKILL.
|
|
7
|
+
#
|
|
8
|
+
# @return [String]
|
|
9
|
+
attr_reader :name
|
|
10
|
+
|
|
11
|
+
# The number of the signal, e.g. 9 for SIGKILL.
|
|
12
|
+
#
|
|
13
|
+
# @return [Fixnum]
|
|
14
|
+
attr_reader :number
|
|
15
|
+
|
|
16
|
+
# Creates a new signal Watcher.
|
|
17
|
+
#
|
|
18
|
+
# @private
|
|
19
|
+
def initialize(queue, signal, callback)
|
|
20
|
+
if signal.is_a?(String)
|
|
21
|
+
@name = signal
|
|
22
|
+
@number = Signal.list[signal]
|
|
23
|
+
else
|
|
24
|
+
@name = Signal.list.find {|_, n| n == signal}.first
|
|
25
|
+
@number = signal
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
super(queue, @number, :signal, [], nil, callback)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module KQueue
|
|
2
|
+
class Watcher
|
|
3
|
+
# The {Watcher} subclass for events fired based on a timer.
|
|
4
|
+
# Timer events are watched via {Queue#watch_timer}.
|
|
5
|
+
class Timer < Watcher
|
|
6
|
+
# The interval on which the timer fires an event, in seconds.
|
|
7
|
+
#
|
|
8
|
+
# @return [Numeric]
|
|
9
|
+
attr_reader :time
|
|
10
|
+
|
|
11
|
+
# Creates a new timer Watcher.
|
|
12
|
+
#
|
|
13
|
+
# @private
|
|
14
|
+
def initialize(time, callback)
|
|
15
|
+
time, unit =
|
|
16
|
+
if time < 10**-3
|
|
17
|
+
[(time * 10**9).round, :nseconds]
|
|
18
|
+
elsif time < 1
|
|
19
|
+
[(time * 10**6).round, :useconds]
|
|
20
|
+
elsif time < 10**3 && !time.is_a?(Fixnum)
|
|
21
|
+
[(time * 10**3).round, nil] # milliseconds
|
|
22
|
+
else
|
|
23
|
+
[time.round, :seconds]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
super(queue, time, :timer, Array(unit), nil, callback)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/rb-kqueue/watcher.rb
CHANGED
|
@@ -102,7 +102,7 @@ module KQueue
|
|
|
102
102
|
native[:ident] = @ident
|
|
103
103
|
native[:filter] = Native::Flags.to_flag("EVFILT", @filter)
|
|
104
104
|
native[:flags] = Native::Flags.to_mask("EV", @flags | flags)
|
|
105
|
-
native[:fflags] = Native::Flags.to_mask("
|
|
105
|
+
native[:fflags] = Native::Flags.to_mask("NOTE_#{@filter.to_s.upcase}", @fflags)
|
|
106
106
|
native[:data] = @data if @data
|
|
107
107
|
native
|
|
108
108
|
end
|
data/lib/rb-kqueue.rb
CHANGED
|
@@ -13,7 +13,7 @@ require 'rb-kqueue/queue'
|
|
|
13
13
|
# * {Watcher} -- A watcher for a single sort of event
|
|
14
14
|
# * {Event} -- A notification that an event has occurred
|
|
15
15
|
module KQueue
|
|
16
|
-
VERSION = [0,
|
|
16
|
+
VERSION = [0, 1, 0]
|
|
17
17
|
|
|
18
18
|
# Raise an exception for a native kqueue error.
|
|
19
19
|
#
|
data/rb-kqueue.gemspec
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |s|
|
|
7
7
|
s.name = %q{rb-kqueue}
|
|
8
|
-
s.version = "0.0
|
|
8
|
+
s.version = "0.1.0"
|
|
9
9
|
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
11
|
s.authors = ["Nathan Weizenbaum"]
|
|
@@ -31,7 +31,9 @@ Gem::Specification.new do |s|
|
|
|
31
31
|
"lib/rb-kqueue/watcher/file.rb",
|
|
32
32
|
"lib/rb-kqueue/watcher/process.rb",
|
|
33
33
|
"lib/rb-kqueue/watcher/read_write.rb",
|
|
34
|
+
"lib/rb-kqueue/watcher/signal.rb",
|
|
34
35
|
"lib/rb-kqueue/watcher/socket_read_write.rb",
|
|
36
|
+
"lib/rb-kqueue/watcher/timer.rb",
|
|
35
37
|
"rb-kqueue.gemspec"
|
|
36
38
|
]
|
|
37
39
|
s.homepage = %q{http://github.com/nex3/rb-kqueue}
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rb-kqueue
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nathan Weizenbaum
|
|
@@ -56,7 +56,9 @@ files:
|
|
|
56
56
|
- lib/rb-kqueue/watcher/file.rb
|
|
57
57
|
- lib/rb-kqueue/watcher/process.rb
|
|
58
58
|
- lib/rb-kqueue/watcher/read_write.rb
|
|
59
|
+
- lib/rb-kqueue/watcher/signal.rb
|
|
59
60
|
- lib/rb-kqueue/watcher/socket_read_write.rb
|
|
61
|
+
- lib/rb-kqueue/watcher/timer.rb
|
|
60
62
|
- rb-kqueue.gemspec
|
|
61
63
|
has_rdoc: true
|
|
62
64
|
homepage: http://github.com/nex3/rb-kqueue
|