eloop.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. /** @file eloop.c
  2. * @brief Class for
  3. */
  4. #ifdef HAVE_CONFIG_H
  5. #include "config.h"
  6. #endif /* HAVE_CONFIG_H */
  7. #include <stdlib.h>
  8. #include <stdint.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <assert.h>
  12. #include <unistd.h>
  13. #include <errno.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <fcntl.h>
  17. #include <time.h>
  18. #include <signal.h>
  19. #include <poll.h>
  20. #include <sys/signalfd.h>
  21. #include "faux/faux.h"
  22. #include "faux/str.h"
  23. #include "faux/net.h"
  24. #include "faux/sched.h"
  25. #include "faux/eloop.h"
  26. #include "private.h"
  27. #define TIMESPEC_TO_MILISECONDS(t) ((t.tv_sec * 1000) + (t.tv_nsec / 1000000l))
  28. #ifdef HAVE_SIGNALFD
  29. #define SIGNALFD_FLAGS (SFD_NONBLOCK | SFD_CLOEXEC)
  30. #else // Standard signals
  31. static void *faux_eloop_static_user_data = NULL;
  32. static void faux_eloop_static_sighandler(int signo)
  33. {
  34. int pipe = -1;
  35. if (!faux_eloop_static_user_data)
  36. return;
  37. pipe = *((int *)faux_eloop_static_user_data);
  38. write(pipe, &signo, sizeof(signo));
  39. }
  40. #endif
  41. static int faux_eloop_fd_compare(const void *first, const void *second)
  42. {
  43. const faux_eloop_fd_t *f = (const faux_eloop_fd_t *)first;
  44. const faux_eloop_fd_t *s = (const faux_eloop_fd_t *)second;
  45. return (f->fd - s->fd);
  46. }
  47. static int faux_eloop_fd_kcompare(const void *key, const void *list_item)
  48. {
  49. int *f = (int *)key;
  50. const faux_eloop_fd_t *s = (const faux_eloop_fd_t *)list_item;
  51. return (*f - s->fd);
  52. }
  53. static int faux_eloop_signal_compare(const void *first, const void *second)
  54. {
  55. const faux_eloop_signal_t *f = (const faux_eloop_signal_t *)first;
  56. const faux_eloop_signal_t *s = (const faux_eloop_signal_t *)second;
  57. return (f->signo - s->signo);
  58. }
  59. static int faux_eloop_signal_kcompare(const void *key, const void *list_item)
  60. {
  61. int *f = (int *)key;
  62. const faux_eloop_signal_t *s = (const faux_eloop_signal_t *)list_item;
  63. return (*f - s->signo);
  64. }
  65. faux_eloop_t *faux_eloop_new(faux_eloop_cb_f *default_event_cb)
  66. {
  67. faux_eloop_t *eloop = NULL;
  68. eloop = faux_zmalloc(sizeof(*eloop));
  69. assert(eloop);
  70. if (!eloop)
  71. return NULL;
  72. // Init
  73. eloop->working = BOOL_FALSE;
  74. eloop->default_event_cb = default_event_cb;
  75. // Sched
  76. eloop->sched = faux_sched_new();
  77. assert(eloop->sched);
  78. // FD
  79. eloop->fds = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  80. faux_eloop_fd_compare, faux_eloop_fd_kcompare, faux_free);
  81. assert(eloop->fds);
  82. eloop->pollfds = faux_pollfd_new();
  83. assert(eloop->pollfds);
  84. // Signal
  85. eloop->signals = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  86. faux_eloop_signal_compare, faux_eloop_signal_kcompare, faux_free);
  87. assert(eloop->signals);
  88. sigemptyset(&eloop->sig_set);
  89. sigfillset(&eloop->sig_mask);
  90. #ifdef HAVE_SIGNALFD
  91. eloop->signal_fd = -1;
  92. #endif
  93. return eloop;
  94. }
  95. void faux_eloop_free(faux_eloop_t *eloop)
  96. {
  97. if (!eloop)
  98. return;
  99. faux_list_free(eloop->signals);
  100. faux_pollfd_free(eloop->pollfds);
  101. faux_list_free(eloop->fds);
  102. faux_sched_free(eloop->sched);
  103. faux_free(eloop);
  104. }
  105. bool_t faux_eloop_loop(faux_eloop_t *eloop)
  106. {
  107. bool_t retval = BOOL_TRUE;
  108. bool_t stop = BOOL_FALSE;
  109. sigset_t blocked_signals;
  110. sigset_t orig_sig_set;
  111. #ifdef HAVE_PPOLL
  112. sigset_t *sigset_for_ppoll = NULL;
  113. #endif // HAVE_PPOLL
  114. #ifndef HAVE_SIGNALFD
  115. int signal_pipe[2];
  116. int fflags = 0;
  117. #endif // not HAVE_SIGNALFD
  118. // If event loop is active already and we try to start nested loop
  119. // then return.
  120. if (eloop->working)
  121. return BOOL_FALSE;
  122. eloop->working = BOOL_TRUE;
  123. // Block signals to prevent race conditions while loop and ppoll()
  124. // Catch signals while ppoll() only
  125. sigfillset(&blocked_signals);
  126. sigprocmask(SIG_SETMASK, &blocked_signals, &orig_sig_set);
  127. #ifdef HAVE_SIGNALFD
  128. // Create Linux-specific signal file descriptor. Wait for all signals.
  129. // Unneeded signals will be filtered out later.
  130. eloop->signal_fd = signalfd(eloop->signal_fd, &eloop->sig_set,
  131. SIGNALFD_FLAGS);
  132. faux_pollfd_add(eloop->pollfds, eloop->signal_fd, POLLIN);
  133. #else // Standard signal processing
  134. #ifdef PPOLL
  135. sigset_for_ppoll = &eloop->sig_mask;
  136. #endif // HAVE_PPOLL
  137. // Create signal pipe pair to get signal number on pipe read end
  138. pipe(signal_pipe);
  139. fcntl(signal_pipe[0], F_SETFD, FD_CLOEXEC);
  140. fflags = fcntl(signal_pipe[0], F_GETFL);
  141. fcntl(signal_pipe[0], F_SETFL, fflags | O_NONBLOCK);
  142. fcntl(signal_pipe[1], F_SETFD, FD_CLOEXEC);
  143. fflags = fcntl(signal_pipe[1], F_GETFL);
  144. fcntl(signal_pipe[1], F_SETFL, fflags | O_NONBLOCK);
  145. faux_eloop_static_user_data = &signal_pipe[1];
  146. faux_pollfd_add(eloop->pollfds, signal_pipe[0], POLLIN);
  147. if (faux_list_len(eloop->signals) != 0) {
  148. faux_list_node_t *iter = faux_list_head(eloop->signals);
  149. faux_eloop_signal_t *sig = NULL;
  150. struct sigaction sig_act = {};
  151. sig_act.sa_flags = 0;
  152. sig_act.sa_mask = eloop->sig_set;
  153. sig_act.sa_handler = &faux_eloop_static_sighandler;
  154. while ((sig = (faux_eloop_signal_t *)faux_list_each(&iter)))
  155. sigaction(sig->signo, &sig_act, &sig->oldact);
  156. }
  157. #endif // HAVE_SIGNALFD
  158. // Main loop
  159. while (!stop) {
  160. int sn = 0;
  161. struct timespec *timeout = NULL;
  162. struct timespec next_interval = {};
  163. faux_pollfd_iterator_t pollfd_iter;
  164. struct pollfd *pollfd = NULL;
  165. // Find out next scheduled interval
  166. if (faux_sched_next_interval(eloop->sched, &next_interval) < 0)
  167. timeout = NULL;
  168. else
  169. timeout = &next_interval;
  170. // Wait for events
  171. #ifdef HAVE_PPOLL
  172. sn = ppoll(faux_pollfd_vector(eloop->pollfds),
  173. faux_pollfd_len(eloop->pollfds), timeout, sigset_for_ppoll);
  174. #else // poll()
  175. sigprocmask(SIG_SETMASK, &eloop->sig_mask, NULL);
  176. sn = poll(faux_pollfd_vector(eloop->pollfds),
  177. faux_pollfd_len(eloop->pollfds),
  178. timeout ? TIMESPEC_TO_MILISECONDS(next_interval) : -1);
  179. sigprocmask(SIG_SETMASK, &blocked_signals, NULL);
  180. #endif // HAVE_PPOLL
  181. // Error or signal
  182. if (sn < 0) {
  183. // Let poll() read signal pipe or signalfd on next step
  184. if (EINTR == errno)
  185. continue;
  186. retval = BOOL_FALSE;
  187. break;
  188. }
  189. // Scheduled event
  190. if (0 == sn) {
  191. int ev_id = 0; // Event idenftifier
  192. faux_eloop_context_t *context = NULL; // Event data
  193. // Some scheduled events
  194. while(faux_sched_pop(eloop->sched, &ev_id, (void **)&context) == 0) {
  195. faux_eloop_info_sched_t info = {};
  196. faux_eloop_cb_f *event_cb = NULL;
  197. bool_t r = BOOL_TRUE;
  198. event_cb = context->event_cb;
  199. if (!event_cb)
  200. event_cb = eloop->default_event_cb;
  201. if (!event_cb) // Callback is not defined
  202. continue;
  203. info.ev_id = ev_id;
  204. // Execute callback
  205. r = event_cb(eloop, FAUX_ELOOP_SCHED, &info,
  206. context->user_data);
  207. // BOOL_FALSE return value means "break the loop"
  208. if (!r)
  209. stop = BOOL_TRUE;
  210. // Free non-periodic event's data
  211. if (!faux_sched_id_exist(eloop->sched, ev_id))
  212. faux_free(context);
  213. }
  214. continue;
  215. }
  216. // File descriptor
  217. faux_pollfd_init_iterator(eloop->pollfds, &pollfd_iter);
  218. while ((pollfd = faux_pollfd_each_active(eloop->pollfds, &pollfd_iter))) {
  219. int fd = pollfd->fd;
  220. faux_eloop_info_fd_t info = {};
  221. faux_eloop_cb_f *event_cb = NULL;
  222. faux_eloop_fd_t *entry = NULL;
  223. bool_t r = BOOL_TRUE;
  224. // Read special signal file descriptor
  225. #ifdef HAVE_SIGNALFD
  226. if (fd == eloop->signal_fd) {
  227. struct signalfd_siginfo signal_info = {};
  228. while (faux_read_block(fd, &signal_info,
  229. sizeof(signal_info)) == sizeof(signal_info)) {
  230. int signo = signal_info.ssi_signo;
  231. #else
  232. if (fd == signal_pipe[0]) {
  233. int tmp = 0;
  234. while (faux_read_block(fd, &tmp,
  235. sizeof(tmp)) == sizeof(tmp)) {
  236. int signo = tmp;
  237. #endif // HAVE_SIGNALFD
  238. faux_eloop_info_signal_t sinfo = {};
  239. faux_eloop_signal_t *sentry =
  240. (faux_eloop_signal_t *)faux_list_kfind(
  241. eloop->signals, &signo);
  242. if (!sentry) // Not registered signal. Drop it.
  243. continue;
  244. event_cb = sentry->context.event_cb;
  245. if (!event_cb)
  246. event_cb = eloop->default_event_cb;
  247. if (!event_cb) // Callback is not defined
  248. continue;
  249. sinfo.signo = signo;
  250. // Execute callback
  251. r = event_cb(eloop, FAUX_ELOOP_SIGNAL, &sinfo,
  252. sentry->context.user_data);
  253. // BOOL_FALSE return value means "break the loop"
  254. if (!r)
  255. stop = BOOL_TRUE;
  256. }
  257. continue; // Another fds are common, not signal
  258. }
  259. // Prepare event data
  260. entry = (faux_eloop_fd_t *)faux_list_kfind(eloop->fds, &fd);
  261. assert(entry);
  262. if (!entry) // Something went wrong
  263. continue;
  264. event_cb = entry->context.event_cb;
  265. if (!event_cb)
  266. event_cb = eloop->default_event_cb;
  267. if (!event_cb) // Callback function is not defined for this event
  268. continue;
  269. info.fd = fd;
  270. info.revents = pollfd->revents;
  271. // Execute callback
  272. r = event_cb(eloop, FAUX_ELOOP_FD, &info, entry->context.user_data);
  273. // BOOL_FALSE return value means "break the loop"
  274. if (!r)
  275. stop = BOOL_TRUE;
  276. }
  277. } // Loop end
  278. #ifdef HAVE_SIGNALFD
  279. // Close signal file descriptor
  280. faux_pollfd_del_by_fd(eloop->pollfds, eloop->signal_fd);
  281. close(eloop->signal_fd);
  282. eloop->signal_fd = -1;
  283. #else // Standard signals. Restore signal handlers
  284. if (faux_list_len(eloop->signals) != 0) {
  285. faux_list_node_t *iter = faux_list_head(eloop->signals);
  286. faux_eloop_signal_t *sig = NULL;
  287. while ((sig = (faux_eloop_signal_t *)faux_list_each(&iter)))
  288. sigaction(sig->signo, &sig->oldact, NULL);
  289. }
  290. faux_pollfd_del_by_fd(eloop->pollfds, signal_pipe[0]);
  291. close(signal_pipe[0]);
  292. close(signal_pipe[1]);
  293. #endif
  294. // Unblock signals
  295. sigprocmask(SIG_SETMASK, &orig_sig_set, NULL);
  296. // Deactivate loop flag
  297. eloop->working = BOOL_FALSE;
  298. return retval;
  299. }
  300. bool_t faux_eloop_add_fd(faux_eloop_t *eloop, int fd, short events,
  301. faux_eloop_cb_f *event_cb, void *user_data)
  302. {
  303. faux_eloop_fd_t *entry = NULL;
  304. faux_list_node_t *new_node = NULL;
  305. if (!eloop || (fd < 0))
  306. return BOOL_FALSE;
  307. entry = faux_zmalloc(sizeof(*entry));
  308. if (!entry)
  309. return BOOL_FALSE;
  310. entry->fd = fd;
  311. entry->events = events;
  312. entry->context.event_cb = event_cb;
  313. entry->context.user_data = user_data;
  314. if (!(new_node = faux_list_add(eloop->fds, entry))) {
  315. faux_free(entry);
  316. return BOOL_FALSE;
  317. }
  318. if (!faux_pollfd_add(eloop->pollfds, entry->fd, entry->events)) {
  319. faux_list_del(eloop->fds, new_node);
  320. faux_free(entry);
  321. return BOOL_FALSE;
  322. }
  323. return BOOL_TRUE;
  324. }
  325. bool_t faux_eloop_del_fd(faux_eloop_t *eloop, int fd)
  326. {
  327. if (!eloop || (fd < 0))
  328. return BOOL_FALSE;
  329. if (!faux_list_kdel(eloop->fds, &fd))
  330. return BOOL_FALSE;
  331. if (!faux_pollfd_del_by_fd(eloop->pollfds, fd))
  332. return BOOL_FALSE;
  333. return BOOL_TRUE;
  334. }
  335. bool_t faux_eloop_add_signal(faux_eloop_t *eloop, int signo,
  336. faux_eloop_cb_f *event_cb, void *user_data)
  337. {
  338. faux_eloop_signal_t *entry = NULL;
  339. if (!eloop || (signo < 0))
  340. return BOOL_FALSE;
  341. if (sigismember(&eloop->sig_set, signo) == 1)
  342. return BOOL_FALSE; // Already exists
  343. // Firstly try to add signal to sigset. Library function will validate
  344. // signal number value.
  345. if (sigaddset(&eloop->sig_set, signo) < 0)
  346. return BOOL_FALSE; // Invalid signal number
  347. sigdelset(&eloop->sig_mask, signo);
  348. entry = faux_zmalloc(sizeof(*entry));
  349. if (!entry) {
  350. sigdelset(&eloop->sig_set, signo);
  351. sigaddset(&eloop->sig_mask, signo);
  352. return BOOL_FALSE;
  353. }
  354. entry->signo = signo;
  355. entry->context.event_cb = event_cb;
  356. entry->context.user_data = user_data;
  357. if (!faux_list_add(eloop->signals, entry)) {
  358. faux_free(entry);
  359. sigdelset(&eloop->sig_set, signo);
  360. sigaddset(&eloop->sig_mask, signo);
  361. return BOOL_FALSE;
  362. }
  363. if (eloop->working) { // Add signal on the fly
  364. #ifdef HAVE_SIGNALFD
  365. // Reattach signalfd handler with updated sig_set
  366. eloop->signal_fd = signalfd(eloop->signal_fd, &eloop->sig_set,
  367. SIGNALFD_FLAGS);
  368. #else // Standard signals
  369. struct sigaction sig_act = {};
  370. sig_act.sa_flags = 0;
  371. sig_act.sa_mask = eloop->sig_set;
  372. sig_act.sa_handler = &faux_eloop_static_sighandler;
  373. sigaction(signo, &sig_act, &entry->oldact);
  374. #endif
  375. }
  376. return BOOL_TRUE;
  377. }
  378. bool_t faux_eloop_del_signal(faux_eloop_t *eloop, int signo)
  379. {
  380. if (!eloop || (signo < 0))
  381. return BOOL_FALSE;
  382. if (sigismember(&eloop->sig_set, signo) != 1)
  383. return BOOL_FALSE; // Doesn't exist
  384. sigdelset(&eloop->sig_set, signo);
  385. sigaddset(&eloop->sig_mask, signo);
  386. if (eloop->working) { // Del signal on the fly
  387. #ifdef HAVE_SIGNALFD
  388. // Reattach signalfd handler with updated sig_set
  389. eloop->signal_fd = signalfd(eloop->signal_fd, &eloop->sig_set,
  390. SIGNALFD_FLAGS);
  391. #else // Standard signals
  392. faux_eloop_signal_t *sig = faux_list_kfind(eloop->signals, &signo);
  393. sigaction(signo, &sig->oldact, NULL);
  394. #endif
  395. }
  396. faux_list_kdel(eloop->signals, &signo);
  397. return BOOL_TRUE;
  398. }
  399. static faux_eloop_context_t *faux_eloop_new_context(
  400. faux_eloop_cb_f *event_cb, void *data)
  401. {
  402. faux_eloop_context_t *context = NULL;
  403. context = faux_zmalloc(sizeof(*context));
  404. assert(context);
  405. if (!context)
  406. return NULL;
  407. context->event_cb = event_cb;
  408. context->user_data = data;
  409. return context;
  410. }
  411. bool_t faux_eloop_add_sched_once(faux_eloop_t *eloop, const struct timespec *time,
  412. int ev_id, faux_eloop_cb_f *event_cb, void *data)
  413. {
  414. faux_eloop_context_t *context = NULL;
  415. assert(eloop);
  416. if (!eloop)
  417. return BOOL_FALSE;
  418. if (faux_sched_id_exist(eloop->sched, ev_id))
  419. return BOOL_FALSE; // ID must be unique
  420. context = faux_eloop_new_context(event_cb, data);
  421. assert(context);
  422. if (!context)
  423. return BOOL_FALSE;
  424. if (faux_sched_once(eloop->sched, time, ev_id, context) < 0) {
  425. faux_free(context);
  426. return BOOL_FALSE;
  427. }
  428. return BOOL_TRUE;
  429. }
  430. bool_t faux_eloop_add_sched_once_delayed(faux_eloop_t *eloop, const struct timespec *interval,
  431. int ev_id, faux_eloop_cb_f *event_cb, void *data)
  432. {
  433. faux_eloop_context_t *context = NULL;
  434. assert(eloop);
  435. if (!eloop)
  436. return BOOL_FALSE;
  437. if (faux_sched_id_exist(eloop->sched, ev_id))
  438. return BOOL_FALSE; // ID must be unique
  439. context = faux_eloop_new_context(event_cb, data);
  440. assert(context);
  441. if (!context)
  442. return BOOL_FALSE;
  443. if (faux_sched_once_delayed(eloop->sched, interval, ev_id, context) < 0) {
  444. faux_free(context);
  445. return BOOL_FALSE;
  446. }
  447. return BOOL_TRUE;
  448. }
  449. bool_t faux_eloop_add_sched_periodic(faux_eloop_t *eloop, const struct timespec *time,
  450. int ev_id, faux_eloop_cb_f *event_cb, void *data,
  451. const struct timespec *period, unsigned int cycle_num)
  452. {
  453. faux_eloop_context_t *context = NULL;
  454. assert(eloop);
  455. if (!eloop)
  456. return BOOL_FALSE;
  457. if (faux_sched_id_exist(eloop->sched, ev_id))
  458. return BOOL_FALSE; // ID must be unique
  459. context = faux_eloop_new_context(event_cb, data);
  460. assert(context);
  461. if (!context)
  462. return BOOL_FALSE;
  463. if (faux_sched_periodic(eloop->sched, time, ev_id, context,
  464. period, cycle_num) < 0) {
  465. faux_free(context);
  466. return BOOL_FALSE;
  467. }
  468. return BOOL_TRUE;
  469. }
  470. bool_t faux_eloop_add_sched_periodic_delayed(faux_eloop_t *eloop,
  471. int ev_id, faux_eloop_cb_f *event_cb, void *data,
  472. const struct timespec *period, unsigned int cycle_num)
  473. {
  474. faux_eloop_context_t *context = NULL;
  475. assert(eloop);
  476. if (!eloop)
  477. return BOOL_FALSE;
  478. if (faux_sched_id_exist(eloop->sched, ev_id))
  479. return BOOL_FALSE; // ID must be unique
  480. context = faux_eloop_new_context(event_cb, data);
  481. assert(context);
  482. if (!context)
  483. return BOOL_FALSE;
  484. if (faux_sched_periodic_delayed(eloop->sched, ev_id, context,
  485. period, cycle_num) < 0) {
  486. faux_free(context);
  487. return BOOL_FALSE;
  488. }
  489. return BOOL_TRUE;
  490. }
  491. bool_t faux_eloop_del_sched(faux_eloop_t *eloop, int id)
  492. {
  493. faux_eloop_context_t *context = NULL;
  494. assert(eloop);
  495. if (!eloop)
  496. return BOOL_FALSE;
  497. if (!faux_sched_get_by_id(eloop->sched, id, (void **)&context, NULL))
  498. return BOOL_FALSE;
  499. faux_sched_remove_by_id(eloop->sched, id);
  500. faux_free(context);
  501. return BOOL_TRUE;
  502. }