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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. /*
  2. * Copyright 2000-2004 Niels Provos <provos@citi.umich.edu>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. The name of the author may not be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  17. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  21. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  22. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  23. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #ifdef HAVE_CONFIG_H
  28. #include "config.h"
  29. #endif
  30. #include <sys/types.h>
  31. #include <sys/resource.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/devpoll.h>
  39. #include <signal.h>
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <unistd.h>
  44. #include <fcntl.h>
  45. #include <errno.h>
  46. #include <assert.h>
  47. #include "event.h"
  48. #include "evsignal.h"
  49. #include "log.h"
  50. extern volatile sig_atomic_t evsignal_caught;
  51. /* due to limitations in the devpoll interface, we need to keep track of
  52. * all file descriptors outself.
  53. */
  54. struct evdevpoll {
  55. struct event *evread;
  56. struct event *evwrite;
  57. };
  58. struct devpollop {
  59. struct evdevpoll *fds;
  60. int nfds;
  61. struct pollfd *events;
  62. int nevents;
  63. int dpfd;
  64. struct pollfd *changes;
  65. int nchanges;
  66. };
  67. void *devpoll_init (void);
  68. int devpoll_add (void *, struct event *);
  69. int devpoll_del (void *, struct event *);
  70. int devpoll_recalc (struct event_base *, void *, int);
  71. int devpoll_dispatch (struct event_base *, void *, struct timeval *);
  72. void devpoll_dealloc (void *);
  73. struct eventop devpollops = {
  74. "devpoll",
  75. devpoll_init,
  76. devpoll_add,
  77. devpoll_del,
  78. devpoll_recalc,
  79. devpoll_dispatch,
  80. devpoll_dealloc
  81. };
  82. #define NEVENT 32000
  83. static int
  84. devpoll_commit(struct devpollop *devpollop)
  85. {
  86. /*
  87. * Due to a bug in Solaris, we have to use pwrite with an offset of 0.
  88. * Write is limited to 2GB of data, until it will fail.
  89. */
  90. if (pwrite(devpollop->dpfd, devpollop->changes,
  91. sizeof(struct pollfd) * devpollop->nchanges, 0) == -1)
  92. return(-1);
  93. devpollop->nchanges = 0;
  94. return(0);
  95. }
  96. static int
  97. devpoll_queue(struct devpollop *devpollop, int fd, int events) {
  98. struct pollfd *pfd;
  99. if (devpollop->nchanges >= devpollop->nevents) {
  100. /*
  101. * Change buffer is full, must commit it to /dev/poll before
  102. * adding more
  103. */
  104. if (devpoll_commit(devpollop) != 0)
  105. return(-1);
  106. }
  107. pfd = &devpollop->changes[devpollop->nchanges++];
  108. pfd->fd = fd;
  109. pfd->events = events;
  110. pfd->revents = 0;
  111. return(0);
  112. }
  113. void *
  114. devpoll_init(void)
  115. {
  116. int dpfd, nfiles = NEVENT;
  117. struct rlimit rl;
  118. struct devpollop *devpollop;
  119. /* Disable devpoll when this environment variable is set */
  120. if (getenv("EVENT_NODEVPOLL"))
  121. return (NULL);
  122. if (!(devpollop = calloc(1, sizeof(struct devpollop))))
  123. return (NULL);
  124. if (getrlimit(RLIMIT_NOFILE, &rl) == 0 &&
  125. rl.rlim_cur != RLIM_INFINITY)
  126. nfiles = rl.rlim_cur - 1;
  127. /* Initialize the kernel queue */
  128. if ((dpfd = open("/dev/poll", O_RDWR)) == -1) {
  129. event_warn("open: /dev/poll");
  130. free(devpollop);
  131. return (NULL);
  132. }
  133. devpollop->dpfd = dpfd;
  134. /* Initialize fields */
  135. devpollop->events = calloc(nfiles, sizeof(struct pollfd));
  136. if (devpollop->events == NULL) {
  137. free(devpollop);
  138. close(dpfd);
  139. return (NULL);
  140. }
  141. devpollop->nevents = nfiles;
  142. devpollop->fds = calloc(nfiles, sizeof(struct evdevpoll));
  143. if (devpollop->fds == NULL) {
  144. free(devpollop->events);
  145. free(devpollop);
  146. close(dpfd);
  147. return (NULL);
  148. }
  149. devpollop->nfds = nfiles;
  150. devpollop->changes = calloc(nfiles, sizeof(struct pollfd));
  151. if (devpollop->changes == NULL) {
  152. free(devpollop->fds);
  153. free(devpollop->events);
  154. free(devpollop);
  155. close(dpfd);
  156. return (NULL);
  157. }
  158. evsignal_init();
  159. return (devpollop);
  160. }
  161. int
  162. devpoll_recalc(struct event_base *base, void *arg, int max)
  163. {
  164. struct devpollop *devpollop = arg;
  165. if (max > devpollop->nfds) {
  166. struct evdevpoll *fds;
  167. int nfds;
  168. nfds = devpollop->nfds;
  169. while (nfds < max)
  170. nfds <<= 1;
  171. fds = realloc(devpollop->fds, nfds * sizeof(struct evdevpoll));
  172. if (fds == NULL) {
  173. event_warn("realloc");
  174. return (-1);
  175. }
  176. devpollop->fds = fds;
  177. memset(fds + devpollop->nfds, 0,
  178. (nfds - devpollop->nfds) * sizeof(struct evdevpoll));
  179. devpollop->nfds = nfds;
  180. }
  181. return (0);
  182. }
  183. int
  184. devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
  185. {
  186. struct devpollop *devpollop = arg;
  187. struct pollfd *events = devpollop->events;
  188. struct dvpoll dvp;
  189. struct evdevpoll *evdp;
  190. int i, res, timeout;
  191. if (devpollop->nchanges)
  192. devpoll_commit(devpollop);
  193. timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
  194. dvp.dp_fds = devpollop->events;
  195. dvp.dp_nfds = devpollop->nevents;
  196. dvp.dp_timeout = timeout;
  197. res = ioctl(devpollop->dpfd, DP_POLL, &dvp);
  198. if (res == -1) {
  199. if (errno != EINTR) {
  200. event_warn("ioctl: DP_POLL");
  201. return (-1);
  202. }
  203. evsignal_process();
  204. return (0);
  205. } else if (evsignal_caught)
  206. evsignal_process();
  207. event_debug(("%s: devpoll_wait reports %d", __func__, res));
  208. for (i = 0; i < res; i++) {
  209. int which = 0;
  210. int what = events[i].revents;
  211. struct event *evread = NULL, *evwrite = NULL;
  212. assert(events[i].fd < devpollop->nfds);
  213. evdp = &devpollop->fds[events[i].fd];
  214. if (what & POLLHUP)
  215. what |= POLLIN | POLLOUT;
  216. else if (what & POLLERR)
  217. what |= POLLIN | POLLOUT;
  218. if (what & POLLIN) {
  219. evread = evdp->evread;
  220. which |= EV_READ;
  221. }
  222. if (what & POLLOUT) {
  223. evwrite = evdp->evwrite;
  224. which |= EV_WRITE;
  225. }
  226. if (!which)
  227. continue;
  228. if (evread != NULL && !(evread->ev_events & EV_PERSIST))
  229. event_del(evread);
  230. if (evwrite != NULL && evwrite != evread &&
  231. !(evwrite->ev_events & EV_PERSIST))
  232. event_del(evwrite);
  233. if (evread != NULL)
  234. event_active(evread, EV_READ, 1);
  235. if (evwrite != NULL)
  236. event_active(evwrite, EV_WRITE, 1);
  237. }
  238. return (0);
  239. }
  240. int
  241. devpoll_add(void *arg, struct event *ev)
  242. {
  243. struct devpollop *devpollop = arg;
  244. struct evdevpoll *evdp;
  245. int fd, events;
  246. if (ev->ev_events & EV_SIGNAL)
  247. return (evsignal_add(ev));
  248. fd = ev->ev_fd;
  249. if (fd >= devpollop->nfds) {
  250. /* Extend the file descriptor array as necessary */
  251. if (devpoll_recalc(ev->ev_base, devpollop, fd) == -1)
  252. return (-1);
  253. }
  254. evdp = &devpollop->fds[fd];
  255. /*
  256. * It's not necessary to OR the existing read/write events that we
  257. * are currently interested in with the new event we are adding.
  258. * The /dev/poll driver ORs any new events with the existing events
  259. * that it has cached for the fd.
  260. */
  261. events = 0;
  262. if (ev->ev_events & EV_READ) {
  263. if (evdp->evread && evdp->evread != ev) {
  264. /* There is already a different read event registered */
  265. return(-1);
  266. }
  267. events |= POLLIN;
  268. }
  269. if (ev->ev_events & EV_WRITE) {
  270. if (evdp->evwrite && evdp->evwrite != ev) {
  271. /* There is already a different write event registered */
  272. return(-1);
  273. }
  274. events |= POLLOUT;
  275. }
  276. if (devpoll_queue(devpollop, fd, events) != 0)
  277. return(-1);
  278. /* Update events responsible */
  279. if (ev->ev_events & EV_READ)
  280. evdp->evread = ev;
  281. if (ev->ev_events & EV_WRITE)
  282. evdp->evwrite = ev;
  283. return (0);
  284. }
  285. int
  286. devpoll_del(void *arg, struct event *ev)
  287. {
  288. struct devpollop *devpollop = arg;
  289. struct evdevpoll *evdp;
  290. int fd, events;
  291. int needwritedelete = 1, needreaddelete = 1;
  292. if (ev->ev_events & EV_SIGNAL)
  293. return (evsignal_del(ev));
  294. fd = ev->ev_fd;
  295. if (fd >= devpollop->nfds)
  296. return (0);
  297. evdp = &devpollop->fds[fd];
  298. events = 0;
  299. if (ev->ev_events & EV_READ)
  300. events |= POLLIN;
  301. if (ev->ev_events & EV_WRITE)
  302. events |= POLLOUT;
  303. /*
  304. * The only way to remove an fd from the /dev/poll monitored set is
  305. * to use POLLREMOVE by itself. This removes ALL events for the fd
  306. * provided so if we care about two events and are only removing one
  307. * we must re-add the other event after POLLREMOVE.
  308. */
  309. if (devpoll_queue(devpollop, fd, POLLREMOVE) != 0)
  310. return(-1);
  311. if ((events & (POLLIN|POLLOUT)) != (POLLIN|POLLOUT)) {
  312. /*
  313. * We're not deleting all events, so we must resubmit the
  314. * event that we are still interested in if one exists.
  315. */
  316. if ((events & POLLIN) && evdp->evwrite != NULL) {
  317. /* Deleting read, still care about write */
  318. devpoll_queue(devpollop, fd, POLLOUT);
  319. needwritedelete = 0;
  320. } else if ((events & POLLOUT) && evdp->evread != NULL) {
  321. /* Deleting write, still care about read */
  322. devpoll_queue(devpollop, fd, POLLIN);
  323. needreaddelete = 0;
  324. }
  325. }
  326. if (needreaddelete)
  327. evdp->evread = NULL;
  328. if (needwritedelete)
  329. evdp->evwrite = NULL;
  330. return (0);
  331. }
  332. void
  333. devpoll_dealloc(void *arg)
  334. {
  335. struct devpollop *devpollop = arg;
  336. if (devpollop->fds)
  337. free(devpollop->fds);
  338. if (devpollop->events)
  339. free(devpollop->events);
  340. if (devpollop->changes)
  341. free(devpollop->changes);
  342. if (devpollop->dpfd >= 0)
  343. close(devpollop->dpfd);
  344. memset(devpollop, 0, sizeof(struct devpollop));
  345. free(devpollop);
  346. }