rb-kqueue-burke 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ /pkg
2
+ /.yardoc
3
+ /doc
data/.yardopts ADDED
@@ -0,0 +1,5 @@
1
+ --readme README.md
2
+ --markup markdown
3
+ --markup-provider maruku
4
+ --hide-void-return
5
+ --no-private
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Nathan Weizenbaum
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # rb-kqueue
2
+
3
+ This is a simple wrapper over the [kqueue](http://en.wikipedia.org/wiki/Kqueue)
4
+ BSD event notification interface (supported on FreeBSD, NetBSD, OpenBSD, and Darwin).
5
+ It uses the [FFI](http://wiki.github.com/ffi/ffi) gem to avoid having to compile a C extension.
6
+
7
+ [API documentation is available on rdoc.info](http://rdoc.info/projects/nex3/rb-kqueue).
8
+
9
+ ## WARNING
10
+
11
+ This code is incomplete, and didn't work last I had a chance to test it.
12
+ I don't have time to continue working on it at the moment,
13
+ so I'm posting it online for posterity and in case anyone wants to take a crack at it.
14
+
15
+ If anyone wants commit rights, just email me at nex342@gmail.com.
16
+
17
+ ## Usage
18
+
19
+ The API is similar to the kqueue C API, but with a more Rubyish feel.
20
+ First, create a queue:
21
+
22
+ queue = KQueue::Queue.new
23
+
24
+ Then, tell it to watch the events you're interested in:
25
+
26
+ queue.watch_file("path/to/foo.txt", :write) {puts "foo.txt was modified!"}
27
+ queue.watch_process(Process.pid, :fork, :exec) do |event|
28
+ puts "This process has #{event.flags.map {|f| f.to_s + "ed"}.join(" and ")}"
29
+ end
30
+
31
+ KQueue can monitor for all sorts of events.
32
+ For a full list, see the `watch_*` methods on {Queue}.
33
+
34
+ Finally, run the queue:
35
+
36
+ queue.run
37
+
38
+ This will loop infinitely, calling the appropriate callbacks when the events are fired.
39
+ If you don't want infinite looping,
40
+ you can also block until there are available events,
41
+ process them all at once,
42
+ and then continue on your merry way:
43
+
44
+ queue.process
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "rb-kqueue"
8
+ gem.summary = "A Ruby wrapper for BSD's kqueue, using FFI"
9
+ gem.description = gem.summary
10
+ gem.email = "nex342@gmail.com"
11
+ gem.homepage = "http://github.com/nex3/rb-kqueue"
12
+ gem.authors = ["Nathan Weizenbaum"]
13
+ gem.add_dependency "ffi", ">= 0.5.0"
14
+ gem.add_development_dependency "yard", ">= 0.4.0"
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
+ end
20
+
21
+ module Jeweler::VersionHelper::PlaintextExtension
22
+ def write_with_kqueue
23
+ write_without_kqueue
24
+ filename = File.join(File.dirname(__FILE__), "lib/rb-kqueue.rb")
25
+ text = File.read(filename)
26
+ File.open(filename, 'w') do |f|
27
+ f.write text.gsub(/^( VERSION = ).*/, '\1' + [major, minor, patch].inspect)
28
+ end
29
+ end
30
+ alias_method :write_without_kqueue, :write
31
+ alias_method :write, :write_with_kqueue
32
+ end
33
+
34
+ class Jeweler::Commands::Version::Base
35
+ def commit_version_with_kqueue
36
+ return unless self.repo
37
+ self.repo.add(File.join(File.dirname(__FILE__), "lib/rb-kqueue.rb"))
38
+ commit_version_without_kqueue
39
+ end
40
+ alias_method :commit_version_without_kqueue, :commit_version
41
+ alias_method :commit_version, :commit_version_with_kqueue
42
+ end
43
+
44
+ begin
45
+ require 'yard'
46
+ YARD::Rake::YardocTask.new
47
+ rescue LoadError
48
+ task :yardoc do
49
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
50
+ end
51
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/lib/rb-kqueue.rb ADDED
@@ -0,0 +1,40 @@
1
+ require 'rb-kqueue/native'
2
+ require 'rb-kqueue/native/flags'
3
+ require 'rb-kqueue/watcher'
4
+ require 'rb-kqueue/watcher/file'
5
+ require 'rb-kqueue/watcher/read_write'
6
+ require 'rb-kqueue/watcher/process'
7
+ require 'rb-kqueue/event'
8
+ require 'rb-kqueue/queue'
9
+
10
+ # The root module of the library, which is laid out as so:
11
+ #
12
+ # * {Queue} -- The main class, where events are registered
13
+ # * {Watcher} -- A watcher for a single sort of event
14
+ # * {Event} -- A notification that an event has occurred
15
+ module KQueue
16
+ VERSION = [0, 1, 0]
17
+
18
+ # Raise an exception for a native kqueue error.
19
+ #
20
+ # @param errno [Fixnum] The errno identifying the sort of error.
21
+ # This is usually C's `errno` variable,
22
+ # but is sometimes set in a kevent struct
23
+ # @raise [SystemCallError]
24
+ # @private
25
+ def self.handle_error(errno = FFI.errno)
26
+ raise SystemCallError.new(
27
+ "KQueue failed" +
28
+ case errno
29
+ when Errno::EFAULT::Errno; ": There was an error reading or writing the kevent structure."
30
+ when Errno::EBADF::Errno; ": The specified descriptor is invalid."
31
+ when Errno::EINTR::Errno; ": A signal was delivered before the timeout expired and before any events were placed on the kqueue for return."
32
+ when Errno::EINVAL::Errno; ": The specified time limit or filter is invalid."
33
+ when Errno::ENOENT::Errno; ": The event could not be found to be modified or deleted."
34
+ when Errno::ENOMEM::Errno; ": No memory was available to register the event."
35
+ when Errno::ESRCH::Errno; ": The specified process to attach to does not exist."
36
+ else; ""
37
+ end,
38
+ errno)
39
+ end
40
+ end
@@ -0,0 +1,83 @@
1
+ module KQueue
2
+ # An event produced by kqueue.
3
+ # Each {Watcher} can fire many events,
4
+ # which are passed to that Watcher's callback.
5
+ class Event
6
+ # Some integer data, the interpretation of which
7
+ # is specific to each individual {Watcher}.
8
+ # For specifics, see the individual Watcher subclasses.
9
+ #
10
+ # `data` is not meaningful for all events.
11
+ # For example, file-change notifications do not set `data`.
12
+ #
13
+ # @return [Fixnum]
14
+ attr_reader :data
15
+
16
+ # The name of the kqueue filter that created this event,
17
+ # e.g. `:vnode` or `:read`.
18
+ #
19
+ # @private
20
+ # @return [Symbol]
21
+ attr_reader :filter
22
+
23
+ # The {Watcher} that produced this event.
24
+ #
25
+ # @return [Watcher]
26
+ def watcher
27
+ @watcher ||= @queue.watchers[[filter, @native[:ident]]]
28
+ end
29
+
30
+ # An array of flags, the interpretation of which
31
+ # is specific to each individual {Watcher}.
32
+ #
33
+ # If the Watcher watches for different sorts of events,
34
+ # this is usually the specific events that actually occurred.
35
+ # For example, for file-change notifications this could be `[:delete]`.
36
+ #
37
+ # `flags` is not meaningful for all events.
38
+ # For example, readability notifications do not set `flags`.
39
+ #
40
+ # @return [Array<Symbol>]
41
+ def flags
42
+ @fflags ||= Native::Flags.from_mask("NOTE_#{filter.to_s.upcase}", @native[:fflags])
43
+ end
44
+
45
+ # Returns whether the end-of-file flag has been set for this event.
46
+ # The interpretation of this is specific to each individual {Watcher}.
47
+ #
48
+ # `eof?` is not meaningful for all events.
49
+ # For example, file-change notifications don't set `eof?`.
50
+ #
51
+ # @return [Boolean]
52
+ def eof?
53
+ @flags.include?(:eof)
54
+ end
55
+
56
+ # Creates a new event from a native event structure.
57
+ #
58
+ # @private
59
+ # @param native [Native::Event] The native event structure
60
+ # from which to construct this event
61
+ # @param queue [Queue] The queue that produced this event
62
+ # @raise [SystemCallError] If this event signals an error
63
+ def initialize(native, queue)
64
+ @native = native
65
+ @queue = queue
66
+ @data = @native[:data]
67
+ @filter = KQueue::Native::Flags.from_flag("EVFILT", @native[:filter])
68
+ @flags = Native::Flags.from_mask("EV", @native[:flags])
69
+
70
+ KQueue.handle_error @native[:data] if @flags.include?(:error)
71
+ end
72
+
73
+ # Runs the callback for this event.
74
+ # This callback is associated with the {Watcher}
75
+ # that produced the event.
76
+ #
77
+ # @private
78
+ # @return [void]
79
+ def callback!
80
+ watcher.callback! self
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,41 @@
1
+ require 'ffi'
2
+
3
+ module KQueue
4
+ # This module contains the low-level foreign-function interface code
5
+ # for dealing with the kqueue C APIs.
6
+ # It's an implementation detail, and not meant for users to deal with.
7
+ #
8
+ # @private
9
+ module Native
10
+ extend FFI::Library
11
+ ffi_lib FFI::Library::LIBC
12
+
13
+ # The C struct describing a kqueue event.
14
+ #
15
+ # @private
16
+ class KEvent < FFI::Struct
17
+ layout(
18
+ :ident, :uintptr_t,
19
+ :filter, :int16,
20
+ :flags, :uint16,
21
+ :fflags, :uint32,
22
+ :data, :intptr_t,
23
+ :udata, :pointer)
24
+ end
25
+
26
+ # The C struct describing a timeout.
27
+ #
28
+ # @private
29
+ class TimeSpec < FFI::Struct
30
+ layout(
31
+ :tv_sec, :time_t,
32
+ :tv_nsec, :long)
33
+ end
34
+
35
+ attach_function :kqueue, [], :int
36
+ attach_function :kevent, [:int, :pointer, :int, :pointer, :int, :pointer], :int
37
+
38
+ attach_function :open, [:string, :int], :int
39
+ attach_function :close, [:int], :int
40
+ end
41
+ end
@@ -0,0 +1,114 @@
1
+ module KQueue
2
+ module Native
3
+ # A module containing all the C-level integer flags
4
+ # that are used with kqueue.
5
+ #
6
+ # @private
7
+ module Flags
8
+ # Filters
9
+ EVFILT_READ = -1
10
+ EVFILT_WRITE = -2
11
+ EVFILT_AIO = -3 # Attached to aio requests
12
+ EVFILT_VNODE = -4 # Attached to vnodes
13
+ EVFILT_PROC = -5 # Attached to struct proc
14
+ EVFILT_SIGNAL = -6 # Attached to struct proc
15
+ EVFILT_TIMER = -7 # Timers
16
+ EVFILT_MACHPORT = -8 # Mach portsets
17
+ EVFILT_FS = -9 # Filesystem events
18
+ EVFILT_USER = -10 # User events
19
+ EVFILT_SESSION = -11 # Audit session events
20
+
21
+
22
+ # Actions
23
+ EV_ADD = 0x0001 # Add event to kq (implies enable)
24
+ EV_DELETE = 0x0002 # Delete event from kq
25
+ EV_ENABLE = 0x0004 # Enable event
26
+ EV_DISABLE = 0x0008 # Disable event (not reported)
27
+ EV_RECEIPT = 0x0040 # Force EV_ERROR on success, data == 0
28
+
29
+ # Flags
30
+ EV_ONESHOT = 0x0010 # Only report one occurrence
31
+ EV_CLEAR = 0x0020 # Clear event state after reporting
32
+ EV_DISPATCH = 0x0080 # Disable event after reporting
33
+
34
+ # Returned values
35
+ EV_EOF = 0x8000 # EOF detected
36
+ EV_ERROR = 0x4000 # Error, data contains errno
37
+
38
+
39
+ # For `EVFILT_{READ,WRITE}`
40
+ NOTE_READ_LOWAT = NOTE_WRITE_LOWAT = 0x00000001 # Low water mark
41
+
42
+ # For `EVFILT_VNODE`
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
+
51
+ # For `EVFILT_PROC`
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
66
+
67
+
68
+ # Converts a list of flags to the bitmask that the C API expects.
69
+ #
70
+ # @param prefix [String] The prefix for the C names of the flags
71
+ # @param flags [Array<Symbol>]
72
+ # @return [Fixnum]
73
+ def self.to_mask(prefix, flags)
74
+ flags.map {|flag| const_get("#{prefix}_#{flag.to_s.upcase}")}.
75
+ inject(0) {|mask, flag| mask | flag}
76
+ end
77
+
78
+ # Converts a bitmask from the C API into a list of flags.
79
+ #
80
+ # @param prefix [String] The prefix for the C names of the flags
81
+ # @param mask [Fixnum]
82
+ # @return [Array<Symbol>]
83
+ def self.from_mask(prefix, mask)
84
+ re = /^#{Regexp.quote prefix}_/
85
+ constants.select do |c|
86
+ next false unless c =~ re
87
+ const_get(c) & mask != 0
88
+ end.map {|c| c.to_s.sub("#{prefix}_", "").downcase.to_sym}
89
+ end
90
+
91
+ # Converts a flag to the integer that the C API expects.
92
+ #
93
+ # @param prefix [String] The prefix for the C names of the flags
94
+ # @param flag [Symbol]
95
+ # @return [Fixnum]
96
+ def self.to_flag(prefix, flag)
97
+ const_get("#{prefix}_#{flag.to_s.upcase}")
98
+ end
99
+
100
+ # Converts an integer from the C API into a flag.
101
+ #
102
+ # @param prefix [String] The prefix for the C names of the flags
103
+ # @param flag [Fixnum]
104
+ # @return [Symbol]
105
+ def self.from_flag(prefix, flag)
106
+ re = /^#{Regexp.quote prefix}_/
107
+ constants.each do |c|
108
+ next unless c =~ re
109
+ return c.to_s.sub("#{prefix}_", "").downcase.to_sym if const_get(c) == flag
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,365 @@
1
+ module KQueue
2
+ # Queue wraps a single instance of kqueue.
3
+ # It's possible to have more than one instance,
4
+ # but usually unnecessary.
5
+ #
6
+ # New event watchers are added to a queue
7
+ # via various `watch_*` methods.
8
+ # For example, \{#watch\_stream\_for\_read} watches for a stream
9
+ # to become readable, and \{#watch\_file} watches for a file to change.
10
+ #
11
+ # Once watchers are added, \{#run} or \{#process} can be used to fire events.
12
+ # Note that if any event-causing conditions happen
13
+ # between adding a watcher and running one of these methods,
14
+ # these events are also fired once the methods are called.
15
+ #
16
+ # @example
17
+ # # Create the queue
18
+ # queue = KQueue::Queue.new
19
+ #
20
+ # # Run this callback whenever the file path/to/foo.txt is read
21
+ # queue.watch_file("path/to/foo.txt", :write) do
22
+ # puts "Foo.txt was modified!"
23
+ # end
24
+ #
25
+ # # Run this callback whenever this process forks or execs
26
+ # queue.watch_process(Process.pid, :fork, :exec) do |event|
27
+ # # The #flags field of the event object contains the actions that happened
28
+ # puts "This process has #{event.flags.map {|f| f.to_s + "ed"}.join(" and ")}"
29
+ # end
30
+ #
31
+ # # Nothing happens until you run the queue!
32
+ # queue.run
33
+ class Queue
34
+ # The file descriptor of the kqueue.
35
+ #
36
+ # @private
37
+ # @return [Fixnum]
38
+ attr_reader :fd
39
+
40
+ # A hash from filter names and idents to {Watcher}s.
41
+ # The kqueue API guarantees that a (filter, ident) pair
42
+ # uniquely identifies a watcher.
43
+ #
44
+ # This hash allows events to retrieve their watchers.
45
+ #
46
+ # @private
47
+ # @return [{(Symbol, Fixnum) => Watcher}]
48
+ attr_reader :watchers
49
+
50
+ # Creates a new, empty queue.
51
+ def initialize
52
+ @fd = Native.kqueue
53
+ @watchers = {}
54
+ end
55
+
56
+ # Watches a stream and produces an event when there's data available to read.
57
+ #
58
+ # This can watch files, pipes, fifos, and BPF devices.
59
+ # For files, an event is fired whenever the file pointer
60
+ # is not at the end of the file,
61
+ # and the {Event#data} field is set to the offset
62
+ # from the current position to the end of the file.
63
+ # {Event#data} may be negative.
64
+ #
65
+ # For pipes and fifos, an event is fired whenever there's data to read.
66
+ # The {Event#data} field is set to the number of bytes available.
67
+ # When the last writer disconnects, {Event#eof?} will be set.
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
+ #
80
+ # @param fd [IO, Fixnum] A Ruby IO stream, or the file descriptor
81
+ # for a native IO stream.
82
+ # @yield [event] A block that will be run when the specified stream
83
+ # has data to read.
84
+ # @yieldparam event [Event] The Event object containing information
85
+ # about the event that occurred.
86
+ # @return [Watcher] The Watcher for this event.
87
+ # @raise [SystemCallError] If something goes wrong when registering the Watcher.
88
+ def watch_stream_for_read(fd, &callback)
89
+ Watcher::ReadWrite.new(self, fd, :read, callback)
90
+ end
91
+
92
+ # Watches a socket and produces an event when there's data available to read.
93
+ #
94
+ # Sockets which have previously had `Socket#listen` called fire events
95
+ # when there is an incoming connection pending.
96
+ # In this case, {Event#data} contains the size of the listen backlog.
97
+ #
98
+ # Other sockets return when there is data to be read,
99
+ # subject to the SO_RCVLOWAT value of the socket buffer.
100
+ # This may be overridden via the `low_water` parameter,
101
+ # which sets a new low-water mark.
102
+ # In this case, {Event#data} contains the number of bytes
103
+ # of protocol data available to read.
104
+ #
105
+ # If the read direction of the socket has shut down,
106
+ # then {Event#eof?} is set.
107
+ # It's possible for {Event#eof?} to be set while there's still
108
+ # data pending in the socket buffer.
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
+ #
114
+ # @param fd [Socket, Fixnum] A Ruby Socket, or the file descriptor
115
+ # for a native Socket.
116
+ # @param low_water [Fixnum] The low-water mark for new data.
117
+ # @yield [event] A block that will be run when the specified socket
118
+ # has data to read.
119
+ # @yieldparam event [Event] The Event object containing information
120
+ # about the event that occurred.
121
+ # @return [Watcher] The Watcher for this event.
122
+ # @raise [SystemCallError] If something goes wrong when registering the Watcher.
123
+ def watch_socket_for_read(fd, low_water = nil, &callback)
124
+ Watcher::SocketReadWrite.new(self, fd, :read, low_water, callback)
125
+ end
126
+
127
+ # Watches a stream and produces an event
128
+ # when it's possible to write to the stream.
129
+ #
130
+ # This can watch pipes and fifos.
131
+ # The {Event#data} field is set to the amount of space
132
+ # remaining in the write buffer.
133
+ # When the reader disconnects, {Event#eof?} will be set.
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
+ #
139
+ # @param fd [IO, Fixnum] A Ruby IO stream, or the file descriptor
140
+ # for a native IO stream.
141
+ # @yield [event] A block that will be run when the specified stream
142
+ # has data to read.
143
+ # @yieldparam event [Event] The Event object containing information
144
+ # about the event that occurred.
145
+ # @return [Watcher] The Watcher for this event.
146
+ # @raise [SystemCallError] If something goes wrong when registering the Watcher.
147
+ def watch_stream_for_write(fd, &callback)
148
+ Watcher::ReadWrite.new(self, fd, :write, callback)
149
+ end
150
+
151
+ # Watches a socket and produces an event when it's possible to write.
152
+ # The {Event#data} field is set to the amount of space
153
+ # remaining in the write buffer.
154
+ #
155
+ # When an event is fired is subject to the
156
+ # subject to the SO_RCVLOWAT value of the socket buffer.
157
+ # This may be overridden via the `low_water` parameter,
158
+ # which sets a new low-water mark.
159
+ #
160
+ # If the write direction of the socket has shut down,
161
+ # then {Event#eof?} is set.
162
+ # It's possible for {Event#eof?} to be set while there's still
163
+ # data pending in the socket buffer.
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
+ #
169
+ # @param fd [Socket, Fixnum] A Ruby Socket, or the file descriptor
170
+ # for a native Socket.
171
+ # @param low_water [Fixnum] The low-water mark for new data.
172
+ # @yield [event] A block that will be run when it's possible
173
+ # to write to the specified socket.
174
+ # @yieldparam event [Event] The Event object containing information
175
+ # about the event that occurred.
176
+ # @return [Watcher] The Watcher for this event.
177
+ # @raise [SystemCallError] If something goes wrong when registering the Watcher.
178
+ def watch_socket_for_write(fd, low_water = nil, &callback)
179
+ Watcher::SocketReadWrite.new(self, fd, :write, low_water, callback)
180
+ end
181
+
182
+ # Watches a file or directory for changes.
183
+ # The `flags` parameter specifies which changes
184
+ # will fire events.
185
+ #
186
+ # The {Event#flags} field contains the changes that caused the event to be fired.
187
+ # {Event#data} and {Event#eof?} are unused.
188
+ #
189
+ # Note that this only watches a single file.
190
+ # If the file is a direcotry,
191
+ # it will only report changes to the directory itself,
192
+ # not to any files within the directory.
193
+ #
194
+ # ## Flags
195
+ #
196
+ # `:delete`
197
+ # : The file was deleted.
198
+ #
199
+ # `:write`
200
+ # : The file was modified.
201
+ #
202
+ # `:extend`
203
+ # : The size of the file increased.
204
+ #
205
+ # `:attrib`
206
+ # : Attributes of the file, such as timestamp or permissions, changed.
207
+ #
208
+ # `:link`
209
+ # : The link count of the file changed.
210
+ #
211
+ # `:rename`
212
+ # : The file was renamed.
213
+ #
214
+ # `:revoke`
215
+ # : Access to the file was revoked,
216
+ # either via the `revoke(2)` system call
217
+ # or because the underlying filesystem was unmounted.
218
+ #
219
+ # @param path [String] The path to the file or directory.
220
+ # @param flags [Array<Symbol>] Which events to watch for.
221
+ # @yield [event] A block that will be run when the file changes.
222
+ # @yieldparam event [Event] The Event object containing information
223
+ # about the event that occurred.
224
+ # @return [Watcher] The Watcher for this event.
225
+ # @raise [SystemCallError] If something goes wrong when registering the Watcher.
226
+ def watch_file(path, *flags, &callback)
227
+ Watcher::File.new(self, path, flags, callback)
228
+ end
229
+
230
+ # Watches a process for changes.
231
+ # The `flags` parameter specifies which changes
232
+ # will fire events.
233
+ #
234
+ # The {Event#flags} field contains the changes that caused the event to be fired.
235
+ # {Event#data} and {Event#eof?} are unused.
236
+ #
237
+ # ## Flags
238
+ #
239
+ # `:exit`
240
+ # : The process has exited.
241
+ #
242
+ # `:fork`
243
+ # : The process has created a child process via `fork(2)` or similar.
244
+ #
245
+ # `:exec`
246
+ # : The process has executed a new process via `exec(2)` or similar.
247
+ #
248
+ # `:signal`
249
+ # : The process was sent a signal.
250
+ # This is only supported under Darwin/OS X.
251
+ #
252
+ # `:reap`
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.
263
+ #
264
+ # @param pid [Fixnum] The id of the process.
265
+ # @param flags [Array<Symbol>] Which events to watch for.
266
+ # @yield [event] A block that will be run when the process changes.
267
+ # @yieldparam event [Event] The Event object containing information
268
+ # about the event that occurred.
269
+ # @return [Watcher] The Watcher for this event.
270
+ # @raise [SystemCallError] If something goes wrong when registering the Watcher.
271
+ def watch_process(pid, *flags, &callback)
272
+ Watcher::Process.new(self, path, flags, callback)
273
+ end
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
+
309
+ # Starts the queue watching for events.
310
+ # Blocks until \{#stop} is called.
311
+ #
312
+ # @see #process
313
+ # @return [void]
314
+ def run
315
+ @stop = false
316
+ process until @stop
317
+ end
318
+
319
+ # Stop watching for events.
320
+ # That is, if we're in a \{#run} loop,
321
+ # exit out as soon as we finish handling
322
+ # the current batch of events.
323
+ #
324
+ # @return [void]
325
+ def stop
326
+ @stop = true
327
+ end
328
+
329
+ # Blocks until there are one or more events
330
+ # that this queue has watchers registered for.
331
+ # Once there are events, the appropriate callbacks are called
332
+ # and this function returns.
333
+ #
334
+ # @see #run
335
+ # @return [void]
336
+ def process
337
+ read_events.each {|event| event.callback!}
338
+ end
339
+
340
+ def poll
341
+ read_events(false).each {|event| event.callback!}
342
+ end
343
+
344
+ NULL_TIMEOUT = Native::TimeSpec.new.tap { |ts|
345
+ ts[:tv_sec] = 0
346
+ ts[:tv_nsec] = 0
347
+ }
348
+
349
+ # Blocks until there are one or more filesystem events
350
+ # that this notifier has watchers registered for.
351
+ # Once there are events, returns their {Event} objects.
352
+ #
353
+ # @private
354
+ def read_events(blocking = true)
355
+ size = 1024
356
+ eventlist = FFI::MemoryPointer.new(Native::KEvent, size)
357
+
358
+ timeout = blocking ? nil : NULL_TIMEOUT
359
+ res = Native.kevent(@fd, nil, 0, eventlist, size, timeout)
360
+
361
+ KQueue.handle_error if res < 0
362
+ (0...res).map {|i| KQueue::Event.new(Native::KEvent.new(eventlist[i]), self)}
363
+ end
364
+ end
365
+ end
@@ -0,0 +1,124 @@
1
+ module KQueue
2
+ # Watchers monitor for a single sort of event,
3
+ # specified by the specific subclass and its parameters.
4
+ # A watcher is usually created via one of the `watch_*` methods
5
+ # on {Queue}.
6
+ #
7
+ # One {Queue} may have many {Watcher}s.
8
+ # The Queue actually takes care of the checking for events,
9
+ # via \{Queue#run #run} or \{Queue#process #process}.
10
+ #
11
+ # Watcher objects themselves have several useful capabilities.
12
+ # Each subclass keeps track of its own specific information.
13
+ # In addition, all Watchers can be \{#delete! deleted from the queue},
14
+ # \{#add! added back in}, \{#disable! disabled}, and \{#enable! enabled}.
15
+ class Watcher
16
+ # The {Queue} that created this Watcher.
17
+ #
18
+ # @return [Queue]
19
+ attr_reader :queue
20
+
21
+ # Creates a new Watcher.
22
+ #
23
+ # @private
24
+ # @param queue [Queue] The queue for which this watcher will be used.
25
+ # @param ident [Fixnum] The underlying kqueue identifier for this watcher.
26
+ # @param filter [Symbol] The name of the underlying kqueue filter for this watcher.
27
+ # @param fflags [Array<Symbol>] Filter-specific flags.
28
+ # @param data [Fixnum] Filter-specific data.
29
+ # @param callback [Proc{Event -> void}] The callback that will be called
30
+ # on any events fired by this watcher.
31
+ # @raise [SystemCallError] If something goes wrong when registering this Watcher.
32
+ def initialize(queue, ident, filter, fflags, data, callback)
33
+ @queue = queue
34
+ @ident = ident
35
+ @filter = filter
36
+ @flags = []
37
+ @fflags = fflags
38
+ @data = data
39
+ @callback = callback
40
+ add!
41
+ end
42
+
43
+ # Adds this Watcher to \{#queue its Queue}.
44
+ # Note that this is done automatically when the Watcher is created.
45
+ #
46
+ # @raise [SystemCallError] If something goes wrong when adding this Watcher.
47
+ # @return [void]
48
+ def add!
49
+ kevent! :add, :clear # TODO: Don't always enable :clear
50
+ @queue.watchers[[@filter, @ident]] = self
51
+ end
52
+
53
+ # Removes this Watcher from \{#queue its Queue}.
54
+ # This means that events won't be fired
55
+ # or even checked for.
56
+ #
57
+ # @raise [SystemCallError] If something goes wrong when deleting this Watcher.
58
+ # @return [void]
59
+ def delete!
60
+ kevent! :delete
61
+ @queue.watchers.delete([@filter, @ident])
62
+ end
63
+
64
+ # Enables this Watcher.
65
+ # Note that this is done automatically when the Watcher is created,
66
+ # as well as whenever \{#add!} is called.
67
+ #
68
+ # @raise [SystemCallError] If something goes wrong when enabling this Watcher.
69
+ # @return [void]
70
+ def enable!
71
+ kevent! :enable
72
+ end
73
+
74
+ # Disables this Watcher.
75
+ # This means that events won't be fired,
76
+ # but they'll still be checked for.
77
+ #
78
+ # @raise [SystemCallError] If something goes wrong when enabling this Watcher.
79
+ # @return [void]
80
+ def disable!
81
+ kevent! :disable
82
+ end
83
+
84
+ # Calls this Watcher's callback with the given {Event}.
85
+ #
86
+ # @private
87
+ # @param event [Event]
88
+ # @return [void]
89
+ def callback!(event)
90
+ @callback.call event
91
+ end
92
+
93
+ private
94
+
95
+ # Returns a C struct corresponding to this watcher.
96
+ #
97
+ # @param flags [Array<Symbol>] Flags for the C struct's `flags` field,
98
+ # in addition to the `@flags` var.
99
+ # @return [Native::KEvent]
100
+ def native(flags)
101
+ native = Native::KEvent.new
102
+ native[:ident] = @ident
103
+ native[:filter] = Native::Flags.to_flag("EVFILT", @filter)
104
+ native[:flags] = Native::Flags.to_mask("EV", @flags | flags)
105
+ native[:fflags] = Native::Flags.to_mask("NOTE_#{@filter.to_s.upcase}", @fflags)
106
+ native[:data] = @data if @data
107
+ native
108
+ end
109
+
110
+ # Runs the `kevent` C call with this Watcher's kevent struct as input.
111
+ # This effectively means telling kqueue to perform some action
112
+ # with this Watcher as an argument.
113
+ #
114
+ # @param flags [Array<Symbol>] Flags specifying the action to perform
115
+ # as well as any additional flags.
116
+ # @return [void]
117
+ # @raise [SystemCallError] If something goes wrong when performing the C call.
118
+ def kevent!(*flags)
119
+ if Native.kevent(@queue.fd, native(flags).pointer, 1, nil, 0, nil) < 0
120
+ KQueue.handle_error
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,56 @@
1
+ module KQueue
2
+ class Watcher
3
+ # The {Watcher} subclass for events fired when a file changes.
4
+ # File events are watched via {Queue#watch_file}.
5
+ class File < Watcher
6
+ # The path to the file being watched.
7
+ #
8
+ # @return [String]
9
+ attr_reader :path
10
+
11
+ # Creates a new file Watcher.
12
+ #
13
+ # @private
14
+ def initialize(queue, path, flags, callback)
15
+ @path = path
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)
52
+ super(queue, @fd, :vnode, flags, nil, callback)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,20 @@
1
+ module KQueue
2
+ class Watcher
3
+ # The {Watcher} subclass for process events.
4
+ # Process events are watched via {Queue#watch_process}.
5
+ class Process < Watcher
6
+ # The process id of the process being watched.
7
+ #
8
+ # @return [Fixnum]
9
+ attr_reader :pid
10
+
11
+ # Creates a new process Watcher.
12
+ #
13
+ # @private
14
+ def initialize(queue, pid, flags, callback)
15
+ @pid = pid
16
+ super(queue, pid, :proc, flags, nil, callback)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,44 @@
1
+ module KQueue
2
+ class Watcher
3
+ # The {Watcher} subclass for events
4
+ # fired when a stream can be read from or written to
5
+ # (which of these is determined by \{#type}).
6
+ # Read events are watched via {Queue#watch_stream_for_read},
7
+ # and write events are watched via {Queue#watch_stream_for_write}.
8
+ #
9
+ # Note that read and write events for sockets
10
+ # use the {SocketReadWrite} class.
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
+
19
+ # The file descriptor for the stream being watched.
20
+ #
21
+ # @return [Fixnum]
22
+ attr_reader :fd
23
+
24
+ # The type of watcher, `:read` or `:write`.
25
+ #
26
+ # @return [Symbol]
27
+ attr_reader :type
28
+
29
+ # Creates a new read/write Watcher.
30
+ #
31
+ # @private
32
+ def initialize(queue, fd, type, callback)
33
+ if fd.is_a?(IO)
34
+ @io = fd
35
+ fd = fd.fileno
36
+ end
37
+
38
+ @fd = fd
39
+ @type = type
40
+ super(queue, @fd, type, [], nil, callback)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -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,43 @@
1
+ module KQueue
2
+ class Watcher
3
+ # The {Watcher} subclass for events
4
+ # fired when a socket can be read from or written to
5
+ # (which of these is determined by \{ReadWrite#type}).
6
+ # Read events are watched via {Queue#watch_socket_for_read},
7
+ # and write events are watched via {Queue#watch_socket_for_write}.
8
+ #
9
+ # Note that read and write events for non-socket streams
10
+ # use the {ReadWrite} class.
11
+ class SocketReadWrite < ReadWrite
12
+ # The custom low-water mark for the amount of data necessary
13
+ # to trigger an event,
14
+ # or `nil` if none has been set.
15
+ #
16
+ # @return [Fixnum, nil]
17
+ attr_reader :low_water
18
+
19
+ # Creates a new socket Watcher.
20
+ #
21
+ # @private
22
+ def initialize(queue, fd, type, low_water, callback)
23
+ if fd.is_a?(IO)
24
+ @io = fd
25
+ fd = fd.fileno
26
+ end
27
+
28
+ @fd = fd
29
+ @type = type
30
+
31
+ if low_water
32
+ fflags = [:lowat]
33
+ data = low_water
34
+ else
35
+ fflags = []
36
+ data = nil
37
+ end
38
+
39
+ super(queue, @fd, type, fflags, data, callback)
40
+ end
41
+ end
42
+ end
43
+ 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
@@ -0,0 +1,61 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rb-kqueue-burke}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Nathan Weizenbaum"]
12
+ s.date = %q{2010-02-08}
13
+ s.description = %q{A Ruby wrapper for BSD's kqueue, using FFI}
14
+ s.email = %q{nex342@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ ".yardopts",
21
+ "MIT-LICENSE",
22
+ "README.md",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "lib/rb-kqueue.rb",
26
+ "lib/rb-kqueue/event.rb",
27
+ "lib/rb-kqueue/native.rb",
28
+ "lib/rb-kqueue/native/flags.rb",
29
+ "lib/rb-kqueue/queue.rb",
30
+ "lib/rb-kqueue/watcher.rb",
31
+ "lib/rb-kqueue/watcher/file.rb",
32
+ "lib/rb-kqueue/watcher/process.rb",
33
+ "lib/rb-kqueue/watcher/read_write.rb",
34
+ "lib/rb-kqueue/watcher/signal.rb",
35
+ "lib/rb-kqueue/watcher/socket_read_write.rb",
36
+ "lib/rb-kqueue/watcher/timer.rb",
37
+ "rb-kqueue-burke.gemspec"
38
+ ]
39
+ s.homepage = %q{http://github.com/burke/rb-kqueue}
40
+ s.rdoc_options = ["--charset=UTF-8"]
41
+ s.require_paths = ["lib"]
42
+ s.rubygems_version = %q{1.3.5}
43
+ s.summary = %q{A Ruby wrapper for BSD's kqueue, using FFI}
44
+
45
+ if s.respond_to? :specification_version then
46
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
50
+ s.add_runtime_dependency(%q<ffi>, [">= 0.5.0"])
51
+ s.add_development_dependency(%q<yard>, [">= 0.4.0"])
52
+ else
53
+ s.add_dependency(%q<ffi>, [">= 0.5.0"])
54
+ s.add_dependency(%q<yard>, [">= 0.4.0"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<ffi>, [">= 0.5.0"])
58
+ s.add_dependency(%q<yard>, [">= 0.4.0"])
59
+ end
60
+ end
61
+
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rb-kqueue-burke
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nathan Weizenbaum
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2010-02-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ffi
16
+ requirement: &70244761446700 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.5.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70244761446700
25
+ - !ruby/object:Gem::Dependency
26
+ name: yard
27
+ requirement: &70244761445980 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 0.4.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70244761445980
36
+ description: A Ruby wrapper for BSD's kqueue, using FFI
37
+ email: nex342@gmail.com
38
+ executables: []
39
+ extensions: []
40
+ extra_rdoc_files:
41
+ - README.md
42
+ files:
43
+ - .gitignore
44
+ - .yardopts
45
+ - MIT-LICENSE
46
+ - README.md
47
+ - Rakefile
48
+ - VERSION
49
+ - lib/rb-kqueue.rb
50
+ - lib/rb-kqueue/event.rb
51
+ - lib/rb-kqueue/native.rb
52
+ - lib/rb-kqueue/native/flags.rb
53
+ - lib/rb-kqueue/queue.rb
54
+ - lib/rb-kqueue/watcher.rb
55
+ - lib/rb-kqueue/watcher/file.rb
56
+ - lib/rb-kqueue/watcher/process.rb
57
+ - lib/rb-kqueue/watcher/read_write.rb
58
+ - lib/rb-kqueue/watcher/signal.rb
59
+ - lib/rb-kqueue/watcher/socket_read_write.rb
60
+ - lib/rb-kqueue/watcher/timer.rb
61
+ - rb-kqueue-burke.gemspec
62
+ homepage: http://github.com/burke/rb-kqueue
63
+ licenses: []
64
+ post_install_message:
65
+ rdoc_options:
66
+ - --charset=UTF-8
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 1.8.11
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: A Ruby wrapper for BSD's kqueue, using FFI
87
+ test_files: []