generate empty backtraces for EPIPE and ECONNRESET
[kgio.git] / ext / kgio / read_write.c
blob57fee4ec67f6ed2e6ef580c34fad5cd9fd56a651
1 #include "kgio.h"
2 static VALUE mKgio_WaitReadable, mKgio_WaitWritable;
3 static VALUE eErrno_EPIPE, eErrno_ECONNRESET;
5 /*
6 * we know MSG_DONTWAIT works properly on all stream sockets under Linux
7 * we can define this macro for other platforms as people care and
8 * notice.
9 */
10 #if defined(__linux__) && ! defined(USE_MSG_DONTWAIT)
11 # define USE_MSG_DONTWAIT
12 #endif
14 NORETURN(static void raise_empty_bt(VALUE, const char *));
15 NORETURN(static void my_eof_error(void));
16 NORETURN(static void wr_sys_fail(const char *));
18 static void raise_empty_bt(VALUE err, const char *msg)
20 VALUE exc = rb_exc_new2(err, msg);
21 VALUE bt = rb_ary_new();
23 rb_funcall(exc, rb_intern("set_backtrace"), 1, bt);
24 rb_exc_raise(exc);
27 static void my_eof_error(void)
29 raise_empty_bt(rb_eEOFError, "");
32 static void wr_sys_fail(const char *msg)
34 switch (errno) {
35 case EPIPE:
36 errno = 0;
37 raise_empty_bt(eErrno_EPIPE, msg);
38 case ECONNRESET:
39 errno = 0;
40 raise_empty_bt(eErrno_ECONNRESET, msg);
42 rb_sys_fail(msg);
45 static void prepare_read(struct io_args *a, int argc, VALUE *argv, VALUE io)
47 VALUE length;
49 a->io = io;
50 a->fd = my_fileno(io);
51 rb_scan_args(argc, argv, "11", &length, &a->buf);
52 a->len = NUM2LONG(length);
53 if (NIL_P(a->buf)) {
54 a->buf = rb_str_new(NULL, a->len);
55 } else {
56 StringValue(a->buf);
57 rb_str_resize(a->buf, a->len);
59 a->ptr = RSTRING_PTR(a->buf);
62 static int read_check(struct io_args *a, long n, const char *msg, int io_wait)
64 if (n == -1) {
65 if (errno == EINTR)
66 return -1;
67 rb_str_set_len(a->buf, 0);
68 if (errno == EAGAIN) {
69 if (io_wait) {
70 kgio_wait_readable(a->io, a->fd);
72 /* buf may be modified in other thread/fiber */
73 rb_str_resize(a->buf, a->len);
74 a->ptr = RSTRING_PTR(a->buf);
75 return -1;
76 } else {
77 a->buf = mKgio_WaitReadable;
78 return 0;
81 rb_sys_fail(msg);
83 rb_str_set_len(a->buf, n);
84 if (n == 0)
85 a->buf = Qnil;
86 return 0;
89 static VALUE my_read(int io_wait, int argc, VALUE *argv, VALUE io)
91 struct io_args a;
92 long n;
94 prepare_read(&a, argc, argv, io);
95 set_nonblocking(a.fd);
96 retry:
97 n = (long)read(a.fd, a.ptr, a.len);
98 if (read_check(&a, n, "read", io_wait) != 0)
99 goto retry;
100 return a.buf;
104 * call-seq:
106 * io.kgio_read(maxlen) -> buffer
107 * io.kgio_read(maxlen, buffer) -> buffer
109 * Reads at most maxlen bytes from the stream socket. Returns with a
110 * newly allocated buffer, or may reuse an existing buffer if supplied.
112 * Calls the method assigned to Kgio.wait_readable, or blocks in a
113 * thread-safe manner for writability.
115 * Returns nil on EOF.
117 * This behaves like read(2) and IO#readpartial, NOT fread(3) or
118 * IO#read which possess read-in-full behavior.
120 static VALUE kgio_read(int argc, VALUE *argv, VALUE io)
122 return my_read(1, argc, argv, io);
126 * Same as Kgio::PipeMethods#kgio_read, except EOFError is raised
127 * on EOF without a backtrace
129 static VALUE kgio_read_bang(int argc, VALUE *argv, VALUE io)
131 VALUE rv = my_read(1, argc, argv, io);
133 if (NIL_P(rv)) my_eof_error();
134 return rv;
138 * call-seq:
140 * io.kgio_tryread(maxlen) -> buffer
141 * io.kgio_tryread(maxlen, buffer) -> buffer
143 * Reads at most maxlen bytes from the stream socket. Returns with a
144 * newly allocated buffer, or may reuse an existing buffer if supplied.
146 * Returns nil on EOF.
148 * Returns Kgio::WaitReadable if EAGAIN is encountered.
150 static VALUE kgio_tryread(int argc, VALUE *argv, VALUE io)
152 return my_read(0, argc, argv, io);
155 #ifdef USE_MSG_DONTWAIT
156 static VALUE my_recv(int io_wait, int argc, VALUE *argv, VALUE io)
158 struct io_args a;
159 long n;
161 prepare_read(&a, argc, argv, io);
162 retry:
163 n = (long)recv(a.fd, a.ptr, a.len, MSG_DONTWAIT);
164 if (read_check(&a, n, "recv", io_wait) != 0)
165 goto retry;
166 return a.buf;
170 * This method may be optimized on some systems (e.g. GNU/Linux) to use
171 * MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
172 * Otherwise this is the same as Kgio::PipeMethods#kgio_read
174 static VALUE kgio_recv(int argc, VALUE *argv, VALUE io)
176 return my_recv(1, argc, argv, io);
180 * Same as Kgio::SocketMethods#kgio_read, except EOFError is raised
181 * on EOF without a backtrace
183 static VALUE kgio_recv_bang(int argc, VALUE *argv, VALUE io)
185 VALUE rv = my_recv(1, argc, argv, io);
187 if (NIL_P(rv)) my_eof_error();
188 return rv;
192 * This method may be optimized on some systems (e.g. GNU/Linux) to use
193 * MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
194 * Otherwise this is the same as Kgio::PipeMethods#kgio_tryread
196 static VALUE kgio_tryrecv(int argc, VALUE *argv, VALUE io)
198 return my_recv(0, argc, argv, io);
200 #else /* ! USE_MSG_DONTWAIT */
201 # define kgio_recv kgio_read
202 # define kgio_recv_bang kgio_read_bang
203 # define kgio_tryrecv kgio_tryread
204 #endif /* USE_MSG_DONTWAIT */
206 static void prepare_write(struct io_args *a, VALUE io, VALUE str)
208 a->buf = (TYPE(str) == T_STRING) ? str : rb_obj_as_string(str);
209 a->ptr = RSTRING_PTR(a->buf);
210 a->len = RSTRING_LEN(a->buf);
211 a->io = io;
212 a->fd = my_fileno(io);
215 static int write_check(struct io_args *a, long n, const char *msg, int io_wait)
217 if (a->len == n) {
218 done:
219 a->buf = Qnil;
220 } else if (n == -1) {
221 if (errno == EINTR)
222 return -1;
223 if (errno == EAGAIN) {
224 long written = RSTRING_LEN(a->buf) - a->len;
226 if (io_wait) {
227 kgio_wait_writable(a->io, a->fd);
229 /* buf may be modified in other thread/fiber */
230 a->len = RSTRING_LEN(a->buf) - written;
231 if (a->len <= 0)
232 goto done;
233 a->ptr = RSTRING_PTR(a->buf) + written;
234 return -1;
235 } else if (written > 0) {
236 a->buf = rb_str_new(a->ptr + n, a->len - n);
237 } else {
238 a->buf = mKgio_WaitWritable;
240 return 0;
242 wr_sys_fail(msg);
243 } else {
244 assert(n >= 0 && n < a->len && "write/send syscall broken?");
245 a->ptr += n;
246 a->len -= n;
247 return -1;
249 return 0;
252 static VALUE my_write(VALUE io, VALUE str, int io_wait)
254 struct io_args a;
255 long n;
257 prepare_write(&a, io, str);
258 set_nonblocking(a.fd);
259 retry:
260 n = (long)write(a.fd, a.ptr, a.len);
261 if (write_check(&a, n, "write", io_wait) != 0)
262 goto retry;
263 return a.buf;
267 * call-seq:
269 * io.kgio_write(str) -> nil
271 * Returns nil when the write completes.
273 * Calls the method Kgio.wait_writable if it is set. Otherwise this
274 * blocks in a thread-safe manner until all data is written or a
275 * fatal error occurs.
277 static VALUE kgio_write(VALUE io, VALUE str)
279 return my_write(io, str, 1);
283 * call-seq:
285 * io.kgio_trywrite(str) -> nil or Kgio::WaitWritable
287 * Returns nil if the write was completed in full.
289 * Returns a String containing the unwritten portion if EAGAIN
290 * was encountered, but some portion was successfully written.
292 * Returns Kgio::WaitWritable if EAGAIN is encountered and nothing
293 * was written.
295 static VALUE kgio_trywrite(VALUE io, VALUE str)
297 return my_write(io, str, 0);
300 #ifdef USE_MSG_DONTWAIT
302 * This method behaves like Kgio::PipeMethods#kgio_write, except
303 * it will use send(2) with the MSG_DONTWAIT flag on sockets to
304 * avoid unnecessary calls to fcntl(2).
306 static VALUE my_send(VALUE io, VALUE str, int io_wait)
308 struct io_args a;
309 long n;
311 prepare_write(&a, io, str);
312 retry:
313 n = (long)send(a.fd, a.ptr, a.len, MSG_DONTWAIT);
314 if (write_check(&a, n, "send", io_wait) != 0)
315 goto retry;
316 return a.buf;
320 * This method may be optimized on some systems (e.g. GNU/Linux) to use
321 * MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
322 * Otherwise this is the same as Kgio::PipeMethods#kgio_write
324 static VALUE kgio_send(VALUE io, VALUE str)
326 return my_send(io, str, 1);
330 * This method may be optimized on some systems (e.g. GNU/Linux) to use
331 * MSG_DONTWAIT to avoid explicitly setting the O_NONBLOCK flag via fcntl.
332 * Otherwise this is the same as Kgio::PipeMethods#kgio_trywrite
334 static VALUE kgio_trysend(VALUE io, VALUE str)
336 return my_send(io, str, 0);
338 #else /* ! USE_MSG_DONTWAIT */
339 # define kgio_send kgio_write
340 # define kgio_trysend kgio_trywrite
341 #endif /* ! USE_MSG_DONTWAIT */
343 void init_kgio_read_write(VALUE mKgio)
345 VALUE mPipeMethods, mSocketMethods;
347 mKgio_WaitReadable = rb_const_get(mKgio, rb_intern("WaitReadable"));
348 mKgio_WaitWritable = rb_const_get(mKgio, rb_intern("WaitWritable"));
351 * Document-module: Kgio::PipeMethods
353 * This module may be used used to create classes that respond to
354 * various Kgio methods for reading and writing. This is included
355 * in Kgio::Pipe by default.
357 mPipeMethods = rb_define_module_under(mKgio, "PipeMethods");
358 rb_define_method(mPipeMethods, "kgio_read", kgio_read, -1);
359 rb_define_method(mPipeMethods, "kgio_read!", kgio_read_bang, -1);
360 rb_define_method(mPipeMethods, "kgio_write", kgio_write, 1);
361 rb_define_method(mPipeMethods, "kgio_tryread", kgio_tryread, -1);
362 rb_define_method(mPipeMethods, "kgio_trywrite", kgio_trywrite, 1);
365 * Document-module: Kgio::SocketMethods
367 * This method behaves like Kgio::PipeMethods, but contains
368 * optimizations for sockets on certain operating systems
369 * (e.g. GNU/Linux).
371 mSocketMethods = rb_define_module_under(mKgio, "SocketMethods");
372 rb_define_method(mSocketMethods, "kgio_read", kgio_recv, -1);
373 rb_define_method(mSocketMethods, "kgio_read!", kgio_recv_bang, -1);
374 rb_define_method(mSocketMethods, "kgio_write", kgio_send, 1);
375 rb_define_method(mSocketMethods, "kgio_tryread", kgio_tryrecv, -1);
376 rb_define_method(mSocketMethods, "kgio_trywrite", kgio_trysend, 1);
379 * Returns the client IPv4 address of the socket in dotted quad
380 * form as a string. This is always the value of the
381 * Kgio::LOCALHOST constant for UNIX domain sockets.
383 rb_define_attr(mSocketMethods, "kgio_addr", 1, 1);
385 eErrno_EPIPE = rb_const_get(rb_mErrno, rb_intern("EPIPE"));
386 eErrno_ECONNRESET = rb_const_get(rb_mErrno, rb_intern("ECONNRESET"));