preliminary poll(2) support
[kgio.git] / ext / kgio / poll.c
blob41caafd1e407dae8a0c9208da5f4b3cfb4ad76c1
1 #include "kgio.h"
2 #if defined(HAVE_RB_THREAD_BLOCKING_REGION) && defined(HAVE_POLL)
3 #include <poll.h>
4 #ifdef HAVE_RUBY_ST_H
5 # include <ruby/st.h>
6 #else
7 # include <st.h>
8 #endif
10 static VALUE sym_wait_readable, sym_wait_writable;
11 static ID id_clear;
13 struct poll_args {
14 struct pollfd *fds;
15 nfds_t nfds;
16 int timeout;
17 VALUE ios;
18 st_table *fd_to_io;
21 static int num2timeout(VALUE timeout)
23 switch (TYPE(timeout)) {
24 case T_NIL: return -1;
25 case T_FIXNUM: return FIX2INT(timeout);
26 case T_BIGNUM: return NUM2INT(timeout);
28 rb_raise(rb_eTypeError, "timeout must be integer or nil");
29 return 0;
32 static VALUE poll_free(VALUE args)
34 struct poll_args *a = (struct poll_args *)args;
36 if (a->fds)
37 xfree(a->fds);
38 if (a->fd_to_io)
39 st_free_table(a->fd_to_io);
41 return Qnil;
44 static short value2events(VALUE event)
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");
52 static int io_to_pollfd_i(VALUE key, VALUE value, VALUE args)
54 struct poll_args *a = (struct poll_args *)args;
55 struct pollfd *pollfd = &a->fds[a->nfds++];
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;
63 static void hash2pollfds(struct poll_args *a)
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);
70 static VALUE nogvl_poll(void *ptr)
72 struct poll_args *a = ptr;
73 return (VALUE)poll(a->fds, a->nfds, a->timeout);
76 static VALUE poll_result(int nr, struct poll_args *a)
78 struct pollfd *fds = a->fds;
79 VALUE io;
80 int rc;
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));
92 return a->ios;
95 static VALUE do_poll(VALUE args)
97 struct poll_args *a = (struct poll_args *)args;
98 int nr;
100 Check_Type(a->ios, T_HASH);
101 hash2pollfds(a);
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;
107 return poll_result(nr, a);
111 * call-seq:
113 * Kgio.poll({ $stdin => :wait_readable }, 100) -> hash or nil
114 * Kgio.poll({ $stdin => Kgio::POLLIN }, 100) -> hash or nil
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:
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)
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.
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:
135 * Kgio::POLLERR - error condition occurred on the descriptor
136 * Kgio::POLLHUP - hang up
137 * Kgio::POLLNVAL - invalid request (bad file descriptor)
139 * This method is only available under Ruby 1.9 or any other
140 * implementations that uses native threads and rb_thread_blocking_region()
142 static VALUE s_poll(int argc, VALUE *argv, VALUE self)
144 VALUE timeout;
145 struct poll_args a;
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;
153 return rb_ensure(do_poll, (VALUE)&a, poll_free, (VALUE)&a);
156 void init_kgio_poll(void)
158 VALUE mKgio = rb_define_module("Kgio");
159 rb_define_singleton_method(mKgio, "poll", s_poll, -1);
161 sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
162 sym_wait_writable = ID2SYM(rb_intern("wait_writable"));
163 id_clear = rb_intern("clear");
165 #define c(x) rb_define_const(mKgio,#x,INT2NUM((int)x))
167 /* standard types */
169 c(POLLIN);
170 c(POLLPRI);
171 c(POLLOUT);
173 #ifdef POLLRDHUP
174 c(POLLRDHUP);
175 #endif
177 /* outputs */
178 c(POLLERR);
179 c(POLLHUP);
180 c(POLLNVAL);
182 #else /* ! HAVE_RB_THREAD_BLOCKING_REGION */
183 void init_kgio_poll(void)
186 #endif /* ! HAVE_RB_THREAD_BLOCKIONG_REGION */