kgio 2.2.0 → 2.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.
- data/.document +2 -0
- data/GIT-VERSION-GEN +1 -1
- data/README +1 -1
- data/ext/kgio/accept.c +14 -1
- data/ext/kgio/autopush.c +45 -0
- data/ext/kgio/connect.c +12 -0
- data/ext/kgio/extconf.rb +1 -0
- data/ext/kgio/kgio.h +4 -0
- data/ext/kgio/kgio_ext.c +1 -0
- data/ext/kgio/poll.c +186 -0
- data/ext/kgio/read_write.c +72 -0
- data/lib/kgio.rb +2 -0
- data/pkg.mk +9 -6
- data/test/test_peek.rb +35 -0
- data/test/test_poll.rb +68 -0
- metadata +11 -4
data/.document
CHANGED
data/GIT-VERSION-GEN
CHANGED
data/README
CHANGED
@@ -33,7 +33,7 @@ applications.
|
|
33
33
|
The library consists of a C extension so you'll need a C compiler
|
34
34
|
and Ruby development libraries/headers.
|
35
35
|
|
36
|
-
You may download the tarball from the
|
36
|
+
You may download the tarball from the Rainbows! project page on Rubyforge
|
37
37
|
and run setup.rb after unpacking it:
|
38
38
|
|
39
39
|
http://rubyforge.org/frs/?group_id=8977
|
data/ext/kgio/accept.c
CHANGED
@@ -248,7 +248,7 @@ static VALUE addr_bang(VALUE io)
|
|
248
248
|
* An optional class argument may be specified to override the
|
249
249
|
* Kgio::Socket-class return value:
|
250
250
|
*
|
251
|
-
* server.
|
251
|
+
* server.kgio_tryaccept(MySocket) -> MySocket
|
252
252
|
*/
|
253
253
|
static VALUE tcp_tryaccept(int argc, VALUE *argv, VALUE io)
|
254
254
|
{
|
@@ -453,13 +453,26 @@ void init_kgio_accept(void)
|
|
453
453
|
rb_define_singleton_method(mKgio, "accept_class=", set_accepted, 1);
|
454
454
|
rb_define_singleton_method(mKgio, "accept_class", get_accepted, 0);
|
455
455
|
|
456
|
+
/*
|
457
|
+
* Document-class: Kgio::UNIXServer
|
458
|
+
*
|
459
|
+
* Kgio::UNIXServer should be used in place of the plain UNIXServer
|
460
|
+
* when kgio_accept and kgio_tryaccept methods are needed.
|
461
|
+
*/
|
456
462
|
cUNIXServer = rb_const_get(rb_cObject, rb_intern("UNIXServer"));
|
457
463
|
cUNIXServer = rb_define_class_under(mKgio, "UNIXServer", cUNIXServer);
|
458
464
|
rb_define_method(cUNIXServer, "kgio_tryaccept", unix_tryaccept, -1);
|
459
465
|
rb_define_method(cUNIXServer, "kgio_accept", unix_accept, -1);
|
460
466
|
|
467
|
+
/*
|
468
|
+
* Document-class: Kgio::TCPServer
|
469
|
+
*
|
470
|
+
* Kgio::TCPServer should be used in place of the plain TCPServer
|
471
|
+
* when kgio_accept and kgio_tryaccept methods are needed.
|
472
|
+
*/
|
461
473
|
cTCPServer = rb_const_get(rb_cObject, rb_intern("TCPServer"));
|
462
474
|
cTCPServer = rb_define_class_under(mKgio, "TCPServer", cTCPServer);
|
475
|
+
|
463
476
|
rb_define_method(cTCPServer, "kgio_tryaccept", tcp_tryaccept, -1);
|
464
477
|
rb_define_method(cTCPServer, "kgio_accept", tcp_accept, -1);
|
465
478
|
init_sock_for_fd();
|
data/ext/kgio/autopush.c
CHANGED
@@ -78,11 +78,32 @@ static void state_set(VALUE io, enum autopush_state state)
|
|
78
78
|
static enum autopush_state detect_acceptor_state(VALUE io);
|
79
79
|
static void push_pending_data(VALUE io);
|
80
80
|
|
81
|
+
/*
|
82
|
+
* call-seq:
|
83
|
+
* Kgio.autopush? -> true or false
|
84
|
+
*
|
85
|
+
* Returns whether or not autopush is enabled.
|
86
|
+
*
|
87
|
+
* Only available on systems with TCP_CORK (Linux) or
|
88
|
+
* TCP_NOPUSH (FreeBSD, and maybe other *BSDs).
|
89
|
+
*/
|
81
90
|
static VALUE s_get_autopush(VALUE self)
|
82
91
|
{
|
83
92
|
return enabled ? Qtrue : Qfalse;
|
84
93
|
}
|
85
94
|
|
95
|
+
/*
|
96
|
+
* call-seq:
|
97
|
+
* Kgio.autopush = true
|
98
|
+
* Kgio.autopush = false
|
99
|
+
*
|
100
|
+
* Enables or disables autopush for sockets created with kgio_accept
|
101
|
+
* and kgio_tryaccept methods. Autopush relies on TCP_CORK/TCP_NOPUSH
|
102
|
+
* being enabled on the listen socket.
|
103
|
+
*
|
104
|
+
* Only available on systems with TCP_CORK (Linux) or
|
105
|
+
* TCP_NOPUSH (FreeBSD, and maybe other *BSDs).
|
106
|
+
*/
|
86
107
|
static VALUE s_set_autopush(VALUE self, VALUE val)
|
87
108
|
{
|
88
109
|
enabled = RTEST(val);
|
@@ -90,11 +111,35 @@ static VALUE s_set_autopush(VALUE self, VALUE val)
|
|
90
111
|
return val;
|
91
112
|
}
|
92
113
|
|
114
|
+
/*
|
115
|
+
* call-seq:
|
116
|
+
*
|
117
|
+
* io.kgio_autopush? -> true or false
|
118
|
+
*
|
119
|
+
* Returns the current autopush state of the Kgio::SocketMethods-enabled
|
120
|
+
* socket.
|
121
|
+
*
|
122
|
+
* Only available on systems with TCP_CORK (Linux) or
|
123
|
+
* TCP_NOPUSH (FreeBSD, and maybe other *BSDs).
|
124
|
+
*/
|
93
125
|
static VALUE autopush_get(VALUE io)
|
94
126
|
{
|
95
127
|
return state_get(io) <= 0 ? Qfalse : Qtrue;
|
96
128
|
}
|
97
129
|
|
130
|
+
/*
|
131
|
+
* call-seq:
|
132
|
+
*
|
133
|
+
* io.kgio_autopush = true
|
134
|
+
* io.kgio_autopush = false
|
135
|
+
*
|
136
|
+
* Enables or disables autopush on any given Kgio::SocketMethods-capable
|
137
|
+
* IO object. This does NOT enable or disable TCP_NOPUSH/TCP_CORK right
|
138
|
+
* away, that must be done with IO.setsockopt
|
139
|
+
*
|
140
|
+
* Only available on systems with TCP_CORK (Linux) or
|
141
|
+
* TCP_NOPUSH (FreeBSD, and maybe other *BSDs).
|
142
|
+
*/
|
98
143
|
static VALUE autopush_set(VALUE io, VALUE vbool)
|
99
144
|
{
|
100
145
|
int fd = my_fileno(io);
|
data/ext/kgio/connect.c
CHANGED
@@ -257,12 +257,24 @@ void init_kgio_connect(void)
|
|
257
257
|
rb_define_singleton_method(cKgio_Socket, "new", kgio_connect, 1);
|
258
258
|
rb_define_singleton_method(cKgio_Socket, "start", kgio_start, 1);
|
259
259
|
|
260
|
+
/*
|
261
|
+
* Document-class: Kgio::TCPSocket
|
262
|
+
*
|
263
|
+
* Kgio::TCPSocket should be used in place of the plain TCPSocket
|
264
|
+
* when kgio_* methods are needed.
|
265
|
+
*/
|
260
266
|
cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
261
267
|
cTCPSocket = rb_define_class_under(mKgio, "TCPSocket", cTCPSocket);
|
262
268
|
rb_include_module(cTCPSocket, mSocketMethods);
|
263
269
|
rb_define_singleton_method(cTCPSocket, "new", kgio_tcp_connect, 2);
|
264
270
|
rb_define_singleton_method(cTCPSocket, "start", kgio_tcp_start, 2);
|
265
271
|
|
272
|
+
/*
|
273
|
+
* Document-class: Kgio::UNIXSocket
|
274
|
+
*
|
275
|
+
* Kgio::UNIXSocket should be used in place of the plain UNIXSocket
|
276
|
+
* when kgio_* methods are needed.
|
277
|
+
*/
|
266
278
|
cUNIXSocket = rb_const_get(rb_cObject, rb_intern("UNIXSocket"));
|
267
279
|
cUNIXSocket = rb_define_class_under(mKgio, "UNIXSocket", cUNIXSocket);
|
268
280
|
rb_include_module(cUNIXSocket, mSocketMethods);
|
data/ext/kgio/extconf.rb
CHANGED
@@ -2,6 +2,7 @@ require 'mkmf'
|
|
2
2
|
$CPPFLAGS << ' -D_GNU_SOURCE'
|
3
3
|
$CPPFLAGS << ' -DPOSIX_C_SOURCE=1'
|
4
4
|
|
5
|
+
have_func("poll", "poll.h")
|
5
6
|
have_func("getaddrinfo", %w(sys/types.h sys/socket.h netdb.h)) or
|
6
7
|
abort "getaddrinfo required"
|
7
8
|
have_func("getnameinfo", %w(sys/socket.h netdb.h)) or
|
data/ext/kgio/kgio.h
CHANGED
@@ -35,6 +35,7 @@ void init_kgio_read_write(void);
|
|
35
35
|
void init_kgio_accept(void);
|
36
36
|
void init_kgio_connect(void);
|
37
37
|
void init_kgio_autopush(void);
|
38
|
+
void init_kgio_poll(void);
|
38
39
|
|
39
40
|
void kgio_autopush_accept(VALUE, VALUE);
|
40
41
|
void kgio_autopush_recv(VALUE);
|
@@ -42,5 +43,8 @@ void kgio_autopush_send(VALUE);
|
|
42
43
|
|
43
44
|
VALUE kgio_call_wait_writable(VALUE io);
|
44
45
|
VALUE kgio_call_wait_readable(VALUE io);
|
46
|
+
#if defined(HAVE_RB_THREAD_BLOCKING_REGION) && defined(HAVE_POLL)
|
47
|
+
# define USE_KGIO_POLL
|
48
|
+
#endif /* USE_KGIO_POLL */
|
45
49
|
|
46
50
|
#endif /* KGIO_H */
|
data/ext/kgio/kgio_ext.c
CHANGED
data/ext/kgio/poll.c
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
#include "kgio.h"
|
2
|
+
#if defined(USE_KGIO_POLL)
|
3
|
+
#include <poll.h>
|
4
|
+
#ifdef HAVE_RUBY_ST_H
|
5
|
+
# include <ruby/st.h>
|
6
|
+
#else
|
7
|
+
# include <st.h>
|
8
|
+
#endif
|
9
|
+
|
10
|
+
static VALUE sym_wait_readable, sym_wait_writable;
|
11
|
+
static ID id_clear;
|
12
|
+
|
13
|
+
struct poll_args {
|
14
|
+
struct pollfd *fds;
|
15
|
+
nfds_t nfds;
|
16
|
+
int timeout;
|
17
|
+
VALUE ios;
|
18
|
+
st_table *fd_to_io;
|
19
|
+
};
|
20
|
+
|
21
|
+
static int num2timeout(VALUE timeout)
|
22
|
+
{
|
23
|
+
switch (TYPE(timeout)) {
|
24
|
+
case T_NIL: return -1;
|
25
|
+
case T_FIXNUM: return FIX2INT(timeout);
|
26
|
+
case T_BIGNUM: return NUM2INT(timeout);
|
27
|
+
}
|
28
|
+
rb_raise(rb_eTypeError, "timeout must be integer or nil");
|
29
|
+
return 0;
|
30
|
+
}
|
31
|
+
|
32
|
+
static VALUE poll_free(VALUE args)
|
33
|
+
{
|
34
|
+
struct poll_args *a = (struct poll_args *)args;
|
35
|
+
|
36
|
+
if (a->fds)
|
37
|
+
xfree(a->fds);
|
38
|
+
if (a->fd_to_io)
|
39
|
+
st_free_table(a->fd_to_io);
|
40
|
+
|
41
|
+
return Qnil;
|
42
|
+
}
|
43
|
+
|
44
|
+
static short value2events(VALUE event)
|
45
|
+
{
|
46
|
+
if (event == sym_wait_readable) return POLLIN;
|
47
|
+
if (event == sym_wait_writable) return POLLOUT;
|
48
|
+
if (TYPE(event) == T_FIXNUM) return (short)FIX2INT(event);
|
49
|
+
rb_raise(rb_eArgError, "unrecognized event");
|
50
|
+
}
|
51
|
+
|
52
|
+
static int io_to_pollfd_i(VALUE key, VALUE value, VALUE args)
|
53
|
+
{
|
54
|
+
struct poll_args *a = (struct poll_args *)args;
|
55
|
+
struct pollfd *pollfd = &a->fds[a->nfds++];
|
56
|
+
|
57
|
+
pollfd->fd = my_fileno(key);
|
58
|
+
pollfd->events = value2events(value);
|
59
|
+
st_insert(a->fd_to_io, (st_data_t)pollfd->fd, (st_data_t)key);
|
60
|
+
return ST_CONTINUE;
|
61
|
+
}
|
62
|
+
|
63
|
+
static void hash2pollfds(struct poll_args *a)
|
64
|
+
{
|
65
|
+
a->fds = xmalloc(sizeof(struct poll_args) * RHASH_SIZE(a->ios));
|
66
|
+
a->fd_to_io = st_init_numtable();
|
67
|
+
rb_hash_foreach(a->ios, io_to_pollfd_i, (VALUE)a);
|
68
|
+
}
|
69
|
+
|
70
|
+
static VALUE nogvl_poll(void *ptr)
|
71
|
+
{
|
72
|
+
struct poll_args *a = ptr;
|
73
|
+
return (VALUE)poll(a->fds, a->nfds, a->timeout);
|
74
|
+
}
|
75
|
+
|
76
|
+
static VALUE poll_result(int nr, struct poll_args *a)
|
77
|
+
{
|
78
|
+
struct pollfd *fds = a->fds;
|
79
|
+
VALUE io;
|
80
|
+
int rc;
|
81
|
+
|
82
|
+
if ((nfds_t)nr != a->nfds)
|
83
|
+
rb_funcall(a->ios, id_clear, 0);
|
84
|
+
for (; nr > 0; fds++) {
|
85
|
+
if (fds->revents == 0)
|
86
|
+
continue;
|
87
|
+
--nr;
|
88
|
+
rc = st_lookup(a->fd_to_io, (st_data_t)fds->fd, &io);
|
89
|
+
assert(rc == 1 && "fd => IO mapping failed");
|
90
|
+
rb_hash_aset(a->ios, io, INT2FIX((int)fds->revents));
|
91
|
+
}
|
92
|
+
return a->ios;
|
93
|
+
}
|
94
|
+
|
95
|
+
static VALUE do_poll(VALUE args)
|
96
|
+
{
|
97
|
+
struct poll_args *a = (struct poll_args *)args;
|
98
|
+
int nr;
|
99
|
+
|
100
|
+
Check_Type(a->ios, T_HASH);
|
101
|
+
hash2pollfds(a);
|
102
|
+
|
103
|
+
nr = (int)rb_thread_blocking_region(nogvl_poll, a, RUBY_UBF_IO, NULL);
|
104
|
+
if (nr < 0) rb_sys_fail("poll");
|
105
|
+
if (nr == 0) return Qnil;
|
106
|
+
|
107
|
+
return poll_result(nr, a);
|
108
|
+
}
|
109
|
+
|
110
|
+
/*
|
111
|
+
* call-seq:
|
112
|
+
*
|
113
|
+
* Kgio.poll({ $stdin => :wait_readable }, 100) -> hash or nil
|
114
|
+
* Kgio.poll({ $stdin => Kgio::POLLIN }, 100) -> hash or nil
|
115
|
+
*
|
116
|
+
* Accepts an input hash with IO objects to wait for as the key and
|
117
|
+
* the events to wait for as its value. The events may either be
|
118
|
+
* +:wait_readable+ or +:wait_writable+ symbols or a Fixnum mask of
|
119
|
+
* Kgio::POLL* constants:
|
120
|
+
*
|
121
|
+
* Kgio::POLLIN - there is data to read
|
122
|
+
* Kgio::POLLPRI - there is urgent data to read
|
123
|
+
* Kgio::POLLOUT - writing will not block
|
124
|
+
* Kgio::POLLRDHUP - peer has shutdown writes (Linux 2.6.17+ only)
|
125
|
+
*
|
126
|
+
* Timeout is specified in Integer milliseconds just like the underlying
|
127
|
+
* poll(2), not in seconds like IO.select. A nil timeout means to wait
|
128
|
+
* forever. It must be an Integer or nil.
|
129
|
+
*
|
130
|
+
* Kgio.poll modifies and returns its input hash on success with the
|
131
|
+
* IO-like object as the key and an Integer mask of events as the hash
|
132
|
+
* value. It can return any of the events specified in the input
|
133
|
+
* above, along with the following events:
|
134
|
+
*
|
135
|
+
* Kgio::POLLERR - error condition occurred on the descriptor
|
136
|
+
* Kgio::POLLHUP - hang up
|
137
|
+
* Kgio::POLLNVAL - invalid request (bad file descriptor)
|
138
|
+
*
|
139
|
+
* This method is only available under Ruby 1.9 or any other
|
140
|
+
* implementations that uses native threads and rb_thread_blocking_region()
|
141
|
+
*/
|
142
|
+
static VALUE s_poll(int argc, VALUE *argv, VALUE self)
|
143
|
+
{
|
144
|
+
VALUE timeout;
|
145
|
+
struct poll_args a;
|
146
|
+
|
147
|
+
rb_scan_args(argc, argv, "11", &a.ios, &timeout);
|
148
|
+
a.timeout = num2timeout(timeout);
|
149
|
+
a.nfds = 0;
|
150
|
+
a.fds = NULL;
|
151
|
+
a.fd_to_io = NULL;
|
152
|
+
|
153
|
+
return rb_ensure(do_poll, (VALUE)&a, poll_free, (VALUE)&a);
|
154
|
+
}
|
155
|
+
|
156
|
+
void init_kgio_poll(void)
|
157
|
+
{
|
158
|
+
VALUE mKgio = rb_define_module("Kgio");
|
159
|
+
rb_define_singleton_method(mKgio, "poll", s_poll, -1);
|
160
|
+
|
161
|
+
sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
|
162
|
+
sym_wait_writable = ID2SYM(rb_intern("wait_writable"));
|
163
|
+
id_clear = rb_intern("clear");
|
164
|
+
|
165
|
+
#define c(x) rb_define_const(mKgio,#x,INT2NUM((int)x))
|
166
|
+
|
167
|
+
/* standard types */
|
168
|
+
|
169
|
+
c(POLLIN);
|
170
|
+
c(POLLPRI);
|
171
|
+
c(POLLOUT);
|
172
|
+
|
173
|
+
#ifdef POLLRDHUP
|
174
|
+
c(POLLRDHUP);
|
175
|
+
#endif
|
176
|
+
|
177
|
+
/* outputs */
|
178
|
+
c(POLLERR);
|
179
|
+
c(POLLHUP);
|
180
|
+
c(POLLNVAL);
|
181
|
+
}
|
182
|
+
#else /* ! USE_KGIO_POLL */
|
183
|
+
void init_kgio_poll(void)
|
184
|
+
{
|
185
|
+
}
|
186
|
+
#endif /* ! USE_KGIO_POLL */
|
data/ext/kgio/read_write.c
CHANGED
@@ -10,6 +10,9 @@ static ID id_set_backtrace;
|
|
10
10
|
*/
|
11
11
|
#if defined(__linux__) && ! defined(USE_MSG_DONTWAIT)
|
12
12
|
# define USE_MSG_DONTWAIT
|
13
|
+
static const int peek_flags = MSG_DONTWAIT|MSG_PEEK;
|
14
|
+
#else
|
15
|
+
static const int peek_flags = MSG_PEEK;
|
13
16
|
#endif
|
14
17
|
|
15
18
|
NORETURN(static void raise_empty_bt(VALUE, const char *));
|
@@ -223,6 +226,72 @@ static VALUE kgio_tryrecv(int argc, VALUE *argv, VALUE io)
|
|
223
226
|
# define kgio_tryrecv kgio_tryread
|
224
227
|
#endif /* USE_MSG_DONTWAIT */
|
225
228
|
|
229
|
+
static VALUE my_peek(int io_wait, int argc, VALUE *argv, VALUE io)
|
230
|
+
{
|
231
|
+
struct io_args a;
|
232
|
+
long n;
|
233
|
+
|
234
|
+
prepare_read(&a, argc, argv, io);
|
235
|
+
kgio_autopush_recv(io);
|
236
|
+
|
237
|
+
if (a.len > 0) {
|
238
|
+
if (peek_flags == MSG_PEEK)
|
239
|
+
set_nonblocking(a.fd);
|
240
|
+
retry:
|
241
|
+
n = (long)recv(a.fd, a.ptr, a.len, peek_flags);
|
242
|
+
if (read_check(&a, n, "recv(MSG_PEEK)", io_wait) != 0)
|
243
|
+
goto retry;
|
244
|
+
}
|
245
|
+
return a.buf;
|
246
|
+
}
|
247
|
+
|
248
|
+
/*
|
249
|
+
* call-seq:
|
250
|
+
*
|
251
|
+
* socket.kgio_trypeek(maxlen) -> buffer
|
252
|
+
* socket.kgio_trypeek(maxlen, buffer) -> buffer
|
253
|
+
*
|
254
|
+
* Like kgio_tryread, except it uses MSG_PEEK so it does not drain the
|
255
|
+
* socket buffer. A subsequent read of any type (including another peek)
|
256
|
+
* will return the same data.
|
257
|
+
*/
|
258
|
+
static VALUE kgio_trypeek(int argc, VALUE *argv, VALUE io)
|
259
|
+
{
|
260
|
+
return my_peek(0, argc, argv, io);
|
261
|
+
}
|
262
|
+
|
263
|
+
/*
|
264
|
+
* call-seq:
|
265
|
+
*
|
266
|
+
* socket.kgio_peek(maxlen) -> buffer
|
267
|
+
* socket.kgio_peek(maxlen, buffer) -> buffer
|
268
|
+
*
|
269
|
+
* Like kgio_read, except it uses MSG_PEEK so it does not drain the
|
270
|
+
* socket buffer. A subsequent read of any type (including another peek)
|
271
|
+
* will return the same data.
|
272
|
+
*/
|
273
|
+
static VALUE kgio_peek(int argc, VALUE *argv, VALUE io)
|
274
|
+
{
|
275
|
+
return my_peek(1, argc, argv, io);
|
276
|
+
}
|
277
|
+
|
278
|
+
/*
|
279
|
+
* call-seq:
|
280
|
+
*
|
281
|
+
* Kgio.trypeek(socket, maxlen) -> buffer
|
282
|
+
* Kgio.trypeek(socket, maxlen, buffer) -> buffer
|
283
|
+
*
|
284
|
+
* Like Kgio.tryread, except it uses MSG_PEEK so it does not drain the
|
285
|
+
* socket buffer. This can only be used on sockets and not pipe objects.
|
286
|
+
* Maybe used in place of SocketMethods#kgio_trypeek for non-Kgio objects
|
287
|
+
*/
|
288
|
+
static VALUE s_trypeek(int argc, VALUE *argv, VALUE mod)
|
289
|
+
{
|
290
|
+
if (argc <= 1)
|
291
|
+
rb_raise(rb_eArgError, "wrong number of arguments");
|
292
|
+
return my_peek(0, argc - 1, &argv[1], argv[0]);
|
293
|
+
}
|
294
|
+
|
226
295
|
static void prepare_write(struct io_args *a, VALUE io, VALUE str)
|
227
296
|
{
|
228
297
|
a->buf = (TYPE(str) == T_STRING) ? str : rb_obj_as_string(str);
|
@@ -410,6 +479,7 @@ void init_kgio_read_write(void)
|
|
410
479
|
|
411
480
|
rb_define_singleton_method(mKgio, "tryread", s_tryread, -1);
|
412
481
|
rb_define_singleton_method(mKgio, "trywrite", s_trywrite, 2);
|
482
|
+
rb_define_singleton_method(mKgio, "trypeek", s_trypeek, -1);
|
413
483
|
|
414
484
|
/*
|
415
485
|
* Document-module: Kgio::PipeMethods
|
@@ -438,6 +508,8 @@ void init_kgio_read_write(void)
|
|
438
508
|
rb_define_method(mSocketMethods, "kgio_write", kgio_send, 1);
|
439
509
|
rb_define_method(mSocketMethods, "kgio_tryread", kgio_tryrecv, -1);
|
440
510
|
rb_define_method(mSocketMethods, "kgio_trywrite", kgio_trysend, 1);
|
511
|
+
rb_define_method(mSocketMethods, "kgio_trypeek", kgio_trypeek, -1);
|
512
|
+
rb_define_method(mSocketMethods, "kgio_peek", kgio_peek, -1);
|
441
513
|
|
442
514
|
/*
|
443
515
|
* Returns the client IPv4 address of the socket in dotted quad
|
data/lib/kgio.rb
CHANGED
data/pkg.mk
CHANGED
@@ -7,7 +7,7 @@ GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
|
7
7
|
@./GIT-VERSION-GEN
|
8
8
|
-include GIT-VERSION-FILE
|
9
9
|
-include local.mk
|
10
|
-
DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts
|
10
|
+
DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts RbConfig::CONFIG["DLEXT"]')
|
11
11
|
RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
|
12
12
|
RUBY_ENGINE := $(shell $(RUBY) -e 'puts((RUBY_ENGINE rescue "ruby"))')
|
13
13
|
lib := lib
|
@@ -44,24 +44,27 @@ $(ext_dl): $(ext_src) $(ext_pfx_src) $(ext_pfx)/$(ext)/Makefile
|
|
44
44
|
$(MAKE) -C $(@D)
|
45
45
|
lib := $(lib):$(ext_pfx)/$(ext)
|
46
46
|
build: $(ext_dl)
|
47
|
+
else
|
48
|
+
build:
|
47
49
|
endif
|
48
50
|
|
49
|
-
pkg_extra
|
51
|
+
pkg_extra += GIT-VERSION-FILE NEWS ChangeLog LATEST
|
50
52
|
ChangeLog: GIT-VERSION-FILE .wrongdoc.yml
|
51
53
|
$(WRONGDOC) prepare
|
54
|
+
NEWS LATEST: ChangeLog
|
52
55
|
|
53
56
|
manifest:
|
54
57
|
$(RM) .manifest
|
55
58
|
$(MAKE) .manifest
|
56
59
|
|
57
|
-
.manifest:
|
60
|
+
.manifest: $(pkg_extra)
|
58
61
|
(git ls-files && for i in $@ $(pkg_extra); do echo $$i; done) | \
|
59
62
|
LC_ALL=C sort > $@+
|
60
63
|
cmp $@+ $@ || mv $@+ $@
|
61
64
|
$(RM) $@+
|
62
65
|
|
63
|
-
doc:: .document .wrongdoc.yml
|
64
|
-
find lib -type f -name '*.rbc' -exec rm -f '{}' ';'
|
66
|
+
doc:: .document .wrongdoc.yml $(pkg_extra)
|
67
|
+
-find lib -type f -name '*.rbc' -exec rm -f '{}' ';'
|
65
68
|
-find ext -type f -name '*.rbc' -exec rm -f '{}' ';'
|
66
69
|
$(RM) -r doc
|
67
70
|
$(WRONGDOC) all
|
@@ -144,7 +147,7 @@ test_units := $(wildcard test/test_*.rb)
|
|
144
147
|
test: test-unit
|
145
148
|
test-unit: $(test_units)
|
146
149
|
$(test_units): build
|
147
|
-
$(RUBY) -I $(lib) $@
|
150
|
+
$(RUBY) -I $(lib) $@ $(RUBY_TEST_OPTS)
|
148
151
|
|
149
152
|
# this requires GNU coreutils variants
|
150
153
|
ifneq ($(RSYNC_DEST),)
|
data/test/test_peek.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
$-w = true
|
3
|
+
require 'kgio'
|
4
|
+
|
5
|
+
class TestPeek < Test::Unit::TestCase
|
6
|
+
class EIEIO < Errno::EIO
|
7
|
+
end
|
8
|
+
|
9
|
+
def teardown
|
10
|
+
@rd.close
|
11
|
+
@wr.close
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_peek
|
15
|
+
@rd, @wr = Kgio::UNIXSocket.pair
|
16
|
+
@wr.kgio_write "HELLO"
|
17
|
+
assert_equal "HELLO", @rd.kgio_peek(5)
|
18
|
+
assert_equal "HELLO", @rd.kgio_trypeek(5)
|
19
|
+
assert_equal "HELLO", @rd.kgio_read(5)
|
20
|
+
assert_equal :wait_readable, @rd.kgio_trypeek(5)
|
21
|
+
def @rd.kgio_wait_readable
|
22
|
+
raise EIEIO
|
23
|
+
end
|
24
|
+
assert_raises(EIEIO) { @rd.kgio_peek(5) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_peek_singleton
|
28
|
+
@rd, @wr = UNIXSocket.pair
|
29
|
+
@wr.syswrite "HELLO"
|
30
|
+
assert_equal "HELLO", Kgio.trypeek(@rd, 666)
|
31
|
+
assert_equal "HELLO", Kgio.trypeek(@rd, 666)
|
32
|
+
assert_equal "HELLO", Kgio.tryread(@rd, 666)
|
33
|
+
assert_equal :wait_readable, Kgio.trypeek(@rd, 5)
|
34
|
+
end
|
35
|
+
end
|
data/test/test_poll.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
$-w = true
|
3
|
+
require 'kgio'
|
4
|
+
|
5
|
+
class TestPoll < Test::Unit::TestCase
|
6
|
+
def teardown
|
7
|
+
[ @rd, @wr ].each { |io| io.close unless io.closed? }
|
8
|
+
end
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@rd, @wr = IO.pipe
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_constants
|
15
|
+
assert_kind_of Integer, Kgio::POLLIN
|
16
|
+
assert_kind_of Integer, Kgio::POLLOUT
|
17
|
+
assert_kind_of Integer, Kgio::POLLPRI
|
18
|
+
assert_kind_of Integer, Kgio::POLLHUP
|
19
|
+
assert_kind_of Integer, Kgio::POLLERR
|
20
|
+
assert_kind_of Integer, Kgio::POLLNVAL
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_poll_symbol
|
24
|
+
set = { @rd => :wait_readable, @wr => :wait_writable }
|
25
|
+
res = Kgio.poll(set)
|
26
|
+
assert_equal({@wr => Kgio::POLLOUT}, res)
|
27
|
+
assert_equal set.object_id, res.object_id
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_poll_integer
|
31
|
+
set = { @wr => Kgio::POLLOUT|Kgio::POLLHUP }
|
32
|
+
res = Kgio.poll(set)
|
33
|
+
assert_equal({@wr => Kgio::POLLOUT}, res)
|
34
|
+
assert_equal set.object_id, res.object_id
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_poll_timeout
|
38
|
+
t0 = Time.now
|
39
|
+
res = Kgio.poll({}, 10)
|
40
|
+
diff = Time.now - t0
|
41
|
+
assert diff >= 0.010, "diff=#{diff}"
|
42
|
+
assert_nil res
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_poll_interrupt
|
46
|
+
foo = nil
|
47
|
+
oldquit = trap(:QUIT) { foo = :bar }
|
48
|
+
thr = Thread.new { sleep 0.100; Process.kill(:QUIT, $$) }
|
49
|
+
t0 = Time.now
|
50
|
+
assert_raises(Errno::EINTR) { Kgio.poll({}) }
|
51
|
+
diff = Time.now - t0
|
52
|
+
thr.join
|
53
|
+
assert diff >= 0.010, "diff=#{diff}"
|
54
|
+
ensure
|
55
|
+
trap(:QUIT, "DEFAULT")
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_poll_close
|
59
|
+
foo = nil
|
60
|
+
thr = Thread.new { sleep 0.100; @wr.close }
|
61
|
+
t0 = Time.now
|
62
|
+
res = Kgio.poll({@rd => Kgio::POLLIN})
|
63
|
+
diff = Time.now - t0
|
64
|
+
thr.join
|
65
|
+
assert_equal([ @rd ], res.keys)
|
66
|
+
assert diff >= 0.010, "diff=#{diff}"
|
67
|
+
end
|
68
|
+
end if Kgio.respond_to?(:poll)
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kgio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 3
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 2
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 2.
|
10
|
+
version: 2.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- kgio hackers
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-02-
|
18
|
+
date: 2011-02-09 00:00:00 +00:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -69,8 +69,10 @@ extra_rdoc_files:
|
|
69
69
|
- HACKING
|
70
70
|
- lib/kgio.rb
|
71
71
|
- ext/kgio/accept.c
|
72
|
+
- ext/kgio/autopush.c
|
72
73
|
- ext/kgio/connect.c
|
73
74
|
- ext/kgio/kgio_ext.c
|
75
|
+
- ext/kgio/poll.c
|
74
76
|
- ext/kgio/read_write.c
|
75
77
|
- ext/kgio/wait.c
|
76
78
|
files:
|
@@ -101,6 +103,7 @@ files:
|
|
101
103
|
- ext/kgio/missing_accept4.h
|
102
104
|
- ext/kgio/my_fileno.h
|
103
105
|
- ext/kgio/nonblock.h
|
106
|
+
- ext/kgio/poll.c
|
104
107
|
- ext/kgio/read_write.c
|
105
108
|
- ext/kgio/sock_for_fd.h
|
106
109
|
- ext/kgio/wait.c
|
@@ -116,8 +119,10 @@ files:
|
|
116
119
|
- test/test_default_wait.rb
|
117
120
|
- test/test_kgio_addr.rb
|
118
121
|
- test/test_no_dns_on_tcp_connect.rb
|
122
|
+
- test/test_peek.rb
|
119
123
|
- test/test_pipe_popen.rb
|
120
124
|
- test/test_pipe_read_write.rb
|
125
|
+
- test/test_poll.rb
|
121
126
|
- test/test_singleton_read_write.rb
|
122
127
|
- test/test_socketpair_read_write.rb
|
123
128
|
- test/test_tcp6_client_read_server_write.rb
|
@@ -168,6 +173,8 @@ signing_key:
|
|
168
173
|
specification_version: 3
|
169
174
|
summary: kinder, gentler I/O for Ruby
|
170
175
|
test_files:
|
176
|
+
- test/test_poll.rb
|
177
|
+
- test/test_peek.rb
|
171
178
|
- test/test_default_wait.rb
|
172
179
|
- test/test_no_dns_on_tcp_connect.rb
|
173
180
|
- test/test_unix_connect.rb
|