A clone of btpd with my configuration changes.
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

414 рядки
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. }