public
Description: KQueue bindings for Ruby
Clone URL: git://github.com/kevinclark/ruby-kqueue.git
Search Repo:
[NEW] Deregistration of events
[FIX] Don't block on kevent call
[API] Change Event.register to take a filter or filter class
kevinclark (author)
Wed Apr 02 18:59:47 -0700 2008
commit  ee1e2e5306e2d6e1645a1ca57440edd9addee67a
tree    17eb9edaf8d04499fda0800ba10fd015d908b9fc
parent  b83fa685a421d74a509ca55543a81f2cbd27eac0
...
2
3
4
5
6
7
8
...
2
3
4
 
5
6
7
0
@@ -2,7 +2,6 @@ History.txt
0
 Manifest.txt
0
 README.txt
0
 Rakefile
0
-bin/ruby-kqueue
0
 lib/ruby-kqueue.rb
0
 lib/ruby-kqueue/event.rb
0
 lib/ruby-kqueue/vnode_event.rb
...
55
56
57
 
58
59
60
61
62
63
64
65
 
66
67
 
 
68
69
70
71
72
 
 
 
 
 
73
 
 
 
 
 
74
75
76
...
81
82
83
84
 
85
86
87
...
91
92
93
94
95
96
 
 
 
 
 
 
 
97
98
99
...
107
108
109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
111
112
113
114
115
 
116
117
118
...
158
159
160
161
 
 
 
 
 
 
 
 
 
162
163
164
...
55
56
57
58
59
60
61
62
 
 
 
 
63
64
 
65
66
67
68
69
70
 
71
72
73
74
75
76
77
78
79
80
81
82
83
84
...
89
90
91
 
92
93
94
95
...
99
100
101
 
 
 
102
103
104
105
106
107
108
109
110
111
...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
 
149
150
151
152
...
192
193
194
 
195
196
197
198
199
200
201
202
203
204
205
206
0
@@ -55,22 +55,30 @@ module RubyKQueue
0
         VALUE c_handle_events() {
0
           int nevents, i, num_to_fetch;
0
           struct kevent *events;
0
+ struct timespec timeout;
0
           fd_set read_set;
0
       
0
           FD_ZERO(&read_set);
0
           FD_SET(kq, &read_set);
0
-
0
- // Don't actually run this method until we've got an event
0
- rb_thread_select(kq + 1, &read_set, NULL, NULL, NULL);
0
-
0
+
0
           events = (struct kevent*)malloc(MAX_EVENTS * sizeof(struct kevent));
0
-
0
+ bzero(&timeout, sizeof(struct timespec));
0
+
0
           if (NULL == events) {
0
             rb_raise(rb_eStandardError, strerror(errno));
0
           }
0
       
0
- nevents = kevent(kq, NULL, 0, events, MAX_EVENTS, NULL);
0
+ // Don't actually run this method until we've got an event
0
+ if (rb_thread_select(kq + 1, &read_set, NULL, NULL, NULL) <= 0) {
0
+ free(events);
0
+ rb_raise(rb_eStandardError, strerror(errno));
0
+ }
0
       
0
+ // In testing kevent has been blocking, even though select continues
0
+ // so set a tiny timeout just in case. It _should_ execute immediately
0
+ timeout.tv_nsec = 10;
0
+ nevents = kevent(kq, NULL, 0, events, MAX_EVENTS, &timeout);
0
+
0
           if (-1 == nevents) {
0
             free(events);
0
             rb_raise(rb_eStandardError, strerror(errno));
0
@@ -81,7 +89,7 @@ module RubyKQueue
0
           }
0
       
0
           free(events);
0
-
0
+
0
           return INT2FIX(nevents);
0
         }
0
       END
0
@@ -91,9 +99,13 @@ module RubyKQueue
0
     
0
     # TODO: Allow a lower level interface for direct manipulation
0
     # of registration flags (EV_ONESHOT and the like)
