nio4r 0.1.0-java

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,153 @@
1
+ /*
2
+ * libev win32 compatibility cruft (_not_ a backend)
3
+ *
4
+ * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann <libev@schmorp.de>
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without modifica-
8
+ * tion, are permitted provided that the following conditions are met:
9
+ *
10
+ * 1. Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ *
13
+ * 2. Redistributions in binary form must reproduce the above copyright
14
+ * notice, this list of conditions and the following disclaimer in the
15
+ * documentation and/or other materials provided with the distribution.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
19
+ * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
21
+ * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
25
+ * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ *
28
+ * Alternatively, the contents of this file may be used under the terms of
29
+ * the GNU General Public License ("GPL") version 2 or any later version,
30
+ * in which case the provisions of the GPL are applicable instead of
31
+ * the above. If you wish to allow the use of your version of this file
32
+ * only under the terms of the GPL and not to allow others to use your
33
+ * version of this file under the BSD license, indicate your decision
34
+ * by deleting the provisions above and replace them with the notice
35
+ * and other provisions required by the GPL. If you do not delete the
36
+ * provisions above, a recipient may use your version of this file under
37
+ * either the BSD or the GPL.
38
+ */
39
+
40
+ #ifdef _WIN32
41
+
42
+ /* timeb.h is actually xsi legacy functionality */
43
+ #include <sys/timeb.h>
44
+
45
+ /* note: the comment below could not be substantiated, but what would I care */
46
+ /* MSDN says this is required to handle SIGFPE */
47
+ /* my wild guess would be that using something floating-pointy is required */
48
+ /* for the crt to do something about it */
49
+ volatile double SIGFPE_REQ = 0.0f;
50
+
51
+ /* oh, the humanity! */
52
+ static int
53
+ ev_pipe (int filedes [2])
54
+ {
55
+ struct sockaddr_in addr = { 0 };
56
+ int addr_size = sizeof (addr);
57
+ struct sockaddr_in adr2;
58
+ int adr2_size = sizeof (adr2);
59
+ SOCKET listener;
60
+ SOCKET sock [2] = { -1, -1 };
61
+
62
+ if ((listener = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
63
+ return -1;
64
+
65
+ addr.sin_family = AF_INET;
66
+ addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
67
+ addr.sin_port = 0;
68
+
69
+ if (bind (listener, (struct sockaddr *)&addr, addr_size))
70
+ goto fail;
71
+
72
+ if (getsockname (listener, (struct sockaddr *)&addr, &addr_size))
73
+ goto fail;
74
+
75
+ if (listen (listener, 1))
76
+ goto fail;
77
+
78
+ if ((sock [0] = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
79
+ goto fail;
80
+
81
+ if (connect (sock [0], (struct sockaddr *)&addr, addr_size))
82
+ goto fail;
83
+
84
+ if ((sock [1] = accept (listener, 0, 0)) < 0)
85
+ goto fail;
86
+
87
+ /* windows vista returns fantasy port numbers for sockets:
88
+ * example for two interconnected tcp sockets:
89
+ *
90
+ * (Socket::unpack_sockaddr_in getsockname $sock0)[0] == 53364
91
+ * (Socket::unpack_sockaddr_in getpeername $sock0)[0] == 53363
92
+ * (Socket::unpack_sockaddr_in getsockname $sock1)[0] == 53363
93
+ * (Socket::unpack_sockaddr_in getpeername $sock1)[0] == 53365
94
+ *
95
+ * wow! tridirectional sockets!
96
+ *
97
+ * this way of checking ports seems to work:
98
+ */
99
+ if (getpeername (sock [0], (struct sockaddr *)&addr, &addr_size))
100
+ goto fail;
101
+
102
+ if (getsockname (sock [1], (struct sockaddr *)&adr2, &adr2_size))
103
+ goto fail;
104
+
105
+ errno = WSAEINVAL;
106
+ if (addr_size != adr2_size
107
+ || addr.sin_addr.s_addr != adr2.sin_addr.s_addr /* just to be sure, I mean, it's windows */
108
+ || addr.sin_port != adr2.sin_port)
109
+ goto fail;
110
+
111
+ closesocket (listener);
112
+
113
+ #if EV_SELECT_IS_WINSOCKET
114
+ filedes [0] = EV_WIN32_HANDLE_TO_FD (sock [0]);
115
+ filedes [1] = EV_WIN32_HANDLE_TO_FD (sock [1]);
116
+ #else
117
+ /* when select isn't winsocket, we also expect socket, connect, accept etc.
118
+ * to work on fds */
119
+ filedes [0] = sock [0];
120
+ filedes [1] = sock [1];
121
+ #endif
122
+
123
+ return 0;
124
+
125
+ fail:
126
+ closesocket (listener);
127
+
128
+ if (sock [0] != INVALID_SOCKET) closesocket (sock [0]);
129
+ if (sock [1] != INVALID_SOCKET) closesocket (sock [1]);
130
+
131
+ return -1;
132
+ }
133
+
134
+ #undef pipe
135
+ #define pipe(filedes) ev_pipe (filedes)
136
+
137
+ #define EV_HAVE_EV_TIME 1
138
+ ev_tstamp
139
+ ev_time (void)
140
+ {
141
+ FILETIME ft;
142
+ ULARGE_INTEGER ui;
143
+
144
+ GetSystemTimeAsFileTime (&ft);
145
+ ui.u.LowPart = ft.dwLowDateTime;
146
+ ui.u.HighPart = ft.dwHighDateTime;
147
+
148
+ /* msvc cannot convert ulonglong to double... yes, it is that sucky */
149
+ return (LONGLONG)(ui.QuadPart - 116444736000000000) * 1e-7;
150
+ }
151
+
152
+ #endif
153
+
@@ -0,0 +1,196 @@
1
+ /* DO NOT EDIT, automatically generated by update_ev_wrap */
2
+ #ifndef EV_WRAP_H
3
+ #define EV_WRAP_H
4
+ #define now_floor ((loop)->now_floor)
5
+ #define mn_now ((loop)->mn_now)
6
+ #define rtmn_diff ((loop)->rtmn_diff)
7
+ #define io_blocktime ((loop)->io_blocktime)
8
+ #define timeout_blocktime ((loop)->timeout_blocktime)
9
+ #define backend ((loop)->backend)
10
+ #define activecnt ((loop)->activecnt)
11
+ #define loop_done ((loop)->loop_done)
12
+ #define backend_fd ((loop)->backend_fd)
13
+ #define backend_fudge ((loop)->backend_fudge)
14
+ #define backend_modify ((loop)->backend_modify)
15
+ #define backend_poll ((loop)->backend_poll)
16
+ #define anfds ((loop)->anfds)
17
+ #define anfdmax ((loop)->anfdmax)
18
+ #define pendings ((loop)->pendings)
19
+ #define pendingmax ((loop)->pendingmax)
20
+ #define pendingcnt ((loop)->pendingcnt)
21
+ #define pending_w ((loop)->pending_w)
22
+ #define rfeeds ((loop)->rfeeds)
23
+ #define rfeedmax ((loop)->rfeedmax)
24
+ #define rfeedcnt ((loop)->rfeedcnt)
25
+ #define evfd ((loop)->evfd)
26
+ #define evpipe ((loop)->evpipe)
27
+ #define pipe_w ((loop)->pipe_w)
28
+ #define curpid ((loop)->curpid)
29
+ #define postfork ((loop)->postfork)
30
+ #define vec_ri ((loop)->vec_ri)
31
+ #define vec_ro ((loop)->vec_ro)
32
+ #define vec_wi ((loop)->vec_wi)
33
+ #define vec_wo ((loop)->vec_wo)
34
+ #define vec_eo ((loop)->vec_eo)
35
+ #define vec_max ((loop)->vec_max)
36
+ #define polls ((loop)->polls)
37
+ #define pollmax ((loop)->pollmax)
38
+ #define pollcnt ((loop)->pollcnt)
39
+ #define pollidxs ((loop)->pollidxs)
40
+ #define pollidxmax ((loop)->pollidxmax)
41
+ #define epoll_events ((loop)->epoll_events)
42
+ #define epoll_eventmax ((loop)->epoll_eventmax)
43
+ #define epoll_eperms ((loop)->epoll_eperms)
44
+ #define epoll_epermcnt ((loop)->epoll_epermcnt)
45
+ #define epoll_epermmax ((loop)->epoll_epermmax)
46
+ #define kqueue_changes ((loop)->kqueue_changes)
47
+ #define kqueue_changemax ((loop)->kqueue_changemax)
48
+ #define kqueue_changecnt ((loop)->kqueue_changecnt)
49
+ #define kqueue_events ((loop)->kqueue_events)
50
+ #define kqueue_eventmax ((loop)->kqueue_eventmax)
51
+ #define port_events ((loop)->port_events)
52
+ #define port_eventmax ((loop)->port_eventmax)
53
+ #define iocp ((loop)->iocp)
54
+ #define fdchanges ((loop)->fdchanges)
55
+ #define fdchangemax ((loop)->fdchangemax)
56
+ #define fdchangecnt ((loop)->fdchangecnt)
57
+ #define timers ((loop)->timers)
58
+ #define timermax ((loop)->timermax)
59
+ #define timercnt ((loop)->timercnt)
60
+ #define periodics ((loop)->periodics)
61
+ #define periodicmax ((loop)->periodicmax)
62
+ #define periodiccnt ((loop)->periodiccnt)
63
+ #define idles ((loop)->idles)
64
+ #define idlemax ((loop)->idlemax)
65
+ #define idlecnt ((loop)->idlecnt)
66
+ #define idleall ((loop)->idleall)
67
+ #define prepares ((loop)->prepares)
68
+ #define preparemax ((loop)->preparemax)
69
+ #define preparecnt ((loop)->preparecnt)
70
+ #define checks ((loop)->checks)
71
+ #define checkmax ((loop)->checkmax)
72
+ #define checkcnt ((loop)->checkcnt)
73
+ #define forks ((loop)->forks)
74
+ #define forkmax ((loop)->forkmax)
75
+ #define forkcnt ((loop)->forkcnt)
76
+ #define cleanups ((loop)->cleanups)
77
+ #define cleanupmax ((loop)->cleanupmax)
78
+ #define cleanupcnt ((loop)->cleanupcnt)
79
+ #define async_pending ((loop)->async_pending)
80
+ #define asyncs ((loop)->asyncs)
81
+ #define asyncmax ((loop)->asyncmax)
82
+ #define asynccnt ((loop)->asynccnt)
83
+ #define fs_fd ((loop)->fs_fd)
84
+ #define fs_w ((loop)->fs_w)
85
+ #define fs_2625 ((loop)->fs_2625)
86
+ #define fs_hash ((loop)->fs_hash)
87
+ #define sig_pending ((loop)->sig_pending)
88
+ #define nosigmask ((loop)->nosigmask)
89
+ #define sigfd ((loop)->sigfd)
90
+ #define sigfd_w ((loop)->sigfd_w)
91
+ #define sigfd_set ((loop)->sigfd_set)
92
+ #define origflags ((loop)->origflags)
93
+ #define loop_count ((loop)->loop_count)
94
+ #define loop_depth ((loop)->loop_depth)
95
+ #define userdata ((loop)->userdata)
96
+ #define release_cb ((loop)->release_cb)
97
+ #define acquire_cb ((loop)->acquire_cb)
98
+ #define invoke_cb ((loop)->invoke_cb)
99
+ #else
100
+ #undef EV_WRAP_H
101
+ #undef now_floor
102
+ #undef mn_now
103
+ #undef rtmn_diff
104
+ #undef io_blocktime
105
+ #undef timeout_blocktime
106
+ #undef backend
107
+ #undef activecnt
108
+ #undef loop_done
109
+ #undef backend_fd
110
+ #undef backend_fudge
111
+ #undef backend_modify
112
+ #undef backend_poll
113
+ #undef anfds
114
+ #undef anfdmax
115
+ #undef pendings
116
+ #undef pendingmax
117
+ #undef pendingcnt
118
+ #undef pending_w
119
+ #undef rfeeds
120
+ #undef rfeedmax
121
+ #undef rfeedcnt
122
+ #undef evfd
123
+ #undef evpipe
124
+ #undef pipe_w
125
+ #undef curpid
126
+ #undef postfork
127
+ #undef vec_ri
128
+ #undef vec_ro
129
+ #undef vec_wi
130
+ #undef vec_wo
131
+ #undef vec_eo
132
+ #undef vec_max
133
+ #undef polls
134
+ #undef pollmax
135
+ #undef pollcnt
136
+ #undef pollidxs
137
+ #undef pollidxmax
138
+ #undef epoll_events
139
+ #undef epoll_eventmax
140
+ #undef epoll_eperms
141
+ #undef epoll_epermcnt
142
+ #undef epoll_epermmax
143
+ #undef kqueue_changes
144
+ #undef kqueue_changemax
145
+ #undef kqueue_changecnt
146
+ #undef kqueue_events
147
+ #undef kqueue_eventmax
148
+ #undef port_events
149
+ #undef port_eventmax
150
+ #undef iocp
151
+ #undef fdchanges
152
+ #undef fdchangemax
153
+ #undef fdchangecnt
154
+ #undef timers
155
+ #undef timermax
156
+ #undef timercnt
157
+ #undef periodics
158
+ #undef periodicmax
159
+ #undef periodiccnt
160
+ #undef idles
161
+ #undef idlemax
162
+ #undef idlecnt
163
+ #undef idleall
164
+ #undef prepares
165
+ #undef preparemax
166
+ #undef preparecnt
167
+ #undef checks
168
+ #undef checkmax
169
+ #undef checkcnt
170
+ #undef forks
171
+ #undef forkmax
172
+ #undef forkcnt
173
+ #undef cleanups
174
+ #undef cleanupmax
175
+ #undef cleanupcnt
176
+ #undef async_pending
177
+ #undef asyncs
178
+ #undef asyncmax
179
+ #undef asynccnt
180
+ #undef fs_fd
181
+ #undef fs_w
182
+ #undef fs_2625
183
+ #undef fs_hash
184
+ #undef sig_pending
185
+ #undef nosigmask
186
+ #undef sigfd
187
+ #undef sigfd_w
188
+ #undef sigfd_set
189
+ #undef origflags
190
+ #undef loop_count
191
+ #undef loop_depth
192
+ #undef userdata
193
+ #undef release_cb
194
+ #undef acquire_cb
195
+ #undef invoke_cb
196
+ #endif
@@ -0,0 +1,123 @@
1
+ // a single header file is required
2
+ #include <ev.h>
3
+ #include <stdio.h>
4
+ #include <io.h>
5
+
6
+ // every watcher type has its own typedef'd struct
7
+ // with the name ev_TYPE
8
+ ev_io stdin_watcher;
9
+ ev_timer timeout_watcher;
10
+
11
+ // all watcher callbacks have a similar signature
12
+ // this callback is called when data is readable on stdin
13
+ static void
14
+ stdin_cb (EV_P_ ev_io *w, int revents)
15
+ {
16
+ puts ("stdin ready or done or something");
17
+ // for one-shot events, one must manually stop the watcher
18
+ // with its corresponding stop function.
19
+ //ev_io_stop (EV_A_ w);
20
+
21
+ // this causes all nested ev_loop's to stop iterating
22
+ //ev_unloop (EV_A_ EVUNLOOP_ALL);
23
+ }
24
+
25
+ // another callback, this time for a time-out
26
+ static void
27
+ timeout_cb (EV_P_ ev_timer *w, int revents)
28
+ {
29
+ puts ("timeout");
30
+ // this causes the innermost ev_loop to stop iterating
31
+ ev_unloop (EV_A_ EVUNLOOP_ONE);
32
+ }
33
+
34
+
35
+
36
+ #include <winsock.h>
37
+
38
+ #include <stdlib.h>
39
+ #include <iostream>
40
+ int get_server_fd()
41
+ {
42
+
43
+ //----------------------
44
+ // Initialize Winsock.
45
+ WSADATA wsaData;
46
+ int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
47
+ if (iResult != NO_ERROR) {
48
+ printf("Error at WSAStartup()\n");
49
+ return 1;
50
+ }
51
+
52
+ //----------------------
53
+ // Create a SOCKET for listening for
54
+ // incoming connection requests.
55
+ SOCKET ListenSocket;
56
+ ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
57
+ if (ListenSocket == INVALID_SOCKET) {
58
+ printf("Error at socket(): %ld\n", WSAGetLastError());
59
+ WSACleanup();
60
+ return 1;
61
+ }
62
+ printf("socket returned %d\n", ListenSocket);
63
+
64
+ //----------------------
65
+ // The sockaddr_in structure specifies the address family,
66
+ // IP address, and port for the socket that is being bound.
67
+ sockaddr_in service;
68
+ service.sin_family = AF_INET;
69
+ service.sin_addr.s_addr = inet_addr("127.0.0.1");
70
+ service.sin_port = htons(4444);
71
+
72
+ if (bind( ListenSocket,
73
+ (SOCKADDR*) &service,
74
+ sizeof(service)) == SOCKET_ERROR) {
75
+ printf("bind() failed.\n");
76
+ closesocket(ListenSocket);
77
+ WSACleanup();
78
+ return 1;
79
+ }
80
+
81
+ //----------------------
82
+ // Listen for incoming connection requests.
83
+ // on the created socket
84
+ if (listen( ListenSocket, 1 ) == SOCKET_ERROR) {
85
+ printf("Error listening on socket.\n");
86
+ closesocket(ListenSocket);
87
+ WSACleanup();
88
+ return 1;
89
+ }
90
+
91
+
92
+ printf("sock and osf handle are %d %d, error is \n", ListenSocket, _get_osfhandle (ListenSocket)); // -1 is invalid file handle: http://msdn.microsoft.com/en-us/library/ks2530z6.aspx
93
+ printf("err was %d\n", WSAGetLastError());
94
+ //----------------------
95
+ return ListenSocket;
96
+ }
97
+
98
+
99
+ int
100
+ main (void)
101
+ {
102
+ struct ev_loop *loopy = ev_default_loop(0);
103
+ int fd = get_server_fd();
104
+ int fd_real = _open_osfhandle(fd, NULL);
105
+ int conv = _get_osfhandle(fd_real);
106
+ printf("got server fd %d, loop %d, fd_real %d, that converted %d\n", fd, loopy, fd_real, conv);
107
+ // accept(fd, NULL, NULL);
108
+ // initialise an io watcher, then start it
109
+ // this one will watch for stdin to become readable
110
+ ev_io_init (&stdin_watcher, stdin_cb, /*STDIN_FILENO*/ conv, EV_READ);
111
+ ev_io_start (loopy, &stdin_watcher);
112
+
113
+ // initialise a timer watcher, then start it
114
+ // simple non-repeating 5.5 second timeout
115
+ //ev_timer_init (&timeout_watcher, timeout_cb, 15.5, 0.);
116
+ //ev_timer_start (loopy, &timeout_watcher);
117
+ printf("starting loop\n");
118
+ // now wait for events to arrive
119
+ ev_loop (loopy, 0);
120
+
121
+ // unloop was called, so exit
122
+ return 0;
123
+ }
@@ -0,0 +1,44 @@
1
+ require 'mkmf'
2
+
3
+ if have_func('rb_thread_blocking_region')
4
+ $defs << '-DHAVE_RB_THREAD_BLOCKING_REGION'
5
+ end
6
+
7
+ if have_header('sys/select.h')
8
+ $defs << '-DEV_USE_SELECT'
9
+ end
10
+
11
+ if have_header('poll.h')
12
+ $defs << '-DEV_USE_POLL'
13
+ end
14
+
15
+ if have_header('sys/epoll.h')
16
+ $defs << '-DEV_USE_EPOLL'
17
+ end
18
+
19
+ if have_header('sys/event.h') and have_header('sys/queue.h')
20
+ $defs << '-DEV_USE_KQUEUE'
21
+ end
22
+
23
+ if have_header('port.h')
24
+ $defs << '-DEV_USE_PORT'
25
+ end
26
+
27
+ if have_header('sys/resource.h')
28
+ $defs << '-DHAVE_SYS_RESOURCE_H'
29
+ end
30
+
31
+ dir_config 'nio4r_ext'
32
+ create_makefile 'nio4r_ext'
33
+
34
+ # win32 needs to link in "just the right order" for some reason or ioctlsocket will be mapped to an [inverted] ruby specific version.
35
+ # See libev mailing list for (not so helpful discussion--true cause I'm not sure, but this overcomes the symptom)
36
+ if RUBY_PLATFORM =~ /mingw|win32/
37
+ makefile_contents = File.read 'Makefile'
38
+
39
+ # "Init_cool could not be found" when loading cool.io.so.
40
+ makefile_contents.gsub! 'DLDFLAGS = ', 'DLDFLAGS = -export-all '
41
+
42
+ makefile_contents.gsub! 'LIBS = $(LIBRUBYARG_SHARED)', 'LIBS = -lws2_32 $(LIBRUBYARG_SHARED)'
43
+ File.open('Makefile', 'w') { |f| f.write makefile_contents }
44
+ end
data/ext/nio4r/libev.h ADDED
@@ -0,0 +1,8 @@
1
+ #define EV_STANDALONE /* keeps ev from requiring config.h */
2
+
3
+ #ifdef _WIN32
4
+ #define EV_SELECT_IS_WINSOCKET 1
5
+ #define FD_SETSIZE 512
6
+ #endif
7
+
8
+ #include "../libev/ev.h"
@@ -0,0 +1,164 @@
1
+ /*
2
+ * Copyright (c) 2011 Tony Arcieri. Distributed under the MIT License. See
3
+ * LICENSE.txt for further details.
4
+ */
5
+
6
+ #include "nio4r.h"
7
+ #include <assert.h>
8
+
9
+ static VALUE mNIO = Qnil;
10
+ static VALUE cNIO_Monitor = Qnil;
11
+
12
+ /* Allocator/deallocator */
13
+ static VALUE NIO_Monitor_allocate(VALUE klass);
14
+ static void NIO_Monitor_mark(struct NIO_Monitor *monitor);
15
+ static void NIO_Monitor_free(struct NIO_Monitor *monitor);
16
+
17
+ /* Methods */
18
+ static VALUE NIO_Monitor_initialize(VALUE self, VALUE selector, VALUE io, VALUE interests);
19
+ static VALUE NIO_Monitor_close(VALUE self);
20
+ static VALUE NIO_Monitor_is_closed(VALUE self);
21
+ static VALUE NIO_Monitor_io(VALUE self);
22
+ static VALUE NIO_Monitor_interests(VALUE self);
23
+ static VALUE NIO_Monitor_value(VALUE self);
24
+ static VALUE NIO_Monitor_set_value(VALUE self, VALUE obj);
25
+
26
+ /* Internal functions */
27
+ static void NIO_Monitor_callback(struct ev_loop *ev_loop, struct ev_io *io, int revents);
28
+
29
+ #if HAVE_RB_IO_T
30
+ rb_io_t *fptr;
31
+ #else
32
+ OpenFile *fptr;
33
+ #endif
34
+
35
+ /* Monitor control how a channel is being waited for by a monitor */
36
+ void Init_NIO_Monitor()
37
+ {
38
+ mNIO = rb_define_module("NIO");
39
+ cNIO_Monitor = rb_define_class_under(mNIO, "Monitor", rb_cObject);
40
+ rb_define_alloc_func(cNIO_Monitor, NIO_Monitor_allocate);
41
+
42
+ rb_define_method(cNIO_Monitor, "initialize", NIO_Monitor_initialize, 3);
43
+ rb_define_method(cNIO_Monitor, "close", NIO_Monitor_close, 0);
44
+ rb_define_method(cNIO_Monitor, "closed?", NIO_Monitor_is_closed, 0);
45
+ rb_define_method(cNIO_Monitor, "io", NIO_Monitor_io, 0);
46
+ rb_define_method(cNIO_Monitor, "interests", NIO_Monitor_interests, 0);
47
+ rb_define_method(cNIO_Monitor, "value", NIO_Monitor_value, 0);
48
+ rb_define_method(cNIO_Monitor, "value=", NIO_Monitor_set_value, 1);
49
+ }
50
+
51
+ static VALUE NIO_Monitor_allocate(VALUE klass)
52
+ {
53
+ struct NIO_Monitor *monitor = (struct NIO_Monitor *)xmalloc(sizeof(struct NIO_Monitor));
54
+
55
+ return Data_Wrap_Struct(klass, NIO_Monitor_mark, NIO_Monitor_free, monitor);
56
+ }
57
+
58
+ static void NIO_Monitor_mark(struct NIO_Monitor *monitor)
59
+ {
60
+ }
61
+
62
+ static void NIO_Monitor_free(struct NIO_Monitor *monitor)
63
+ {
64
+ xfree(monitor);
65
+ }
66
+
67
+ static VALUE NIO_Monitor_initialize(VALUE self, VALUE selector_obj, VALUE io, VALUE interests)
68
+ {
69
+ struct NIO_Monitor *monitor;
70
+ struct NIO_Selector *selector;
71
+ int events;
72
+ ID interests_id;
73
+
74
+ #if HAVE_RB_IO_T
75
+ rb_io_t *fptr;
76
+ #else
77
+ OpenFile *fptr;
78
+ #endif
79
+
80
+ interests_id = SYM2ID(interests);
81
+
82
+ if(interests_id == rb_intern("r")) {
83
+ events = EV_READ;
84
+ } else if(interests_id == rb_intern("w")) {
85
+ events = EV_WRITE;
86
+ } else if(interests_id == rb_intern("rw")) {
87
+ events = EV_READ | EV_WRITE;
88
+ } else {
89
+ rb_raise(rb_eArgError, "invalid event type %s (must be :r, :w, or :rw)",
90
+ RSTRING_PTR(rb_funcall(interests, rb_intern("inspect"), 0, 0)));
91
+ }
92
+
93
+ Data_Get_Struct(self, struct NIO_Monitor, monitor);
94
+
95
+ GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
96
+ ev_io_init(&monitor->ev_io, NIO_Monitor_callback, FPTR_TO_FD(fptr), events);
97
+
98
+ rb_ivar_set(self, rb_intern("selector"), selector_obj);
99
+ rb_ivar_set(self, rb_intern("io"), io);
100
+ rb_ivar_set(self, rb_intern("interests"), interests);
101
+
102
+ Data_Get_Struct(selector_obj, struct NIO_Selector, selector);
103
+
104
+ monitor->self = self;
105
+ monitor->ev_io.data = (void *)monitor;
106
+
107
+ /* We can safely hang onto this as we also hang onto a reference to the
108
+ object where it originally came from */
109
+ monitor->selector = selector;
110
+
111
+ ev_io_start(selector->ev_loop, &monitor->ev_io);
112
+
113
+ return Qnil;
114
+ }
115
+
116
+ static VALUE NIO_Monitor_close(VALUE self)
117
+ {
118
+ struct NIO_Monitor *monitor;
119
+ Data_Get_Struct(self, struct NIO_Monitor, monitor);
120
+
121
+ if(monitor->selector) {
122
+ ev_io_stop(monitor->selector->ev_loop, &monitor->ev_io);
123
+ monitor->selector = 0;
124
+ }
125
+
126
+ return Qnil;
127
+ }
128
+
129
+ static VALUE NIO_Monitor_is_closed(VALUE self)
130
+ {
131
+ struct NIO_Monitor *monitor;
132
+ Data_Get_Struct(self, struct NIO_Monitor, monitor);
133
+
134
+ return !monitor->selector;
135
+ }
136
+
137
+ static VALUE NIO_Monitor_io(VALUE self)
138
+ {
139
+ return rb_ivar_get(self, rb_intern("io"));
140
+ }
141
+
142
+ static VALUE NIO_Monitor_interests(VALUE self)
143
+ {
144
+ return rb_ivar_get(self, rb_intern("interests"));
145
+ }
146
+
147
+ static VALUE NIO_Monitor_value(VALUE self)
148
+ {
149
+ return rb_ivar_get(self, rb_intern("value"));
150
+ }
151
+
152
+ static VALUE NIO_Monitor_set_value(VALUE self, VALUE obj)
153
+ {
154
+ return rb_ivar_set(self, rb_intern("value"), obj);
155
+ }
156
+
157
+ /* libev callback fired whenever this monitor gets events */
158
+ static void NIO_Monitor_callback(struct ev_loop *ev_loop, struct ev_io *io, int revents)
159
+ {
160
+ struct NIO_Monitor *monitor = (struct NIO_Monitor *)io->data;
161
+
162
+ assert(monitor->selector != 0);
163
+ NIO_Selector_handle_event(monitor->selector, monitor->self, revents);
164
+ }