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.

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