1/**********************************************************************
2
3  io/wait.c -
4
5  $Author: kosaki $
6  created at: Tue Jul 14 21:53:18 2009
7
8  All the files in this distribution are covered under the Ruby's
9  license (see the file COPYING).
10
11**********************************************************************/
12
13#include "ruby.h"
14#include "ruby/io.h"
15#ifdef HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18#include <fcntl.h>
19
20#ifdef F_GETFL
21static int
22io_nonblock_mode(int fd)
23{
24    int f = fcntl(fd, F_GETFL);
25    if (f == -1) rb_sys_fail(0);
26    return f;
27}
28#else
29#define io_nonblock_mode(fd) ((void)(fd), 0)
30#endif
31
32#ifdef F_GETFL
33static VALUE
34rb_io_nonblock_p(VALUE io)
35{
36    rb_io_t *fptr;
37    GetOpenFile(io, fptr);
38    if (io_nonblock_mode(fptr->fd) & O_NONBLOCK)
39	return Qtrue;
40    return Qfalse;
41}
42#else
43#define rb_io_nonblock_p rb_f_notimplement
44#endif
45
46#ifdef F_SETFL
47static void
48io_nonblock_set(int fd, int f, int nb)
49{
50    if (nb) {
51	if ((f & O_NONBLOCK) != 0)
52	    return;
53	f |= O_NONBLOCK;
54    }
55    else {
56	if ((f & O_NONBLOCK) == 0)
57	    return;
58	f &= ~O_NONBLOCK;
59    }
60    if (fcntl(fd, F_SETFL, f) == -1)
61	rb_sys_fail(0);
62}
63
64static VALUE
65rb_io_nonblock_set(VALUE io, VALUE nb)
66{
67    rb_io_t *fptr;
68    GetOpenFile(io, fptr);
69    io_nonblock_set(fptr->fd, io_nonblock_mode(fptr->fd), RTEST(nb));
70    return io;
71}
72
73static VALUE
74io_nonblock_restore(VALUE arg)
75{
76    int *restore = (int *)arg;
77    if (fcntl(restore[0], F_SETFL, restore[1]) == -1)
78	rb_sys_fail(0);
79    return Qnil;
80}
81
82static VALUE
83rb_io_nonblock_block(int argc, VALUE *argv, VALUE io)
84{
85    int nb = 1;
86    rb_io_t *fptr;
87    int f, restore[2];
88
89    GetOpenFile(io, fptr);
90    if (argc > 0) {
91	VALUE v;
92	rb_scan_args(argc, argv, "01", &v);
93	nb = RTEST(v);
94    }
95    f = io_nonblock_mode(fptr->fd);
96    restore[0] = fptr->fd;
97    restore[1] = f;
98    io_nonblock_set(fptr->fd, f, nb);
99    return rb_ensure(rb_yield, io, io_nonblock_restore, (VALUE)restore);
100}
101#else
102#define rb_io_nonblock_set rb_f_notimplement
103#define rb_io_nonblock_block rb_f_notimplement
104#endif
105
106void
107Init_nonblock(void)
108{
109    VALUE io = rb_cIO;
110
111    rb_define_method(io, "nonblock?", rb_io_nonblock_p, 0);
112    rb_define_method(io, "nonblock=", rb_io_nonblock_set, 1);
113    rb_define_method(io, "nonblock", rb_io_nonblock_block, -1);
114}
115