BReactor.c 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363
  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 <misc/balloc.h>
  37. #include <base/BLog.h>
  38. #include <system/BReactor.h>
  39. #include <generated/blog_channel_BReactor.h>
  40. #define KEVENT_TAG_FD 1
  41. #define KEVENT_TAG_KEVENT 2
  42. static int timer_comparator (void *user, btime_t *val1, btime_t *val2)
  43. {
  44. if (*val1 < *val2) {
  45. return -1;
  46. }
  47. if (*val1 > *val2) {
  48. return 1;
  49. }
  50. return 0;
  51. }
  52. static int move_expired_timers (BReactor *bsys, btime_t now)
  53. {
  54. int moved = 0;
  55. // move timed out timers to the expired list
  56. BHeapNode *heap_node;
  57. while (heap_node = BHeap_GetFirst(&bsys->timers_heap)) {
  58. BTimer *timer = UPPER_OBJECT(heap_node, BTimer, heap_node);
  59. ASSERT(timer->active)
  60. // if it's in the future, stop
  61. if (timer->absTime > now) {
  62. break;
  63. }
  64. moved = 1;
  65. // remove from running timers heap
  66. BHeap_Remove(&bsys->timers_heap, &timer->heap_node);
  67. // add to expired timers list
  68. LinkedList1_Append(&bsys->timers_expired_list, &timer->list_node);
  69. // set expired
  70. timer->expired = 1;
  71. }
  72. return moved;
  73. }
  74. static void move_first_timers (BReactor *bsys)
  75. {
  76. // get the time of the first timer
  77. BHeapNode *heap_node = BHeap_GetFirst(&bsys->timers_heap);
  78. ASSERT(heap_node)
  79. BTimer *first_timer = UPPER_OBJECT(heap_node, BTimer, heap_node);
  80. ASSERT(first_timer->active)
  81. btime_t first_time = first_timer->absTime;
  82. // remove from running timers heap
  83. BHeap_Remove(&bsys->timers_heap, &first_timer->heap_node);
  84. // add to expired timers list
  85. LinkedList1_Append(&bsys->timers_expired_list, &first_timer->list_node);
  86. // set expired
  87. first_timer->expired = 1;
  88. // also move other timers with the same timeout
  89. while (heap_node = BHeap_GetFirst(&bsys->timers_heap)) {
  90. BTimer *timer = UPPER_OBJECT(heap_node, BTimer, heap_node);
  91. ASSERT(timer->active)
  92. ASSERT(timer->absTime >= first_time)
  93. // if it's in the future, stop
  94. if (timer->absTime > first_time) {
  95. break;
  96. }
  97. // remove from running timers heap
  98. BHeap_Remove(&bsys->timers_heap, &timer->heap_node);
  99. // add to expired timers list
  100. LinkedList1_Append(&bsys->timers_expired_list, &timer->list_node);
  101. // set expired
  102. timer->expired = 1;
  103. }
  104. }
  105. #ifdef BADVPN_USE_WINAPI
  106. static void set_iocp_ready (BReactorIOCPOverlapped *olap, int succeeded, DWORD bytes)
  107. {
  108. BReactor *reactor = olap->reactor;
  109. ASSERT(!olap->is_ready)
  110. // set parameters
  111. olap->ready_succeeded = succeeded;
  112. olap->ready_bytes = bytes;
  113. // insert to IOCP ready list
  114. LinkedList1_Append(&reactor->iocp_ready_list, &olap->ready_list_node);
  115. // set ready
  116. olap->is_ready = 1;
  117. }
  118. #endif
  119. #ifdef BADVPN_USE_EPOLL
  120. static void set_epoll_fd_pointers (BReactor *bsys)
  121. {
  122. // Write pointers to our entry pointers into file descriptors.
  123. // If a handler function frees some other file descriptor, the
  124. // free routine will set our pointer to NULL so we don't dispatch it.
  125. for (int i = 0; i < bsys->epoll_results_num; i++) {
  126. struct epoll_event *event = &bsys->epoll_results[i];
  127. ASSERT(event->data.ptr)
  128. BFileDescriptor *bfd = (BFileDescriptor *)event->data.ptr;
  129. ASSERT(bfd->active)
  130. ASSERT(!bfd->epoll_returned_ptr)
  131. bfd->epoll_returned_ptr = (BFileDescriptor **)&event->data.ptr;
  132. }
  133. }
  134. #endif
  135. #ifdef BADVPN_USE_KEVENT
  136. static void set_kevent_fd_pointers (BReactor *bsys)
  137. {
  138. for (int i = 0; i < bsys->kevent_results_num; i++) {
  139. struct kevent *event = &bsys->kevent_results[i];
  140. ASSERT(event->udata)
  141. int *tag = event->udata;
  142. switch (*tag) {
  143. case KEVENT_TAG_FD: {
  144. BFileDescriptor *bfd = UPPER_OBJECT(tag, BFileDescriptor, kevent_tag);
  145. ASSERT(bfd->active)
  146. ASSERT(!bfd->kevent_returned_ptr)
  147. bfd->kevent_returned_ptr = (int **)&event->udata;
  148. } break;
  149. case KEVENT_TAG_KEVENT: {
  150. BReactorKEvent *kev = UPPER_OBJECT(tag, BReactorKEvent, kevent_tag);
  151. ASSERT(kev->reactor == bsys)
  152. ASSERT(!kev->kevent_returned_ptr)
  153. kev->kevent_returned_ptr = (int **)&event->udata;
  154. } break;
  155. default:
  156. ASSERT(0);
  157. }
  158. }
  159. }
  160. static void update_kevent_fd_events (BReactor *bsys, BFileDescriptor *bs, int events)
  161. {
  162. struct kevent event;
  163. if (!(bs->waitEvents & BREACTOR_READ) && (events & BREACTOR_READ)) {
  164. memset(&event, 0, sizeof(event));
  165. event.ident = bs->fd;
  166. event.filter = EVFILT_READ;
  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_READ) && !(events & BREACTOR_READ)) {
  172. memset(&event, 0, sizeof(event));
  173. event.ident = bs->fd;
  174. event.filter = EVFILT_READ;
  175. event.flags = EV_DELETE;
  176. ASSERT_FORCE(kevent(bsys->kqueue_fd, &event, 1, NULL, 0, NULL) == 0)
  177. }
  178. if (!(bs->waitEvents & BREACTOR_WRITE) && (events & BREACTOR_WRITE)) {
  179. memset(&event, 0, sizeof(event));
  180. event.ident = bs->fd;
  181. event.filter = EVFILT_WRITE;
  182. event.flags = EV_ADD;
  183. event.udata = &bs->kevent_tag;
  184. ASSERT_FORCE(kevent(bsys->kqueue_fd, &event, 1, NULL, 0, NULL) == 0)
  185. }
  186. else if ((bs->waitEvents & BREACTOR_WRITE) && !(events & BREACTOR_WRITE)) {
  187. memset(&event, 0, sizeof(event));
  188. event.ident = bs->fd;
  189. event.filter = EVFILT_WRITE;
  190. event.flags = EV_DELETE;
  191. ASSERT_FORCE(kevent(bsys->kqueue_fd, &event, 1, NULL, 0, NULL) == 0)
  192. }
  193. }
  194. #endif
  195. #ifdef BADVPN_USE_POLL
  196. static void set_poll_fd_pointers (BReactor *bsys)
  197. {
  198. for (int i = 0; i < bsys->poll_results_num; i++) {
  199. BFileDescriptor *bfd = bsys->poll_results_bfds[i];
  200. ASSERT(bfd)
  201. ASSERT(bfd->active)
  202. ASSERT(bfd->poll_returned_index == -1)
  203. bfd->poll_returned_index = i;
  204. }
  205. }
  206. #endif
  207. static void wait_for_events (BReactor *bsys)
  208. {
  209. // must have processed all pending events
  210. ASSERT(!BPendingGroup_HasJobs(&bsys->pending_jobs))
  211. ASSERT(LinkedList1_IsEmpty(&bsys->timers_expired_list))
  212. #ifdef BADVPN_USE_WINAPI
  213. ASSERT(LinkedList1_IsEmpty(&bsys->iocp_ready_list))
  214. #endif
  215. #ifdef BADVPN_USE_EPOLL
  216. ASSERT(bsys->epoll_results_pos == bsys->epoll_results_num)
  217. #endif
  218. #ifdef BADVPN_USE_KEVENT
  219. ASSERT(bsys->kevent_results_pos == bsys->kevent_results_num)
  220. #endif
  221. #ifdef BADVPN_USE_POLL
  222. ASSERT(bsys->poll_results_pos == bsys->poll_results_num)
  223. #endif
  224. // clean up epoll results
  225. #ifdef BADVPN_USE_EPOLL
  226. bsys->epoll_results_num = 0;
  227. bsys->epoll_results_pos = 0;
  228. #endif
  229. // clean up kevent results
  230. #ifdef BADVPN_USE_KEVENT
  231. bsys->kevent_results_num = 0;
  232. bsys->kevent_results_pos = 0;
  233. #endif
  234. // clean up poll results
  235. #ifdef BADVPN_USE_POLL
  236. bsys->poll_results_num = 0;
  237. bsys->poll_results_pos = 0;
  238. #endif
  239. // timeout vars
  240. int have_timeout = 0;
  241. btime_t timeout_abs;
  242. btime_t now;
  243. // compute timeout
  244. BHeapNode *first_node;
  245. if (first_node = BHeap_GetFirst(&bsys->timers_heap)) {
  246. // get current time
  247. now = btime_gettime();
  248. // if some timers have already timed out, return them immediately
  249. if (move_expired_timers(bsys, now)) {
  250. BLog(BLOG_DEBUG, "Got already expired timers");
  251. return;
  252. }
  253. // timeout is first timer, remember absolute time
  254. BTimer *first_timer = UPPER_OBJECT(first_node, BTimer, heap_node);
  255. have_timeout = 1;
  256. timeout_abs = first_timer->absTime;
  257. }
  258. // wait until the timeout is reached or the file descriptor / handle in ready
  259. while (1) {
  260. // compute timeout
  261. btime_t timeout_rel;
  262. btime_t timeout_rel_trunc;
  263. if (have_timeout) {
  264. timeout_rel = timeout_abs - now;
  265. timeout_rel_trunc = timeout_rel;
  266. }
  267. // perform wait
  268. #ifdef BADVPN_USE_WINAPI
  269. if (have_timeout) {
  270. if (timeout_rel_trunc > INFINITE - 1) {
  271. timeout_rel_trunc = INFINITE - 1;
  272. }
  273. }
  274. DWORD bytes = 0;
  275. ULONG_PTR key;
  276. BReactorIOCPOverlapped *olap = NULL;
  277. BOOL res = GetQueuedCompletionStatus(bsys->iocp_handle, &bytes, &key, (OVERLAPPED **)&olap, (have_timeout ? timeout_rel_trunc : INFINITE));
  278. ASSERT_FORCE(olap || have_timeout)
  279. if (olap || timeout_rel_trunc == timeout_rel) {
  280. if (olap) {
  281. BLog(BLOG_DEBUG, "GetQueuedCompletionStatus returned event");
  282. DebugObject_Access(&olap->d_obj);
  283. ASSERT(olap->reactor == bsys)
  284. ASSERT(!olap->is_ready)
  285. set_iocp_ready(olap, (res == TRUE), bytes);
  286. } else {
  287. BLog(BLOG_DEBUG, "GetQueuedCompletionStatus timed out");
  288. move_first_timers(bsys);
  289. }
  290. break;
  291. }
  292. #endif
  293. #ifdef BADVPN_USE_EPOLL
  294. if (have_timeout) {
  295. if (timeout_rel_trunc > INT_MAX) {
  296. timeout_rel_trunc = INT_MAX;
  297. }
  298. }
  299. BLog(BLOG_DEBUG, "Calling epoll_wait");
  300. int waitres = epoll_wait(bsys->efd, bsys->epoll_results, BSYSTEM_MAX_RESULTS, (have_timeout ? timeout_rel_trunc : -1));
  301. if (waitres < 0) {
  302. int error = errno;
  303. if (error == EINTR) {
  304. BLog(BLOG_DEBUG, "epoll_wait interrupted");
  305. goto try_again;
  306. }
  307. perror("epoll_wait");
  308. ASSERT_FORCE(0)
  309. }
  310. ASSERT_FORCE(!(waitres == 0) || have_timeout)
  311. ASSERT_FORCE(waitres <= BSYSTEM_MAX_RESULTS)
  312. if (waitres != 0 || timeout_rel_trunc == timeout_rel) {
  313. if (waitres != 0) {
  314. BLog(BLOG_DEBUG, "epoll_wait returned %d file descriptors", waitres);
  315. bsys->epoll_results_num = waitres;
  316. set_epoll_fd_pointers(bsys);
  317. } else {
  318. BLog(BLOG_DEBUG, "epoll_wait timed out");
  319. move_first_timers(bsys);
  320. }
  321. break;
  322. }
  323. #endif
  324. #ifdef BADVPN_USE_KEVENT
  325. struct timespec ts;
  326. if (have_timeout) {
  327. if (timeout_rel_trunc > 86400000) {
  328. timeout_rel_trunc = 86400000;
  329. }
  330. ts.tv_sec = timeout_rel_trunc / 1000;
  331. ts.tv_nsec = (timeout_rel_trunc % 1000) * 1000000;
  332. }
  333. BLog(BLOG_DEBUG, "Calling kevent");
  334. int waitres = kevent(bsys->kqueue_fd, NULL, 0, bsys->kevent_results, BSYSTEM_MAX_RESULTS, (have_timeout ? &ts : NULL));
  335. if (waitres < 0) {
  336. int error = errno;
  337. if (error == EINTR) {
  338. BLog(BLOG_DEBUG, "kevent interrupted");
  339. goto try_again;
  340. }
  341. perror("kevent");
  342. ASSERT_FORCE(0)
  343. }
  344. ASSERT_FORCE(!(waitres == 0) || have_timeout)
  345. ASSERT_FORCE(waitres <= BSYSTEM_MAX_RESULTS)
  346. if (waitres != 0 || timeout_rel_trunc == timeout_rel) {
  347. if (waitres != 0) {
  348. BLog(BLOG_DEBUG, "kevent returned %d events", waitres);
  349. bsys->kevent_results_num = waitres;
  350. set_kevent_fd_pointers(bsys);
  351. } else {
  352. BLog(BLOG_DEBUG, "kevent timed out");
  353. move_first_timers(bsys);
  354. }
  355. break;
  356. }
  357. #endif
  358. #ifdef BADVPN_USE_POLL
  359. if (have_timeout) {
  360. if (timeout_rel_trunc > INT_MAX) {
  361. timeout_rel_trunc = INT_MAX;
  362. }
  363. }
  364. ASSERT(bsys->poll_num_enabled_fds >= 0)
  365. ASSERT(bsys->poll_num_enabled_fds <= BSYSTEM_MAX_POLL_FDS)
  366. int num_fds = 0;
  367. LinkedList1Node *list_node = LinkedList1_GetFirst(&bsys->poll_enabled_fds_list);
  368. while (list_node) {
  369. BFileDescriptor *bfd = UPPER_OBJECT(list_node, BFileDescriptor, poll_enabled_fds_list_node);
  370. ASSERT(bfd->active)
  371. ASSERT(bfd->poll_returned_index == -1)
  372. // calculate poll events
  373. int pevents = 0;
  374. if ((bfd->waitEvents & BREACTOR_READ)) {
  375. pevents |= POLLIN;
  376. }
  377. if ((bfd->waitEvents & BREACTOR_WRITE)) {
  378. pevents |= POLLOUT;
  379. }
  380. // write pollfd entry
  381. struct pollfd *pfd = &bsys->poll_results_pollfds[num_fds];
  382. pfd->fd = bfd->fd;
  383. pfd->events = pevents;
  384. pfd->revents = 0;
  385. // write BFileDescriptor reference entry
  386. bsys->poll_results_bfds[num_fds] = bfd;
  387. // increment number of fds in array
  388. num_fds++;
  389. list_node = LinkedList1Node_Next(list_node);
  390. }
  391. BLog(BLOG_DEBUG, "Calling poll");
  392. int waitres = poll(bsys->poll_results_pollfds, num_fds, (have_timeout ? timeout_rel_trunc : -1));
  393. if (waitres < 0) {
  394. int error = errno;
  395. if (error == EINTR) {
  396. BLog(BLOG_DEBUG, "poll interrupted");
  397. goto try_again;
  398. }
  399. perror("poll");
  400. ASSERT_FORCE(0)
  401. }
  402. ASSERT_FORCE(!(waitres == 0) || have_timeout)
  403. if (waitres != 0 || timeout_rel_trunc == timeout_rel) {
  404. if (waitres != 0) {
  405. BLog(BLOG_DEBUG, "poll returned %d file descriptors", waitres);
  406. bsys->poll_results_num = num_fds;
  407. bsys->poll_results_pos = 0;
  408. set_poll_fd_pointers(bsys);
  409. } else {
  410. BLog(BLOG_DEBUG, "poll timed out");
  411. move_first_timers(bsys);
  412. }
  413. break;
  414. }
  415. #endif
  416. try_again:
  417. if (have_timeout) {
  418. // get current time
  419. now = btime_gettime();
  420. // check if we already reached the time we're waiting for
  421. if (now >= timeout_abs) {
  422. BLog(BLOG_DEBUG, "already timed out while trying again");
  423. move_first_timers(bsys);
  424. break;
  425. }
  426. }
  427. }
  428. // reset limit objects
  429. LinkedList1Node *list_node;
  430. while (list_node = LinkedList1_GetFirst(&bsys->active_limits_list)) {
  431. BReactorLimit *limit = UPPER_OBJECT(list_node, BReactorLimit, active_limits_list_node);
  432. ASSERT(limit->count > 0)
  433. limit->count = 0;
  434. LinkedList1_Remove(&bsys->active_limits_list, &limit->active_limits_list_node);
  435. }
  436. }
  437. #ifndef BADVPN_USE_WINAPI
  438. void BFileDescriptor_Init (BFileDescriptor *bs, int fd, BFileDescriptor_handler handler, void *user)
  439. {
  440. bs->fd = fd;
  441. bs->handler = handler;
  442. bs->user = user;
  443. bs->active = 0;
  444. }
  445. #endif
  446. void BTimer_Init (BTimer *bt, btime_t msTime, BTimer_handler handler, void *handler_pointer)
  447. {
  448. bt->msTime = msTime;
  449. bt->handler = handler;
  450. bt->handler_pointer = handler_pointer;
  451. bt->active = 0;
  452. }
  453. int BTimer_IsRunning (BTimer *bt)
  454. {
  455. ASSERT(bt->active == 0 || bt->active == 1)
  456. return bt->active;
  457. }
  458. int BReactor_Init (BReactor *bsys)
  459. {
  460. BLog(BLOG_DEBUG, "Reactor initializing");
  461. // set not exiting
  462. bsys->exiting = 0;
  463. // init jobs
  464. BPendingGroup_Init(&bsys->pending_jobs);
  465. // init timers
  466. BHeap_Init(&bsys->timers_heap, OFFSET_DIFF(BTimer, absTime, heap_node), (BHeap_comparator)timer_comparator, NULL);
  467. LinkedList1_Init(&bsys->timers_expired_list);
  468. // init limits
  469. LinkedList1_Init(&bsys->active_limits_list);
  470. #ifdef BADVPN_USE_WINAPI
  471. // init IOCP list
  472. LinkedList1_Init(&bsys->iocp_list);
  473. // init IOCP handle
  474. if (!(bsys->iocp_handle = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1))) {
  475. BLog(BLOG_ERROR, "CreateIoCompletionPort failed");
  476. goto fail0;
  477. }
  478. // init IOCP ready list
  479. LinkedList1_Init(&bsys->iocp_ready_list);
  480. #endif
  481. #ifdef BADVPN_USE_EPOLL
  482. // create epoll fd
  483. if ((bsys->efd = epoll_create(10)) < 0) {
  484. BLog(BLOG_ERROR, "epoll_create failed");
  485. goto fail0;
  486. }
  487. // init results array
  488. bsys->epoll_results_num = 0;
  489. bsys->epoll_results_pos = 0;
  490. #endif
  491. #ifdef BADVPN_USE_KEVENT
  492. // create kqueue fd
  493. if ((bsys->kqueue_fd = kqueue()) < 0) {
  494. BLog(BLOG_ERROR, "kqueue failed");
  495. goto fail0;
  496. }
  497. // init results array
  498. bsys->kevent_results_num = 0;
  499. bsys->kevent_results_pos = 0;
  500. #endif
  501. #ifdef BADVPN_USE_POLL
  502. // init enabled fds list
  503. LinkedList1_Init(&bsys->poll_enabled_fds_list);
  504. // set zero enabled fds
  505. bsys->poll_num_enabled_fds = 0;
  506. // allocate results arrays
  507. if (!(bsys->poll_results_pollfds = BAllocArray(BSYSTEM_MAX_POLL_FDS, sizeof(bsys->poll_results_pollfds[0])))) {
  508. BLog(BLOG_ERROR, "BAllocArray failed");
  509. goto fail0;
  510. }
  511. if (!(bsys->poll_results_bfds = BAllocArray(BSYSTEM_MAX_POLL_FDS, sizeof(bsys->poll_results_bfds[0])))) {
  512. BLog(BLOG_ERROR, "BAllocArray failed");
  513. goto fail1;
  514. }
  515. // init results array
  516. bsys->poll_results_num = 0;
  517. bsys->poll_results_pos = 0;
  518. #endif
  519. DebugObject_Init(&bsys->d_obj);
  520. #ifndef BADVPN_USE_WINAPI
  521. DebugCounter_Init(&bsys->d_fds_counter);
  522. #endif
  523. #ifdef BADVPN_USE_KEVENT
  524. DebugCounter_Init(&bsys->d_kevent_ctr);
  525. #endif
  526. DebugCounter_Init(&bsys->d_limits_ctr);
  527. return 1;
  528. #ifdef BADVPN_USE_POLL
  529. fail1:
  530. BFree(bsys->poll_results_pollfds);
  531. #endif
  532. fail0:
  533. BPendingGroup_Free(&bsys->pending_jobs);
  534. BLog(BLOG_ERROR, "Reactor failed to initialize");
  535. return 0;
  536. }
  537. void BReactor_Free (BReactor *bsys)
  538. {
  539. DebugObject_Access(&bsys->d_obj);
  540. #ifdef BADVPN_USE_WINAPI
  541. while (!LinkedList1_IsEmpty(&bsys->iocp_list)) {
  542. BReactorIOCPOverlapped *olap = UPPER_OBJECT(LinkedList1_GetLast(&bsys->iocp_list), BReactorIOCPOverlapped, iocp_list_node);
  543. ASSERT(olap->reactor == bsys)
  544. olap->handler(olap->user, BREACTOR_IOCP_EVENT_EXITING, 0);
  545. }
  546. #endif
  547. // {pending group has no BPending objects}
  548. ASSERT(!BPendingGroup_HasJobs(&bsys->pending_jobs))
  549. ASSERT(!BHeap_GetFirst(&bsys->timers_heap))
  550. ASSERT(LinkedList1_IsEmpty(&bsys->timers_expired_list))
  551. ASSERT(LinkedList1_IsEmpty(&bsys->active_limits_list))
  552. DebugObject_Free(&bsys->d_obj);
  553. #ifdef BADVPN_USE_WINAPI
  554. ASSERT(LinkedList1_IsEmpty(&bsys->iocp_ready_list))
  555. ASSERT(LinkedList1_IsEmpty(&bsys->iocp_list))
  556. #endif
  557. #ifndef BADVPN_USE_WINAPI
  558. DebugCounter_Free(&bsys->d_fds_counter);
  559. #endif
  560. #ifdef BADVPN_USE_KEVENT
  561. DebugCounter_Free(&bsys->d_kevent_ctr);
  562. #endif
  563. DebugCounter_Free(&bsys->d_limits_ctr);
  564. #ifdef BADVPN_USE_POLL
  565. ASSERT(bsys->poll_num_enabled_fds == 0)
  566. ASSERT(LinkedList1_IsEmpty(&bsys->poll_enabled_fds_list))
  567. #endif
  568. BLog(BLOG_DEBUG, "Reactor freeing");
  569. #ifdef BADVPN_USE_WINAPI
  570. // close IOCP handle
  571. ASSERT_FORCE(CloseHandle(bsys->iocp_handle))
  572. #endif
  573. #ifdef BADVPN_USE_EPOLL
  574. // close epoll fd
  575. ASSERT_FORCE(close(bsys->efd) == 0)
  576. #endif
  577. #ifdef BADVPN_USE_KEVENT
  578. // close kqueue fd
  579. ASSERT_FORCE(close(bsys->kqueue_fd) == 0)
  580. #endif
  581. #ifdef BADVPN_USE_POLL
  582. // free results arrays
  583. BFree(bsys->poll_results_bfds);
  584. BFree(bsys->poll_results_pollfds);
  585. #endif
  586. // free jobs
  587. BPendingGroup_Free(&bsys->pending_jobs);
  588. }
  589. int BReactor_Exec (BReactor *bsys)
  590. {
  591. BLog(BLOG_DEBUG, "Entering event loop");
  592. while (!bsys->exiting) {
  593. // dispatch job
  594. if (BPendingGroup_HasJobs(&bsys->pending_jobs)) {
  595. BPendingGroup_ExecuteJob(&bsys->pending_jobs);
  596. continue;
  597. }
  598. // dispatch timer
  599. LinkedList1Node *list_node = LinkedList1_GetFirst(&bsys->timers_expired_list);
  600. if (list_node) {
  601. BTimer *timer = UPPER_OBJECT(list_node, BTimer, list_node);
  602. ASSERT(timer->active)
  603. ASSERT(timer->expired)
  604. // remove from expired list
  605. LinkedList1_Remove(&bsys->timers_expired_list, &timer->list_node);
  606. // set inactive
  607. timer->active = 0;
  608. // call handler
  609. BLog(BLOG_DEBUG, "Dispatching timer");
  610. timer->handler(timer->handler_pointer);
  611. continue;
  612. }
  613. #ifdef BADVPN_USE_WINAPI
  614. if (!LinkedList1_IsEmpty(&bsys->iocp_ready_list)) {
  615. BReactorIOCPOverlapped *olap = UPPER_OBJECT(LinkedList1_GetFirst(&bsys->iocp_ready_list), BReactorIOCPOverlapped, ready_list_node);
  616. ASSERT(olap->is_ready)
  617. ASSERT(olap->handler)
  618. // remove from ready list
  619. LinkedList1_Remove(&bsys->iocp_ready_list, &olap->ready_list_node);
  620. // set not ready
  621. olap->is_ready = 0;
  622. int event = (olap->ready_succeeded ? BREACTOR_IOCP_EVENT_SUCCEEDED : BREACTOR_IOCP_EVENT_FAILED);
  623. // call handler
  624. olap->handler(olap->user, event, olap->ready_bytes);
  625. continue;
  626. }
  627. #endif
  628. #ifdef BADVPN_USE_EPOLL
  629. // dispatch file descriptor
  630. if (bsys->epoll_results_pos < bsys->epoll_results_num) {
  631. // grab event
  632. struct epoll_event *event = &bsys->epoll_results[bsys->epoll_results_pos];
  633. bsys->epoll_results_pos++;
  634. // check if the BFileDescriptor was removed
  635. if (!event->data.ptr) {
  636. continue;
  637. }
  638. // get BFileDescriptor
  639. BFileDescriptor *bfd = (BFileDescriptor *)event->data.ptr;
  640. ASSERT(bfd->active)
  641. ASSERT(bfd->epoll_returned_ptr == (BFileDescriptor **)&event->data.ptr)
  642. // zero pointer to the epoll entry
  643. bfd->epoll_returned_ptr = NULL;
  644. // calculate events to report
  645. int events = 0;
  646. if ((bfd->waitEvents&BREACTOR_READ) && (event->events&EPOLLIN)) {
  647. events |= BREACTOR_READ;
  648. }
  649. if ((bfd->waitEvents&BREACTOR_WRITE) && (event->events&EPOLLOUT)) {
  650. events |= BREACTOR_WRITE;
  651. }
  652. if ((event->events&EPOLLERR) || (event->events&EPOLLHUP)) {
  653. events |= BREACTOR_ERROR;
  654. }
  655. if (!events) {
  656. BLog(BLOG_ERROR, "no events detected?");
  657. continue;
  658. }
  659. // call handler
  660. BLog(BLOG_DEBUG, "Dispatching file descriptor");
  661. bfd->handler(bfd->user, events);
  662. continue;
  663. }
  664. #endif
  665. #ifdef BADVPN_USE_KEVENT
  666. // dispatch kevent
  667. if (bsys->kevent_results_pos < bsys->kevent_results_num) {
  668. // grab event
  669. struct kevent *event = &bsys->kevent_results[bsys->kevent_results_pos];
  670. bsys->kevent_results_pos++;
  671. // check if the event was removed
  672. if (!event->udata) {
  673. continue;
  674. }
  675. // check tag
  676. int *tag = event->udata;
  677. switch (*tag) {
  678. case KEVENT_TAG_FD: {
  679. // get BFileDescriptor
  680. BFileDescriptor *bfd = UPPER_OBJECT(tag, BFileDescriptor, kevent_tag);
  681. ASSERT(bfd->active)
  682. ASSERT(bfd->kevent_returned_ptr == (int **)&event->udata)
  683. // zero pointer to the kevent entry
  684. bfd->kevent_returned_ptr = NULL;
  685. // calculate event to report
  686. int events = 0;
  687. if ((bfd->waitEvents&BREACTOR_READ) && event->filter == EVFILT_READ) {
  688. events |= BREACTOR_READ;
  689. }
  690. if ((bfd->waitEvents&BREACTOR_WRITE) && event->filter == EVFILT_WRITE) {
  691. events |= BREACTOR_WRITE;
  692. }
  693. if (!events) {
  694. BLog(BLOG_ERROR, "no events detected?");
  695. continue;
  696. }
  697. // call handler
  698. BLog(BLOG_DEBUG, "Dispatching file descriptor");
  699. bfd->handler(bfd->user, events);
  700. continue;
  701. } break;
  702. case KEVENT_TAG_KEVENT: {
  703. // get BReactorKEvent
  704. BReactorKEvent *kev = UPPER_OBJECT(tag, BReactorKEvent, kevent_tag);
  705. ASSERT(kev->reactor == bsys)
  706. ASSERT(kev->kevent_returned_ptr == (int **)&event->udata)
  707. // zero pointer to the kevent entry
  708. kev->kevent_returned_ptr = NULL;
  709. // call handler
  710. BLog(BLOG_DEBUG, "Dispatching kevent");
  711. kev->handler(kev->user, event->fflags, event->data);
  712. continue;
  713. } break;
  714. default:
  715. ASSERT(0);
  716. }
  717. }
  718. #endif
  719. #ifdef BADVPN_USE_POLL
  720. if (bsys->poll_results_pos < bsys->poll_results_num) {
  721. // grab event
  722. struct pollfd *pfd = &bsys->poll_results_pollfds[bsys->poll_results_pos];
  723. BFileDescriptor *bfd = bsys->poll_results_bfds[bsys->poll_results_pos];
  724. bsys->poll_results_pos++;
  725. // skip removed entry
  726. if (!bfd) {
  727. continue;
  728. }
  729. ASSERT(bfd->active)
  730. ASSERT(bfd->poll_returned_index == bsys->poll_results_pos - 1)
  731. // remove result reference
  732. bfd->poll_returned_index = -1;
  733. // calculate events to report
  734. int events = 0;
  735. if ((bfd->waitEvents & BREACTOR_READ) && (pfd->revents & POLLIN)) {
  736. events |= BREACTOR_READ;
  737. }
  738. if ((bfd->waitEvents & BREACTOR_WRITE) && (pfd->revents & POLLOUT)) {
  739. events |= BREACTOR_WRITE;
  740. }
  741. if ((pfd->revents & POLLERR) || (pfd->revents & POLLHUP)) {
  742. events |= BREACTOR_ERROR;
  743. }
  744. if (!events) {
  745. continue;
  746. }
  747. // call handler
  748. BLog(BLOG_DEBUG, "Dispatching file descriptor");
  749. bfd->handler(bfd->user, events);
  750. continue;
  751. }
  752. #endif
  753. wait_for_events(bsys);
  754. }
  755. BLog(BLOG_DEBUG, "Exiting event loop, exit code %d", bsys->exit_code);
  756. return bsys->exit_code;
  757. }
  758. void BReactor_Quit (BReactor *bsys, int code)
  759. {
  760. bsys->exiting = 1;
  761. bsys->exit_code = code;
  762. }
  763. void BReactor_SetTimer (BReactor *bsys, BTimer *bt)
  764. {
  765. BReactor_SetTimerAfter(bsys, bt, bt->msTime);
  766. }
  767. void BReactor_SetTimerAfter (BReactor *bsys, BTimer *bt, btime_t after)
  768. {
  769. BReactor_SetTimerAbsolute(bsys, bt, btime_add(btime_gettime(), after));
  770. }
  771. void BReactor_SetTimerAbsolute (BReactor *bsys, BTimer *bt, btime_t time)
  772. {
  773. // unlink it if it's already in the list
  774. BReactor_RemoveTimer(bsys, bt);
  775. // initialize timer
  776. bt->active = 1;
  777. bt->expired = 0;
  778. bt->absTime = time;
  779. // insert to running timers heap
  780. BHeap_Insert(&bsys->timers_heap, &bt->heap_node);
  781. }
  782. void BReactor_RemoveTimer (BReactor *bsys, BTimer *bt)
  783. {
  784. if (!bt->active) {
  785. return;
  786. }
  787. if (bt->expired) {
  788. // remove from expired list
  789. LinkedList1_Remove(&bsys->timers_expired_list, &bt->list_node);
  790. } else {
  791. // remove from running heap
  792. BHeap_Remove(&bsys->timers_heap, &bt->heap_node);
  793. }
  794. // set inactive
  795. bt->active = 0;
  796. }
  797. BPendingGroup * BReactor_PendingGroup (BReactor *bsys)
  798. {
  799. return &bsys->pending_jobs;
  800. }
  801. int BReactor_Synchronize (BReactor *bsys, BPending *ref)
  802. {
  803. ASSERT(ref)
  804. while (!bsys->exiting) {
  805. ASSERT(BPendingGroup_HasJobs(&bsys->pending_jobs))
  806. if (BPendingGroup_PeekJob(&bsys->pending_jobs) == ref) {
  807. return 1;
  808. }
  809. BPendingGroup_ExecuteJob(&bsys->pending_jobs);
  810. }
  811. return 0;
  812. }
  813. #ifndef BADVPN_USE_WINAPI
  814. int BReactor_AddFileDescriptor (BReactor *bsys, BFileDescriptor *bs)
  815. {
  816. ASSERT(!bs->active)
  817. #ifdef BADVPN_USE_EPOLL
  818. // add epoll entry
  819. struct epoll_event event;
  820. memset(&event, 0, sizeof(event));
  821. event.events = 0;
  822. event.data.ptr = bs;
  823. if (epoll_ctl(bsys->efd, EPOLL_CTL_ADD, bs->fd, &event) < 0) {
  824. int error = errno;
  825. BLog(BLOG_ERROR, "epoll_ctl failed: %d", error);
  826. return 0;
  827. }
  828. // set epoll returned pointer
  829. bs->epoll_returned_ptr = NULL;
  830. #endif
  831. #ifdef BADVPN_USE_KEVENT
  832. // set kevent tag
  833. bs->kevent_tag = KEVENT_TAG_FD;
  834. // set kevent returned pointer
  835. bs->kevent_returned_ptr = NULL;
  836. #endif
  837. #ifdef BADVPN_USE_POLL
  838. if (bsys->poll_num_enabled_fds == BSYSTEM_MAX_POLL_FDS) {
  839. BLog(BLOG_ERROR, "too many fds");
  840. return 0;
  841. }
  842. // append to enabled fds list
  843. LinkedList1_Append(&bsys->poll_enabled_fds_list, &bs->poll_enabled_fds_list_node);
  844. bsys->poll_num_enabled_fds++;
  845. // set not returned
  846. bs->poll_returned_index = -1;
  847. #endif
  848. bs->active = 1;
  849. bs->waitEvents = 0;
  850. DebugCounter_Increment(&bsys->d_fds_counter);
  851. return 1;
  852. }
  853. void BReactor_RemoveFileDescriptor (BReactor *bsys, BFileDescriptor *bs)
  854. {
  855. ASSERT(bs->active)
  856. DebugCounter_Decrement(&bsys->d_fds_counter);
  857. bs->active = 0;
  858. #ifdef BADVPN_USE_EPOLL
  859. // delete epoll entry
  860. ASSERT_FORCE(epoll_ctl(bsys->efd, EPOLL_CTL_DEL, bs->fd, NULL) == 0)
  861. // write through epoll returned pointer
  862. if (bs->epoll_returned_ptr) {
  863. *bs->epoll_returned_ptr = NULL;
  864. }
  865. #endif
  866. #ifdef BADVPN_USE_KEVENT
  867. // delete kevents
  868. update_kevent_fd_events(bsys, bs, 0);
  869. // write through kevent returned pointer
  870. if (bs->kevent_returned_ptr) {
  871. *bs->kevent_returned_ptr = NULL;
  872. }
  873. #endif
  874. #ifdef BADVPN_USE_POLL
  875. // invalidate results entry
  876. if (bs->poll_returned_index != -1) {
  877. ASSERT(bs->poll_returned_index >= bsys->poll_results_pos)
  878. ASSERT(bs->poll_returned_index < bsys->poll_results_num)
  879. ASSERT(bsys->poll_results_bfds[bs->poll_returned_index] == bs)
  880. bsys->poll_results_bfds[bs->poll_returned_index] = NULL;
  881. }
  882. // remove from enabled fds list
  883. LinkedList1_Remove(&bsys->poll_enabled_fds_list, &bs->poll_enabled_fds_list_node);
  884. bsys->poll_num_enabled_fds--;
  885. #endif
  886. }
  887. void BReactor_SetFileDescriptorEvents (BReactor *bsys, BFileDescriptor *bs, int events)
  888. {
  889. ASSERT(bs->active)
  890. ASSERT(!(events&~(BREACTOR_READ|BREACTOR_WRITE)))
  891. if (bs->waitEvents == events) {
  892. return;
  893. }
  894. #ifdef BADVPN_USE_EPOLL
  895. // calculate epoll events
  896. int eevents = 0;
  897. if ((events & BREACTOR_READ)) {
  898. eevents |= EPOLLIN;
  899. }
  900. if ((events & BREACTOR_WRITE)) {
  901. eevents |= EPOLLOUT;
  902. }
  903. // update epoll entry
  904. struct epoll_event event;
  905. memset(&event, 0, sizeof(event));
  906. event.events = eevents;
  907. event.data.ptr = bs;
  908. ASSERT_FORCE(epoll_ctl(bsys->efd, EPOLL_CTL_MOD, bs->fd, &event) == 0)
  909. #endif
  910. #ifdef BADVPN_USE_KEVENT
  911. update_kevent_fd_events(bsys, bs, events);
  912. #endif
  913. // update events
  914. bs->waitEvents = events;
  915. }
  916. #endif
  917. void BReactorLimit_Init (BReactorLimit *o, BReactor *reactor, int limit)
  918. {
  919. DebugObject_Access(&reactor->d_obj);
  920. ASSERT(limit > 0)
  921. // init arguments
  922. o->reactor = reactor;
  923. o->limit = limit;
  924. // set count zero
  925. o->count = 0;
  926. DebugCounter_Increment(&reactor->d_limits_ctr);
  927. DebugObject_Init(&o->d_obj);
  928. }
  929. void BReactorLimit_Free (BReactorLimit *o)
  930. {
  931. BReactor *reactor = o->reactor;
  932. DebugObject_Free(&o->d_obj);
  933. DebugCounter_Decrement(&reactor->d_limits_ctr);
  934. // remove from active limits list
  935. if (o->count > 0) {
  936. LinkedList1_Remove(&reactor->active_limits_list, &o->active_limits_list_node);
  937. }
  938. }
  939. int BReactorLimit_Increment (BReactorLimit *o)
  940. {
  941. BReactor *reactor = o->reactor;
  942. DebugObject_Access(&o->d_obj);
  943. // check count against limit
  944. if (o->count >= o->limit) {
  945. return 0;
  946. }
  947. // increment count
  948. o->count++;
  949. // if limit was zero, add to active limits list
  950. if (o->count == 1) {
  951. LinkedList1_Append(&reactor->active_limits_list, &o->active_limits_list_node);
  952. }
  953. return 1;
  954. }
  955. void BReactorLimit_SetLimit (BReactorLimit *o, int limit)
  956. {
  957. DebugObject_Access(&o->d_obj);
  958. ASSERT(limit > 0)
  959. // set limit
  960. o->limit = limit;
  961. }
  962. #ifdef BADVPN_USE_KEVENT
  963. int BReactorKEvent_Init (BReactorKEvent *o, BReactor *reactor, BReactorKEvent_handler handler, void *user, uintptr_t ident, short filter, u_int fflags, intptr_t data)
  964. {
  965. DebugObject_Access(&reactor->d_obj);
  966. // init arguments
  967. o->reactor = reactor;
  968. o->handler = handler;
  969. o->user = user;
  970. o->ident = ident;
  971. o->filter = filter;
  972. // add kevent
  973. struct kevent event;
  974. memset(&event, 0, sizeof(event));
  975. event.ident = o->ident;
  976. event.filter = o->filter;
  977. event.flags = EV_ADD;
  978. event.fflags = fflags;
  979. event.data = data;
  980. event.udata = &o->kevent_tag;
  981. if (kevent(o->reactor->kqueue_fd, &event, 1, NULL, 0, NULL) < 0) {
  982. return 0;
  983. }
  984. // set kevent tag
  985. o->kevent_tag = KEVENT_TAG_KEVENT;
  986. // set kevent returned pointer
  987. o->kevent_returned_ptr = NULL;
  988. DebugObject_Init(&o->d_obj);
  989. DebugCounter_Increment(&o->reactor->d_kevent_ctr);
  990. return 1;
  991. }
  992. void BReactorKEvent_Free (BReactorKEvent *o)
  993. {
  994. DebugObject_Free(&o->d_obj);
  995. DebugCounter_Decrement(&o->reactor->d_kevent_ctr);
  996. // write through kevent returned pointer
  997. if (o->kevent_returned_ptr) {
  998. *o->kevent_returned_ptr = NULL;
  999. }
  1000. // delete kevent
  1001. struct kevent event;
  1002. memset(&event, 0, sizeof(event));
  1003. event.ident = o->ident;
  1004. event.filter = o->filter;
  1005. event.flags = EV_DELETE;
  1006. ASSERT_FORCE(kevent(o->reactor->kqueue_fd, &event, 1, NULL, 0, NULL) == 0)
  1007. }
  1008. #endif
  1009. #ifdef BADVPN_USE_WINAPI
  1010. HANDLE BReactor_GetIOCPHandle (BReactor *reactor)
  1011. {
  1012. DebugObject_Access(&reactor->d_obj);
  1013. return reactor->iocp_handle;
  1014. }
  1015. void BReactorIOCPOverlapped_Init (BReactorIOCPOverlapped *o, BReactor *reactor, void *user, BReactorIOCPOverlapped_handler handler)
  1016. {
  1017. DebugObject_Access(&reactor->d_obj);
  1018. // init arguments
  1019. o->reactor = reactor;
  1020. o->user = user;
  1021. o->handler = handler;
  1022. // zero overlapped
  1023. memset(&o->olap, 0, sizeof(o->olap));
  1024. // append to IOCP list
  1025. LinkedList1_Append(&reactor->iocp_list, &o->iocp_list_node);
  1026. // set not ready
  1027. o->is_ready = 0;
  1028. DebugObject_Init(&o->d_obj);
  1029. }
  1030. void BReactorIOCPOverlapped_Free (BReactorIOCPOverlapped *o)
  1031. {
  1032. BReactor *reactor = o->reactor;
  1033. DebugObject_Free(&o->d_obj);
  1034. // remove from IOCP ready list
  1035. if (o->is_ready) {
  1036. LinkedList1_Remove(&reactor->iocp_ready_list, &o->ready_list_node);
  1037. }
  1038. // remove from IOCP list
  1039. LinkedList1_Remove(&reactor->iocp_list, &o->iocp_list_node);
  1040. }
  1041. void BReactorIOCPOverlapped_Wait (BReactorIOCPOverlapped *o, int *out_succeeded, DWORD *out_bytes)
  1042. {
  1043. BReactor *reactor = o->reactor;
  1044. DebugObject_Access(&o->d_obj);
  1045. // wait for IOCP events until we get an event for this olap
  1046. while (!o->is_ready) {
  1047. DWORD bytes = 0;
  1048. ULONG_PTR key;
  1049. BReactorIOCPOverlapped *olap = NULL;
  1050. BOOL res = GetQueuedCompletionStatus(reactor->iocp_handle, &bytes, &key, (OVERLAPPED **)&olap, INFINITE);
  1051. ASSERT_FORCE(olap)
  1052. DebugObject_Access(&olap->d_obj);
  1053. ASSERT(olap->reactor == reactor)
  1054. // regular I/O should be done synchronously, so we shoudln't ever get a second completion before an
  1055. // existing one is dispatched. If however PostQueuedCompletionStatus is being used to signal events,
  1056. // just discard any excess events.
  1057. if (!olap->is_ready) {
  1058. set_iocp_ready(olap, (res == TRUE), bytes);
  1059. }
  1060. }
  1061. // remove from IOCP ready list
  1062. LinkedList1_Remove(&reactor->iocp_ready_list, &o->ready_list_node);
  1063. // set not ready
  1064. o->is_ready = 0;
  1065. if (out_succeeded) {
  1066. *out_succeeded = o->ready_succeeded;
  1067. }
  1068. if (out_bytes) {
  1069. *out_bytes = o->ready_bytes;
  1070. }
  1071. }
  1072. #endif