A clone of btpd with my configuration changes.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

398 lines
9.4 KiB

  1. /* $OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
  2. /*
  3. * Copyright 2000-2003 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/tree.h>
  39. #include <poll.h>
  40. #include <signal.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #include <unistd.h>
  45. #include <errno.h>
  46. #ifdef CHECK_INVARIANTS
  47. #include <assert.h>
  48. #endif
  49. #include "event.h"
  50. #include "event-internal.h"
  51. #include "evsignal.h"
  52. #include "log.h"
  53. extern volatile sig_atomic_t evsignal_caught;
  54. struct pollop {
  55. int event_count; /* Highest number alloc */
  56. int nfds; /* Size of event_* */
  57. int fd_count; /* Size of idxplus1_by_fd */
  58. struct pollfd *event_set;
  59. struct event **event_r_back;
  60. struct event **event_w_back;
  61. int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so
  62. * that 0 (which is easy to memset) can mean
  63. * "no entry." */
  64. sigset_t evsigmask;
  65. };
  66. void *poll_init (void);
  67. int poll_add (void *, struct event *);
  68. int poll_del (void *, struct event *);
  69. int poll_recalc (struct event_base *, void *, int);
  70. int poll_dispatch (struct event_base *, void *, struct timeval *);
  71. void poll_dealloc (void *);
  72. const struct eventop pollops = {
  73. "poll",
  74. poll_init,
  75. poll_add,
  76. poll_del,
  77. poll_recalc,
  78. poll_dispatch,
  79. poll_dealloc
  80. };
  81. void *
  82. poll_init(void)
  83. {
  84. struct pollop *pollop;
  85. /* Disable poll when this environment variable is set */
  86. if (getenv("EVENT_NOPOLL"))
  87. return (NULL);
  88. if (!(pollop = calloc(1, sizeof(struct pollop))))
  89. return (NULL);
  90. evsignal_init(&pollop->evsigmask);
  91. return (pollop);
  92. }
  93. /*
  94. * Called with the highest fd that we know about. If it is 0, completely
  95. * recalculate everything.
  96. */
  97. int
  98. poll_recalc(struct event_base *base, void *arg, int max)
  99. {
  100. struct pollop *pop = arg;
  101. return (evsignal_recalc(&pop->evsigmask));
  102. }
  103. #ifdef CHECK_INVARIANTS
  104. static void
  105. poll_check_ok(struct pollop *pop)
  106. {
  107. int i, idx;
  108. struct event *ev;
  109. for (i = 0; i < pop->fd_count; ++i) {
  110. idx = pop->idxplus1_by_fd[i]-1;
  111. if (idx < 0)
  112. continue;
  113. assert(pop->event_set[idx].fd == i);
  114. if (pop->event_set[idx].events & POLLIN) {
  115. ev = pop->event_r_back[idx];
  116. assert(ev);
  117. assert(ev->ev_events & EV_READ);
  118. assert(ev->ev_fd == i);
  119. }
  120. if (pop->event_set[idx].events & POLLOUT) {
  121. ev = pop->event_w_back[idx];
  122. assert(ev);
  123. assert(ev->ev_events & EV_WRITE);
  124. assert(ev->ev_fd == i);
  125. }
  126. }
  127. for (i = 0; i < pop->nfds; ++i) {
  128. struct pollfd *pfd = &pop->event_set[i];
  129. assert(pop->idxplus1_by_fd[pfd->fd] == i+1);
  130. }
  131. }
  132. #else
  133. #define poll_check_ok(pop)
  134. #endif
  135. int
  136. poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
  137. {
  138. int res, i, sec, nfds;
  139. struct pollop *pop = arg;
  140. if (evsignal_deliver(&pop->evsigmask) == -1)
  141. return (-1);
  142. poll_check_ok(pop);
  143. sec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
  144. nfds = pop->nfds;
  145. res = poll(pop->event_set, nfds, sec);
  146. if (evsignal_recalc(&pop->evsigmask) == -1)
  147. return (-1);
  148. if (res == -1) {
  149. if (errno != EINTR) {
  150. event_warn("poll");
  151. return (-1);
  152. }
  153. evsignal_process();
  154. return (0);
  155. } else if (evsignal_caught)
  156. evsignal_process();
  157. event_debug(("%s: poll reports %d", __func__, res));
  158. if (res == 0)
  159. return (0);
  160. for (i = 0; i < nfds; i++) {
  161. int what = pop->event_set[i].revents;
  162. struct event *r_ev = NULL, *w_ev = NULL;
  163. if (!what)
  164. continue;
  165. res = 0;
  166. /* If the file gets closed notify */
  167. if (what & (POLLHUP|POLLERR))
  168. what |= POLLIN|POLLOUT;
  169. if (what & POLLIN) {
  170. res |= EV_READ;
  171. r_ev = pop->event_r_back[i];
  172. }
  173. if (what & POLLOUT) {
  174. res |= EV_WRITE;
  175. w_ev = pop->event_w_back[i];
  176. }
  177. if (res == 0)
  178. continue;
  179. if (r_ev && (res & r_ev->ev_events)) {
  180. if (!(r_ev->ev_events & EV_PERSIST))
  181. event_del(r_ev);
  182. event_active(r_ev, res & r_ev->ev_events, 1);
  183. }
  184. if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
  185. if (!(w_ev->ev_events & EV_PERSIST))
  186. event_del(w_ev);
  187. event_active(w_ev, res & w_ev->ev_events, 1);
  188. }
  189. }
  190. return (0);
  191. }
  192. int
  193. poll_add(void *arg, struct event *ev)
  194. {
  195. struct pollop *pop = arg;
  196. struct pollfd *pfd = NULL;
  197. int i;
  198. if (ev->ev_events & EV_SIGNAL)
  199. return (evsignal_add(&pop->evsigmask, ev));
  200. if (!(ev->ev_events & (EV_READ|EV_WRITE)))
  201. return (0);
  202. poll_check_ok(pop);
  203. if (pop->nfds + 1 >= pop->event_count) {
  204. struct pollfd *tmp_event_set;
  205. struct event **tmp_event_r_back;
  206. struct event **tmp_event_w_back;
  207. int tmp_event_count;
  208. if (pop->event_count < 32)
  209. tmp_event_count = 32;
  210. else
  211. tmp_event_count = pop->event_count * 2;
  212. /* We need more file descriptors */
  213. tmp_event_set = realloc(pop->event_set,
  214. tmp_event_count * sizeof(struct pollfd));
  215. if (tmp_event_set == NULL) {
  216. event_warn("realloc");
  217. return (-1);
  218. }
  219. pop->event_set = tmp_event_set;
  220. tmp_event_r_back = realloc(pop->event_r_back,
  221. tmp_event_count * sizeof(struct event *));
  222. if (tmp_event_r_back == NULL) {
  223. /* event_set overallocated; that's okay. */
  224. event_warn("realloc");
  225. return (-1);
  226. }
  227. pop->event_r_back = tmp_event_r_back;
  228. tmp_event_w_back = realloc(pop->event_w_back,
  229. tmp_event_count * sizeof(struct event *));
  230. if (tmp_event_w_back == NULL) {
  231. /* event_set and event_r_back overallocated; that's
  232. * okay. */
  233. event_warn("realloc");
  234. return (-1);
  235. }
  236. pop->event_w_back = tmp_event_w_back;
  237. pop->event_count = tmp_event_count;
  238. }
  239. if (ev->ev_fd >= pop->fd_count) {
  240. int *tmp_idxplus1_by_fd;
  241. int new_count;
  242. if (pop->fd_count < 32)
  243. new_count = 32;
  244. else
  245. new_count = pop->fd_count * 2;
  246. while (new_count <= ev->ev_fd)
  247. new_count *= 2;
  248. tmp_idxplus1_by_fd =
  249. realloc(pop->idxplus1_by_fd, new_count * sizeof(int));
  250. if (tmp_idxplus1_by_fd == NULL) {
  251. event_warn("realloc");
  252. return (-1);
  253. }
  254. pop->idxplus1_by_fd = tmp_idxplus1_by_fd;
  255. memset(pop->idxplus1_by_fd + pop->fd_count,
  256. 0, sizeof(int)*(new_count - pop->fd_count));
  257. pop->fd_count = new_count;
  258. }
  259. i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
  260. if (i >= 0) {
  261. pfd = &pop->event_set[i];
  262. } else {
  263. i = pop->nfds++;
  264. pfd = &pop->event_set[i];
  265. pfd->events = 0;
  266. pfd->fd = ev->ev_fd;
  267. pop->event_w_back[i] = pop->event_r_back[i] = NULL;
  268. pop->idxplus1_by_fd[ev->ev_fd] = i + 1;
  269. }
  270. pfd->revents = 0;
  271. if (ev->ev_events & EV_WRITE) {
  272. pfd->events |= POLLOUT;
  273. pop->event_w_back[i] = ev;
  274. }
  275. if (ev->ev_events & EV_READ) {
  276. pfd->events |= POLLIN;
  277. pop->event_r_back[i] = ev;
  278. }
  279. poll_check_ok(pop);
  280. return (0);
  281. }
  282. /*
  283. * Nothing to be done here.
  284. */
  285. int
  286. poll_del(void *arg, struct event *ev)
  287. {
  288. struct pollop *pop = arg;
  289. struct pollfd *pfd = NULL;
  290. int i;
  291. if (ev->ev_events & EV_SIGNAL)
  292. return (evsignal_del(&pop->evsigmask, ev));
  293. if (!(ev->ev_events & (EV_READ|EV_WRITE)))
  294. return (0);
  295. poll_check_ok(pop);
  296. i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
  297. if (i < 0)
  298. return (-1);
  299. /* Do we still want to read or write? */
  300. pfd = &pop->event_set[i];
  301. if (ev->ev_events & EV_READ) {
  302. pfd->events &= ~POLLIN;
  303. pop->event_r_back[i] = NULL;
  304. }
  305. if (ev->ev_events & EV_WRITE) {
  306. pfd->events &= ~POLLOUT;
  307. pop->event_w_back[i] = NULL;
  308. }
  309. poll_check_ok(pop);
  310. if (pfd->events)
  311. /* Another event cares about that fd. */
  312. return (0);
  313. /* Okay, so we aren't interested in that fd anymore. */
  314. pop->idxplus1_by_fd[ev->ev_fd] = 0;
  315. --pop->nfds;
  316. if (i != pop->nfds) {
  317. /*
  318. * Shift the last pollfd down into the now-unoccupied
  319. * position.
  320. */
  321. memcpy(&pop->event_set[i], &pop->event_set[pop->nfds],
  322. sizeof(struct pollfd));
  323. pop->event_r_back[i] = pop->event_r_back[pop->nfds];
  324. pop->event_w_back[i] = pop->event_w_back[pop->nfds];
  325. pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1;
  326. }
  327. poll_check_ok(pop);
  328. return (0);
  329. }
  330. void
  331. poll_dealloc(void *arg)
  332. {
  333. struct pollop *pop = arg;
  334. if (pop->event_set)
  335. free(pop->event_set);
  336. if (pop->event_r_back)
  337. free(pop->event_r_back);
  338. if (pop->event_w_back)
  339. free(pop->event_w_back);
  340. if (pop->idxplus1_by_fd)
  341. free(pop->idxplus1_by_fd);
  342. memset(pop, 0, sizeof(struct pollop));
  343. free(pop);
  344. }