0
- def self.register(ident, filter_class, *flags, &block)
0
- ident = filter_class.normalize_ident(ident)
0
- filter = filter_class::FILTER
0
+ def self.register(ident, filter_or_filter_class, *flags, &block)
0
+ if filter_or_filter_class.is_a? Class
0
+ ident = filter_or_filter_class.normalize_ident(ident)
0
+ filter = filter_or_filter_class::FILTER
0
+ else
0
+ filter = filter_or_filter_class
0
+ end
0
       
0
       @@registry[filter] ||= {}
0
       @@registry[filter][ident] ||= {}
0
@@ -107,12 +119,34 @@ module RubyKQueue
0
       c_register(ident, EV_ADD | EV_ENABLE, filter, mask)
0
     end
0
     
0
+ def self.deregister(ident, filter_or_filter_class, *flags)
0
+ # puts "Calling deregister"
0
+ # puts "Registry like: #{@@registry.inspect}"
0
+ if filter_or_filter_class.is_a? Class
0
+ ident = filter_or_filter_class.normalize_ident(ident)
0
+ filter = filter_or_filter_class::FILTER
0
+ else
0
+ filter = filter_or_filter_class
0
+ end
0
+
0
+ flags.each do |flag|
0
+ @@registry[filter][ident].delete(flag) rescue nil
0
+ end
0
+
0
+ # puts "Now registry like: #{@@registry.inspect}"
0
+
0
+ mask = flags.inject {|msk, flg| msk | flg }
0
+
0
+ # puts "Calling c_register"
0
+ c_register(ident, EV_DELETE, filter, mask)
0
+ end
0
+
0
     def self.trigger(id, filter, flag)
0
       Event.new(id, filter, flag).trigger
0
     end
0
     
0
     def self.handle
0
- c_handle_events
0
+ @@handler_thread ||= Thread.new { loop { c_handle_events } }
0
     end
0
     
0
     def self.registry
0
@@ -158,6 +192,14 @@ module RubyKQueue
0
         # TODO: ignore or raise?
0
       end
0
     end
0
-
0
+
0
+ def register
0
+ self.class.register(self.id, self.filter, self.flag)
0
+ end
0
+
0
+ def deregister
0
+ self.class.deregister(self.id, self.filter, self.flag)
0
+ end
0
+
0
   end
0
 end
0
\ No newline at end of file
...
22
23
24
25
26
27
 
 
 
 
 
 
 
28
29
30
 
31
32
33
34
35
36
 
 
37
38
 
 
39
40
 
 
 
41
42
43
...
22
23
24
 
 
 
25
26
27
28
29
30
31
32
33
 
34
35
36
37
38
39
40
41
42
43
 
44
45
46
 
47
48
49
50
51
52
0
@@ -22,22 +22,31 @@ module RubyKQueue
0
         42
0
       end
0
       
0
- Event.new(@dir, VNodeEvent, VNodeEvent::WRITE).trigger.should == 42
0
-
0
- # TODO: Deregister
0
+ ev = Event.new(@dir, VNodeEvent, VNodeEvent::WRITE)
0
+
0
+ ev.trigger.should == 42
0
+
0
+ ev.deregister
0
+
0
+ ev.trigger.should == nil
0
     end
0
     
0
- it "should be triggered by an event" do
0
+ it "should be triggered by an event if registered" do
0
       t = Thread.new { Event.handle }
0
       Event.register(@dir, VNodeEvent, VNodeEvent::WRITE) do
0
         $ret = 42
0
       end
0
       
0
       File.open("#{@dir}/writing", 'w+') {|f|}
0
+ sleep 0.00001
0
+ $ret.should == 42
0
       
0
- sleep 0.001
0
+ Event.deregister(@dir, VNodeEvent, VNodeEvent::WRITE)
0
+ $ret = nil
0
       
0
- $ret.should == 42
0
+ File.open("#{@dir}/writing_again", 'w+') {|f|}
0
+ sleep 0.00001
0
+ $ret.should == nil
0
     end
0
   end
0
   

Comments

    No one has commented yet.