A clone of btpd with my configuration changes.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

414 lignes
9.2 KiB

  1. /* $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $ */
  2. /*
  3. * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. The name of the author may not be used to endorse or promote products
  15. * derived from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #ifdef HAVE_CONFIG_H
  29. #include "config.h"
  30. #endif
  31. #include <sys/types.h>
  32. #ifdef HAVE_SYS_TIME_H
  33. #include <sys/time.h>
  34. #else
  35. #include <sys/_time.h>
  36. #endif
  37. #include <sys/queue.h>
  38. #include <sys/event.h>
  39. #include <signal.h>
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <unistd.h>
  44. #include <errno.h>
  45. #ifdef HAVE_INTTYPES_H
  46. #include <inttypes.h>
  47. #endif
  48. #if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__)
  49. #define INTPTR(x) (intptr_t)x
  50. #else
  51. #define INTPTR(x) x
  52. #endif
  53. #include "event.h"
  54. #include "log.h"
  55. #define EVLIST_X_KQINKERNEL 0x1000
  56. #define NEVENT 64
  57. struct kqop {
  58. struct kevent *changes;
  59. int nchanges;
  60. struct kevent *events;
  61. int nevents;
  62. int kq;
  63. };
  64. void *kq_init (void);
  65. int kq_add (void *, struct event *);
  66. int kq_del (void *, struct event *);
  67. int kq_recalc (struct event_base *, void *, int);
  68. int kq_dispatch (struct event_base *, void *, struct timeval *);
  69. int kq_insert (struct kqop *, struct kevent *);
  70. void kq_dealloc (void *);
  71. const struct eventop kqops = {
  72. "kqueue",
  73. kq_init,
  74. kq_add,
  75. kq_del,
  76. kq_recalc,
  77. kq_dispatch,
  78. kq_dealloc
  79. };
  80. void *
  81. kq_init(void)
  82. {
  83. int kq;
  84. struct kqop *kqueueop;
  85. /* Disable kqueue when this environment variable is set */
  86. if (getenv("EVENT_NOKQUEUE"))
  87. return (NULL);
  88. if (!(kqueueop = calloc(1, sizeof(struct kqop))))
  89. return (NULL);
  90. /* Initalize the kernel queue */
  91. if ((kq = kqueue()) == -1) {
  92. event_warn("kqueue");
  93. free (kqueueop);
  94. return (NULL);
  95. }
  96. kqueueop->kq = kq;
  97. /* Initalize fields */
  98. kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
  99. if (kqueueop->changes == NULL) {
  100. free (kqueueop);
  101. return (NULL);
  102. }
  103. kqueueop->events = malloc(NEVENT * sizeof(struct kevent));
  104. if (kqueueop->events == NULL) {
  105. free (kqueueop->changes);
  106. free (kqueueop);
  107. return (NULL);
  108. }
  109. kqueueop->nevents = NEVENT;
  110. /* Check for Mac OS X kqueue bug. */
  111. kqueueop->changes[0].ident = -1;
  112. kqueueop->changes[0].filter = EVFILT_READ;
  113. kqueueop->changes[0].flags = EV_ADD;
  114. /*
  115. * If kqueue works, then kevent will succeed, and it will
  116. * stick an error in events[0]. If kqueue is broken, then
  117. * kevent will fail.
  118. */
  119. if (kevent(kq,
  120. kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
  121. kqueueop->events[0].ident != -1 ||
  122. kqueueop->events[0].flags != EV_ERROR) {
  123. event_warn("%s: detected broken kqueue; not using.", __func__);
  124. free(kqueueop->changes);
  125. free(kqueueop->events);
  126. free(kqueueop);
  127. close(kq);
  128. return (NULL);
  129. }
  130. return (kqueueop);
  131. }
  132. int
  133. kq_recalc(struct event_base *base, void *arg, int max)
  134. {
  135. return (0);
  136. }
  137. int
  138. kq_insert(struct kqop *kqop, struct kevent *kev)
  139. {
  140. int nevents = kqop->nevents;
  141. if (kqop->nchanges == nevents) {
  142. struct kevent *newchange;
  143. struct kevent *newresult;
  144. nevents *= 2;
  145. newchange = realloc(kqop->changes,
  146. nevents * sizeof(struct kevent));
  147. if (newchange == NULL) {
  148. event_warn("%s: malloc", __func__);
  149. return (-1);
  150. }
  151. kqop->changes = newchange;
  152. newresult = realloc(kqop->events,
  153. nevents * sizeof(struct kevent));
  154. /*
  155. * If we fail, we don't have to worry about freeing,
  156. * the next realloc will pick it up.
  157. */
  158. if (newresult == NULL) {
  159. event_warn("%s: malloc", __func__);
  160. return (-1);
  161. }
  162. kqop->events = newresult;
  163. kqop->nevents = nevents;
  164. }
  165. memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
  166. event_debug(("%s: fd %d %s%s",
  167. __func__, kev->ident,
  168. kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
  169. kev->flags == EV_DELETE ? " (del)" : ""));
  170. return (0);
  171. }
  172. static void
  173. kq_sighandler(int sig)
  174. {
  175. /* Do nothing here */
  176. }
  177. int
  178. kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
  179. {
  180. struct kqop *kqop = arg;
  181. struct kevent *changes = kqop->changes;
  182. struct kevent *events = kqop->events;
  183. struct event *ev;
  184. struct timespec ts;
  185. int i, res;
  186. TIMEVAL_TO_TIMESPEC(tv, &ts);
  187. res = kevent(kqop->kq, changes, kqop->nchanges,
  188. events, kqop->nevents, &ts);
  189. kqop->nchanges = 0;
  190. if (res == -1) {
  191. if (errno != EINTR) {
  192. event_warn("kevent");
  193. return (-1);
  194. }
  195. return (0);
  196. }
  197. event_debug(("%s: kevent reports %d", __func__, res));
  198. for (i = 0; i < res; i++) {
  199. int which = 0;
  200. if (events[i].flags & EV_ERROR) {
  201. /*
  202. * Error messages that can happen, when a delete fails.
  203. * EBADF happens when the file discriptor has been
  204. * closed,
  205. * ENOENT when the file discriptor was closed and
  206. * then reopened.
  207. * EINVAL for some reasons not understood; EINVAL
  208. * should not be returned ever; but FreeBSD does :-\
  209. * An error is also indicated when a callback deletes
  210. * an event we are still processing. In that case
  211. * the data field is set to ENOENT.
  212. */
  213. if (events[i].data == EBADF ||
  214. events[i].data == EINVAL ||
  215. events[i].data == ENOENT)
  216. continue;
  217. errno = events[i].data;
  218. return (-1);
  219. }
  220. ev = (struct event *)events[i].udata;
  221. if (events[i].filter == EVFILT_READ) {
  222. which |= EV_READ;
  223. } else if (events[i].filter == EVFILT_WRITE) {
  224. which |= EV_WRITE;
  225. } else if (events[i].filter == EVFILT_SIGNAL) {
  226. which |= EV_SIGNAL;
  227. }
  228. if (!which)
  229. continue;
  230. if (!(ev->ev_events & EV_PERSIST))
  231. event_del(ev);
  232. event_active(ev, which,
  233. ev->ev_events & EV_SIGNAL ? events[i].data : 1);
  234. }
  235. return (0);
  236. }
  237. int
  238. kq_add(void *arg, struct event *ev)
  239. {
  240. struct kqop *kqop = arg;
  241. struct kevent kev;
  242. if (ev->ev_events & EV_SIGNAL) {
  243. int nsignal = EVENT_SIGNAL(ev);
  244. memset(&kev, 0, sizeof(kev));
  245. kev.ident = nsignal;
  246. kev.filter = EVFILT_SIGNAL;
  247. kev.flags = EV_ADD;
  248. if (!(ev->ev_events & EV_PERSIST))
  249. kev.flags |= EV_ONESHOT;
  250. kev.udata = INTPTR(ev);
  251. if (kq_insert(kqop, &kev) == -1)
  252. return (-1);
  253. if (signal(nsignal, kq_sighandler) == SIG_ERR)
  254. return (-1);
  255. ev->ev_flags |= EVLIST_X_KQINKERNEL;
  256. return (0);
  257. }
  258. if (ev->ev_events & EV_READ) {
  259. memset(&kev, 0, sizeof(kev));
  260. kev.ident = ev->ev_fd;
  261. kev.filter = EVFILT_READ;
  262. #ifdef NOTE_EOF
  263. /* Make it behave like select() and poll() */
  264. kev.fflags = NOTE_EOF;
  265. #endif
  266. kev.flags = EV_ADD;
  267. if (!(ev->ev_events & EV_PERSIST))
  268. kev.flags |= EV_ONESHOT;
  269. kev.udata = INTPTR(ev);
  270. if (kq_insert(kqop, &kev) == -1)
  271. return (-1);
  272. ev->ev_flags |= EVLIST_X_KQINKERNEL;
  273. }
  274. if (ev->ev_events & EV_WRITE) {
  275. memset(&kev, 0, sizeof(kev));
  276. kev.ident = ev->ev_fd;
  277. kev.filter = EVFILT_WRITE;
  278. kev.flags = EV_ADD;
  279. if (!(ev->ev_events & EV_PERSIST))
  280. kev.flags |= EV_ONESHOT;
  281. kev.udata = INTPTR(ev);
  282. if (kq_insert(kqop, &kev) == -1)
  283. return (-1);
  284. ev->ev_flags |= EVLIST_X_KQINKERNEL;
  285. }
  286. return (0);
  287. }
  288. int
  289. kq_del(void *arg, struct event *ev)
  290. {
  291. struct kqop *kqop = arg;
  292. struct kevent kev;
  293. if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
  294. return (0);
  295. if (ev->ev_events & EV_SIGNAL) {
  296. int nsignal = EVENT_SIGNAL(ev);
  297. memset(&kev, 0, sizeof(kev));
  298. kev.ident = nsignal;
  299. kev.filter = EVFILT_SIGNAL;
  300. kev.flags = EV_DELETE;
  301. if (kq_insert(kqop, &kev) == -1)
  302. return (-1);
  303. if (signal(nsignal, SIG_DFL) == SIG_ERR)
  304. return (-1);
  305. ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
  306. return (0);
  307. }
  308. if (ev->ev_events & EV_READ) {
  309. memset(&kev, 0, sizeof(kev));
  310. kev.ident = ev->ev_fd;
  311. kev.filter = EVFILT_READ;
  312. kev.flags = EV_DELETE;
  313. if (kq_insert(kqop, &kev) == -1)
  314. return (-1);
  315. ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
  316. }
  317. if (ev->ev_events & EV_WRITE) {
  318. memset(&kev, 0, sizeof(kev));
  319. kev.ident = ev->ev_fd;
  320. kev.filter = EVFILT_WRITE;
  321. kev.flags = EV_DELETE;
  322. if (kq_insert(kqop, &kev) == -1)
  323. return (-1);
  324. ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
  325. }
  326. return (0);
  327. }
  328. void
  329. kq_dealloc(void *arg)
  330. {
  331. struct kqop *kqop = arg;
  332. if (kqop->changes)
  333. free(kqop->changes);
  334. if (kqop->events)
  335. free(kqop->events);
  336. if (kqop->kq)
  337. close(kqop->kq);
  338. memset(kqop, 0, sizeof(struct kqop));
  339. free(kqop);
  340. }