epoll 0.3.0

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: af3e6c1172e4e5d592bc3684a61f2dd25ba9613b
4
+ data.tar.gz: bffa9bab1512afd08c4deb1367e3b0fc87e1fe98
5
+ SHA512:
6
+ metadata.gz: 9f8249e738f8e48e519a086a1508c64ec6cbd0d03e27893480836410e4e4af3d18449ccd7b2ea4689686b606e11aab152b633eb548906134bfbdc2164a462ef7
7
+ data.tar.gz: 189aa3dcf3f0ea548ed3eb0111d8fe16b417c76ed5f21daf56a7788a9f3dceca9384340d0bde472b16e0276363749e2308c92b84a9ea07c0015944bb43710a70
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ *.rbc
3
+ *.bundle
4
+ *.so
5
+ *.o
6
+ tmp
7
+ pkg
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.4
4
+ - 2.2.0
5
+ os:
6
+ - linux
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
+ epoll (0.3.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ power_assert (0.1.3)
10
+ rake (10.3.2)
11
+ rake-compiler (0.8.3)
12
+ rake
13
+ test-unit (3.0.1)
14
+ power_assert
15
+
16
+ PLATFORMS
17
+ ruby
18
+
19
+ DEPENDENCIES
20
+ bundler
21
+ epoll!
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,119 @@
1
+ epoll
2
+ ===
3
+
4
+ [![Build Status](https://travis-ci.org/ksss/epoll.svg?branch=master)](https://travis-ci.org/ksss/epoll)
5
+
6
+ A binding of epoll(7) on Ruby.
7
+
8
+ **epoll(7)** can use Linux only. (because must be installed sys/epoll.h)
9
+
10
+ # Usage
11
+
12
+ ```ruby
13
+ require 'epoll'
14
+
15
+ # Epoll < IO
16
+
17
+ # Epoll.create
18
+ # call epoll_create(2)
19
+ # it's just alias of `open`
20
+ # Epoll object stock a File Descriptor returned by epoll_create(2)
21
+ # return: instance of Epoll (kind of IO)
22
+ epoll = Epoll.create
23
+
24
+ # IO object add to interest list
25
+ # call epoll_ctl(2)
26
+ epoll.add(io, Epoll::IN) # same way to epoll.ctl(Epoll::CTL_ADD, io, Epoll::IN)
27
+
28
+ # change waiting events
29
+ # call epoll_ctl(2)
30
+ epoll.mod(io, Epoll::OUT) # same way to epoll.ctl(Epoll::CTL_MOD, io, Epoll::OUT)
31
+
32
+ # remove from interest list
33
+ # call epoll_ctl(2)
34
+ epoll.del(io) # same way to epoll.ctl(Epoll::CTL_DEL, io)
35
+
36
+ loop do
37
+ # Epoll#wait(timeout=-1)
38
+ # call epoll_wait(2)
39
+ # timeout = -1: block until receive event or signals
40
+ # timeout = 0: return all io's can I/O on non block
41
+ # timeout > 0: block when timeout pass miri second or receive events or signals
42
+ # return: Array of Epoll::Event
43
+ evlist = epoll.wait
44
+
45
+ # ev is instance of Epoll::Event like `struct epoll_event`
46
+ # it's instance of `class Epoll::Event < Struct.new(:data, :events); end`
47
+ evlist.each do |ev|
48
+ # Epoll::Event#events is event flag bits (Fixnum)
49
+ if (ev.events & Epoll::IN) != 0
50
+ # Epoll::Event#data is notified IO (IO)
51
+ # e.g. it's expect to I/O readable
52
+ puts ev.data.read
53
+ elsif (ev.events & Epoll::HUP|Epoll::ERR) != 0
54
+ ev.data.close
55
+ break
56
+ end
57
+ end
58
+ end
59
+
60
+ # you can close File Descriptor for epoll when finish to use
61
+ epoll.close #=> nil
62
+
63
+ # and you can check closed
64
+ epoll.closed? #=> true
65
+
66
+ # and very useful way is that call `create` with block like `IO.open`
67
+ # return: block result
68
+ Epoll.create do |epoll|
69
+ # ensure automatic call `epoll.close` when out block
70
+ end
71
+ ```
72
+
73
+ ## ctl options
74
+
75
+ ctl options|description
76
+ ---|---
77
+ **Epoll::CTL_ADD**|add to interest list for created epoll fd
78
+ **Epoll::CTL_MOD**|change io events
79
+ **Epoll::CTL_DEL**|delete in interest list
80
+
81
+ ## Event flags
82
+
83
+ event flags|ctl|wait|description
84
+ ---|---|---|---
85
+ **Epoll::IN**|o|o|readable
86
+ **Epoll::PRI**|o|o|high priority read
87
+ **Epoll::HUP**|o|o|peer socket was shutdown
88
+ **Epoll::OUT**|o|o|writable
89
+ **Epoll::ET**|o|x|use edge trigger
90
+ **Epoll::ONESHOT**|o|x|auto watching stop when notified(but stay in list)
91
+ **Epoll::ERR**|x|o|raise error
92
+ **Epoll::HUP**|x|o|raise hang up
93
+
94
+ see also **man epoll(7)**
95
+
96
+ ## Installation
97
+
98
+ Add this line to your application's Gemfile:
99
+
100
+ gem 'epoll'
101
+
102
+ And then execute:
103
+
104
+ $ bundle
105
+
106
+ Or install it yourself as:
107
+
108
+ $ gem install epoll
109
+
110
+ # Pro Tips
111
+
112
+ - Support call without GVL in CRuby (use rb\_thread\_call\_without\_gvl())
113
+ - Close on exec flag set by default if you can use (use epoll_create1(EPOLL_CLOEXEC))
114
+ - Epoll#wait max return array size is 256 on one time (of course, overflowing and then carried next)
115
+
116
+ # Fork Me !
117
+
118
+ This is experimental implementation.
119
+ I'm waiting for your idea and Pull Request !
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/extensiontask'
3
+ require 'rake/testtask'
4
+
5
+ task :default => [:compile, :test]
6
+
7
+ Rake::ExtensionTask.new('core') do |ext|
8
+ ext.ext_dir = 'ext/epoll'
9
+ ext.lib_dir = 'lib/epoll'
10
+ end
11
+ Rake::TestTask.new {|t| t.libs << 'test'}
@@ -0,0 +1,21 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "epoll"
3
+ spec.version = "0.3.0"
4
+ spec.authors = ["ksss"]
5
+ spec.email = ["co000ri@gmail.com"]
6
+ spec.summary = %q{A Ruby binding for epoll(7)}
7
+ spec.description = %q{A Ruby binding for epoll(7)}
8
+ spec.homepage = "https://github.com/ksss/epoll"
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/epoll/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,46 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'epoll'
4
+ require 'socket'
5
+
6
+ server = TCPServer.open(4000)
7
+ puts "run http://127.0.0.1:4000/"
8
+
9
+ response = [
10
+ "HTTP/1.0 200 OK\r\n",
11
+ "Content-Length: 5\r\n",
12
+ "Content-Type: text/html\r\n",
13
+ "\r\n",
14
+ "HELLO\r\n",
15
+ ].join("")
16
+
17
+ ep = Epoll.create
18
+ ep.add server, Epoll::IN
19
+
20
+ Signal.trap(:INT) {
21
+ ep.close
22
+ server.close
23
+ }
24
+
25
+ loop do
26
+ ep.wait.each do |ev|
27
+ data = ev.data
28
+ events = ev.events
29
+
30
+ if data == server
31
+ socket = server.accept
32
+ ep.add socket, Epoll::IN|Epoll::ET
33
+ elsif (events & Epoll::IN) != 0
34
+ data.recv(1024)
35
+ ep.mod data, Epoll::OUT|Epoll::ET
36
+ elsif (events & Epoll::OUT) != 0
37
+ data.puts response
38
+ ep.del data
39
+ data.close
40
+ elsif (events & (Epoll::HUP|Epoll::ERR)) != 0
41
+ p "Epoll::HUP|Epoll::ERR"
42
+ else
43
+ raise IOError
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,194 @@
1
+ #include "ruby.h"
2
+ #include "ruby/io.h"
3
+ #include "ruby/thread.h"
4
+
5
+ #ifdef HAVE_SYS_EPOLL_H
6
+
7
+ #include <sys/epoll.h>
8
+ #include <fcntl.h>
9
+
10
+ #define EPOLL_WAIT_MAX_EVENTS 256
11
+
12
+ VALUE cEpoll;
13
+ VALUE cEpoll_Constants;
14
+ VALUE cEpoll_Event;
15
+
16
+ static VALUE
17
+ rb_epoll_initialize(VALUE self)
18
+ {
19
+ rb_io_t *fp;
20
+ int fd;
21
+
22
+ #if defined(HAVE_EPOLL_CREATE1) && defined(EPOLL_CLOEXEC)
23
+ fd = epoll_create1(EPOLL_CLOEXEC);
24
+ if (fd == -1)
25
+ rb_sys_fail("epoll_create1(2) was failed");
26
+ #else
27
+ fd = epoll_create(1024);
28
+ if (fd == -1)
29
+ rb_sys_fail("epoll_create(2) was failed");
30
+ #endif
31
+ rb_update_max_fd(fd);
32
+
33
+ MakeOpenFile(self, fp);
34
+ fp->fd = fd;
35
+ fp->mode = FMODE_READABLE|FMODE_BINMODE;
36
+ rb_io_ascii8bit_binmode(self);
37
+
38
+ /**
39
+ * It's also using GC mark.
40
+ * So, I don't know other way how to GC guard io objects.
41
+ */
42
+ rb_ivar_set(self, rb_intern("@evlist"), rb_ary_new());
43
+ return self;
44
+ }
45
+
46
+ static VALUE
47
+ rb_epoll_ctl(int argc, VALUE *argv, VALUE self)
48
+ {
49
+ struct epoll_event ev;
50
+ VALUE flag;
51
+ VALUE io;
52
+ VALUE events;
53
+ VALUE evlist;
54
+ rb_io_t *fptr;
55
+ rb_io_t *fptr_io;
56
+ int fd;
57
+
58
+ fptr = RFILE(self)->fptr;
59
+ rb_io_check_initialized(fptr);
60
+
61
+ switch (rb_scan_args(argc, argv, "21", &flag, &io, &events)) {
62
+ case 2:
63
+ if (FIX2INT(flag) != EPOLL_CTL_DEL)
64
+ rb_raise(rb_eArgError, "too few argument for CTL_ADD or CTL_MOD");
65
+ break;
66
+ case 3:
67
+ if (FIX2INT(flag) == EPOLL_CTL_DEL)
68
+ rb_raise(rb_eArgError, "too many argument for CTL_DEL");
69
+
70
+ if ((FIX2LONG(events) & (EPOLLIN|EPOLLPRI|EPOLLRDHUP|EPOLLOUT|EPOLLET|EPOLLONESHOT)) == 0)
71
+ rb_raise(rb_eIOError, "undefined events");
72
+
73
+ ev.events = FIX2LONG(events);
74
+ ev.data.ptr = (void*)io;
75
+ break;
76
+ }
77
+
78
+ GetOpenFile(rb_io_get_io(io), fptr_io);
79
+ fd = fptr_io->fd;
80
+
81
+ if (epoll_ctl(fptr->fd, FIX2INT(flag), fd, &ev) == -1) {
82
+ char buf[128];
83
+ sprintf(buf, "epoll_ctl(2) was failed(epoll fd:%d, io fd:%d)", fptr->fd, fd);
84
+ rb_sys_fail(buf);
85
+ }
86
+
87
+ switch (FIX2INT(flag)) {
88
+ case EPOLL_CTL_ADD:
89
+ evlist = rb_ivar_get(self, rb_intern("@evlist"));
90
+ rb_ary_push(evlist, io);
91
+ rb_ivar_set(self, rb_intern("@evlist"), evlist);
92
+ break;
93
+ case EPOLL_CTL_DEL:
94
+ evlist = rb_ivar_get(self, rb_intern("@evlist"));
95
+ rb_ary_delete(evlist, io);
96
+ rb_ivar_set(self, rb_intern("@evlist"), evlist);
97
+ break;
98
+ }
99
+
100
+ return self;
101
+ }
102
+
103
+ struct epoll_wait_args {
104
+ int fd;
105
+ int ev_len;
106
+ struct epoll_event *evlist;
107
+ int timeout;
108
+ };
109
+
110
+ static void *
111
+ rb_epoll_wait_func(void *ptr)
112
+ {
113
+ const struct epoll_wait_args *data = ptr;
114
+ return (void*)(long)epoll_wait(data->fd, data->evlist, data->ev_len, data->timeout);
115
+ }
116
+
117
+ static VALUE
118
+ rb_epoll_wait(int argc, VALUE *argv, VALUE self)
119
+ {
120
+ struct epoll_event evlist[EPOLL_WAIT_MAX_EVENTS];
121
+ struct epoll_wait_args data;
122
+ int i, ready, timeout, ev_len;
123
+ VALUE ready_evlist;
124
+ VALUE event;
125
+ rb_io_t *fptr;
126
+ GetOpenFile(self, fptr);
127
+
128
+ switch (argc) {
129
+ case 0:
130
+ timeout = -1;
131
+ break;
132
+ case 1:
133
+ timeout = FIX2INT(argv[0]);
134
+ break;
135
+ default:
136
+ rb_raise(rb_eArgError, "too many argument");
137
+ break;
138
+ }
139
+
140
+ ev_len = RARRAY_LEN(rb_ivar_get(self, rb_intern("@evlist")));
141
+ if (ev_len <= 0)
142
+ rb_raise(rb_eIOError, "empty interest list");
143
+
144
+ data.fd = fptr->fd;
145
+ data.ev_len = ev_len < EPOLL_WAIT_MAX_EVENTS ? ev_len : EPOLL_WAIT_MAX_EVENTS;
146
+ data.evlist = evlist;
147
+ data.timeout = timeout;
148
+
149
+ RETRY:
150
+ ready = (int)(long)rb_thread_call_without_gvl(rb_epoll_wait_func, &data, RUBY_UBF_IO, 0);
151
+ if (ready == -1) {
152
+ if (errno == EINTR)
153
+ goto RETRY;
154
+ else
155
+ rb_sys_fail("epoll_wait(2) was failed");
156
+ }
157
+
158
+ ready_evlist = rb_ary_new_capa(ready);
159
+ for (i = 0; i < ready; i++) {
160
+ event = rb_obj_alloc(cEpoll_Event);
161
+ RSTRUCT_SET(event, 0, (VALUE) evlist[i].data.ptr);
162
+ RSTRUCT_SET(event, 1, LONG2FIX(evlist[i].events));
163
+ rb_ary_store(ready_evlist, i, event);
164
+ }
165
+ return ready_evlist;
166
+ }
167
+
168
+ #endif // HAVE_SYS_EPOLL_H
169
+
170
+ void
171
+ Init_core()
172
+ {
173
+ #ifdef HAVE_SYS_EPOLL_H
174
+ cEpoll = rb_define_class("Epoll", rb_cIO);
175
+ rb_define_method(cEpoll, "initialize", rb_epoll_initialize, 0);
176
+ rb_define_method(cEpoll, "ctl", rb_epoll_ctl, -1);
177
+ rb_define_method(cEpoll, "wait", rb_epoll_wait, -1);
178
+
179
+ cEpoll_Constants = rb_define_module_under(cEpoll, "Constants");
180
+ rb_define_const(cEpoll_Constants, "IN", INT2FIX(EPOLLIN));
181
+ rb_define_const(cEpoll_Constants, "PRI", INT2FIX(EPOLLPRI));
182
+ rb_define_const(cEpoll_Constants, "RDHUP", INT2FIX(EPOLLRDHUP));
183
+ rb_define_const(cEpoll_Constants, "OUT", INT2FIX(EPOLLOUT));
184
+ rb_define_const(cEpoll_Constants, "ET", INT2FIX(EPOLLET));
185
+ rb_define_const(cEpoll_Constants, "ONESHOT", INT2FIX(EPOLLONESHOT));
186
+ rb_define_const(cEpoll_Constants, "ERR", INT2FIX(EPOLLERR));
187
+ rb_define_const(cEpoll_Constants, "HUP", INT2FIX(EPOLLHUP));
188
+ rb_define_const(cEpoll_Constants, "CTL_ADD", INT2FIX(EPOLL_CTL_ADD));
189
+ rb_define_const(cEpoll_Constants, "CTL_MOD", INT2FIX(EPOLL_CTL_MOD));
190
+ rb_define_const(cEpoll_Constants, "CTL_DEL", INT2FIX(EPOLL_CTL_DEL));
191
+
192
+ cEpoll_Event = rb_struct_define_under(cEpoll, "Event", "data", "events", NULL);
193
+ #endif
194
+ }
@@ -0,0 +1,8 @@
1
+ require 'mkmf'
2
+
3
+ if !have_header("sys/epoll.h")
4
+ puts "*** complie error: gem 'epoll' must be installed <sys/epoll.h>. ***"
5
+ puts "*** you can require 'io/epoll'. But, you can not use IO::Epoll APIs. ***"
6
+ end
7
+ have_func("epoll_create1", "sys/epoll.h")
8
+ create_makefile('epoll/core')
@@ -0,0 +1,2 @@
1
+ require 'epoll/core'
2
+ require 'epoll/ext'
@@ -0,0 +1,26 @@
1
+ class Epoll
2
+ attr_accessor :evlist
3
+
4
+ include Epoll::Constants
5
+
6
+ class << self
7
+ alias create open
8
+ end
9
+
10
+ def size
11
+ @evlist.size
12
+ end
13
+ alias length size
14
+
15
+ def add(io, events)
16
+ ctl CTL_ADD, io, events
17
+ end
18
+
19
+ def mod(io, events)
20
+ ctl CTL_MOD, io, events
21
+ end
22
+
23
+ def del(io)
24
+ ctl CTL_DEL, io
25
+ end
26
+ end
@@ -0,0 +1,213 @@
1
+ require 'test/unit'
2
+ require 'timeout'
3
+ require_relative '../lib/epoll'
4
+
5
+ class TestIOEpoll < Test::Unit::TestCase
6
+ def test_initalize
7
+ assert_instance_of(Epoll, Epoll.new);
8
+ assert_instance_of(Epoll, Epoll.create);
9
+ end
10
+
11
+ def test_create_with_block
12
+ instance = nil
13
+ ret_val = Epoll.create do |ep|
14
+ instance = ep
15
+ assert { instance.closed? == false }
16
+ :block_end
17
+ end
18
+ assert { instance.kind_of?(Epoll) == true }
19
+ assert { instance.closed? == true }
20
+ assert { ret_val == :block_end }
21
+ end
22
+
23
+ def test_create_with_block_ensure_close
24
+ instance = nil
25
+ catch do |ok|
26
+ Epoll.create do |ep|
27
+ instance = ep
28
+ throw ok
29
+ end
30
+ end
31
+ assert { true == instance.closed? }
32
+
33
+ assert_nothing_raised do
34
+ Epoll.create do |ep|
35
+ ep.close
36
+ end
37
+ end
38
+ end
39
+
40
+ def test_inspect
41
+ Epoll.create do |ep|
42
+ fd = ep.fileno
43
+ assert { "#<Epoll:fd #{fd}>" == ep.inspect }
44
+ ep.close
45
+ assert { "#<Epoll:(closed)>" == ep.inspect }
46
+ end
47
+ end
48
+
49
+ def test_fileno
50
+ ep = Epoll.create
51
+ assert { 0 < ep.fileno }
52
+ ep.close
53
+ assert_raise(IOError) { ep.fileno }
54
+ end
55
+
56
+ def test_ctl
57
+ Epoll.create do |ep|
58
+ io = IO.new(1, 'w')
59
+ assert { ep == ep.ctl(Epoll::CTL_ADD, io , Epoll::OUT) }
60
+ assert_raise(ArgumentError) { ep.ctl }
61
+ assert_raise(ArgumentError) { ep.ctl(Epoll::CTL_ADD) }
62
+ assert_raise(ArgumentError) { ep.ctl(Epoll::CTL_ADD, io) }
63
+ assert_raise(ArgumentError) { ep.ctl(-1, io) }
64
+ assert_raise(TypeError) { ep.ctl(nil, nil, nil) }
65
+ end
66
+ end
67
+
68
+ def test_add
69
+ ep = Epoll.create
70
+ io = IO.new(1, 'w')
71
+ assert_raise(IOError) { ep.add(io, 0) }
72
+ assert { ep == ep.add(io, Epoll::IN|Epoll::PRI|Epoll::RDHUP|Epoll::ET|Epoll::OUT) }
73
+ ep.close
74
+ assert_raise(Errno::EBADF) { ep.add(io, Epoll::OUT) }
75
+ end
76
+
77
+ def test_mod
78
+ ep = Epoll.create
79
+ io = IO.new(1, 'w')
80
+ assert_raise(Errno::ENOENT) { ep.mod(io, Epoll::IN) }
81
+ ep == ep.add(io, Epoll::OUT)
82
+ assert { ep == ep.mod(io, Epoll::IN) }
83
+ ep.close
84
+ assert_raise(Errno::EBADF) { ep.add(io, Epoll::OUT) }
85
+ end
86
+
87
+ def test_del
88
+ ep = Epoll.create
89
+ io = IO.new(1, 'w')
90
+ assert_raise(Errno::ENOENT) { ep.del(io) }
91
+ ep.add(io, Epoll::OUT)
92
+ assert { ep == ep.del(io) }
93
+ ep.close
94
+ assert_raise(Errno::EBADF) { ep.del(io) }
95
+ end
96
+
97
+ def test_wait
98
+ Epoll.create do |ep|
99
+ IO.pipe do |r, w|
100
+ ep.add(r, Epoll::IN)
101
+ ep.add(w, Epoll::OUT)
102
+ evlist = ep.wait
103
+ assert { [Epoll::Event.new(w, Epoll::OUT)] == evlist }
104
+
105
+ w.write('ok')
106
+ assert { 2 == ep.wait.length }
107
+
108
+ assert_raise(IOError) { Epoll.create.wait }
109
+ end
110
+ end
111
+ end
112
+
113
+ def test_wait_with_timeout
114
+ Epoll.create do |ep|
115
+ io = IO.new(1, 'w')
116
+ ep.add(io, Epoll::IN)
117
+ assert { [] == ep.wait(0) }
118
+ assert { [] == ep.wait(1) }
119
+ assert_raise(TimeoutError) do
120
+ timeout(0.01) { ep.wait(-1) }
121
+ end
122
+ assert_raise(TypeError) { ep.wait(nil) }
123
+ end
124
+ end
125
+
126
+ def test_size
127
+ Epoll.create do |ep|
128
+ IO.pipe do |r, w|
129
+ ep.add(r, Epoll::IN)
130
+ assert { 1 == ep.size }
131
+ ep.add(w, Epoll::OUT)
132
+ assert { 2 == ep.size }
133
+ ep.del(w)
134
+ assert { 1 == ep.size }
135
+ ep.del(r)
136
+ assert { 0 == ep.size }
137
+ end
138
+ end
139
+ end
140
+
141
+ def test_close
142
+ assert_nothing_raised do
143
+ fileno = nil
144
+ 10.times do
145
+ ep = Epoll.create
146
+ fileno = ep.fileno unless fileno
147
+ assert { fileno == ep.fileno }
148
+ ep.close
149
+
150
+ Epoll.create do
151
+ end
152
+ end
153
+ end
154
+
155
+ ep = Epoll.create
156
+ ep.close
157
+ assert_raise(IOError){ ep.close }
158
+ end
159
+
160
+ def test_closed?
161
+ ep = Epoll.create
162
+ assert { false == ep.closed? }
163
+ ep.close
164
+ assert { true == ep.closed? }
165
+ end
166
+
167
+ def test_dup
168
+ Epoll.create do |ep|
169
+ IO.pipe do |r, w|
170
+ ep.add(r, Epoll::IN)
171
+ ep.add(w, Epoll::OUT)
172
+ dup = ep.dup
173
+ assert { ep != dup }
174
+ assert { ep.fileno != dup.fileno }
175
+ assert { 2 == dup.size }
176
+ assert { 1 == dup.wait.length }
177
+ w.write 'ok'
178
+ assert { 2 == dup.wait.length }
179
+ end
180
+ end
181
+ end
182
+
183
+ def test_close_on_exec
184
+ if defined? Fcntl::FD_CLOEXEC
185
+ Epoll.create do |ep|
186
+ assert { true == ep.close_on_exec? }
187
+ ep.close_on_exec = false
188
+ assert { false == ep.close_on_exec? }
189
+ ep.close_on_exec = true
190
+ assert { true == ep.close_on_exec? }
191
+ ep.close_on_exec = false
192
+ assert { false == ep.close_on_exec? }
193
+ ep.close
194
+ assert_raise { ep.close_on_exec = true }
195
+ assert_raise { ep.close_on_exec? }
196
+ end
197
+ else
198
+ pend "Fcntl::FD_CLOEXEC undefined"
199
+ end
200
+ end
201
+
202
+ def test_thread
203
+ Epoll.create do |ep|
204
+ io = IO.new(1, 'w')
205
+ ep.add(io, Epoll::OUT)
206
+ ret = nil
207
+ Thread.start {
208
+ ret = ep.wait
209
+ }.join
210
+ assert { io == ret[0].data }
211
+ end
212
+ end
213
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: epoll
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - ksss
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-09 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 epoll(7)
70
+ email:
71
+ - co000ri@gmail.com
72
+ executables: []
73
+ extensions:
74
+ - ext/epoll/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
+ - epoll.gemspec
85
+ - examples/epoll_server.rb
86
+ - ext/epoll/core.c
87
+ - ext/epoll/extconf.rb
88
+ - lib/epoll.rb
89
+ - lib/epoll/ext.rb
90
+ - test/test_epoll.rb
91
+ homepage: https://github.com/ksss/epoll
92
+ licenses:
93
+ - MIT
94
+ metadata: {}
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 2.2.2
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: A Ruby binding for epoll(7)
115
+ test_files:
116
+ - test/test_epoll.rb