BReactor.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026
  1. /**
  2. * @file BReactor.c
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * This file is part of BadVPN.
  8. *
  9. * BadVPN is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2
  11. * as published by the Free Software Foundation.
  12. *
  13. * BadVPN is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. */
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <stdio.h>
  25. #include <stddef.h>
  26. #ifdef BADVPN_USE_WINAPI
  27. #include <windows.h>
  28. #else
  29. #include <limits.h>
  30. #include <sys/types.h>
  31. #include <errno.h>
  32. #include <unistd.h>
  33. #endif
  34. #include <misc/debug.h>
  35. #include <misc/offset.h>
  36. #include <system/BLog.h>
  37. #include <system/BReactor.h>
  38. #include <generated/blog_channel_BReactor.h>
  39. #define KEVENT_TAG_FD 1
  40. #define KEVENT_TAG_KEVENT 2
  41. static int timer_comparator (void *user, btime_t *val1, btime_t *val2)
  42. {
  43. if (*val1 < *val2) {
  44. return -1;
  45. }
  46. if (*val1 > *val2) {
  47. return 1;
  48. }
  49. return 0;
  50. }
  51. static int move_expired_timers (BReactor *bsys, btime_t now)
  52. {
  53. int moved = 0;
  54. // move timed out timers to the expired list
  55. BHeapNode *heap_node;
  56. while (heap_node = BHeap_GetFirst(&bsys->timers_heap)) {
  57. BTimer *timer = UPPER_OBJECT(heap_node, BTimer, heap_node);
  58. ASSERT(timer->active)
  59. // if it's in the future, stop
  60. if (timer->absTime > now) {
  61. break;
  62. }
  63. moved = 1;
  64. // remove from running timers heap
  65. BHeap_Remove(&bsys->timers_heap, &timer->heap_node);
  66. // add to expired timers list
  67. LinkedList1_Append(&bsys->timers_expired_list, &timer->list_node);
  68. // set expired
  69. timer->expired = 1;
  70. }
  71. return moved;
  72. }
  73. static void move_first_timers (BReactor *bsys)
  74. {
  75. // get the time of the first timer
  76. BHeapNode *heap_node = BHeap_GetFirst(&bsys->timers_heap);
  77. ASSERT(heap_node)
  78. BTimer *first_timer = UPPER_OBJECT(heap_node, BTimer, heap_node);
  79. ASSERT(first_timer->active)
  80. btime_t first_time = first_timer->absTime;
  81. // remove from running timers heap
  82. BHeap_Remove(&bsys->timers_heap, &first_timer->heap_node);
  83. // add to expired timers list
  84. LinkedList1_Append(&bsys->timers_expired_list, &first_timer->list_node);
  85. // set expired
  86. first_timer->expired = 1;
  87. // also move other timers with the same timeout
  88. while (heap_node = BHeap_GetFirst(&bsys->timers_heap)) {
  89. BTimer *timer = UPPER_OBJECT(heap_node, BTimer, heap_node);
  90. ASSERT(timer->active)
  91. ASSERT(timer->absTime >= first_time)
  92. // if it's in the future, stop
  93. if (timer->absTime > first_time) {
  94. break;
  95. }
  96. // remove from running timers heap
  97. BHeap_Remove(&bsys->timers_heap, &timer->heap_node);
  98. // add to expired timers list
  99. LinkedList1_Append(&bsys->timers_expired_list, &timer->list_node);
  100. // set expired
  101. timer->expired = 1;
  102. }
  103. }
  104. #ifdef BADVPN_USE_EPOLL
  105. static void set_epoll_fd_pointers (BReactor *bsys)
  106. {
  107. // Write pointers to our entry pointers into file descriptors.
  108. // If a handler function frees some other file descriptor, the
  109. // free routine will set our pointer to NULL so we don't dispatch it.
  110. for (int i = 0; i < bsys->epoll_results_num; i++) {
  111. struct epoll_event *event = &bsys->epoll_results[i];
  112. ASSERT(event->data.ptr)
  113. BFileDescriptor *bfd = (BFileDescriptor *)event->data.ptr;
  114. ASSERT(bfd->active)
  115. ASSERT(!bfd->epoll_returned_ptr)
  116. bfd->epoll_returned_ptr = (BFileDescriptor **)&event->data.ptr;
  117. }
  118. }
  119. #endif
  120. #ifdef BADVPN_USE_KEVENT
  121. static void set_kevent_fd_pointers (BReactor *bsys)
  122. {
  123. for (int i = 0; i < bsys->kevent_results_num; i++) {
  124. struct kevent *event = &bsys->kevent_results[i];
  125. ASSERT(event->udata)
  126. int *tag = event->udata;
  127. switch (*tag) {
  128. case KEVENT_TAG_FD: {
  129. BFileDescriptor *bfd = UPPER_OBJECT(tag, BFileDescriptor, kevent_tag);
  130. ASSERT(bfd->active)
  131. ASSERT(!bfd->kevent_returned_ptr)
  132. bfd->kevent_returned_ptr = (int **)&event->udata;
  133. } break;
  134. case KEVENT_TAG_KEVENT: {
  135. BReactorKEvent *kev = UPPER_OBJECT(tag, BReactorKEvent, kevent_tag);
  136. ASSERT(kev->reactor == bsys)
  137. ASSERT(!kev->kevent_returned_ptr)
  138. kev->kevent_returned_ptr = (int **)&event->udata;
  139. } break;
  140. default:
  141. ASSERT(0);
  142. }
  143. }
  144. }
  145. static void update_kevent_fd_events (BReactor *bsys, BFileDescriptor *bs, int events)
  146. {
  147. struct kevent event;
  148. if (!(bs->waitEvents & BREACTOR_READ) && (events & BREACTOR_READ)) {
  149. memset(&event, 0, sizeof(event));
  150. event.ident = bs->fd;
  151. event.filter = EVFILT_READ;
  152. event.flags = EV_ADD;
  153. event.udata = &bs->kevent_tag;
  154. ASSERT_FORCE(kevent(bsys->kqueue_fd, &event, 1, NULL, 0, NULL) == 0)
  155. }
  156. else if ((bs->waitEvents & BREACTOR_READ) && !(events & BREACTOR_READ)) {
  157. memset(&event, 0, sizeof(event));
  158. event.ident = bs->fd;
  159. event.filter = EVFILT_READ;
  160. event.flags = EV_DELETE;
  161. ASSERT_FORCE(kevent(bsys->kqueue_fd, &event, 1, NULL, 0, NULL) == 0)
  162. }
  163. if (!(bs->waitEvents & BREACTOR_WRITE) && (events & BREACTOR_WRITE)) {
  164. memset(&event, 0, sizeof(event));
  165. event.ident = bs->fd;
  166. event.filter = EVFILT_WRITE;
  167. event.flags = EV_ADD;
  168. event.udata = &bs->kevent_tag;
  169. ASSERT_FORCE(kevent(bsys->kqueue_fd, &event, 1, NULL, 0, NULL) == 0)
  170. }
  171. else if ((bs->waitEvents & BREACTOR_WRITE) && !(events & BREACTOR_WRITE)) {
  172. memset(&event, 0, sizeof(event));
  173. event.ident = bs->fd;
  174. event.filter = EVFILT_WRITE;
  175. event.flags = EV_DELETE;
  176. ASSERT_FORCE(kevent(bsys->kqueue_fd, &event, 1, NULL, 0, NULL) == 0)
  177. }
  178. }
  179. #endif
  180. static void wait_for_events (BReactor *bsys)
  181. {
  182. // must have processed all pending events
  183. ASSERT(!BPendingGroup_HasJobs(&bsys->pending_jobs))
  184. ASSERT(LinkedList1_IsEmpty(&bsys->timers_expired_list))
  185. #ifdef BADVPN_USE_WINAPI
  186. ASSERT(!bsys->returned_object)
  187. #endif
  188. #ifdef BADVPN_USE_EPOLL
  189. ASSERT(bsys->epoll_results_pos == bsys->epoll_results_num)
  190. #endif
  191. #ifdef BADVPN_USE_KEVENT
  192. ASSERT(bsys->kevent_results_pos == bsys->kevent_results_num)
  193. #endif
  194. // clean up epoll results
  195. #ifdef BADVPN_USE_EPOLL
  196. bsys->epoll_results_num = 0;
  197. bsys->epoll_results_pos = 0;
  198. #endif
  199. // clean up kevent results
  200. #ifdef BADVPN_USE_KEVENT
  201. bsys->kevent_results_num = 0;
  202. bsys->kevent_results_pos = 0;
  203. #endif
  204. // timeout vars
  205. int have_timeout = 0;
  206. btime_t timeout_abs;
  207. btime_t now;
  208. // compute timeout
  209. BHeapNode *first_node;
  210. if (first_node = BHeap_GetFirst(&bsys->timers_heap)) {
  211. // get current time
  212. now = btime_gettime();
  213. // if some timers have already timed out, return them immediately
  214. if (move_expired_timers(bsys, now)) {
  215. BLog(BLOG_DEBUG, "Got already expired timers");
  216. return;
  217. }
  218. // timeout is first timer, remember absolute time
  219. BTimer *first_timer = UPPER_OBJECT(first_node, BTimer, heap_node);
  220. have_timeout = 1;
  221. timeout_abs = first_timer->absTime;
  222. }
  223. // wait until the timeout is reached or the file descriptor / handle in ready
  224. while (1) {
  225. // compute timeout
  226. btime_t timeout_rel;
  227. btime_t timeout_rel_trunc;
  228. if (have_timeout) {
  229. timeout_rel = timeout_abs - now;
  230. timeout_rel_trunc = timeout_rel;
  231. }
  232. // perform wait
  233. #ifdef BADVPN_USE_WINAPI
  234. if (have_timeout) {
  235. if (timeout_rel_trunc > INFINITE - 1) {
  236. timeout_rel_trunc = INFINITE - 1;
  237. }
  238. }
  239. BLog(BLOG_DEBUG, "Calling WaitForMultipleObjects on %d handles", bsys->enabled_num);
  240. DWORD waitres = WaitForMultipleObjects(bsys->enabled_num, bsys->enabled_handles, FALSE, (have_timeout ? timeout_rel_trunc : INFINITE));
  241. ASSERT_FORCE(waitres != WAIT_FAILED)
  242. ASSERT_FORCE(!(waitres == WAIT_TIMEOUT) || have_timeout)
  243. ASSERT_FORCE(!(waitres != WAIT_TIMEOUT) || (waitres >= WAIT_OBJECT_0 && waitres < WAIT_OBJECT_0 + bsys->enabled_num))
  244. if (waitres != WAIT_TIMEOUT || timeout_rel_trunc == timeout_rel) {
  245. if (waitres != WAIT_TIMEOUT) {
  246. int handle_index = waitres - WAIT_OBJECT_0;
  247. BLog(BLOG_DEBUG, "WaitForMultipleObjects returned handle %d", handle_index);
  248. bsys->returned_object = bsys->enabled_objects[handle_index];
  249. } else {
  250. BLog(BLOG_DEBUG, "WaitForMultipleObjects timed out");
  251. move_first_timers(bsys);
  252. }
  253. break;
  254. }
  255. #endif
  256. #ifdef BADVPN_USE_EPOLL
  257. if (have_timeout) {
  258. if (timeout_rel_trunc > INT_MAX) {
  259. timeout_rel_trunc = INT_MAX;
  260. }
  261. }
  262. BLog(BLOG_DEBUG, "Calling epoll_wait");
  263. int waitres = epoll_wait(bsys->efd, bsys->epoll_results, BSYSTEM_MAX_RESULTS, (have_timeout ? timeout_rel_trunc : -1));
  264. if (waitres < 0) {
  265. int error = errno;
  266. if (error == EINTR) {
  267. BLog(BLOG_DEBUG, "epoll_wait interrupted");
  268. goto try_again;
  269. }
  270. perror("epoll_wait");
  271. ASSERT_FORCE(0)
  272. }
  273. ASSERT_FORCE(!(waitres == 0) || have_timeout)
  274. ASSERT_FORCE(waitres <= BSYSTEM_MAX_RESULTS)
  275. if (waitres != 0 || timeout_rel_trunc == timeout_rel) {
  276. if (waitres != 0) {
  277. BLog(BLOG_DEBUG, "epoll_wait returned %d file descriptors", waitres);
  278. bsys->epoll_results_num = waitres;
  279. set_epoll_fd_pointers(bsys);
  280. } else {
  281. BLog(BLOG_DEBUG, "epoll_wait timed out");
  282. move_first_timers(bsys);
  283. }
  284. break;
  285. }
  286. #endif
  287. #ifdef BADVPN_USE_KEVENT
  288. struct timespec ts;
  289. if (have_timeout) {
  290. if (timeout_rel_trunc > 86400000) {
  291. timeout_rel_trunc = 86400000;
  292. }
  293. ts.tv_sec = timeout_rel_trunc / 1000;
  294. ts.tv_nsec = (timeout_rel_trunc % 1000) * 1000000;
  295. }
  296. BLog(BLOG_DEBUG, "Calling kevent");
  297. int waitres = kevent(bsys->kqueue_fd, NULL, 0, bsys->kevent_results, BSYSTEM_MAX_RESULTS, (have_timeout ? &ts : NULL));
  298. if (waitres < 0) {
  299. int error = errno;
  300. if (error == EINTR) {
  301. BLog(BLOG_DEBUG, "kevent interrupted");
  302. goto try_again;
  303. }
  304. perror("kevent");
  305. ASSERT_FORCE(0)
  306. }
  307. ASSERT_FORCE(!(waitres == 0) || have_timeout)
  308. ASSERT_FORCE(waitres <= BSYSTEM_MAX_RESULTS)
  309. if (waitres != 0 || timeout_rel_trunc == timeout_rel) {
  310. if (waitres != 0) {
  311. BLog(BLOG_DEBUG, "kevent returned %d events", waitres);
  312. bsys->kevent_results_num = waitres;
  313. set_kevent_fd_pointers(bsys);
  314. } else {
  315. BLog(BLOG_DEBUG, "kevent timed out");
  316. move_first_timers(bsys);
  317. }
  318. break;
  319. }
  320. #endif
  321. try_again:
  322. if (have_timeout) {
  323. // get current time
  324. now = btime_gettime();
  325. // check if we already reached the time we're waiting for
  326. if (now >= timeout_abs) {
  327. BLog(BLOG_DEBUG, "already timed out while trying again");
  328. move_first_timers(bsys);
  329. break;
  330. }
  331. }
  332. }
  333. }
  334. #ifdef BADVPN_USE_WINAPI
  335. void BHandle_Init (BHandle *bh, HANDLE handle, BHandle_handler handler, void *user)
  336. {
  337. bh->h = handle;
  338. bh->handler = handler;
  339. bh->user = user;
  340. bh->active = 0;
  341. }
  342. #else
  343. void BFileDescriptor_Init (BFileDescriptor *bs, int fd, BFileDescriptor_handler handler, void *user)
  344. {
  345. bs->fd = fd;
  346. bs->handler = handler;
  347. bs->user = user;
  348. bs->active = 0;
  349. }
  350. #endif
  351. void BTimer_Init (BTimer *bt, btime_t msTime, BTimer_handler handler, void *handler_pointer)
  352. {
  353. bt->msTime = msTime;
  354. bt->handler = handler;
  355. bt->handler_pointer = handler_pointer;
  356. bt->active = 0;
  357. }
  358. int BTimer_IsRunning (BTimer *bt)
  359. {
  360. ASSERT(bt->active == 0 || bt->active == 1)
  361. return bt->active;
  362. }
  363. int BReactor_Init (BReactor *bsys)
  364. {
  365. BLog(BLOG_DEBUG, "Reactor initializing");
  366. bsys->exiting = 0;
  367. // init jobs
  368. BPendingGroup_Init(&bsys->pending_jobs);
  369. // init timers
  370. BHeap_Init(&bsys->timers_heap, OFFSET_DIFF(BTimer, absTime, heap_node), (BHeap_comparator)timer_comparator, NULL);
  371. LinkedList1_Init(&bsys->timers_expired_list);
  372. #ifdef BADVPN_USE_WINAPI
  373. bsys->num_handles = 0;
  374. bsys->enabled_num = 0;
  375. bsys->returned_object = NULL;
  376. #endif
  377. #ifdef BADVPN_USE_EPOLL
  378. // create epoll fd
  379. if ((bsys->efd = epoll_create(10)) < 0) {
  380. BLog(BLOG_ERROR, "epoll_create failed");
  381. goto fail0;
  382. }
  383. // init results array
  384. bsys->epoll_results_num = 0;
  385. bsys->epoll_results_pos = 0;
  386. #endif
  387. #ifdef BADVPN_USE_KEVENT
  388. // create kqueue fd
  389. if ((bsys->kqueue_fd = kqueue()) < 0) {
  390. BLog(BLOG_ERROR, "kqueue failed");
  391. goto fail0;
  392. }
  393. // init results array
  394. bsys->kevent_results_num = 0;
  395. bsys->kevent_results_pos = 0;
  396. #endif
  397. DebugObject_Init(&bsys->d_obj);
  398. #ifndef BADVPN_USE_WINAPI
  399. DebugCounter_Init(&bsys->d_fds_counter);
  400. #endif
  401. #ifdef BADVPN_USE_KEVENT
  402. DebugCounter_Init(&bsys->d_kevent_ctr);
  403. #endif
  404. return 1;
  405. fail0:
  406. BPendingGroup_Free(&bsys->pending_jobs);
  407. BLog(BLOG_ERROR, "Reactor failed to initialize");
  408. return 0;
  409. }
  410. void BReactor_Free (BReactor *bsys)
  411. {
  412. // {pending group has no BPending objects}
  413. ASSERT(!BPendingGroup_HasJobs(&bsys->pending_jobs))
  414. ASSERT(!BHeap_GetFirst(&bsys->timers_heap))
  415. ASSERT(LinkedList1_IsEmpty(&bsys->timers_expired_list))
  416. #ifdef BADVPN_USE_WINAPI
  417. ASSERT(bsys->num_handles == 0)
  418. #endif
  419. DebugObject_Free(&bsys->d_obj);
  420. #ifndef BADVPN_USE_WINAPI
  421. DebugCounter_Free(&bsys->d_fds_counter);
  422. #endif
  423. #ifdef BADVPN_USE_KEVENT
  424. DebugCounter_Free(&bsys->d_kevent_ctr);
  425. #endif
  426. BLog(BLOG_DEBUG, "Reactor freeing");
  427. #ifdef BADVPN_USE_EPOLL
  428. // close epoll fd
  429. ASSERT_FORCE(close(bsys->efd) == 0)
  430. #endif
  431. #ifdef BADVPN_USE_KEVENT
  432. // close kqueue fd
  433. ASSERT_FORCE(close(bsys->kqueue_fd) == 0)
  434. #endif
  435. // free jobs
  436. BPendingGroup_Free(&bsys->pending_jobs);
  437. }
  438. int BReactor_Exec (BReactor *bsys)
  439. {
  440. BLog(BLOG_DEBUG, "Entering event loop");
  441. while (!bsys->exiting) {
  442. // dispatch job
  443. if (BPendingGroup_HasJobs(&bsys->pending_jobs)) {
  444. BPendingGroup_ExecuteJob(&bsys->pending_jobs);
  445. continue;
  446. }
  447. // dispatch timer
  448. LinkedList1Node *list_node = LinkedList1_GetFirst(&bsys->timers_expired_list);
  449. if (list_node) {
  450. BTimer *timer = UPPER_OBJECT(list_node, BTimer, list_node);
  451. ASSERT(timer->active)
  452. ASSERT(timer->expired)
  453. // remove from expired list
  454. LinkedList1_Remove(&bsys->timers_expired_list, &timer->list_node);
  455. // set inactive
  456. timer->active = 0;
  457. // call handler
  458. BLog(BLOG_DEBUG, "Dispatching timer");
  459. timer->handler(timer->handler_pointer);
  460. continue;
  461. }
  462. #ifdef BADVPN_USE_WINAPI
  463. // dispatch handle
  464. if (bsys->returned_object) {
  465. BHandle *bh = bsys->returned_object;
  466. bsys->returned_object = NULL;
  467. ASSERT(bh->active)
  468. ASSERT(bh->position >= 0 && bh->position < bsys->enabled_num)
  469. ASSERT(bh == bsys->enabled_objects[bh->position])
  470. ASSERT(bh->h == bsys->enabled_handles[bh->position])
  471. // call handler
  472. BLog(BLOG_DEBUG, "Dispatching handle");
  473. bh->handler(bh->user);
  474. continue;
  475. }
  476. #endif
  477. #ifdef BADVPN_USE_EPOLL
  478. // dispatch file descriptor
  479. if (bsys->epoll_results_pos < bsys->epoll_results_num) {
  480. // grab event
  481. struct epoll_event *event = &bsys->epoll_results[bsys->epoll_results_pos];
  482. bsys->epoll_results_pos++;
  483. // check if the BFileDescriptor was removed
  484. if (!event->data.ptr) {
  485. continue;
  486. }
  487. // get BFileDescriptor
  488. BFileDescriptor *bfd = (BFileDescriptor *)event->data.ptr;
  489. ASSERT(bfd->active)
  490. ASSERT(bfd->epoll_returned_ptr == (BFileDescriptor **)&event->data.ptr)
  491. // zero pointer to the epoll entry
  492. bfd->epoll_returned_ptr = NULL;
  493. // calculate events to report
  494. int events = 0;
  495. if ((bfd->waitEvents&BREACTOR_READ) && (event->events&EPOLLIN)) {
  496. events |= BREACTOR_READ;
  497. }
  498. if ((bfd->waitEvents&BREACTOR_WRITE) && (event->events&EPOLLOUT)) {
  499. events |= BREACTOR_WRITE;
  500. }
  501. if ((event->events&EPOLLERR) || (event->events&EPOLLHUP)) {
  502. events |= BREACTOR_ERROR;
  503. }
  504. if (!events) {
  505. BLog(BLOG_ERROR, "no events detected?");
  506. continue;
  507. }
  508. // call handler
  509. BLog(BLOG_DEBUG, "Dispatching file descriptor");
  510. bfd->handler(bfd->user, events);
  511. continue;
  512. }
  513. #endif
  514. #ifdef BADVPN_USE_KEVENT
  515. // dispatch kevent
  516. if (bsys->kevent_results_pos < bsys->kevent_results_num) {
  517. // grab event
  518. struct kevent *event = &bsys->kevent_results[bsys->kevent_results_pos];
  519. bsys->kevent_results_pos++;
  520. // check if the event was removed
  521. if (!event->udata) {
  522. continue;
  523. }
  524. // check tag
  525. int *tag = event->udata;
  526. switch (*tag) {
  527. case KEVENT_TAG_FD: {
  528. // get BFileDescriptor
  529. BFileDescriptor *bfd = UPPER_OBJECT(tag, BFileDescriptor, kevent_tag);
  530. ASSERT(bfd->active)
  531. ASSERT(bfd->kevent_returned_ptr == (int **)&event->udata)
  532. // zero pointer to the kevent entry
  533. bfd->kevent_returned_ptr = NULL;
  534. // calculate event to report
  535. int events = 0;
  536. if ((bfd->waitEvents&BREACTOR_READ) && event->filter == EVFILT_READ) {
  537. events |= BREACTOR_READ;
  538. }
  539. if ((bfd->waitEvents&BREACTOR_WRITE) && event->filter == EVFILT_WRITE) {
  540. events |= BREACTOR_WRITE;
  541. }
  542. if (!events) {
  543. BLog(BLOG_ERROR, "no events detected?");
  544. continue;
  545. }
  546. // call handler
  547. BLog(BLOG_DEBUG, "Dispatching file descriptor");
  548. bfd->handler(bfd->user, events);
  549. continue;
  550. } break;
  551. case KEVENT_TAG_KEVENT: {
  552. // get BReactorKEvent
  553. BReactorKEvent *kev = UPPER_OBJECT(tag, BReactorKEvent, kevent_tag);
  554. ASSERT(kev->reactor == bsys)
  555. ASSERT(kev->kevent_returned_ptr == (int **)&event->udata)
  556. // zero pointer to the kevent entry
  557. kev->kevent_returned_ptr = NULL;
  558. // call handler
  559. BLog(BLOG_DEBUG, "Dispatching kevent");
  560. kev->handler(kev->user, event->fflags, event->data);
  561. continue;
  562. } break;
  563. default:
  564. ASSERT(0);
  565. }
  566. }
  567. #endif
  568. wait_for_events(bsys);
  569. }
  570. BLog(BLOG_DEBUG, "Exiting event loop, exit code %d", bsys->exit_code);
  571. return bsys->exit_code;
  572. }
  573. void BReactor_Quit (BReactor *bsys, int code)
  574. {
  575. bsys->exiting = 1;
  576. bsys->exit_code = code;
  577. }
  578. void BReactor_SetTimer (BReactor *bsys, BTimer *bt)
  579. {
  580. BReactor_SetTimerAfter(bsys, bt, bt->msTime);
  581. }
  582. void BReactor_SetTimerAfter (BReactor *bsys, BTimer *bt, btime_t after)
  583. {
  584. BReactor_SetTimerAbsolute(bsys, bt, btime_add(btime_gettime(), after));
  585. }
  586. void BReactor_SetTimerAbsolute (BReactor *bsys, BTimer *bt, btime_t time)
  587. {
  588. // unlink it if it's already in the list
  589. BReactor_RemoveTimer(bsys, bt);
  590. // initialize timer
  591. bt->active = 1;
  592. bt->expired = 0;
  593. bt->absTime = time;
  594. // insert to running timers heap
  595. BHeap_Insert(&bsys->timers_heap, &bt->heap_node);
  596. }
  597. void BReactor_RemoveTimer (BReactor *bsys, BTimer *bt)
  598. {
  599. if (!bt->active) {
  600. return;
  601. }
  602. if (bt->expired) {
  603. // remove from expired list
  604. LinkedList1_Remove(&bsys->timers_expired_list, &bt->list_node);
  605. } else {
  606. // remove from running heap
  607. BHeap_Remove(&bsys->timers_heap, &bt->heap_node);
  608. }
  609. // set inactive
  610. bt->active = 0;
  611. }
  612. BPendingGroup * BReactor_PendingGroup (BReactor *bsys)
  613. {
  614. return &bsys->pending_jobs;
  615. }
  616. int BReactor_Synchronize (BReactor *bsys, BPending *ref)
  617. {
  618. ASSERT(ref)
  619. while (!bsys->exiting) {
  620. ASSERT(BPendingGroup_HasJobs(&bsys->pending_jobs))
  621. if (BPendingGroup_PeekJob(&bsys->pending_jobs) == ref) {
  622. return 1;
  623. }
  624. BPendingGroup_ExecuteJob(&bsys->pending_jobs);
  625. }
  626. return 0;
  627. }
  628. #ifdef BADVPN_USE_WINAPI
  629. int BReactor_AddHandle (BReactor *bsys, BHandle *bh)
  630. {
  631. ASSERT(!bh->active)
  632. if (bsys->num_handles >= BSYSTEM_MAX_HANDLES) {
  633. return 0;
  634. }
  635. bh->active = 1;
  636. bh->position = -1;
  637. bsys->num_handles++;
  638. return 1;
  639. }
  640. void BReactor_RemoveHandle (BReactor *bsys, BHandle *bh)
  641. {
  642. ASSERT(bh->active)
  643. if (bh->position >= 0) {
  644. BReactor_DisableHandle(bsys, bh);
  645. }
  646. bh->active = 0;
  647. ASSERT(bsys->num_handles > 0)
  648. bsys->num_handles--;
  649. }
  650. void BReactor_EnableHandle (BReactor *bsys, BHandle *bh)
  651. {
  652. ASSERT(bh->active)
  653. ASSERT(bh->position == -1)
  654. ASSERT(bsys->enabled_num < BSYSTEM_MAX_HANDLES)
  655. bsys->enabled_handles[bsys->enabled_num] = bh->h;
  656. bsys->enabled_objects[bsys->enabled_num] = bh;
  657. bh->position = bsys->enabled_num;
  658. bsys->enabled_num++;
  659. }
  660. void BReactor_DisableHandle (BReactor *bsys, BHandle *bh)
  661. {
  662. ASSERT(bh->active)
  663. ASSERT(bh->position >= 0)
  664. ASSERT(bh->position < bsys->enabled_num)
  665. ASSERT(bh == bsys->enabled_objects[bh->position])
  666. ASSERT(bh->h == bsys->enabled_handles[bh->position])
  667. // if there are more handles after this one, move the last
  668. // one into its position
  669. if (bh->position < bsys->enabled_num - 1) {
  670. int move_position = bsys->enabled_num - 1;
  671. BHandle *move_handle = bsys->enabled_objects[move_position];
  672. ASSERT(move_handle->active)
  673. ASSERT(move_handle->position == move_position)
  674. ASSERT(move_handle->h == bsys->enabled_handles[move_position])
  675. bsys->enabled_handles[bh->position] = move_handle->h;
  676. bsys->enabled_objects[bh->position] = move_handle;
  677. move_handle->position = bh->position;
  678. }
  679. bh->position = -1;
  680. bsys->enabled_num--;
  681. // make sure the handler will not be called
  682. if (bsys->returned_object == bh) {
  683. bsys->returned_object = NULL;
  684. }
  685. }
  686. #else
  687. int BReactor_AddFileDescriptor (BReactor *bsys, BFileDescriptor *bs)
  688. {
  689. ASSERT(!bs->active)
  690. #ifdef BADVPN_USE_EPOLL
  691. // add epoll entry
  692. struct epoll_event event;
  693. memset(&event, 0, sizeof(event));
  694. event.events = 0;
  695. event.data.ptr = bs;
  696. if (epoll_ctl(bsys->efd, EPOLL_CTL_ADD, bs->fd, &event) < 0) {
  697. int error = errno;
  698. BLog(BLOG_ERROR, "epoll_ctl failed: %d", error);
  699. return 0;
  700. }
  701. // set epoll returned pointer
  702. bs->epoll_returned_ptr = NULL;
  703. #endif
  704. #ifdef BADVPN_USE_KEVENT
  705. // set kevent tag
  706. bs->kevent_tag = KEVENT_TAG_FD;
  707. // set kevent returned pointer
  708. bs->kevent_returned_ptr = NULL;
  709. #endif
  710. bs->active = 1;
  711. bs->waitEvents = 0;
  712. DebugCounter_Increment(&bsys->d_fds_counter);
  713. return 1;
  714. }
  715. void BReactor_RemoveFileDescriptor (BReactor *bsys, BFileDescriptor *bs)
  716. {
  717. ASSERT(bs->active)
  718. DebugCounter_Decrement(&bsys->d_fds_counter);
  719. bs->active = 0;
  720. #ifdef BADVPN_USE_EPOLL
  721. // delete epoll entry
  722. ASSERT_FORCE(epoll_ctl(bsys->efd, EPOLL_CTL_DEL, bs->fd, NULL) == 0)
  723. // write through epoll returned pointer
  724. if (bs->epoll_returned_ptr) {
  725. *bs->epoll_returned_ptr = NULL;
  726. }
  727. #endif
  728. #ifdef BADVPN_USE_KEVENT
  729. // delete kevents
  730. update_kevent_fd_events(bsys, bs, 0);
  731. // write through kevent returned pointer
  732. if (bs->kevent_returned_ptr) {
  733. *bs->kevent_returned_ptr = NULL;
  734. }
  735. #endif
  736. }
  737. void BReactor_SetFileDescriptorEvents (BReactor *bsys, BFileDescriptor *bs, int events)
  738. {
  739. ASSERT(bs->active)
  740. ASSERT(!(events&~(BREACTOR_READ|BREACTOR_WRITE)))
  741. if (bs->waitEvents == events) {
  742. return;
  743. }
  744. #ifdef BADVPN_USE_EPOLL
  745. // calculate epoll events
  746. int eevents = 0;
  747. if ((events & BREACTOR_READ)) {
  748. eevents |= EPOLLIN;
  749. }
  750. if ((events & BREACTOR_WRITE)) {
  751. eevents |= EPOLLOUT;
  752. }
  753. // update epoll entry
  754. struct epoll_event event;
  755. memset(&event, 0, sizeof(event));
  756. event.events = eevents;
  757. event.data.ptr = bs;
  758. ASSERT_FORCE(epoll_ctl(bsys->efd, EPOLL_CTL_MOD, bs->fd, &event) == 0)
  759. #endif
  760. #ifdef BADVPN_USE_KEVENT
  761. update_kevent_fd_events(bsys, bs, events);
  762. #endif
  763. // update events
  764. bs->waitEvents = events;
  765. }
  766. #endif
  767. #ifdef BADVPN_USE_KEVENT
  768. int BReactorKEvent_Init (BReactorKEvent *o, BReactor *reactor, BReactorKEvent_handler handler, void *user, uintptr_t ident, short filter, u_int fflags, intptr_t data)
  769. {
  770. DebugObject_Access(&reactor->d_obj);
  771. // init arguments
  772. o->reactor = reactor;
  773. o->handler = handler;
  774. o->user = user;
  775. o->ident = ident;
  776. o->filter = filter;
  777. // add kevent
  778. struct kevent event;
  779. memset(&event, 0, sizeof(event));
  780. event.ident = o->ident;
  781. event.filter = o->filter;
  782. event.flags = EV_ADD;
  783. event.fflags = fflags;
  784. event.data = data;
  785. event.udata = &o->kevent_tag;
  786. if (kevent(o->reactor->kqueue_fd, &event, 1, NULL, 0, NULL) < 0) {
  787. return 0;
  788. }
  789. // set kevent tag
  790. o->kevent_tag = KEVENT_TAG_KEVENT;
  791. // set kevent returned pointer
  792. o->kevent_returned_ptr = NULL;
  793. DebugObject_Init(&o->d_obj);
  794. DebugCounter_Increment(&o->reactor->d_kevent_ctr);
  795. return 1;
  796. }
  797. void BReactorKEvent_Free (BReactorKEvent *o)
  798. {
  799. DebugObject_Free(&o->d_obj);
  800. DebugCounter_Decrement(&o->reactor->d_kevent_ctr);
  801. // write through kevent returned pointer
  802. if (o->kevent_returned_ptr) {
  803. *o->kevent_returned_ptr = NULL;
  804. }
  805. // delete kevent
  806. struct kevent event;
  807. memset(&event, 0, sizeof(event));
  808. event.ident = o->ident;
  809. event.filter = o->filter;
  810. event.flags = EV_DELETE;
  811. ASSERT_FORCE(kevent(o->reactor->kqueue_fd, &event, 1, NULL, 0, NULL) == 0)
  812. }
  813. #endif