epoll 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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