A clone of btpd with my configuration changes.
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

evport.c 13 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /*
  2. * Submitted by David Pacheco (dp.spambait@gmail.com)
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * 3. The name of the author may not be used to endorse or promote products
  13. * derived from this software without specific prior written permission.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  16. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  19. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. /*
  27. * Copyright (c) 2006 Sun Microsystems. All rights reserved.
  28. * Use is subject to license terms.
  29. */
  30. /*
  31. * evport.c: event backend using Solaris 10 event ports. See port_create(3C).
  32. * This implementation is loosely modeled after the one used for select(2) (in
  33. * select.c).
  34. *
  35. * The outstanding events are tracked in a data structure called evport_data.
  36. * Each entry in the ed_fds array corresponds to a file descriptor, and contains
  37. * pointers to the read and write events that correspond to that fd. (That is,
  38. * when the file is readable, the "read" event should handle it, etc.)
  39. *
  40. * evport_add and evport_del update this data structure. evport_dispatch uses it
  41. * to determine where to callback when an event occurs (which it gets from
  42. * port_getn).
  43. *
  44. * Helper functions are used: grow() grows the file descriptor array as
  45. * necessary when large fd's come in. reassociate() takes care of maintaining
  46. * the proper file-descriptor/event-port associations.
  47. *
  48. * As in the select(2) implementation, signals are handled by evsignal, and
  49. * evport_recalc does almost nothing.
  50. */
  51. #ifdef HAVE_CONFIG_H
  52. #include "config.h"
  53. #endif
  54. #ifdef HAVE_SYS_TIME_H
  55. #include <sys/time.h>
  56. #else
  57. #include <sys/_time.h>
  58. #endif
  59. #include <assert.h>
  60. #include <sys/queue.h>
  61. #include <sys/tree.h>
  62. #include <errno.h>
  63. #include <poll.h>
  64. #include <port.h>
  65. #include <signal.h>
  66. #include <stdio.h>
  67. #include <stdlib.h>
  68. #include <string.h>
  69. #include <time.h>
  70. #include <unistd.h>
  71. #ifdef CHECK_INVARIANTS
  72. #include <assert.h>
  73. #endif
  74. #include "event.h"
  75. #include "event-internal.h"
  76. #include "log.h"
  77. #include "evsignal.h"
  78. extern volatile sig_atomic_t evsignal_caught;
  79. /*
  80. * Default value for ed_nevents, which is the maximum file descriptor number we
  81. * can handle. If an event comes in for a file descriptor F > nevents, we will
  82. * grow the array of file descriptors, doubling its size.
  83. */
  84. #define DEFAULT_NFDS 16
  85. /*
  86. * EVENTS_PER_GETN is the maximum number of events to retrieve from port_getn on
  87. * any particular call. You can speed things up by increasing this, but it will
  88. * (obviously) require more memory.
  89. */
  90. #define EVENTS_PER_GETN 8
  91. /*
  92. * Per-file-descriptor information about what events we're subscribed to. These
  93. * fields are NULL if no event is subscribed to either of them.
  94. */
  95. struct fd_info {
  96. struct event* fdi_revt; /* the event responsible for the "read" */
  97. struct event* fdi_wevt; /* the event responsible for the "write" */
  98. };
  99. #define FDI_HAS_READ(fdi) ((fdi)->fdi_revt != NULL)
  100. #define FDI_HAS_WRITE(fdi) ((fdi)->fdi_wevt != NULL)
  101. #define FDI_HAS_EVENTS(fdi) (FDI_HAS_READ(fdi) || FDI_HAS_WRITE(fdi))
  102. #define FDI_TO_SYSEVENTS(fdi) (FDI_HAS_READ(fdi) ? POLLIN : 0) | \
  103. (FDI_HAS_WRITE(fdi) ? POLLOUT : 0)
  104. struct evport_data {
  105. int ed_port; /* event port for system events */
  106. sigset_t ed_sigmask; /* for evsignal */
  107. int ed_nevents; /* number of allocated fdi's */
  108. struct fd_info *ed_fds; /* allocated fdi table */
  109. /* fdi's that we need to reassoc */
  110. struct fd_info *ed_pending[EVENTS_PER_GETN];
  111. };
  112. static void* evport_init (void);
  113. static int evport_add (void *, struct event *);
  114. static int evport_del (void *, struct event *);
  115. static int evport_recalc (struct event_base *, void *, int);
  116. static int evport_dispatch (struct event_base *, void *, struct timeval *);
  117. const struct eventop evportops = {
  118. "event ports",
  119. evport_init,
  120. evport_add,
  121. evport_del,
  122. evport_recalc,
  123. evport_dispatch
  124. };
  125. /*
  126. * Initialize the event port implementation.
  127. */
  128. static void*
  129. evport_init(void)
  130. {
  131. struct evport_data *evpd;
  132. /*
  133. * Disable event ports when this environment variable is set
  134. */
  135. if (getenv("EVENT_NOEVPORT"))
  136. return (NULL);
  137. if (!(evpd = calloc(1, sizeof(struct evport_data))))
  138. return (NULL);
  139. if ((evpd->ed_port = port_create()) == -1) {
  140. free(evpd);
  141. return (NULL);
  142. }
  143. /*
  144. * Initialize file descriptor structure
  145. */
  146. evpd->ed_fds = calloc(DEFAULT_NFDS, sizeof(struct fd_info));
  147. if (evpd->ed_fds == NULL) {
  148. close(evpd->ed_port);
  149. free(evpd);
  150. return (NULL);
  151. }
  152. evpd->ed_nevents = DEFAULT_NFDS;
  153. memset(&evpd->ed_pending, 0, EVENTS_PER_GETN * sizeof(struct fd_info*));
  154. evsignal_init(&evpd->ed_sigmask);
  155. return (evpd);
  156. }
  157. #ifdef CHECK_INVARIANTS
  158. /*
  159. * Checks some basic properties about the evport_data structure. Because it
  160. * checks all file descriptors, this function can be expensive when the maximum
  161. * file descriptor ever used is rather large.
  162. */
  163. static void
  164. check_evportop(struct evport_data *evpd)
  165. {
  166. assert(evpd);
  167. assert(evpd->ed_nevents > 0);
  168. assert(evpd->ed_port > 0);
  169. assert(evpd->ed_fds > 0);
  170. /*
  171. * Verify the integrity of the fd_info struct as well as the events to
  172. * which it points (at least, that they're valid references and correct
  173. * for their position in the structure).
  174. */
  175. int i;
  176. for (i = 0; i < evpd->ed_nevents; ++i) {
  177. struct event *ev;
  178. struct fd_info *fdi;
  179. fdi = &evpd->ed_fds[i];
  180. if ((ev = fdi->fdi_revt) != NULL) {
  181. assert(ev->ev_fd == i);
  182. }
  183. if ((ev = fdi->fdi_wevt) != NULL) {
  184. assert(ev->ev_fd == i);
  185. }
  186. }
  187. }
  188. /*
  189. * Verifies very basic integrity of a given port_event.
  190. */
  191. static void
  192. check_event(port_event_t* pevt)
  193. {
  194. /*
  195. * We've only registered for PORT_SOURCE_FD events. The only
  196. * other thing we can legitimately receive is PORT_SOURCE_ALERT,
  197. * but since we're not using port_alert either, we can assume
  198. * PORT_SOURCE_FD.
  199. */
  200. assert(pevt->portev_source == PORT_SOURCE_FD);
  201. assert(pevt->portev_user == NULL);
  202. }
  203. #else
  204. #define check_evportop(epop)
  205. #define check_event(pevt)
  206. #endif /* CHECK_INVARIANTS */
  207. /*
  208. * Doubles the size of the allocated file descriptor array.
  209. */
  210. static int
  211. grow(struct evport_data *epdp, int factor)
  212. {
  213. struct fd_info *tmp;
  214. int oldsize = epdp->ed_nevents;
  215. int newsize = factor * oldsize;
  216. assert(factor > 1);
  217. check_evportop(epdp);
  218. tmp = realloc(epdp->ed_fds, sizeof(struct fd_info) * newsize);
  219. if (NULL == tmp)
  220. return -1;
  221. epdp->ed_fds = tmp;
  222. memset((char*) (epdp->ed_fds + oldsize), 0,
  223. (newsize - oldsize)*sizeof(struct fd_info));
  224. epdp->ed_nevents = newsize;
  225. check_evportop(epdp);
  226. return 0;
  227. }
  228. /*
  229. * (Re)associates the given file descriptor with the event port. The OS events
  230. * are specified (implicitly) from the fd_info struct.
  231. */
  232. static int
  233. reassociate(struct evport_data *epdp, struct fd_info *fdip, int fd)
  234. {
  235. int sysevents = FDI_TO_SYSEVENTS(fdip);
  236. if (sysevents != 0) {
  237. if ((-1 == port_associate(epdp->ed_port, PORT_SOURCE_FD,
  238. fd, sysevents, NULL))) {
  239. perror("port_associate");
  240. return (-1);
  241. }
  242. } else {
  243. if (-1 == port_dissociate(epdp->ed_port, PORT_SOURCE_FD, fd)) {
  244. perror("port_dissociate");
  245. return (-1);
  246. }
  247. }
  248. check_evportop(epdp);
  249. return (0);
  250. }
  251. /*
  252. * Main event loop - polls port_getn for some number of events, and processes
  253. * them.
  254. */
  255. static int
  256. evport_dispatch(struct event_base *base, void *arg, struct timeval *tv)
  257. {
  258. int i, res;
  259. struct evport_data *epdp = arg;
  260. port_event_t pevtlist[EVENTS_PER_GETN];
  261. /*
  262. * port_getn will block until it has at least nevents events. It will
  263. * also return how many it's given us (which may be more than we asked
  264. * for, as long as it's less than our maximum (EVENTS_PER_GETN)) in
  265. * nevents.
  266. */
  267. int nevents = 1;
  268. /*
  269. * We have to convert a struct timeval to a struct timespec
  270. * (only difference is nanoseconds vs. microseconds)
  271. */
  272. struct timespec ts = {tv->tv_sec, tv->tv_usec * 1000};
  273. /*
  274. * Before doing anything else, we need to reassociate the events we hit
  275. * last time which need reassociation. See comment at the end of the
  276. * loop below.
  277. */
  278. for (i = 0; i < EVENTS_PER_GETN; ++i) {
  279. struct fd_info *fdi = epdp->ed_pending[i];
  280. if (fdi != NULL && FDI_HAS_EVENTS(fdi)) {
  281. int fd = FDI_HAS_READ(fdi) ? fdi->fdi_revt->ev_fd :
  282. fdi->fdi_wevt->ev_fd;
  283. reassociate(epdp, fdi, fd);
  284. epdp->ed_pending[i] = NULL;
  285. }
  286. }
  287. if (evsignal_deliver(&epdp->ed_sigmask) == -1)
  288. return (-1);
  289. if ((res = port_getn(epdp->ed_port, pevtlist, EVENTS_PER_GETN,
  290. &nevents, &ts)) == -1) {
  291. if (errno == EINTR) {
  292. evsignal_process();
  293. return (0);
  294. } else if (errno == ETIME) {
  295. if (nevents == 0)
  296. return (0);
  297. } else {
  298. perror("port_getn");
  299. return (-1);
  300. }
  301. } else if (evsignal_caught) {
  302. evsignal_process();
  303. }
  304. event_debug(("%s: port_getn reports %d events", __func__, nevents));
  305. for (i = 0; i < nevents; ++i) {
  306. struct event *ev;
  307. struct fd_info *fdi;
  308. port_event_t *pevt = &pevtlist[i];
  309. int fd = (int) pevt->portev_object;
  310. check_evportop(epdp);
  311. check_event(pevt);
  312. /*
  313. * Figure out what kind of event it was
  314. * (because we have to pass this to the callback)
  315. */
  316. res = 0;
  317. if (pevt->portev_events & POLLIN)
  318. res |= EV_READ;
  319. if (pevt->portev_events & POLLOUT)
  320. res |= EV_WRITE;
  321. assert(epdp->ed_nevents > fd);
  322. fdi = &(epdp->ed_fds[fd]);
  323. /*
  324. * We now check for each of the possible events (READ or WRITE).
  325. * If the event is not persistent, then we delete it. Then, we
  326. * activate the event (which will cause its callback to be
  327. * executed).
  328. */
  329. if ((res & EV_READ) && ((ev = fdi->fdi_revt) != NULL)) {
  330. if (!(ev->ev_events & EV_PERSIST))
  331. event_del(ev);
  332. event_active(ev, res, 1);
  333. }
  334. if ((res & EV_WRITE) && ((ev = fdi->fdi_wevt) != NULL)) {
  335. if (!(ev->ev_events & EV_PERSIST))
  336. event_del(ev);
  337. event_active(ev, res, 1);
  338. }
  339. /*
  340. * If there are still events (they haven't been deleted), then
  341. * we must reassociate the port, since the event port interface
  342. * dissociates them automatically.
  343. *
  344. * But we can't do it right away, because the event hasn't
  345. * handled this event yet, so of course there's still data
  346. * waiting!
  347. */
  348. if(FDI_HAS_EVENTS(fdi)) {
  349. epdp->ed_pending[i] = fdi;
  350. }
  351. } /* end of all events gotten */
  352. check_evportop(epdp);
  353. if (evsignal_recalc(&epdp->ed_sigmask) == -1)
  354. return (-1);
  355. return (0);
  356. }
  357. /*
  358. * Copied from the version in select.c
  359. */
  360. static int
  361. evport_recalc(struct event_base *base, void *arg, int max)
  362. {
  363. struct evport_data *evpd = arg;
  364. check_evportop(evpd);
  365. return (evsignal_recalc(&evpd->ed_sigmask));
  366. }
  367. /*
  368. * Adds the given event (so that you will be notified when it happens via
  369. * the callback function).
  370. */
  371. static int
  372. evport_add(void *arg, struct event *ev)
  373. {
  374. struct evport_data *evpd = arg;
  375. struct fd_info *fdi;
  376. int factor;
  377. check_evportop(evpd);
  378. /*
  379. * Delegate, if it's not ours to handle.
  380. */
  381. if (ev->ev_events & EV_SIGNAL)
  382. return (evsignal_add(&evpd->ed_sigmask, ev));
  383. /*
  384. * If necessary, grow the file descriptor info table
  385. */
  386. factor = 1;
  387. while (ev->ev_fd >= factor * evpd->ed_nevents)
  388. factor *= 2;
  389. if (factor > 1) {
  390. if (-1 == grow(evpd, factor)) {
  391. return (-1);
  392. }
  393. }
  394. fdi = &evpd->ed_fds[ev->ev_fd];
  395. if (ev->ev_events & EV_READ)
  396. fdi->fdi_revt = ev;
  397. if (ev->ev_events & EV_WRITE)
  398. fdi->fdi_wevt = ev;
  399. return reassociate(evpd, fdi, ev->ev_fd);
  400. }
  401. /*
  402. * Removes the given event from the list of events to wait for.
  403. */
  404. static int
  405. evport_del(void *arg, struct event *ev)
  406. {
  407. struct evport_data *evpd = arg;
  408. struct fd_info *fdi;
  409. check_evportop(evpd);
  410. /*
  411. * Delegate, if it's not ours to handle
  412. */
  413. if (ev->ev_events & EV_SIGNAL) {
  414. return (evsignal_del(&evpd->ed_sigmask, ev));
  415. }
  416. if (evpd->ed_nevents < ev->ev_fd) {
  417. return (-1);
  418. }
  419. fdi = &evpd->ed_fds[ev->ev_fd];
  420. if (ev->ev_events & EV_READ)
  421. fdi->fdi_revt = NULL;
  422. if (ev->ev_events & EV_WRITE)
  423. fdi->fdi_wevt = NULL;
  424. return reassociate(evpd, fdi, ev->ev_fd);
  425. }