kqueue 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 06a7b8bdf52804dcef98ac5f11bcf3164ef7d334
4
+ data.tar.gz: d0151bed17fd2237b52b9d556c999e1005a3704e
5
+ SHA512:
6
+ metadata.gz: cc8b761373f7eb7228e4c1917112bf984c43dc4e31a7e99c649013b419e633535818d9a93692dd3884e5fb017bb11346c758447bb7a16f5c33a5cef6d3b159cb
7
+ data.tar.gz: 1ec0ad58c3c8f5c748c2d4d94d32a18444736299809ad47a60b065527a697b6797cfb6cf3a23bb741bc1d3138e1d9ab84295ece794073dc23f9e024df652d73d
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ *.rbc
3
+ *.bundle
4
+ *.so
5
+ *.o
6
+ tmp
7
+ pkg
@@ -0,0 +1,7 @@
1
+ language: objective-c # osx hack
2
+ rvm:
3
+ - 2.1.5
4
+ os:
5
+ - osx
6
+ script:
7
+ - "bundle exec rake clean compile test"
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,24 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ kqueue (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ power_assert (0.2.2)
10
+ rake (10.4.0)
11
+ rake-compiler (0.9.3)
12
+ rake
13
+ test-unit (3.0.7)
14
+ power_assert
15
+
16
+ PLATFORMS
17
+ ruby
18
+
19
+ DEPENDENCIES
20
+ bundler
21
+ kqueue!
22
+ rake
23
+ rake-compiler
24
+ test-unit
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 ksss
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,143 @@
1
+ kqueue
2
+ ===
3
+
4
+ [![Build Status](https://travis-ci.org/ksss/kqueue.svg?branch=master)](https://travis-ci.org/ksss/kqueue)
5
+
6
+ A binding of kqueue on Ruby.
7
+
8
+ **kqueue** can use BSD system only. (because must be installed sys/event.h)
9
+
10
+ # Usage
11
+
12
+ ```ruby
13
+ require 'kqueue'
14
+
15
+ # Inheritance
16
+ # class Kqueue < IO
17
+ # # ident: file descriptor identifier for this event
18
+ # # filter: filter for event(just one)
19
+ # # flags: general flags(complex fragment)
20
+ # # fflags: filter-specific flags(complex fragment)
21
+ # # data: filter-specific data
22
+ # # udata: opaque user data(can set any object)
23
+ # class Event < Struct.new(:ident, :filter, :flags, :fflags, :data, :udata)
24
+ # # Event::Constants include all kqueue constants
25
+ # include Event::Constants
26
+ # end
27
+ # end
28
+
29
+ # create kqueue object and ensure close
30
+ Kqueue.open do |kq|
31
+ # ...
32
+ end
33
+
34
+ # or
35
+ begin
36
+ kq = Kqueue.new
37
+ # ...
38
+ ensure
39
+ kq.close
40
+ end
41
+
42
+ # watch event
43
+ IO.pipe do |r, w|
44
+ Kqueue.open do |kq|
45
+ kev = Kqueue::Event.new(r.fileno, EVFILT_READ, EV_ADD, 0, 0, proc {
46
+ puts "you can read #{r.fileno} with non block!"
47
+ })
48
+ # set a event
49
+ kq.kevent([kev], 0)
50
+
51
+ # wait a event
52
+ # wait until event occur
53
+ kq.kevent(nil, 1)
54
+
55
+ # wait 0.1 sec
56
+ kq.kevent(nil, 1, 0.1) #=> []
57
+
58
+ w.write 'ok go'
59
+ w.flush
60
+
61
+ # get a notified event
62
+ kevs = kq.kevent(nil, 1) #=> [#<a Event object>]
63
+
64
+ # udata have one any object
65
+ kevs.first.udata.call #=> you can read 7 with non block!
66
+ end
67
+ end
68
+ ```
69
+
70
+ ## filter
71
+
72
+ filter|description
73
+ ---|---
74
+ EVFILT_READ|on read
75
+ EVFILT_WRITE|on write
76
+ EVFILT_AIO|attached to aio requests
77
+ EVFILT_VNODE|attached to vnodes
78
+ EVFILT_PROC|attached to struct proc
79
+ EVFILT_SIGNAL|attached to signal
80
+ EVFILT_TIMER|timers
81
+ EVFILT_MACHPORT|Mach portsets
82
+
83
+ ## flags
84
+
85
+ flags|description
86
+ ---|---
87
+ EV_ADD|add event to kq (implies enable)
88
+ EV_DELETE|delete event from kq
89
+ EV_ENABLE|enable event
90
+ EV_DISABLE|disable event (not reported)
91
+ EV_ONESHOT|only report one occurrence
92
+ EV_CLEAR|clear event state after reporting
93
+ EV_RECEIPT|force EV_ERROR on success, data == 0
94
+ EV_ERROR|error, data contains errno(returned value)
95
+ EV_EOF|EOF detected(returned value)
96
+
97
+ # fflags
98
+
99
+ fflags|description
100
+ ---|---
101
+ NOTE_DELETE|vnode was removed
102
+ NOTE_WRITE|data contents changed
103
+ NOTE_EXTEND|size increased
104
+ NOTE_ATTRIB|attributes changed
105
+ NOTE_LINK|link count changed
106
+ NOTE_RENAME|vnode was renamed
107
+ NOTE_REVOKE|vnode access was revoked
108
+ NOTE_EXIT|process exited
109
+ NOTE_EXITSTATUS|exit status to be returned, valid for child process only
110
+ NOTE_FORK|process forked
111
+ NOTE_EXEC|process exec'd
112
+ NOTE_SIGNAL|shared with EVFILT_SIGNAL
113
+ NOTE_REAP|process reaped
114
+
115
+ ## Installation
116
+
117
+ Add this line to your application's Gemfile:
118
+
119
+ gem 'kqueue'
120
+
121
+ And then execute:
122
+
123
+ $ bundle
124
+
125
+ Or install it yourself as:
126
+
127
+ $ gem install kqueue
128
+
129
+ # Pro Tips
130
+
131
+ - Support call without GVL in CRuby (use rb\_thread\_call\_without\_gvl())
132
+
133
+ # Fork Me !
134
+
135
+ This is experimental implementation.
136
+ I'm waiting for your idea and Pull Request !
137
+
138
+ # see also
139
+
140
+ - man kqueue
141
+ - http://people.freebsd.org/~jlemon/papers/kqueue_freenix.pdf
142
+ - https://www.freebsd.org/cgi/man.cgi?query=kqueue
143
+ - your /usr/include/sys/event.h
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/extensiontask'
3
+ require 'rake/testtask'
4
+
5
+ task :default => [:compile, :test]
6
+
7
+ Rake::ExtensionTask.new('kqueue') do |ext|
8
+ end
9
+ Rake::TestTask.new {|t| t.libs << 'test'}
@@ -0,0 +1,76 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'kqueue'
4
+ require 'socket'
5
+
6
+ class KqServer
7
+ include Kqueue::Event::Constants
8
+
9
+ def self.start(port)
10
+ kqs = new(port)
11
+ yield kqs
12
+ loop do
13
+ kqs.wait.each do |ev|
14
+ ev.udata && ev.udata[1].call(ev.udata[0])
15
+ end
16
+ end
17
+ end
18
+
19
+ def initialize(port)
20
+ @kq = Kqueue.new
21
+ @server = TCPServer.open(port)
22
+ set_event @server, EVFILT_READ do
23
+ socket = @server.accept
24
+ set_event socket, EVFILT_READ do |socket|
25
+ loop do
26
+ chunk = socket.recv(1024)
27
+ @on_data && @on_data.call(chunk)
28
+ break if chunk.length < 4 || chunk[-4..-1] == "\r\n\r\n"
29
+ end
30
+ set_event socket, EVFILT_WRITE do |socket|
31
+ @on_end && @on_end.call(socket)
32
+ del_event(socket, EVFILT_READ)
33
+ del_event(socket, EVFILT_WRITE)
34
+ socket.close
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def set_event(io, filter, &block)
41
+ @kq.kevent([Kqueue::Event.new(io.fileno, filter, EV_ADD, 0, 0, [io, block])], 0)
42
+ end
43
+
44
+ def del_event(io, filter)
45
+ @kq.kevent([Kqueue::Event.new(io.fileno, filter, EV_DELETE, 0, 0, nil)], 0)
46
+ end
47
+
48
+ def wait
49
+ @kq.kevent(nil, 128, 5)
50
+ end
51
+
52
+ def on_data(&block)
53
+ @on_data = block
54
+ end
55
+
56
+ def on_end(&block)
57
+ @on_end = block
58
+ end
59
+ end
60
+
61
+ puts "run http://127.0.0.1:4000/"
62
+
63
+ KqServer.start(4000) do |s|
64
+ s.on_data do |chunk|
65
+ print chunk
66
+ end
67
+ s.on_end do |socket|
68
+ socket.write [
69
+ "HTTP/1.0 200 OK\r\n",
70
+ "Content-Length: 11\r\n",
71
+ "Content-Type: text/html\r\n",
72
+ "\r\n",
73
+ "Hello World\r\n",
74
+ ].join("")
75
+ end
76
+ end
@@ -0,0 +1,238 @@
1
+ #include "ruby.h"
2
+ #include "ruby/io.h"
3
+ #include "ruby/thread.h"
4
+
5
+ #if defined(HAVE_SYS_TYPES_H) && defined(HAVE_SYS_EVENT_H) && defined(HAVE_SYS_TIME_H)
6
+
7
+ #include <fcntl.h>
8
+ #include <alloca.h>
9
+ #include <sys/types.h>
10
+ #include <sys/event.h>
11
+ #include <sys/time.h>
12
+
13
+ VALUE cKqueue;
14
+ VALUE mKqueue_Event_Constants;
15
+ VALUE cKqueue_Event;
16
+ ID id_udata_marks;
17
+
18
+ #define IVAR_GET(self) rb_ivar_get((self), id_udata_marks)
19
+ #define IVAR_SET(self, obj) rb_ivar_set((self), id_udata_marks, (obj))
20
+
21
+ enum enumEvents {
22
+ IDENT,
23
+ FILTER,
24
+ FLAGS,
25
+ FFLAGS,
26
+ DATA,
27
+ UDATA
28
+ };
29
+
30
+ static VALUE
31
+ rb_kqueue_initialize(VALUE self)
32
+ {
33
+ rb_io_t *fp;
34
+ int fd;
35
+
36
+ fd = kqueue();
37
+ if (fd == -1)
38
+ rb_sys_fail("kqueue");
39
+ rb_update_max_fd(fd);
40
+
41
+ MakeOpenFile(self, fp);
42
+ fp->fd = fd;
43
+ fp->mode = FMODE_READABLE|FMODE_BINMODE;
44
+ rb_io_ascii8bit_binmode(self);
45
+
46
+ IVAR_SET(self, rb_hash_new());
47
+
48
+ return self;
49
+ }
50
+
51
+ struct kqueue_kevent_args {
52
+ int fd;
53
+ struct kevent *chl;
54
+ int ch_len;
55
+ struct kevent *evl;
56
+ int ev_len;
57
+ struct timespec *ts;
58
+ };
59
+
60
+ static void *
61
+ rb_kqueue_kevent_func(void *ptr)
62
+ {
63
+ const struct kqueue_kevent_args *args = ptr;
64
+ return (void*)(long)kevent(args->fd, args->chl, args->ch_len, args->evl, args->ev_len, args->ts);
65
+ }
66
+
67
+ static VALUE
68
+ rb_kqueue_kevent(int argc, VALUE *argv, VALUE self)
69
+ {
70
+ VALUE ch_list, max_events, timeout, ev, ready_evlist;
71
+ struct kqueue_kevent_args args;
72
+ struct timespec ts;
73
+ struct timespec *pts = NULL;
74
+ struct timeval tv;
75
+ int i;
76
+ int ev_len = 0, ch_len = 0;
77
+ int ready;
78
+ struct kevent *chl = NULL, *evl = NULL;
79
+ rb_io_t *fptr, *fptr_io;
80
+
81
+ fptr = RFILE(self)->fptr;
82
+ rb_io_check_initialized(fptr);
83
+
84
+ rb_scan_args(argc, argv, "21", &ch_list, &max_events, &timeout);
85
+ if (!NIL_P(max_events)) {
86
+ ev_len = FIX2INT(max_events);
87
+ }
88
+
89
+ if (!NIL_P(timeout)) {
90
+ tv = rb_time_timeval(timeout);
91
+ ts.tv_sec = (time_t)tv.tv_sec;
92
+ ts.tv_nsec = (long)tv.tv_usec * 1000;
93
+ pts = &ts;
94
+ }
95
+
96
+ if (!NIL_P(ch_list)) {
97
+ Check_Type(ch_list, T_ARRAY);
98
+ ch_len = RARRAY_LEN(ch_list);
99
+
100
+ chl = alloca(sizeof(struct kevent) * ch_len);
101
+ for (i = 0; i < ch_len; i++) {
102
+ ev = RARRAY_AREF(ch_list, i);
103
+ if (!rb_obj_is_kind_of(ev, cKqueue_Event)) {
104
+ rb_raise(rb_eTypeError, "must be set Array of Event object");
105
+ }
106
+
107
+ chl[i].ident = FIX2INT(RSTRUCT_GET(ev, IDENT));
108
+ chl[i].filter = FIX2INT(RSTRUCT_GET(ev, FILTER));
109
+ chl[i].flags = FIX2UINT(RSTRUCT_GET(ev, FLAGS));
110
+ chl[i].fflags = FIX2UINT(RSTRUCT_GET(ev, FFLAGS));
111
+ chl[i].data = NUM2LONG(RSTRUCT_GET(ev, DATA));
112
+ {
113
+ VALUE fileno = RSTRUCT_GET(ev, IDENT);
114
+ VALUE filter = RSTRUCT_GET(ev, FILTER);
115
+ VALUE udata = RSTRUCT_GET(ev, UDATA);
116
+ VALUE ivar = IVAR_GET(self);
117
+ VALUE h = rb_hash_aref(ivar, fileno);
118
+ if ((chl[i].flags & EV_DELETE) == EV_DELETE) {
119
+ if (chl[i].flags & ~EV_DELETE) {
120
+ rb_raise(rb_eArgError, "EV_DELETE cannot set with other");
121
+ }
122
+ if (NIL_P(h)) {
123
+ rb_raise(rb_eArgError, "delete udata not found");
124
+ }
125
+ rb_hash_delete(h, filter);
126
+ if (RHASH_EMPTY_P(h)) {
127
+ rb_hash_delete(ivar, fileno);
128
+ }
129
+ udata = (VALUE)0;
130
+ }
131
+ else {
132
+ if (NIL_P(h)) {
133
+ h = rb_hash_aset(ivar, fileno, rb_hash_new());
134
+ }
135
+ rb_hash_aset(h, filter, udata);
136
+ }
137
+ IVAR_SET(self, ivar);
138
+ chl[i].udata = (void*)udata;
139
+ }
140
+ }
141
+ }
142
+
143
+ if (0 < ev_len) {
144
+ evl = alloca(sizeof(struct kevent) * ev_len);
145
+ }
146
+ else if (ev_len < 0) {
147
+ rb_raise(rb_eArgError, "negative size");
148
+ }
149
+
150
+ args.fd = fptr->fd;
151
+ args.chl = chl;
152
+ args.ch_len = ch_len;
153
+ args.evl = evl;
154
+ args.ev_len = ev_len;
155
+ args.ts = pts;
156
+
157
+ RETRY:
158
+ ready = (int)(long)rb_thread_call_without_gvl(rb_kqueue_kevent_func, &args, RUBY_UBF_IO, 0);
159
+ if (ready == -1) {
160
+ if (errno == EINTR)
161
+ goto RETRY;
162
+ else
163
+ rb_sys_fail("kevent");
164
+ }
165
+
166
+ ready_evlist = rb_ary_new_capa(ready);
167
+ for (i = 0; i < ready; i++) {
168
+ ev = rb_obj_alloc(cKqueue_Event);
169
+ RSTRUCT_SET(ev, IDENT, INT2FIX(evl[i].ident));
170
+ RSTRUCT_SET(ev, FILTER, INT2FIX(evl[i].filter));
171
+ RSTRUCT_SET(ev, FLAGS, INT2FIX(evl[i].flags));
172
+ RSTRUCT_SET(ev, FFLAGS, INT2FIX(evl[i].fflags));
173
+ RSTRUCT_SET(ev, FLAGS, INT2FIX(evl[i].flags));
174
+ RSTRUCT_SET(ev, DATA, INT2FIX(evl[i].data));
175
+ RSTRUCT_SET(ev, UDATA, (VALUE)evl[i].udata);
176
+ rb_ary_store(ready_evlist, i, ev);
177
+ }
178
+ return ready_evlist;
179
+ }
180
+ #endif
181
+
182
+ void
183
+ Init_kqueue()
184
+ {
185
+ #if defined(HAVE_SYS_TYPES_H) && defined(HAVE_SYS_EVENT_H) && defined(HAVE_SYS_TIME_H)
186
+
187
+ id_udata_marks = rb_intern("@udata_marks");
188
+
189
+ cKqueue = rb_define_class("Kqueue", rb_cIO);
190
+ rb_define_method(cKqueue, "initialize", rb_kqueue_initialize, 0);
191
+ rb_define_method(cKqueue, "kevent", rb_kqueue_kevent, -1);
192
+
193
+ cKqueue_Event = rb_struct_define_under(cKqueue, "Event", "ident", "filter", "flags", "fflags", "data", "udata", NULL);
194
+
195
+ mKqueue_Event_Constants = rb_define_module_under(cKqueue_Event, "Constants");
196
+
197
+ rb_include_module(cKqueue_Event, mKqueue_Event_Constants);
198
+
199
+ /* actions */
200
+ rb_define_const(mKqueue_Event_Constants, "EV_ADD", INT2FIX((u_short)EV_ADD));
201
+ rb_define_const(mKqueue_Event_Constants, "EV_ENABLE", INT2FIX((u_short)EV_ENABLE));
202
+ rb_define_const(mKqueue_Event_Constants, "EV_DISABLE", INT2FIX((u_short)EV_DISABLE));
203
+ rb_define_const(mKqueue_Event_Constants, "EV_DELETE", INT2FIX((u_short)EV_DELETE));
204
+ rb_define_const(mKqueue_Event_Constants, "EV_RECEIPT", INT2FIX((u_short)EV_RECEIPT));
205
+ /* flags */
206
+ rb_define_const(mKqueue_Event_Constants, "EV_ONESHOT", INT2FIX((u_short)EV_ONESHOT));
207
+ rb_define_const(mKqueue_Event_Constants, "EV_CLEAR", INT2FIX((u_short)EV_CLEAR));
208
+ /* returned values */
209
+ rb_define_const(mKqueue_Event_Constants, "EV_EOF", INT2FIX((u_short)EV_EOF));
210
+ rb_define_const(mKqueue_Event_Constants, "EV_ERROR", INT2FIX((u_short)EV_ERROR));
211
+
212
+ /* for filter */
213
+ rb_define_const(mKqueue_Event_Constants, "EVFILT_READ", INT2FIX((short)EVFILT_READ));
214
+ rb_define_const(mKqueue_Event_Constants, "EVFILT_WRITE", INT2FIX((short)EVFILT_WRITE));
215
+ rb_define_const(mKqueue_Event_Constants, "EVFILT_AIO", INT2FIX((short)EVFILT_AIO));
216
+ rb_define_const(mKqueue_Event_Constants, "EVFILT_VNODE", INT2FIX((short)EVFILT_VNODE));
217
+ rb_define_const(mKqueue_Event_Constants, "EVFILT_PROC", INT2FIX((short)EVFILT_PROC));
218
+ rb_define_const(mKqueue_Event_Constants, "EVFILT_SIGNAL", INT2FIX((short)EVFILT_SIGNAL));
219
+ rb_define_const(mKqueue_Event_Constants, "EVFILT_MACHPORT", INT2FIX((short)EVFILT_MACHPORT));
220
+
221
+ // for EVFILT_VNODE
222
+ rb_define_const(mKqueue_Event_Constants, "NOTE_DELETE", INT2FIX((u_int)NOTE_DELETE));
223
+ rb_define_const(mKqueue_Event_Constants, "NOTE_WRITE", INT2FIX((u_int)NOTE_WRITE));
224
+ rb_define_const(mKqueue_Event_Constants, "NOTE_EXTEND", INT2FIX((u_int)NOTE_EXTEND));
225
+ rb_define_const(mKqueue_Event_Constants, "NOTE_ATTRIB", INT2FIX((u_int)NOTE_ATTRIB));
226
+ rb_define_const(mKqueue_Event_Constants, "NOTE_LINK", INT2FIX((u_int)NOTE_LINK));
227
+ rb_define_const(mKqueue_Event_Constants, "NOTE_RENAME", INT2FIX((u_int)NOTE_RENAME));
228
+ rb_define_const(mKqueue_Event_Constants, "NOTE_REVOKE", INT2FIX((u_int)NOTE_REVOKE));
229
+
230
+ // for EVFILT_PROC
231
+ rb_define_const(mKqueue_Event_Constants, "NOTE_EXIT", INT2FIX((u_int)NOTE_EXIT));
232
+ rb_define_const(mKqueue_Event_Constants, "NOTE_EXITSTATUS", INT2FIX((u_int)NOTE_EXITSTATUS));
233
+ rb_define_const(mKqueue_Event_Constants, "NOTE_FORK", INT2FIX((u_int)NOTE_FORK));
234
+ rb_define_const(mKqueue_Event_Constants, "NOTE_EXEC", INT2FIX((u_int)NOTE_EXEC));
235
+ rb_define_const(mKqueue_Event_Constants, "NOTE_SIGNAL", INT2FIX((u_int)NOTE_SIGNAL));
236
+ rb_define_const(mKqueue_Event_Constants, "NOTE_REAP", INT2FIX((u_int)NOTE_REAP));
237
+ #endif
238
+ }
@@ -0,0 +1,10 @@
1
+ require 'mkmf'
2
+
3
+ headers = %w(sys/types.h sys/event.h sys/time.h)
4
+
5
+ unless headers.all?{|h| have_header(h)}
6
+ puts "*** complie error: gem 'kqueue' must be installed #{headers.to_s}. ***"
7
+ puts "*** you can require 'kqueue'. But, you can not use Kqueue APIs. ***"
8
+ end
9
+
10
+ create_makefile('kqueue')
@@ -0,0 +1,21 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "kqueue"
3
+ spec.version = "0.0.1"
4
+ spec.authors = ["ksss"]
5
+ spec.email = ["co000ri@gmail.com"]
6
+ spec.summary = %q{A Ruby binding for kqueue(2)}
7
+ spec.description = %q{A Ruby binding for kqueue(2)}
8
+ spec.homepage = "https://github.com/ksss/kqueue"
9
+ spec.license = "MIT"
10
+
11
+ spec.files = `git ls-files`.split($/)
12
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
13
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
14
+ spec.require_paths = ["lib"]
15
+ spec.extensions = ["ext/kqueue/extconf.rb"]
16
+
17
+ spec.add_development_dependency "bundler"
18
+ spec.add_development_dependency "rake"
19
+ spec.add_development_dependency 'rake-compiler'
20
+ spec.add_development_dependency 'test-unit'
21
+ end
@@ -0,0 +1,149 @@
1
+ require 'test/unit'
2
+ require 'timeout'
3
+ require 'tempfile'
4
+ require 'kqueue'
5
+
6
+ class TestIOKqueue < Test::Unit::TestCase
7
+ include Kqueue::Event::Constants
8
+
9
+ def test_initalize
10
+ kq = Kqueue.new
11
+ assert_instance_of(Kqueue, kq)
12
+ assert_kind_of(IO, kq)
13
+ assert { true == kq.close_on_exec? }
14
+ kq.close
15
+
16
+ Kqueue.open do |kq|
17
+ assert_instance_of(Kqueue, kq)
18
+ assert_instance_of(Kqueue::Event, Kqueue::Event.new)
19
+ end
20
+ end
21
+
22
+ def test_kevent
23
+ Tempfile.open("test") do |f|
24
+ Kqueue.open do |kq|
25
+ kev_r = Kqueue::Event.new(f.fileno, EVFILT_READ, EV_ADD, 0, 0, nil)
26
+ kev_w = Kqueue::Event.new(f.fileno, EVFILT_WRITE, EV_ADD, 0, 0, nil)
27
+ assert { [] == kq.kevent([kev_r, kev_w], 0) }
28
+ assert { [] == kq.kevent(nil, 0) }
29
+ assert { [Kqueue::Event.new(f.fileno, EVFILT_WRITE, EV_ADD, 0, 1, nil)] == kq.kevent(nil, 2) }
30
+ assert { [Kqueue::Event.new(f.fileno, EVFILT_WRITE, EV_ADD, 0, 1, nil)] == kq.kevent(nil, 2) }
31
+ message = 'hello world'
32
+ f.write message
33
+ f.rewind
34
+
35
+ expect = [
36
+ Kqueue::Event.new(f.fileno, EVFILT_WRITE, EV_ADD, 0, 1, nil),
37
+ Kqueue::Event.new(f.fileno, EVFILT_READ, EV_ADD, 0, message.length, nil)
38
+ ]
39
+ assert { expect == kq.kevent(nil, 2) }
40
+ f.close
41
+ assert { [] == kq.kevent(nil, 2, 0) }
42
+ assert_raise(ArgumentError) { kq.kevent(nil, -1) }
43
+ end
44
+ end
45
+ end
46
+
47
+ def test_kevent_delete
48
+ IO.pipe do |r, w|
49
+ Kqueue.open do |kq|
50
+ kev_w = Kqueue::Event.new(w.fileno, EVFILT_WRITE, EV_ADD, 0, 0, nil)
51
+ kq.kevent([kev_w], 0)
52
+ assert { [Kqueue::Event.new(w.fileno, EVFILT_WRITE, EV_ADD, 0, EV_ERROR, nil)] == kq.kevent(nil, 2, 0) }
53
+
54
+ kev_del = Kqueue::Event.new(w.fileno, EVFILT_WRITE, EV_DELETE, 0, 0, nil)
55
+ kq.kevent([kev_del], 0)
56
+ GC.start
57
+ assert { [] == kq.kevent(nil, 2, 0) }
58
+
59
+ kev_del = Kqueue::Event.new(w.fileno, EVFILT_WRITE, EV_ADD|EV_DELETE, 0, 0, nil)
60
+ assert_raise(ArgumentError) { kq.kevent([kev_del], 0) }
61
+
62
+ kev_del = Kqueue::Event.new(w.fileno, EVFILT_READ, EV_DELETE, 0, 0, nil)
63
+ assert_raise(ArgumentError) { kq.kevent([kev_del], 0) }
64
+ end
65
+ end
66
+ end
67
+
68
+ def test_kevent_have_udata
69
+ IO.pipe do |r, w|
70
+ Kqueue.open do |kq|
71
+ obj = Object.new
72
+ object_id = obj.object_id
73
+ kev_w = Kqueue::Event.new(w.fileno, EVFILT_WRITE, EV_ADD, 0, 0, obj)
74
+ ret = kq.kevent([kev_w], 1)
75
+ GC.start
76
+ assert { object_id == ret.first.udata.object_id }
77
+ end
78
+ end
79
+
80
+ IO.pipe do |r, w|
81
+ Kqueue.open do |kq|
82
+ str = "in_string"
83
+ ary = [:in_array]
84
+ prc = Proc.new{ :in_proc }
85
+ kev_w = Kqueue::Event.new(w.fileno, EVFILT_WRITE, EV_ADD, 0, 0, [str, ary, prc])
86
+ ret = kq.kevent([kev_w], 1)
87
+ GC.start
88
+ assert { [Kqueue::Event.new(w.fileno, EVFILT_WRITE, EV_ADD, 0, EV_ERROR, [str, ary, prc])] == ret }
89
+ assert { "in_string" == ret.first.udata[0] }
90
+ assert { [:in_array] == ret.first.udata[1] }
91
+ assert { prc == ret.first.udata[2] }
92
+ end
93
+ end
94
+ end
95
+
96
+ def test_kevent_timeout
97
+ IO.pipe do |r, w|
98
+ Kqueue.open do |kq|
99
+ kev_r = Kqueue::Event.new(r.fileno, EVFILT_READ, EV_ADD, 0, 0, nil)
100
+ assert { [] == kq.kevent([kev_r], 1, 0) }
101
+ assert { [] == kq.kevent([kev_r], 1, 0.01) }
102
+ assert_raise(Timeout::Error) do
103
+ timeout(0.01) { kq.kevent(nil, 1, 0.02) }
104
+ end
105
+ assert_raise(Errno::EINVAL) do
106
+ kq.kevent(nil, 0, -1)
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ def test_kevent_with_thread
113
+ IO.pipe do |r, w|
114
+ Kqueue.open do |kq|
115
+ message = 'ok go'
116
+ kev_r = Kqueue::Event.new(r.fileno, EVFILT_READ, EV_ADD, 0, 0, nil)
117
+ w.write message
118
+ w.close
119
+ GC.start
120
+ t = Thread.new {
121
+ kq.kevent([kev_r], 1)
122
+ }
123
+ assert { [Kqueue::Event.new(r.fileno, EVFILT_READ, EV_ADD|EV_EOF, 0, message.length, nil)] == t.value }
124
+ end
125
+ end
126
+ end
127
+
128
+ def test_file
129
+ Tempfile.create("test") do |f|
130
+ Kqueue.open do |kq|
131
+ kevs = [
132
+ Kqueue::Event.new(f.fileno, EVFILT_WRITE, EV_ADD|EV_ENABLE|EV_CLEAR, 0, 0, [1]),
133
+ Kqueue::Event.new(f.fileno, EVFILT_READ, EV_ADD|EV_ENABLE|EV_CLEAR, 0, 0, [2]),
134
+ Kqueue::Event.new(f.fileno, EVFILT_WRITE, EV_ADD, 0, 0, [3]),
135
+ Kqueue::Event.new(f.fileno, EVFILT_READ, EV_ADD, 0, 0, [4]),
136
+ ]
137
+ kq.kevent(kevs, 0)
138
+
139
+ GC.start
140
+ assert { [[3]] == kq.kevent(nil, 4).map(&:udata) }
141
+
142
+ f.write 'ok'
143
+ f.rewind
144
+ GC.start
145
+ assert { [[4], [3]] == kq.kevent(nil, 4).map(&:udata) }
146
+ end
147
+ end
148
+ end
149
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kqueue
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - ksss
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake-compiler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: test-unit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A Ruby binding for kqueue(2)
70
+ email:
71
+ - co000ri@gmail.com
72
+ executables: []
73
+ extensions:
74
+ - ext/kqueue/extconf.rb
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - Gemfile.lock
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - examples/kqueue_server.rb
85
+ - ext/kqueue/core.c
86
+ - ext/kqueue/extconf.rb
87
+ - kqueue.gemspec
88
+ - test/test_kqueue.rb
89
+ homepage: https://github.com/ksss/kqueue
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.4.1
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: A Ruby binding for kqueue(2)
113
+ test_files:
114
+ - test/test_kqueue.rb