BReactor_badvpn.c 39 KB

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