1 /* gnu_java_nio_channel_KqueueSelectorImpl.c --
2 Copyright (C) 2006 Free Software Foundation, Inc.
3
4 This file is a part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or (at
9 your option) any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19 USA
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 #if HAVE_CONFIG_H
40 #include <config.h>
41 #endif /* HAVE_CONFIG_H */
42
43 #include <sys/types.h>
44 #if HAVE_SYS_EVENT_H
45 #include <sys/event.h>
46 #endif /* HAVE_SYS_EVENT_H */
47 #include <sys/time.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <unistd.h>
51
52 #include <jni.h>
53 #include <gnu_java_nio_KqueueSelectorImpl.h>
54
55 #include <jcl.h>
56
57 #define KEY_OP_ACCEPT 16
58 #define KEY_OP_CONNECT 8
59 #define KEY_OP_READ 1
60 #define KEY_OP_WRITE 4
61
62 /* XXX this requires -std=gnu99 or c99 */
63 /* #ifdef TRACE_KQUEUE */
64 /* #define TRACE(fmt, ...) fprintf (stderr, "%s: " fmt "\n", __FUNCTION__, __VA_ARGS__); */
65 /* #else */
66 /* #define TRACE(fmt, ...) */
67 /* #endif */
68
69 /* #define TRACE_KQUEUE 1 */
70
71
72 #define throw_not_supported(env) JCL_ThrowException (env, "java/lang/UnsupportedOperationException", "kqueue/kevent support not available")
73
74
75 /*
76 * Class: gnu_java_nio_KqueueSelectorImpl
77 * Method: kqueue_supported
78 * Signature: ()Z
79 */
80 JNIEXPORT jboolean JNICALL
Java_gnu_java_nio_KqueueSelectorImpl_kqueue_1supported(JNIEnv * env,jclass clazz)81 Java_gnu_java_nio_KqueueSelectorImpl_kqueue_1supported (JNIEnv *env __attribute__((unused)),
82 jclass clazz __attribute__((unused)))
83 {
84 #if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
85 return JNI_TRUE;
86 #else
87 return JNI_FALSE;
88 #endif /* HAVE_KQUEUE && HAVE_KEVENT */
89 }
90
91
92 /*
93 * Class: gnu_java_nio_KqueueSelectorImpl
94 * Method: sizeof_struct_kevent
95 * Signature: ()I
96 */
97 JNIEXPORT jint JNICALL
Java_gnu_java_nio_KqueueSelectorImpl_sizeof_1struct_1kevent(JNIEnv * env,jclass clazz)98 Java_gnu_java_nio_KqueueSelectorImpl_sizeof_1struct_1kevent
99 (JNIEnv *env __attribute__((unused)), jclass clazz __attribute__((unused)))
100 {
101 #if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
102 /* TRACE("return sizeof %lu", sizeof (struct kevent)); */
103 return sizeof (struct kevent);
104 #else
105 throw_not_supported (env);
106 return -1;
107 #endif /* HAVE_KQUEUE && HAVE_KEVENT */
108 }
109
110
111 /*
112 * Class: gnu_java_nio_KqueueSelectorImpl
113 * Method: implOpen
114 * Signature: ()I
115 */
116 JNIEXPORT jint JNICALL
Java_gnu_java_nio_KqueueSelectorImpl_implOpen(JNIEnv * env,jclass clazz)117 Java_gnu_java_nio_KqueueSelectorImpl_implOpen
118 (JNIEnv *env, jclass clazz __attribute__((unused)))
119 {
120 #if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
121 int kq = kqueue ();
122 /* TRACE("kqueue returns %d", kq); */
123 if (kq == -1)
124 JCL_ThrowException (env, "java/io/IOException", strerror (errno));
125 return kq;
126 #else
127 throw_not_supported (env);
128 return -1;
129 #endif
130 }
131
132
133 /*
134 * Class: gnu_java_nio_KqueueSelectorImpl
135 * Method: implClose
136 * Signature: (I)V
137 */
138 JNIEXPORT void JNICALL
Java_gnu_java_nio_KqueueSelectorImpl_implClose(JNIEnv * env,jclass clazz,jint kq)139 Java_gnu_java_nio_KqueueSelectorImpl_implClose (JNIEnv *env,
140 jclass clazz __attribute__((unused)),
141 jint kq)
142 {
143 #if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
144 /* TRACE("closing %d", kq); */
145 if (close (kq) != 0)
146 JCL_ThrowException (env, "java/io/IOException", strerror (errno));
147 #else
148 (void) kq;
149 throw_not_supported (env);
150 #endif /* HAVE_KQUEUE && HAVE_KEVENT */
151 }
152
153
154 /*
155 * Class: gnu_java_nio_KqueueSelectorImpl
156 * Method: kevent_set
157 * Signature: (Ljava/nio/ByteBuffer;IIIZ)V
158 */
159 JNIEXPORT void JNICALL
Java_gnu_java_nio_KqueueSelectorImpl_kevent_1set(JNIEnv * env,jclass clazz,jobject nstate,jint i,jint fd,jint ops,jint active,jint key)160 Java_gnu_java_nio_KqueueSelectorImpl_kevent_1set (JNIEnv *env,
161 jclass clazz __attribute__((unused)),
162 jobject nstate, jint i, jint fd,
163 jint ops, jint active, jint key)
164 {
165 #if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
166 struct kevent *kev;
167 short ident;
168
169 kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate);
170
171 #ifdef TRACE_KQUEUE
172 printf ("kevent_set fd:%d p:%p i:%d ops:%x active:%x key:%x\n",
173 fd, (void *) kev, i, ops, active, key);
174 #endif /* TRACE_KQUEUE */
175
176 if (kev == NULL)
177 {
178 JCL_ThrowException (env, "java/lang/InternalError",
179 "GetDirectBufferAddress returned NULL!");
180 return;
181 }
182
183 ident = fd;
184 memset (&kev[i], 0, sizeof (struct kevent));
185
186 if ((ops & KEY_OP_READ) || (ops & KEY_OP_ACCEPT))
187 {
188 /* Add event if it wasn't previously added. */
189 if (!(active & KEY_OP_READ) && !(active & KEY_OP_ACCEPT))
190 EV_SET(&kev[i], ident, EVFILT_READ, EV_ADD, 0, 0, (void *) key);
191 }
192 else
193 {
194 /* Delete event if it was previously added */
195 if ((active & KEY_OP_READ) || (active & KEY_OP_ACCEPT))
196 EV_SET(&kev[i], ident, EVFILT_READ, EV_DELETE, 0, 0, (void *) key);
197 }
198
199 /* Do the same thing for the write filter. */
200 if ((ops & KEY_OP_WRITE) || (ops & KEY_OP_CONNECT))
201 {
202 if (!(active & KEY_OP_WRITE) && !(active & KEY_OP_CONNECT))
203 EV_SET(&kev[i], ident, EVFILT_WRITE, EV_ADD, 0, 0, (void *) key);
204 }
205 else
206 {
207 if ((active & KEY_OP_WRITE) || (active & KEY_OP_CONNECT))
208 EV_SET(&kev[i], ident, EVFILT_WRITE, EV_DELETE, 0, 0, (void *) key);
209 }
210
211 #ifdef TRACE_KQUEUE
212 printf (" set kevent %2d: ident:%u filter:%x flags:%o fflags:%o data:%p udata:%p\n",
213 i, (unsigned) kev[i].ident, kev[i].filter, kev[i].flags, kev[i].fflags,
214 (void *) kev[i].data, kev[i].udata);
215 #endif /* TRACE_KQUEUE */
216 #else
217 (void) nstate;
218 (void) i;
219 (void) fd;
220 (void) ops;
221 (void) key;
222 (void) active;
223 throw_not_supported (env);
224 #endif /* HAVE_KQUEUE && HAVE_KEVENT */
225 }
226
227
228 /*
229 * Class: gnu_java_nio_KqueueSelectorImpl
230 * Method: kevent
231 * Signature: (ILjava/nio/ByteBuffer;IJ)I
232 */
233 JNIEXPORT jint JNICALL
Java_gnu_java_nio_KqueueSelectorImpl_kevent(JNIEnv * env,jobject this,jint kq,jobject nstate,jint nevents,jint maxevents,jlong timeout)234 Java_gnu_java_nio_KqueueSelectorImpl_kevent (JNIEnv *env,
235 jobject this __attribute__((unused)),
236 jint kq, jobject nstate, jint nevents,
237 jint maxevents, jlong timeout)
238 {
239 #if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
240 struct timespec tv;
241 struct timespec *t = NULL;
242 struct kevent *kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate);
243 int ret;
244
245 #ifdef TRACE_KQUEUE
246 int i;
247
248 printf ("[%d] kevent nevents:%d maxevents:%d timeout:%lld\n", kq, nevents, maxevents, timeout);
249 printf ("[%d] addding/deleting %d events\n", kq, nevents);
250 for (i = 0; i < nevents; i++)
251 {
252 printf ("[%d] kevent input [%d]: ident:%u filter:%x flags:%o fflags:%o data:%p udata:%p\n",
253 kq, i, (unsigned) kev[i].ident, kev[i].filter, kev[i].flags, kev[i].fflags,
254 (void *) kev[i].data, kev[i].udata);
255 }
256 #endif
257
258 /* TRACE("events: %p; nevents: %d; timeout: %lld", (void *) kev, nevents, timeout); */
259
260 if (timeout != -1)
261 {
262 tv.tv_sec = timeout / 1000;
263 tv.tv_nsec = (timeout % 1000) * 1000;
264 t = &tv;
265 }
266
267 ret = kevent (kq, (const struct kevent *) kev, nevents, kev, maxevents, t);
268
269 if (ret == -1)
270 {
271 if (errno == EINTR)
272 ret = 0;
273 else
274 JCL_ThrowException (env, "java/io/IOException", strerror (errno));
275 }
276
277 #ifdef TRACE_KQUEUE
278 for (i = 0; i < ret; i++)
279 {
280 printf ("[%d] kevent output [%d]: ident:%u filter:%x flags:%o fflags:%o data:%p udata:%p\n",
281 kq, i, (unsigned) kev[i].ident, kev[i].filter, kev[i].flags, kev[i].fflags,
282 (void *) kev[i].data, kev[i].udata);
283 }
284 #endif
285
286 return ret;
287 #else
288 (void) kq;
289 (void) nstate;
290 (void) nevents;
291 (void) maxevents;
292 (void) timeout;
293 throw_not_supported (env);
294 return -1;
295 #endif /* HAVE_KQUEUE && HAVE_KEVENT */
296 }
297
298
299 /*
300 * Class: gnu_java_nio_KqueueSelectorImpl
301 * Method: fetch_key
302 * Signature: (Ljava/nio/ByteBuffer;)I;
303 */
304 JNIEXPORT jint JNICALL
Java_gnu_java_nio_KqueueSelectorImpl_fetch_1key(JNIEnv * env,jclass clazz,jobject nstate)305 Java_gnu_java_nio_KqueueSelectorImpl_fetch_1key (JNIEnv *env,
306 jclass clazz __attribute__((unused)),
307 jobject nstate)
308 {
309 #if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
310 struct kevent *kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate);
311 /* TRACE("return key %p\n", kev->udata); */
312 return (jint) kev->udata;
313 #else
314 (void) nstate;
315 throw_not_supported (env);
316 return -1;
317 #endif /* HAVE_KQUEUE && HAVE_KEVENT */
318 }
319
320
321 /*
322 * Class: gnu_java_nio_KqueueSelectorImpl
323 * Method: ready_ops
324 * Signature: (Ljava/nio/ByteBuffer;I)I
325 */
326 JNIEXPORT jint JNICALL
Java_gnu_java_nio_KqueueSelectorImpl_ready_1ops(JNIEnv * env,jclass clazz,jobject nstate,jint interest)327 Java_gnu_java_nio_KqueueSelectorImpl_ready_1ops (JNIEnv *env,
328 jclass clazz __attribute__((unused)),
329 jobject nstate, jint interest)
330 {
331 #if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
332 struct kevent *kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate);
333 jint ready = 0;
334
335 if ((kev->flags & EV_ERROR) == EV_ERROR)
336 {
337 printf ("!!! error selecting fd %d: %s", (int) (kev->ident), strerror ((int) (kev->data)));
338 return 0;
339 }
340
341 /* We poll for READ for OP_READ and OP_ACCEPT. */
342 if (kev->filter == EVFILT_READ)
343 {
344 ready = (interest & KEY_OP_READ) | (interest & KEY_OP_ACCEPT);
345 /* TRACE("filter EVFILT_READ. Ready ops set to %x", ready); */
346 }
347
348 /* Poll for WRITE for OP_WRITE and OP_CONNECT; I guess we *should*
349 get a WRITE event if we are connected, but I don't know if we do
350 for real. FIXME */
351 if (kev->filter == EVFILT_WRITE)
352 {
353 ready = (interest & KEY_OP_WRITE) | (interest & KEY_OP_CONNECT);
354 /* TRACE("filter EVFILT_WRITE. Ready ops set to %x", ready); */
355 }
356
357 return ready;
358 #else
359 (void) nstate;
360 (void) interest;
361 throw_not_supported (env);
362 return -1;
363 #endif /* HAVE_KQUEUE && HAVE_KEVENT */
364 }
365
366
367 /*
368 * Class: gnu_java_nio_KqueueSelectorImpl
369 * Method: check_eof
370 * Signature: (Ljava/nio/ByteBuffer;)Z
371 */
372 JNIEXPORT jboolean JNICALL
Java_gnu_java_nio_KqueueSelectorImpl_check_1eof(JNIEnv * env,jclass clazz,jobject nstate)373 Java_gnu_java_nio_KqueueSelectorImpl_check_1eof (JNIEnv *env,
374 jclass clazz __attribute__((unused)),
375 jobject nstate)
376 {
377 #if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
378 struct kevent *kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate);
379 if ((kev->flags & EV_EOF) == EV_EOF)
380 return JNI_TRUE;
381 return JNI_FALSE;
382 #else
383 (void) nstate;
384 throw_not_supported (env);
385 return JNI_FALSE;
386 #endif
387 }
388