evport.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /*
  2. * Submitted by David Pacheco (dp.spambait@gmail.com)
  3. *
  4. * Copyright 2006-2007 Niels Provos
  5. * Copyright 2007-2012 Niels Provos and Nick Mathewson
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. The name of the author may not be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY SUN MICROSYSTEMS, INC. ``AS IS'' AND ANY
  19. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. /*
  30. * Copyright (c) 2007 Sun Microsystems. All rights reserved.
  31. * Use is subject to license terms.
  32. */
  33. /*
  34. * evport.c: event backend using Solaris 10 event ports. See port_create(3C).
  35. * This implementation is loosely modeled after the one used for select(2) (in
  36. * select.c).
  37. *
  38. * The outstanding events are tracked in a data structure called evport_data.
  39. * Each entry in the ed_fds array corresponds to a file descriptor, and contains
  40. * pointers to the read and write events that correspond to that fd. (That is,
  41. * when the file is readable, the "read" event should handle it, etc.)
  42. *
  43. * evport_add and evport_del update this data structure. evport_dispatch uses it
  44. * to determine where to callback when an event occurs (which it gets from
  45. * port_getn).
  46. *
  47. * Helper functions are used: grow() grows the file descriptor array as
  48. * necessary when large fd's come in. reassociate() takes care of maintaining
  49. * the proper file-descriptor/event-port associations.
  50. *
  51. * As in the select(2) implementation, signals are handled by evsignal.
  52. */
  53. #include "event2/event-config.h"
  54. #include "evconfig-private.h"
  55. #ifdef EVENT__HAVE_EVENT_PORTS
  56. #include <sys/time.h>
  57. #include <sys/queue.h>
  58. #include <errno.h>
  59. #include <poll.h>
  60. #include <port.h>
  61. #include <signal.h>
  62. #include <stdio.h>
  63. #include <stdlib.h>
  64. #include <string.h>
  65. #include <time.h>
  66. #include <unistd.h>
  67. #include "event2/thread.h"
  68. #include "evthread-internal.h"
  69. #include "event-internal.h"
  70. #include "log-internal.h"
  71. #include "evsignal-internal.h"
  72. #include "evmap-internal.h"
  73. #define INITIAL_EVENTS_PER_GETN 8
  74. #define MAX_EVENTS_PER_GETN 4096
  75. /*
  76. * Per-file-descriptor information about what events we're subscribed to. These
  77. * fields are NULL if no event is subscribed to either of them.
  78. */
  79. struct fd_info {
  80. /* combinations of EV_READ and EV_WRITE */
  81. short fdi_what;
  82. /* Index of this fd within ed_pending, plus 1. Zero if this fd is
  83. * not in ed_pending. (The +1 is a hack so that memset(0) will set
  84. * it to a nil index. */
  85. int pending_idx_plus_1;
  86. };
  87. #define FDI_HAS_READ(fdi) ((fdi)->fdi_what & EV_READ)
  88. #define FDI_HAS_WRITE(fdi) ((fdi)->fdi_what & EV_WRITE)
  89. #define FDI_HAS_EVENTS(fdi) (FDI_HAS_READ(fdi) || FDI_HAS_WRITE(fdi))
  90. #define FDI_TO_SYSEVENTS(fdi) (FDI_HAS_READ(fdi) ? POLLIN : 0) | \
  91. (FDI_HAS_WRITE(fdi) ? POLLOUT : 0)
  92. struct evport_data {
  93. int ed_port; /* event port for system events */
  94. /* How many elements of ed_pending should we look at? */
  95. int ed_npending;
  96. /* How many elements are allocated in ed_pending and pevtlist? */
  97. int ed_maxevents;
  98. /* fdi's that we need to reassoc */
  99. int *ed_pending;
  100. /* storage space for incoming events. */
  101. port_event_t *ed_pevtlist;
  102. };
  103. static void* evport_init(struct event_base *);
  104. static int evport_add(struct event_base *, int fd, short old, short events, void *);
  105. static int evport_del(struct event_base *, int fd, short old, short events, void *);
  106. static int evport_dispatch(struct event_base *, struct timeval *);
  107. static void evport_dealloc(struct event_base *);
  108. static int grow(struct evport_data *, int min_events);
  109. const struct eventop evportops = {
  110. "evport",
  111. evport_init,
  112. evport_add,
  113. evport_del,
  114. evport_dispatch,
  115. evport_dealloc,
  116. 1, /* need reinit */
  117. 0, /* features */
  118. sizeof(struct fd_info), /* fdinfo length */
  119. };
  120. /*
  121. * Initialize the event port implementation.
  122. */
  123. static void*
  124. evport_init(struct event_base *base)
  125. {
  126. struct evport_data *evpd;
  127. if (!(evpd = mm_calloc(1, sizeof(struct evport_data))))
  128. return (NULL);
  129. if ((evpd->ed_port = port_create()) == -1) {
  130. mm_free(evpd);
  131. return (NULL);
  132. }
  133. if (grow(evpd, INITIAL_EVENTS_PER_GETN) < 0) {
  134. close(evpd->ed_port);
  135. mm_free(evpd);
  136. return NULL;
  137. }
  138. evpd->ed_npending = 0;
  139. evsig_init_(base);
  140. return (evpd);
  141. }
  142. static int
  143. grow(struct evport_data *data, int min_events)
  144. {
  145. int newsize;
  146. int *new_pending;
  147. port_event_t *new_pevtlist;
  148. if (data->ed_maxevents) {
  149. newsize = data->ed_maxevents;
  150. do {
  151. newsize *= 2;
  152. } while (newsize < min_events);
  153. } else {
  154. newsize = min_events;
  155. }
  156. new_pending = mm_realloc(data->ed_pending, sizeof(int)*newsize);
  157. if (new_pending == NULL)
  158. return -1;
  159. data->ed_pending = new_pending;
  160. new_pevtlist = mm_realloc(data->ed_pevtlist, sizeof(port_event_t)*newsize);
  161. if (new_pevtlist == NULL)
  162. return -1;
  163. data->ed_pevtlist = new_pevtlist;
  164. data->ed_maxevents = newsize;
  165. return 0;
  166. }
  167. #ifdef CHECK_INVARIANTS
  168. /*
  169. * Checks some basic properties about the evport_data structure. Because it
  170. * checks all file descriptors, this function can be expensive when the maximum
  171. * file descriptor ever used is rather large.
  172. */
  173. static void
  174. check_evportop(struct evport_data *evpd)
  175. {
  176. EVUTIL_ASSERT(evpd);
  177. EVUTIL_ASSERT(evpd->ed_port > 0);
  178. }
  179. /*
  180. * Verifies very basic integrity of a given port_event.
  181. */
  182. static void
  183. check_event(port_event_t* pevt)
  184. {
  185. /*
  186. * We've only registered for PORT_SOURCE_FD events. The only
  187. * other thing we can legitimately receive is PORT_SOURCE_ALERT,
  188. * but since we're not using port_alert either, we can assume
  189. * PORT_SOURCE_FD.
  190. */
  191. EVUTIL_ASSERT(pevt->portev_source == PORT_SOURCE_FD);
  192. }
  193. #else
  194. #define check_evportop(epop)
  195. #define check_event(pevt)
  196. #endif /* CHECK_INVARIANTS */
  197. /*
  198. * (Re)associates the given file descriptor with the event port. The OS events
  199. * are specified (implicitly) from the fd_info struct.
  200. */
  201. static int
  202. reassociate(struct evport_data *epdp, struct fd_info *fdip, int fd)
  203. {
  204. int sysevents = FDI_TO_SYSEVENTS(fdip);
  205. if (sysevents != 0) {
  206. if (port_associate(epdp->ed_port, PORT_SOURCE_FD,
  207. fd, sysevents, fdip) == -1) {
  208. event_warn("port_associate");
  209. return (-1);
  210. }
  211. }
  212. check_evportop(epdp);
  213. return (0);
  214. }
  215. /*
  216. * Main event loop - polls port_getn for some number of events, and processes
  217. * them.
  218. */
  219. static int
  220. evport_dispatch(struct event_base *base, struct timeval *tv)
  221. {
  222. int i, res;
  223. struct evport_data *epdp = base->evbase;
  224. port_event_t *pevtlist = epdp->ed_pevtlist;
  225. /*
  226. * port_getn will block until it has at least nevents events. It will
  227. * also return how many it's given us (which may be more than we asked
  228. * for, as long as it's less than our maximum (ed_maxevents)) in
  229. * nevents.
  230. */
  231. int nevents = 1;
  232. /*
  233. * We have to convert a struct timeval to a struct timespec
  234. * (only difference is nanoseconds vs. microseconds). If no time-based
  235. * events are active, we should wait for I/O (and tv == NULL).
  236. */
  237. struct timespec ts;
  238. struct timespec *ts_p = NULL;
  239. if (tv != NULL) {
  240. ts.tv_sec = tv->tv_sec;
  241. ts.tv_nsec = tv->tv_usec * 1000;
  242. ts_p = &ts;
  243. }
  244. /*
  245. * Before doing anything else, we need to reassociate the events we hit
  246. * last time which need reassociation. See comment at the end of the
  247. * loop below.
  248. */
  249. for (i = 0; i < epdp->ed_npending; ++i) {
  250. struct fd_info *fdi = NULL;
  251. const int fd = epdp->ed_pending[i];
  252. if (fd != -1) {
  253. /* We might have cleared out this event; we need
  254. * to be sure that it's still set. */
  255. fdi = evmap_io_get_fdinfo_(&base->io, fd);
  256. }
  257. if (fdi != NULL && FDI_HAS_EVENTS(fdi)) {
  258. reassociate(epdp, fdi, fd);
  259. /* epdp->ed_pending[i] = -1; */
  260. fdi->pending_idx_plus_1 = 0;
  261. }
  262. }
  263. EVBASE_RELEASE_LOCK(base, th_base_lock);
  264. res = port_getn(epdp->ed_port, pevtlist, epdp->ed_maxevents,
  265. (unsigned int *) &nevents, ts_p);
  266. EVBASE_ACQUIRE_LOCK(base, th_base_lock);
  267. if (res == -1) {
  268. if (errno == EINTR || errno == EAGAIN) {
  269. return (0);
  270. } else if (errno == ETIME) {
  271. if (nevents == 0)
  272. return (0);
  273. } else {
  274. event_warn("port_getn");
  275. return (-1);
  276. }
  277. }
  278. event_debug(("%s: port_getn reports %d events", __func__, nevents));
  279. for (i = 0; i < nevents; ++i) {
  280. port_event_t *pevt = &pevtlist[i];
  281. int fd = (int) pevt->portev_object;
  282. struct fd_info *fdi = pevt->portev_user;
  283. /*EVUTIL_ASSERT(evmap_io_get_fdinfo_(&base->io, fd) == fdi);*/
  284. check_evportop(epdp);
  285. check_event(pevt);
  286. epdp->ed_pending[i] = fd;
  287. fdi->pending_idx_plus_1 = i + 1;
  288. /*
  289. * Figure out what kind of event it was
  290. * (because we have to pass this to the callback)
  291. */
  292. res = 0;
  293. if (pevt->portev_events & (POLLERR|POLLHUP)) {
  294. res = EV_READ | EV_WRITE;
  295. } else {
  296. if (pevt->portev_events & POLLIN)
  297. res |= EV_READ;
  298. if (pevt->portev_events & POLLOUT)
  299. res |= EV_WRITE;
  300. }
  301. /*
  302. * Check for the error situations or a hangup situation
  303. */
  304. if (pevt->portev_events & (POLLERR|POLLHUP|POLLNVAL))
  305. res |= EV_READ|EV_WRITE;
  306. evmap_io_active_(base, fd, res);
  307. } /* end of all events gotten */
  308. epdp->ed_npending = nevents;
  309. if (nevents == epdp->ed_maxevents &&
  310. epdp->ed_maxevents < MAX_EVENTS_PER_GETN) {
  311. /* we used all the space this time. We should be ready
  312. * for more events next time around. */
  313. grow(epdp, epdp->ed_maxevents * 2);
  314. }
  315. check_evportop(epdp);
  316. return (0);
  317. }
  318. /*
  319. * Adds the given event (so that you will be notified when it happens via
  320. * the callback function).
  321. */
  322. static int
  323. evport_add(struct event_base *base, int fd, short old, short events, void *p)
  324. {
  325. struct evport_data *evpd = base->evbase;
  326. struct fd_info *fdi = p;
  327. check_evportop(evpd);
  328. fdi->fdi_what |= events;
  329. return reassociate(evpd, fdi, fd);
  330. }
  331. /*
  332. * Removes the given event from the list of events to wait for.
  333. */
  334. static int
  335. evport_del(struct event_base *base, int fd, short old, short events, void *p)
  336. {
  337. struct evport_data *evpd = base->evbase;
  338. struct fd_info *fdi = p;
  339. int associated = ! fdi->pending_idx_plus_1;
  340. check_evportop(evpd);
  341. fdi->fdi_what &= ~(events &(EV_READ|EV_WRITE));
  342. if (associated) {
  343. if (!FDI_HAS_EVENTS(fdi) &&
  344. port_dissociate(evpd->ed_port, PORT_SOURCE_FD, fd) == -1) {
  345. /*
  346. * Ignore EBADFD error the fd could have been closed
  347. * before event_del() was called.
  348. */
  349. if (errno != EBADFD) {
  350. event_warn("port_dissociate");
  351. return (-1);
  352. }
  353. } else {
  354. if (FDI_HAS_EVENTS(fdi)) {
  355. return (reassociate(evpd, fdi, fd));
  356. }
  357. }
  358. } else {
  359. if ((fdi->fdi_what & (EV_READ|EV_WRITE)) == 0) {
  360. const int i = fdi->pending_idx_plus_1 - 1;
  361. EVUTIL_ASSERT(evpd->ed_pending[i] == fd);
  362. evpd->ed_pending[i] = -1;
  363. fdi->pending_idx_plus_1 = 0;
  364. }
  365. }
  366. return 0;
  367. }
  368. static void
  369. evport_dealloc(struct event_base *base)
  370. {
  371. struct evport_data *evpd = base->evbase;
  372. evsig_dealloc_(base);
  373. close(evpd->ed_port);
  374. if (evpd->ed_pending)
  375. mm_free(evpd->ed_pending);
  376. if (evpd->ed_pevtlist)
  377. mm_free(evpd->ed_pevtlist);
  378. mm_free(evpd);
  379. }
  380. #endif /* EVENT__HAVE_EVENT_PORTS */