PageRenderTime 29ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/release/src/router/dnscrypt/src/libevent-modified/evport.c

https://gitlab.com/envieidoc/tomato
C | 473 lines | 262 code | 76 blank | 135 comment | 62 complexity | dc10e9596e7536c932590c8b88fbdbe5 MD5 | raw file
  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 <sys/time.h>
  55. #include <sys/queue.h>
  56. #include <errno.h>
  57. #include <poll.h>
  58. #include <port.h>
  59. #include <signal.h>
  60. #include <stdio.h>
  61. #include <stdlib.h>
  62. #include <string.h>
  63. #include <time.h>
  64. #include <unistd.h>
  65. #include "event2/thread.h"
  66. #include "evthread-internal.h"
  67. #include "event-internal.h"
  68. #include "log-internal.h"
  69. #include "evsignal-internal.h"
  70. #include "evmap-internal.h"
  71. /*
  72. * Default value for ed_nevents, which is the maximum file descriptor number we
  73. * can handle. If an event comes in for a file descriptor F > nevents, we will
  74. * grow the array of file descriptors, doubling its size.
  75. */
  76. #define DEFAULT_NFDS 16
  77. /*
  78. * EVENTS_PER_GETN is the maximum number of events to retrieve from port_getn on
  79. * any particular call. You can speed things up by increasing this, but it will
  80. * (obviously) require more memory.
  81. */
  82. #define EVENTS_PER_GETN 8
  83. /*
  84. * Per-file-descriptor information about what events we're subscribed to. These
  85. * fields are NULL if no event is subscribed to either of them.
  86. */
  87. struct fd_info {
  88. short fdi_what; /* combinations of EV_READ and EV_WRITE */
  89. };
  90. #define FDI_HAS_READ(fdi) ((fdi)->fdi_what & EV_READ)
  91. #define FDI_HAS_WRITE(fdi) ((fdi)->fdi_what & EV_WRITE)
  92. #define FDI_HAS_EVENTS(fdi) (FDI_HAS_READ(fdi) || FDI_HAS_WRITE(fdi))
  93. #define FDI_TO_SYSEVENTS(fdi) (FDI_HAS_READ(fdi) ? POLLIN : 0) | \
  94. (FDI_HAS_WRITE(fdi) ? POLLOUT : 0)
  95. struct evport_data {
  96. int ed_port; /* event port for system events */
  97. int ed_nevents; /* number of allocated fdi's */
  98. struct fd_info *ed_fds; /* allocated fdi table */
  99. /* fdi's that we need to reassoc */
  100. int ed_pending[EVENTS_PER_GETN]; /* fd's with pending events */
  101. };
  102. static void* evport_init(struct event_base *);
  103. static int evport_add(struct event_base *, int fd, short old, short events, void *);
  104. static int evport_del(struct event_base *, int fd, short old, short events, void *);
  105. static int evport_dispatch(struct event_base *, struct timeval *);
  106. static void evport_dealloc(struct event_base *);
  107. const struct eventop evportops = {
  108. "evport",
  109. evport_init,
  110. evport_add,
  111. evport_del,
  112. evport_dispatch,
  113. evport_dealloc,
  114. 1, /* need reinit */
  115. 0, /* features */
  116. 0, /* fdinfo length */
  117. };
  118. /*
  119. * Initialize the event port implementation.
  120. */
  121. static void*
  122. evport_init(struct event_base *base)
  123. {
  124. struct evport_data *evpd;
  125. int i;
  126. if (!(evpd = mm_calloc(1, sizeof(struct evport_data))))
  127. return (NULL);
  128. if ((evpd->ed_port = port_create()) == -1) {
  129. mm_free(evpd);
  130. return (NULL);
  131. }
  132. /*
  133. * Initialize file descriptor structure
  134. */
  135. evpd->ed_fds = mm_calloc(DEFAULT_NFDS, sizeof(struct fd_info));
  136. if (evpd->ed_fds == NULL) {
  137. close(evpd->ed_port);
  138. mm_free(evpd);
  139. return (NULL);
  140. }
  141. evpd->ed_nevents = DEFAULT_NFDS;
  142. for (i = 0; i < EVENTS_PER_GETN; i++)
  143. evpd->ed_pending[i] = -1;
  144. evsig_init(base);
  145. return (evpd);
  146. }
  147. #ifdef CHECK_INVARIANTS
  148. /*
  149. * Checks some basic properties about the evport_data structure. Because it
  150. * checks all file descriptors, this function can be expensive when the maximum
  151. * file descriptor ever used is rather large.
  152. */
  153. static void
  154. check_evportop(struct evport_data *evpd)
  155. {
  156. EVUTIL_ASSERT(evpd);
  157. EVUTIL_ASSERT(evpd->ed_nevents > 0);
  158. EVUTIL_ASSERT(evpd->ed_port > 0);
  159. EVUTIL_ASSERT(evpd->ed_fds > 0);
  160. }
  161. /*
  162. * Verifies very basic integrity of a given port_event.
  163. */
  164. static void
  165. check_event(port_event_t* pevt)
  166. {
  167. /*
  168. * We've only registered for PORT_SOURCE_FD events. The only
  169. * other thing we can legitimately receive is PORT_SOURCE_ALERT,
  170. * but since we're not using port_alert either, we can assume
  171. * PORT_SOURCE_FD.
  172. */
  173. EVUTIL_ASSERT(pevt->portev_source == PORT_SOURCE_FD);
  174. EVUTIL_ASSERT(pevt->portev_user == NULL);
  175. }
  176. #else
  177. #define check_evportop(epop)
  178. #define check_event(pevt)
  179. #endif /* CHECK_INVARIANTS */
  180. /*
  181. * Doubles the size of the allocated file descriptor array.
  182. */
  183. static int
  184. grow(struct evport_data *epdp, int factor)
  185. {
  186. struct fd_info *tmp;
  187. int oldsize = epdp->ed_nevents;
  188. int newsize = factor * oldsize;
  189. EVUTIL_ASSERT(factor > 1);
  190. check_evportop(epdp);
  191. tmp = mm_realloc(epdp->ed_fds, sizeof(struct fd_info) * newsize);
  192. if (NULL == tmp)
  193. return -1;
  194. epdp->ed_fds = tmp;
  195. memset((char*) (epdp->ed_fds + oldsize), 0,
  196. (newsize - oldsize)*sizeof(struct fd_info));
  197. epdp->ed_nevents = newsize;
  198. check_evportop(epdp);
  199. return 0;
  200. }
  201. /*
  202. * (Re)associates the given file descriptor with the event port. The OS events
  203. * are specified (implicitly) from the fd_info struct.
  204. */
  205. static int
  206. reassociate(struct evport_data *epdp, struct fd_info *fdip, int fd)
  207. {
  208. int sysevents = FDI_TO_SYSEVENTS(fdip);
  209. if (sysevents != 0) {
  210. if (port_associate(epdp->ed_port, PORT_SOURCE_FD,
  211. fd, sysevents, NULL) == -1) {
  212. event_warn("port_associate");
  213. return (-1);
  214. }
  215. }
  216. check_evportop(epdp);
  217. return (0);
  218. }
  219. /*
  220. * Main event loop - polls port_getn for some number of events, and processes
  221. * them.
  222. */
  223. static int
  224. evport_dispatch(struct event_base *base, struct timeval *tv)
  225. {
  226. int i, res;
  227. struct evport_data *epdp = base->evbase;
  228. port_event_t pevtlist[EVENTS_PER_GETN];
  229. /*
  230. * port_getn will block until it has at least nevents events. It will
  231. * also return how many it's given us (which may be more than we asked
  232. * for, as long as it's less than our maximum (EVENTS_PER_GETN)) in
  233. * nevents.
  234. */
  235. int nevents = 1;
  236. /*
  237. * We have to convert a struct timeval to a struct timespec
  238. * (only difference is nanoseconds vs. microseconds). If no time-based
  239. * events are active, we should wait for I/O (and tv == NULL).
  240. */
  241. struct timespec ts;
  242. struct timespec *ts_p = NULL;
  243. if (tv != NULL) {
  244. ts.tv_sec = tv->tv_sec;
  245. ts.tv_nsec = tv->tv_usec * 1000;
  246. ts_p = &ts;
  247. }
  248. /*
  249. * Before doing anything else, we need to reassociate the events we hit
  250. * last time which need reassociation. See comment at the end of the
  251. * loop below.
  252. */
  253. for (i = 0; i < EVENTS_PER_GETN; ++i) {
  254. struct fd_info *fdi = NULL;
  255. if (epdp->ed_pending[i] != -1) {
  256. fdi = &(epdp->ed_fds[epdp->ed_pending[i]]);
  257. }
  258. if (fdi != NULL && FDI_HAS_EVENTS(fdi)) {
  259. int fd = epdp->ed_pending[i];
  260. reassociate(epdp, fdi, fd);
  261. epdp->ed_pending[i] = -1;
  262. }
  263. }
  264. EVBASE_RELEASE_LOCK(base, th_base_lock);
  265. res = port_getn(epdp->ed_port, pevtlist, EVENTS_PER_GETN,
  266. (unsigned int *) &nevents, ts_p);
  267. EVBASE_ACQUIRE_LOCK(base, th_base_lock);
  268. if (res == -1) {
  269. if (errno == EINTR || errno == EAGAIN) {
  270. return (0);
  271. } else if (errno == ETIME) {
  272. if (nevents == 0)
  273. return (0);
  274. } else {
  275. event_warn("port_getn");
  276. return (-1);
  277. }
  278. }
  279. event_debug(("%s: port_getn reports %d events", __func__, nevents));
  280. for (i = 0; i < nevents; ++i) {
  281. struct fd_info *fdi;
  282. port_event_t *pevt = &pevtlist[i];
  283. int fd = (int) pevt->portev_object;
  284. check_evportop(epdp);
  285. check_event(pevt);
  286. epdp->ed_pending[i] = fd;
  287. /*
  288. * Figure out what kind of event it was
  289. * (because we have to pass this to the callback)
  290. */
  291. res = 0;
  292. if (pevt->portev_events & (POLLERR|POLLHUP)) {
  293. res = EV_READ | EV_WRITE;
  294. } else {
  295. if (pevt->portev_events & POLLIN)
  296. res |= EV_READ;
  297. if (pevt->portev_events & POLLOUT)
  298. res |= EV_WRITE;
  299. }
  300. /*
  301. * Check for the error situations or a hangup situation
  302. */
  303. if (pevt->portev_events & (POLLERR|POLLHUP|POLLNVAL))
  304. res |= EV_READ|EV_WRITE;
  305. EVUTIL_ASSERT(epdp->ed_nevents > fd);
  306. fdi = &(epdp->ed_fds[fd]);
  307. evmap_io_active(base, fd, res);
  308. } /* end of all events gotten */
  309. check_evportop(epdp);
  310. return (0);
  311. }
  312. /*
  313. * Adds the given event (so that you will be notified when it happens via
  314. * the callback function).
  315. */
  316. static int
  317. evport_add(struct event_base *base, int fd, short old, short events, void *p)
  318. {
  319. struct evport_data *evpd = base->evbase;
  320. struct fd_info *fdi;
  321. int factor;
  322. (void)p;
  323. check_evportop(evpd);
  324. /*
  325. * If necessary, grow the file descriptor info table
  326. */
  327. factor = 1;
  328. while (fd >= factor * evpd->ed_nevents)
  329. factor *= 2;
  330. if (factor > 1) {
  331. if (-1 == grow(evpd, factor)) {
  332. return (-1);
  333. }
  334. }
  335. fdi = &evpd->ed_fds[fd];
  336. fdi->fdi_what |= events;
  337. return reassociate(evpd, fdi, fd);
  338. }
  339. /*
  340. * Removes the given event from the list of events to wait for.
  341. */
  342. static int
  343. evport_del(struct event_base *base, int fd, short old, short events, void *p)
  344. {
  345. struct evport_data *evpd = base->evbase;
  346. struct fd_info *fdi;
  347. int i;
  348. int associated = 1;
  349. (void)p;
  350. check_evportop(evpd);
  351. if (evpd->ed_nevents < fd) {
  352. return (-1);
  353. }
  354. for (i = 0; i < EVENTS_PER_GETN; ++i) {
  355. if (evpd->ed_pending[i] == fd) {
  356. associated = 0;
  357. break;
  358. }
  359. }
  360. fdi = &evpd->ed_fds[fd];
  361. if (events & EV_READ)
  362. fdi->fdi_what &= ~EV_READ;
  363. if (events & EV_WRITE)
  364. fdi->fdi_what &= ~EV_WRITE;
  365. if (associated) {
  366. if (!FDI_HAS_EVENTS(fdi) &&
  367. port_dissociate(evpd->ed_port, PORT_SOURCE_FD, fd) == -1) {
  368. /*
  369. * Ignore EBADFD error the fd could have been closed
  370. * before event_del() was called.
  371. */
  372. if (errno != EBADFD) {
  373. event_warn("port_dissociate");
  374. return (-1);
  375. }
  376. } else {
  377. if (FDI_HAS_EVENTS(fdi)) {
  378. return (reassociate(evpd, fdi, fd));
  379. }
  380. }
  381. } else {
  382. if ((fdi->fdi_what & (EV_READ|EV_WRITE)) == 0) {
  383. evpd->ed_pending[i] = -1;
  384. }
  385. }
  386. return 0;
  387. }
  388. static void
  389. evport_dealloc(struct event_base *base)
  390. {
  391. struct evport_data *evpd = base->evbase;
  392. evsig_dealloc(base);
  393. close(evpd->ed_port);
  394. if (evpd->ed_fds)
  395. mm_free(evpd->ed_fds);
  396. mm_free(evpd);
  397. }