gnu_java_nio_KqueueSelectorImpl.c 11 KB

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