A clone of btpd with my configuration changes.
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

424 lines
10 KiB

  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. sigset_t evsigmask;
  65. struct pollfd *changes;
  66. int nchanges;
  67. };
  68. void *devpoll_init (void);
  69. int devpoll_add (void *, struct event *);
  70. int devpoll_del (void *, struct event *);
  71. int devpoll_recalc (struct event_base *, void *, int);
  72. int devpoll_dispatch (struct event_base *, void *, struct timeval *);
  73. void devpoll_dealloc (void *);
  74. struct eventop devpollops = {
  75. "devpoll",
  76. devpoll_init,
  77. devpoll_add,
  78. devpoll_del,
  79. devpoll_recalc,
  80. devpoll_dispatch,
  81. devpoll_dealloc
  82. };
  83. #define NEVENT 32000
  84. static int
  85. devpoll_commit(struct devpollop *devpollop)
  86. {
  87. /*
  88. * Due to a bug in Solaris, we have to use pwrite with an offset of 0.
  89. * Write is limited to 2GB of data, until it will fail.
  90. */
  91. if (pwrite(devpollop->dpfd, devpollop->changes,
  92. sizeof(struct pollfd) * devpollop->nchanges, 0) == -1)
  93. return(-1);
  94. devpollop->nchanges = 0;
  95. return(0);
  96. }
  97. static int
  98. devpoll_queue(struct devpollop *devpollop, int fd, int events) {
  99. struct pollfd *pfd;
  100. if (devpollop->nchanges >= devpollop->nevents) {
  101. /*
  102. * Change buffer is full, must commit it to /dev/poll before
  103. * adding more
  104. */
  105. if (devpoll_commit(devpollop) != 0)
  106. return(-1);
  107. }
  108. pfd = &devpollop->changes[devpollop->nchanges++];
  109. pfd->fd = fd;
  110. pfd->events = events;
  111. pfd->revents = 0;
  112. return(0);
  113. }
  114. void *
  115. devpoll_init(void)
  116. {
  117. int dpfd, nfiles = NEVENT;
  118. struct rlimit rl;
  119. struct devpollop *devpollop;
  120. /* Disable devpoll when this environment variable is set */
  121. if (getenv("EVENT_NODEVPOLL"))
  122. return (NULL);
  123. if (!(devpollop = calloc(1, sizeof(struct devpollop))))
  124. return (NULL);
  125. if (getrlimit(RLIMIT_NOFILE, &rl) == 0 &&
  126. rl.rlim_cur != RLIM_INFINITY)
  127. nfiles = rl.rlim_cur - 1;
  128. /* Initialize the kernel queue */
  129. if ((dpfd = open("/dev/poll", O_RDWR)) == -1) {
  130. event_warn("open: /dev/poll");
  131. free(devpollop);
  132. return (NULL);
  133. }
  134. devpollop->dpfd = dpfd;
  135. /* Initialize fields */
  136. devpollop->events = calloc(nfiles, sizeof(struct pollfd));
  137. if (devpollop->events == NULL) {
  138. free(devpollop);
  139. close(dpfd);
  140. return (NULL);
  141. }
  142. devpollop->nevents = nfiles;
  143. devpollop->fds = calloc(nfiles, sizeof(struct evdevpoll));
  144. if (devpollop->fds == NULL) {
  145. free(devpollop->events);
  146. free(devpollop);
  147. close(dpfd);
  148. return (NULL);
  149. }
  150. devpollop->nfds = nfiles;
  151. devpollop->changes = calloc(nfiles, sizeof(struct pollfd));
  152. if (devpollop->changes == NULL) {
  153. free(devpollop->fds);
  154. free(devpollop->events);
  155. free(devpollop);
  156. close(dpfd);
  157. return (NULL);
  158. }
  159. evsignal_init(&devpollop->evsigmask);
  160. return (devpollop);
  161. }
  162. int
  163. devpoll_recalc(struct event_base *base, void *arg, int max)
  164. {
  165. struct devpollop *devpollop = arg;
  166. if (max > devpollop->nfds) {
  167. struct evdevpoll *fds;
  168. int nfds;
  169. nfds = devpollop->nfds;
  170. while (nfds < max)
  171. nfds <<= 1;
  172. fds = realloc(devpollop->fds, nfds * sizeof(struct evdevpoll));
  173. if (fds == NULL) {
  174. event_warn("realloc");
  175. return (-1);
  176. }
  177. devpollop->fds = fds;
  178. memset(fds + devpollop->nfds, 0,
  179. (nfds - devpollop->nfds) * sizeof(struct evdevpoll));
  180. devpollop->nfds = nfds;
  181. }
  182. return (evsignal_recalc(&devpollop->evsigmask));
  183. }
  184. int
  185. devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
  186. {
  187. struct devpollop *devpollop = arg;
  188. struct pollfd *events = devpollop->events;
  189. struct dvpoll dvp;
  190. struct evdevpoll *evdp;
  191. int i, res, timeout;
  192. if (evsignal_deliver(&devpollop->evsigmask) == -1)
  193. return (-1);
  194. if (devpollop->nchanges)
  195. devpoll_commit(devpollop);
  196. timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
  197. dvp.dp_fds = devpollop->events;
  198. dvp.dp_nfds = devpollop->nevents;
  199. dvp.dp_timeout = timeout;
  200. res = ioctl(devpollop->dpfd, DP_POLL, &dvp);
  201. if (evsignal_recalc(&devpollop->evsigmask) == -1)
  202. return (-1);
  203. if (res == -1) {
  204. if (errno != EINTR) {
  205. event_warn("ioctl: DP_POLL");
  206. return (-1);
  207. }
  208. evsignal_process();
  209. return (0);
  210. } else if (evsignal_caught)
  211. evsignal_process();
  212. event_debug(("%s: devpoll_wait reports %d", __func__, res));
  213. for (i = 0; i < res; i++) {
  214. int which = 0;
  215. int what = events[i].revents;
  216. struct event *evread = NULL, *evwrite = NULL;
  217. assert(events[i].fd < devpollop->nfds);
  218. evdp = &devpollop->fds[events[i].fd];
  219. if (what & POLLHUP)
  220. what |= POLLIN | POLLOUT;
  221. else if (what & POLLERR)
  222. what |= POLLIN | POLLOUT;
  223. if (what & POLLIN) {
  224. evread = evdp->evread;
  225. which |= EV_READ;
  226. }
  227. if (what & POLLOUT) {
  228. evwrite = evdp->evwrite;
  229. which |= EV_WRITE;
  230. }
  231. if (!which)
  232. continue;
  233. if (evread != NULL && !(evread->ev_events & EV_PERSIST))
  234. event_del(evread);
  235. if (evwrite != NULL && evwrite != evread &&
  236. !(evwrite->ev_events & EV_PERSIST))
  237. event_del(evwrite);
  238. if (evread != NULL)
  239. event_active(evread, EV_READ, 1);
  240. if (evwrite != NULL)
  241. event_active(evwrite, EV_WRITE, 1);
  242. }
  243. return (0);
  244. }
  245. int
  246. devpoll_add(void *arg, struct event *ev)
  247. {
  248. struct devpollop *devpollop = arg;
  249. struct evdevpoll *evdp;
  250. int fd, events;
  251. if (ev->ev_events & EV_SIGNAL)
  252. return (evsignal_add(&devpollop->evsigmask, ev));
  253. fd = ev->ev_fd;
  254. if (fd >= devpollop->nfds) {
  255. /* Extend the file descriptor array as necessary */
  256. if (devpoll_recalc(ev->ev_base, devpollop, fd) == -1)
  257. return (-1);
  258. }
  259. evdp = &devpollop->fds[fd];
  260. /*
  261. * It's not necessary to OR the existing read/write events that we
  262. * are currently interested in with the new event we are adding.
  263. * The /dev/poll driver ORs any new events with the existing events
  264. * that it has cached for the fd.
  265. */
  266. events = 0;
  267. if (ev->ev_events & EV_READ) {
  268. if (evdp->evread && evdp->evread != ev) {
  269. /* There is already a different read event registered */
  270. return(-1);
  271. }
  272. events |= POLLIN;
  273. }
  274. if (ev->ev_events & EV_WRITE) {
  275. if (evdp->evwrite && evdp->evwrite != ev) {
  276. /* There is already a different write event registered */
  277. return(-1);
  278. }
  279. events |= POLLOUT;
  280. }
  281. if (devpoll_queue(devpollop, fd, events) != 0)
  282. return(-1);
  283. /* Update events responsible */
  284. if (ev->ev_events & EV_READ)
  285. evdp->evread = ev;
  286. if (ev->ev_events & EV_WRITE)
  287. evdp->evwrite = ev;
  288. return (0);
  289. }
  290. int
  291. devpoll_del(void *arg, struct event *ev)
  292. {
  293. struct devpollop *devpollop = arg;
  294. struct evdevpoll *evdp;
  295. int fd, events;
  296. int needwritedelete = 1, needreaddelete = 1;
  297. if (ev->ev_events & EV_SIGNAL)
  298. return (evsignal_del(&devpollop->evsigmask, ev));
  299. fd = ev->ev_fd;
  300. if (fd >= devpollop->nfds)
  301. return (0);
  302. evdp = &devpollop->fds[fd];
  303. events = 0;
  304. if (ev->ev_events & EV_READ)
  305. events |= POLLIN;
  306. if (ev->ev_events & EV_WRITE)
  307. events |= POLLOUT;
  308. /*
  309. * The only way to remove an fd from the /dev/poll monitored set is
  310. * to use POLLREMOVE by itself. This removes ALL events for the fd
  311. * provided so if we care about two events and are only removing one
  312. * we must re-add the other event after POLLREMOVE.
  313. */
  314. if (devpoll_queue(devpollop, fd, POLLREMOVE) != 0)
  315. return(-1);
  316. if ((events & (POLLIN|POLLOUT)) != (POLLIN|POLLOUT)) {
  317. /*
  318. * We're not deleting all events, so we must resubmit the
  319. * event that we are still interested in if one exists.
  320. */
  321. if ((events & POLLIN) && evdp->evwrite != NULL) {
  322. /* Deleting read, still care about write */
  323. devpoll_queue(devpollop, fd, POLLOUT);
  324. needwritedelete = 0;
  325. } else if ((events & POLLOUT) && evdp->evread != NULL) {
  326. /* Deleting write, still care about read */
  327. devpoll_queue(devpollop, fd, POLLIN);
  328. needreaddelete = 0;
  329. }
  330. }
  331. if (needreaddelete)
  332. evdp->evread = NULL;
  333. if (needwritedelete)
  334. evdp->evwrite = NULL;
  335. return (0);
  336. }
  337. void
  338. devpoll_dealloc(void *arg)
  339. {
  340. struct devpollop *devpollop = arg;
  341. if (devpollop->fds)
  342. free(devpollop->fds);
  343. if (devpollop->events)
  344. free(devpollop->events);
  345. if (devpollop->changes)
  346. free(devpollop->changes);
  347. if (devpollop->dpfd >= 0)
  348. close(devpollop->dpfd);
  349. memset(devpollop, 0, sizeof(struct devpollop));
  350. free(devpollop);
  351. }