eloop.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929
  1. /** @file eloop.c
  2. * @brief Event loop.
  3. *
  4. * It's a class to organize main event loop. Class has unified interface to get
  5. * different types of events: signals, file descriptor events, scheduled time
  6. * events. User can register callbacks for interested events. Callback has
  7. * the same prototype for all types of events. Callback is called with
  8. * associated data. Assiciated data is user data, type of event and additional
  9. * data with information about things specific for current type. It's a number
  10. * of signal for signals, file descriptor and type of file event for file
  11. * descriptor events, event ID and pointer to special event object for scheduled
  12. * time events.
  13. */
  14. #ifdef HAVE_CONFIG_H
  15. #include "config.h"
  16. #endif /* HAVE_CONFIG_H */
  17. #include <stdlib.h>
  18. #include <stdint.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <assert.h>
  22. #include <unistd.h>
  23. #include <errno.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <fcntl.h>
  27. #include <time.h>
  28. #include <signal.h>
  29. #include <poll.h>
  30. #include <sys/signalfd.h>
  31. #include "faux/faux.h"
  32. #include "faux/str.h"
  33. #include "faux/net.h"
  34. #include "faux/sched.h"
  35. #include "faux/eloop.h"
  36. #include "private.h"
  37. #define TIMESPEC_TO_MILISECONDS(t) ((t.tv_sec * 1000) + (t.tv_nsec / 1000000l))
  38. #ifdef HAVE_SIGNALFD
  39. #define SIGNALFD_FLAGS (SFD_NONBLOCK | SFD_CLOEXEC)
  40. #else // Standard signals
  41. static void *faux_eloop_static_user_data = NULL;
  42. /** @brief Signal handler sends signal number to programm over pipe.
  43. *
  44. * Static service function. It's used for non-linux implementation on systems
  45. * that has no signalfd() function. The pipe pair is created. The write end is
  46. * used in signal handler to write signo to it. The read end of pipe is used
  47. * with poll()-like function to get signal number in main programm. It is
  48. * necessary to solve race problem with poll() function and signal handlers. See
  49. * manpage for select() and pselect().
  50. */
  51. static void faux_eloop_static_sighandler(int signo)
  52. {
  53. int pipe = -1;
  54. if (!faux_eloop_static_user_data)
  55. return;
  56. pipe = *((int *)faux_eloop_static_user_data);
  57. write(pipe, &signo, sizeof(signo));
  58. }
  59. #endif
  60. /** @brief Callback compare function for fd list.
  61. */
  62. static int faux_eloop_fd_compare(const void *first, const void *second)
  63. {
  64. const faux_eloop_fd_t *f = (const faux_eloop_fd_t *)first;
  65. const faux_eloop_fd_t *s = (const faux_eloop_fd_t *)second;
  66. return (f->fd - s->fd);
  67. }
  68. /** @brief Callback compare function for fd list to search by key.
  69. */
  70. static int faux_eloop_fd_kcompare(const void *key, const void *list_item)
  71. {
  72. int *f = (int *)key;
  73. const faux_eloop_fd_t *s = (const faux_eloop_fd_t *)list_item;
  74. return (*f - s->fd);
  75. }
  76. /** @brief Callback compare function for signal list.
  77. */
  78. static int faux_eloop_signal_compare(const void *first, const void *second)
  79. {
  80. const faux_eloop_signal_t *f = (const faux_eloop_signal_t *)first;
  81. const faux_eloop_signal_t *s = (const faux_eloop_signal_t *)second;
  82. return (f->signo - s->signo);
  83. }
  84. /** @brief Callback compare function for signal list to search by key.
  85. */
  86. static int faux_eloop_signal_kcompare(const void *key, const void *list_item)
  87. {
  88. int *f = (int *)key;
  89. const faux_eloop_signal_t *s = (const faux_eloop_signal_t *)list_item;
  90. return (*f - s->signo);
  91. }
  92. /** @brief Create new event loop object.
  93. *
  94. * Function gets default event callback as argument. It will be used for all
  95. * events if private callback for event is not specified.
  96. *
  97. * @param [in] default_event_cb Default event callback.
  98. * @return Allocated faux_eloop_t object or NULL on error.
  99. */
  100. faux_eloop_t *faux_eloop_new(faux_eloop_cb_fn default_event_cb)
  101. {
  102. faux_eloop_t *eloop = NULL;
  103. eloop = faux_zmalloc(sizeof(*eloop));
  104. assert(eloop);
  105. if (!eloop)
  106. return NULL;
  107. // Init
  108. eloop->working = BOOL_FALSE;
  109. eloop->default_event_cb = default_event_cb;
  110. // Sched
  111. eloop->sched = faux_sched_new();
  112. assert(eloop->sched);
  113. // FD
  114. eloop->fds = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  115. faux_eloop_fd_compare, faux_eloop_fd_kcompare, faux_free);
  116. assert(eloop->fds);
  117. eloop->pollfds = faux_pollfd_new();
  118. assert(eloop->pollfds);
  119. // Signal
  120. eloop->signals = faux_list_new(FAUX_LIST_SORTED, FAUX_LIST_UNIQUE,
  121. faux_eloop_signal_compare, faux_eloop_signal_kcompare, faux_free);
  122. assert(eloop->signals);
  123. sigemptyset(&eloop->sig_set);
  124. sigfillset(&eloop->sig_mask);
  125. #ifdef HAVE_SIGNALFD
  126. eloop->signal_fd = -1;
  127. #endif
  128. return eloop;
  129. }
  130. /** @brief Free event loop object.
  131. *
  132. * @param [in] Event loop object.
  133. */
  134. void faux_eloop_free(faux_eloop_t *eloop)
  135. {
  136. if (!eloop)
  137. return;
  138. faux_list_free(eloop->signals);
  139. faux_pollfd_free(eloop->pollfds);
  140. faux_list_free(eloop->fds);
  141. faux_sched_free(eloop->sched);
  142. faux_free(eloop);
  143. }
  144. /** @brief Event loop function.
  145. *
  146. * Function blocks and waits for registered events. When event occurs the
  147. * correspondent callback will be called. Callback returns bool_t value. If
  148. * callback returns BOOL_FALSE then loop will break and unblock the programm.
  149. * On BOOL_TRUE the loop will wait for the next event.
  150. *
  151. * @param [in] eloop Allocated and initialized event loop object.
  152. * @returns BOOL_TRUE - success, BOOL_FALSE - error.
  153. */
  154. bool_t faux_eloop_loop(faux_eloop_t *eloop)
  155. {
  156. bool_t retval = BOOL_TRUE;
  157. bool_t stop = BOOL_FALSE;
  158. sigset_t blocked_signals;
  159. sigset_t orig_sig_set;
  160. #ifdef HAVE_PPOLL
  161. sigset_t *sigset_for_ppoll = NULL;
  162. #endif // HAVE_PPOLL
  163. #ifndef HAVE_SIGNALFD
  164. int signal_pipe[2];
  165. int fflags = 0;
  166. void *saved_static_user_data = NULL;
  167. #endif // not HAVE_SIGNALFD
  168. // If event loop is active already and we try to start nested loop
  169. // then return.
  170. if (eloop->working)
  171. return BOOL_FALSE;
  172. eloop->working = BOOL_TRUE;
  173. // Block signals to prevent race conditions while loop and ppoll()
  174. // Catch signals while ppoll() only
  175. sigfillset(&blocked_signals);
  176. sigprocmask(SIG_SETMASK, &blocked_signals, &orig_sig_set);
  177. #ifdef HAVE_SIGNALFD
  178. // Create Linux-specific signal file descriptor. Wait for signals.
  179. eloop->signal_fd = signalfd(eloop->signal_fd, &eloop->sig_set,
  180. SIGNALFD_FLAGS);
  181. faux_pollfd_add(eloop->pollfds, eloop->signal_fd, POLLIN);
  182. #else // Standard signal processing
  183. #ifdef PPOLL
  184. sigset_for_ppoll = &eloop->sig_mask;
  185. #endif // HAVE_PPOLL
  186. // Create signal pipe pair to get signal number on pipe read end
  187. pipe(signal_pipe);
  188. fcntl(signal_pipe[0], F_SETFD, FD_CLOEXEC);
  189. fflags = fcntl(signal_pipe[0], F_GETFL);
  190. fcntl(signal_pipe[0], F_SETFL, fflags | O_NONBLOCK);
  191. fcntl(signal_pipe[1], F_SETFD, FD_CLOEXEC);
  192. fflags = fcntl(signal_pipe[1], F_GETFL);
  193. fcntl(signal_pipe[1], F_SETFL, fflags | O_NONBLOCK);
  194. // Save previous value of static user data. It can be a nested
  195. // invocation of faux_eloop_loop() (i.e. same function but different
  196. // faux_eloop_t objects). So it need to be restored after loop.
  197. saved_static_user_data = faux_eloop_static_user_data;
  198. faux_eloop_static_user_data = &signal_pipe[1];
  199. faux_pollfd_add(eloop->pollfds, signal_pipe[0], POLLIN);
  200. if (faux_list_len(eloop->signals) != 0) {
  201. faux_list_node_t *iter = faux_list_head(eloop->signals);
  202. faux_eloop_signal_t *sig = NULL;
  203. struct sigaction sig_act = {};
  204. sig_act.sa_flags = 0;
  205. sig_act.sa_mask = eloop->sig_set;
  206. sig_act.sa_handler = &faux_eloop_static_sighandler;
  207. while ((sig = (faux_eloop_signal_t *)faux_list_each(&iter)))
  208. sigaction(sig->signo, &sig_act, &sig->oldact);
  209. }
  210. #endif // HAVE_SIGNALFD
  211. // Main loop
  212. while (!stop) {
  213. int sn = 0;
  214. struct timespec *timeout = NULL;
  215. struct timespec next_interval = {};
  216. faux_pollfd_iterator_t pollfd_iter;
  217. struct pollfd *pollfd = NULL;
  218. // Find out next scheduled interval
  219. if (!faux_sched_next_interval(eloop->sched, &next_interval))
  220. timeout = NULL;
  221. else
  222. timeout = &next_interval;
  223. // Wait for events
  224. #ifdef HAVE_PPOLL
  225. sn = ppoll(faux_pollfd_vector(eloop->pollfds),
  226. faux_pollfd_len(eloop->pollfds), timeout, sigset_for_ppoll);
  227. #else // poll()
  228. sigprocmask(SIG_SETMASK, &eloop->sig_mask, NULL);
  229. sn = poll(faux_pollfd_vector(eloop->pollfds),
  230. faux_pollfd_len(eloop->pollfds),
  231. timeout ? TIMESPEC_TO_MILISECONDS(next_interval) : -1);
  232. sigprocmask(SIG_SETMASK, &blocked_signals, NULL);
  233. #endif // HAVE_PPOLL
  234. // Error or signal
  235. if (sn < 0) {
  236. // Let poll() read signal pipe or signalfd on next step
  237. if (EINTR == errno)
  238. continue;
  239. retval = BOOL_FALSE;
  240. break;
  241. }
  242. // Scheduled event
  243. if (0 == sn) {
  244. faux_ev_t *ev = NULL;
  245. // Some scheduled events
  246. while((ev = faux_sched_pop(eloop->sched))) {
  247. faux_eloop_info_sched_t info = {};
  248. bool_t r = BOOL_TRUE;
  249. int ev_id = faux_ev_id(ev);
  250. faux_eloop_context_t *context =
  251. (faux_eloop_context_t *)faux_ev_data(ev);
  252. faux_eloop_cb_fn event_cb = context->event_cb;
  253. void *user_data = context->user_data;
  254. if (!faux_ev_is_busy(ev)) {
  255. faux_ev_free(ev);
  256. ev = NULL;
  257. }
  258. if (!event_cb)
  259. event_cb = eloop->default_event_cb;
  260. if (!event_cb) // Callback is not defined
  261. continue;
  262. info.ev_id = ev_id;
  263. // Callback will get only rescheduled event object.
  264. // If event is not scheduled, callback will get NULL.
  265. info.ev = ev;
  266. // Execute callback
  267. r = event_cb(eloop, FAUX_ELOOP_SCHED, &info,
  268. user_data);
  269. // BOOL_FALSE return value means "break the loop"
  270. if (!r)
  271. stop = BOOL_TRUE;
  272. }
  273. continue;
  274. }
  275. // File descriptor
  276. faux_pollfd_init_iterator(eloop->pollfds, &pollfd_iter);
  277. while ((pollfd = faux_pollfd_each_active(eloop->pollfds, &pollfd_iter))) {
  278. int fd = pollfd->fd;
  279. faux_eloop_info_fd_t info = {};
  280. faux_eloop_cb_fn event_cb = NULL;
  281. faux_eloop_fd_t *entry = NULL;
  282. bool_t r = BOOL_TRUE;
  283. // Read special signal file descriptor
  284. #ifdef HAVE_SIGNALFD
  285. if (fd == eloop->signal_fd) {
  286. struct signalfd_siginfo signal_info = {};
  287. while (faux_read(fd, &signal_info,
  288. sizeof(signal_info)) == sizeof(signal_info)) {
  289. int signo = signal_info.ssi_signo;
  290. #else
  291. if (fd == signal_pipe[0]) {
  292. int tmp = 0;
  293. while (faux_read(fd, &tmp,
  294. sizeof(tmp)) == sizeof(tmp)) {
  295. int signo = tmp;
  296. #endif // HAVE_SIGNALFD
  297. faux_eloop_info_signal_t sinfo = {};
  298. faux_eloop_signal_t *sentry =
  299. (faux_eloop_signal_t *)faux_list_kfind(
  300. eloop->signals, &signo);
  301. if (!sentry) // Not registered signal. Drop it.
  302. continue;
  303. event_cb = sentry->context.event_cb;
  304. if (!event_cb)
  305. event_cb = eloop->default_event_cb;
  306. if (!event_cb) // Callback is not defined
  307. continue;
  308. sinfo.signo = signo;
  309. // Execute callback
  310. r = event_cb(eloop, FAUX_ELOOP_SIGNAL, &sinfo,
  311. sentry->context.user_data);
  312. // BOOL_FALSE return value means "break the loop"
  313. if (!r)
  314. stop = BOOL_TRUE;
  315. }
  316. continue; // Another fds are common, not signal
  317. }
  318. // File descriptor
  319. entry = (faux_eloop_fd_t *)faux_list_kfind(eloop->fds, &fd);
  320. assert(entry);
  321. if (!entry) // Something went wrong
  322. continue;
  323. event_cb = entry->context.event_cb;
  324. if (!event_cb)
  325. event_cb = eloop->default_event_cb;
  326. if (!event_cb) // Callback function is not defined for this event
  327. continue;
  328. info.fd = fd;
  329. info.revents = pollfd->revents;
  330. // Execute callback
  331. r = event_cb(eloop, FAUX_ELOOP_FD, &info, entry->context.user_data);
  332. // BOOL_FALSE return value means "break the loop"
  333. if (!r)
  334. stop = BOOL_TRUE;
  335. }
  336. } // Loop end
  337. #ifdef HAVE_SIGNALFD
  338. // Close signal file descriptor
  339. faux_pollfd_del_by_fd(eloop->pollfds, eloop->signal_fd);
  340. close(eloop->signal_fd);
  341. eloop->signal_fd = -1;
  342. #else // Standard signals. Restore signal handlers
  343. // Restore saved static_user_data. It must be done before sigaction()
  344. // that restores old signal handlers.
  345. faux_eloop_static_user_data = saved_static_user_data;
  346. if (faux_list_len(eloop->signals) != 0) {
  347. faux_list_node_t *iter = faux_list_head(eloop->signals);
  348. faux_eloop_signal_t *sig = NULL;
  349. while ((sig = (faux_eloop_signal_t *)faux_list_each(&iter)))
  350. sigaction(sig->signo, &sig->oldact, NULL);
  351. }
  352. faux_pollfd_del_by_fd(eloop->pollfds, signal_pipe[0]);
  353. close(signal_pipe[0]);
  354. close(signal_pipe[1]);
  355. #endif
  356. // Unblock signals
  357. sigprocmask(SIG_SETMASK, &orig_sig_set, NULL);
  358. // Deactivate loop flag
  359. eloop->working = BOOL_FALSE;
  360. return retval;
  361. }
  362. /** @brief Registers file descriptor to wait for events.
  363. *
  364. * See poll() for explanation of possible file events ("events" argument).
  365. *
  366. * @param [in] eloop Allocated and initialized event loop object.
  367. * @param [in] fd File descriptor to wait on.
  368. * @param [in] events File events mask like POLLIN, POLLOUT.
  369. * @param [in] event_cb Callback for event.
  370. * @param [in] user_data User data to pass to callback.
  371. * @return BOOL_TRUE - success, BOOL_FALSE - error.
  372. */
  373. bool_t faux_eloop_add_fd(faux_eloop_t *eloop, int fd, short events,
  374. faux_eloop_cb_fn event_cb, void *user_data)
  375. {
  376. faux_eloop_fd_t *entry = NULL;
  377. faux_list_node_t *new_node = NULL;
  378. assert(eloop);
  379. if (!eloop || (fd < 0))
  380. return BOOL_FALSE;
  381. entry = faux_zmalloc(sizeof(*entry));
  382. if (!entry)
  383. return BOOL_FALSE;
  384. entry->fd = fd;
  385. entry->events = events;
  386. entry->context.event_cb = event_cb;
  387. entry->context.user_data = user_data;
  388. if (!(new_node = faux_list_add(eloop->fds, entry))) {
  389. faux_free(entry);
  390. return BOOL_FALSE;
  391. }
  392. if (!faux_pollfd_add(eloop->pollfds, entry->fd, entry->events)) {
  393. faux_list_del(eloop->fds, new_node);
  394. faux_free(entry);
  395. return BOOL_FALSE;
  396. }
  397. return BOOL_TRUE;
  398. }
  399. /** @brief Registers additional event for specified fd.
  400. *
  401. * See poll() for explanation of possible file events ("events" argument).
  402. * Suppose some fd was added by faux_eloop_add_fd(). User have specified some
  403. * events like POLLIN. Now user wants to track POLLOUT event too. So it's not
  404. * necessary to remove fd by faux_eloop_del_fd() and then re-add it with new
  405. * event mask. User can include additional events by
  406. * faux_eloop_include_fd_event(). Specified event will be added to existent
  407. * event mask.
  408. *
  409. * @param [in] eloop Allocated and initialized event loop object.
  410. * @param [in] fd File descriptor to change event mask.
  411. * @param [in] events File event to include (like POLLIN, POLLOUT).
  412. * @return BOOL_TRUE - success, BOOL_FALSE - error.
  413. */
  414. bool_t faux_eloop_include_fd_event(faux_eloop_t *eloop, int fd, short event)
  415. {
  416. faux_eloop_fd_t *entry = NULL;
  417. assert(eloop);
  418. if (!eloop)
  419. return BOOL_FALSE;
  420. assert(fd >= 0);
  421. if (fd < 0)
  422. return BOOL_FALSE;
  423. entry = (faux_eloop_fd_t *)faux_list_kfind(eloop->fds, &fd);
  424. if (!entry)
  425. return BOOL_FALSE;
  426. entry->events = entry->events | event;
  427. faux_pollfd_del_by_fd(eloop->pollfds, fd);
  428. faux_pollfd_add(eloop->pollfds, fd, entry->events);
  429. return BOOL_TRUE;
  430. }
  431. /** @brief Unregisters event for specified fd.
  432. *
  433. * See poll() for explanation of possible file events ("events" argument).
  434. * Suppose some fd was added by faux_eloop_add_fd(). User have specified some
  435. * events like POLLIN, POLLOUT. Now user doesn't wants to track one of the
  436. * events (POLLOUT for example). So it's not necessary to remove fd by
  437. * faux_eloop_del_fd() and then re-add it with new event mask. User can exclude
  438. * event by faux_eloop_include_fd_event(). Specified event will be excluded from
  439. * existent event mask.
  440. *
  441. * @param [in] eloop Allocated and initialized event loop object.
  442. * @param [in] fd File descriptor to change event mask.
  443. * @param [in] events File event to exclude (like POLLIN, POLLOUT).
  444. * @return BOOL_TRUE - success, BOOL_FALSE - error.
  445. */
  446. bool_t faux_eloop_exclude_fd_event(faux_eloop_t *eloop, int fd, short event)
  447. {
  448. faux_eloop_fd_t *entry = NULL;
  449. assert(eloop);
  450. if (!eloop)
  451. return BOOL_FALSE;
  452. assert(fd >= 0);
  453. if (fd < 0)
  454. return BOOL_FALSE;
  455. entry = (faux_eloop_fd_t *)faux_list_kfind(eloop->fds, &fd);
  456. if (!entry)
  457. return BOOL_FALSE;
  458. entry->events = entry->events & (~event);
  459. faux_pollfd_del_by_fd(eloop->pollfds, fd);
  460. faux_pollfd_add(eloop->pollfds, fd, entry->events);
  461. return BOOL_TRUE;
  462. }
  463. /** @brief Unregisters file descriptor.
  464. *
  465. * @param [in] eloop Allocated and initialized event loop object.
  466. * @param [in] fd File descriptor to unregister.
  467. * @return BOOL_TRUE - success, BOOL_FALSE - error.
  468. */
  469. bool_t faux_eloop_del_fd(faux_eloop_t *eloop, int fd)
  470. {
  471. if (!eloop || (fd < 0))
  472. return BOOL_FALSE;
  473. if (!faux_list_kdel(eloop->fds, &fd))
  474. return BOOL_FALSE;
  475. if (!faux_pollfd_del_by_fd(eloop->pollfds, fd))
  476. return BOOL_FALSE;
  477. return BOOL_TRUE;
  478. }
  479. /** @brief Unregisters all file descriptors.
  480. *
  481. * @param [in] eloop Allocated and initialized event loop object.
  482. * @return BOOL_TRUE - success, BOOL_FALSE - error.
  483. */
  484. bool_t faux_eloop_del_fd_all(faux_eloop_t *eloop)
  485. {
  486. faux_list_node_t *iter = NULL;
  487. if (!eloop)
  488. return BOOL_FALSE;
  489. // "Del all" function is so complex because pollfd object
  490. // contains not user added fds only. It contains special fd for signals,
  491. // service pipe and may be something else. So del all fds one by one.
  492. while ((iter = faux_list_tail(eloop->fds))) {
  493. faux_eloop_fd_t *entry = NULL;
  494. entry = (faux_eloop_fd_t *)faux_list_data(iter);
  495. faux_eloop_del_fd(eloop, entry->fd);
  496. }
  497. return BOOL_TRUE;
  498. }
  499. /** @brief Registers signal to wait for.
  500. *
  501. * @param [in] eloop Allocated and initialized event loop object.
  502. * @param [in] signal Signal number to wait for.
  503. * @param [in] event_cb Callback for event.
  504. * @param [in] user_data User data to pass to callback.
  505. * @return BOOL_TRUE - success, BOOL_FALSE - error.
  506. */
  507. bool_t faux_eloop_add_signal(faux_eloop_t *eloop, int signo,
  508. faux_eloop_cb_fn event_cb, void *user_data)
  509. {
  510. faux_eloop_signal_t *entry = NULL;
  511. if (!eloop || (signo < 0))
  512. return BOOL_FALSE;
  513. if (sigismember(&eloop->sig_set, signo) == 1) { // Already exists
  514. // Signal must be reassigned. So remove previous one
  515. if (!faux_eloop_del_signal(eloop, signo))
  516. return BOOL_FALSE;
  517. }
  518. // Firstly try to add signal to sigset. Library function will validate
  519. // signal number value.
  520. if (sigaddset(&eloop->sig_set, signo) < 0)
  521. return BOOL_FALSE; // Invalid signal number
  522. sigdelset(&eloop->sig_mask, signo);
  523. entry = faux_zmalloc(sizeof(*entry));
  524. if (!entry) {
  525. sigdelset(&eloop->sig_set, signo);
  526. sigaddset(&eloop->sig_mask, signo);
  527. return BOOL_FALSE;
  528. }
  529. entry->signo = signo;
  530. entry->context.event_cb = event_cb;
  531. entry->context.user_data = user_data;
  532. if (!faux_list_add(eloop->signals, entry)) {
  533. faux_free(entry);
  534. sigdelset(&eloop->sig_set, signo);
  535. sigaddset(&eloop->sig_mask, signo);
  536. return BOOL_FALSE;
  537. }
  538. if (eloop->working) { // Add signal on the fly
  539. #ifdef HAVE_SIGNALFD
  540. // Reattach signalfd handler with updated sig_set
  541. eloop->signal_fd = signalfd(eloop->signal_fd, &eloop->sig_set,
  542. SIGNALFD_FLAGS);
  543. #else // Standard signals
  544. struct sigaction sig_act = {};
  545. sig_act.sa_flags = 0;
  546. sig_act.sa_mask = eloop->sig_set;
  547. sig_act.sa_handler = &faux_eloop_static_sighandler;
  548. sigaction(signo, &sig_act, &entry->oldact);
  549. #endif
  550. }
  551. return BOOL_TRUE;
  552. }
  553. /** @brief Unregisters signal to wait for.
  554. *
  555. * @param [in] eloop Allocated and initialized event loop object.
  556. * @param [in] signal Signal to unregister.
  557. * @return BOOL_TRUE - success, BOOL_FALSE - error.
  558. */
  559. bool_t faux_eloop_del_signal(faux_eloop_t *eloop, int signo)
  560. {
  561. if (!eloop || (signo < 0))
  562. return BOOL_FALSE;
  563. if (sigismember(&eloop->sig_set, signo) != 1)
  564. return BOOL_FALSE; // Doesn't exist
  565. sigdelset(&eloop->sig_set, signo);
  566. sigaddset(&eloop->sig_mask, signo);
  567. if (eloop->working) { // Del signal on the fly
  568. #ifdef HAVE_SIGNALFD
  569. // Reattach signalfd handler with updated sig_set
  570. eloop->signal_fd = signalfd(eloop->signal_fd, &eloop->sig_set,
  571. SIGNALFD_FLAGS);
  572. #else // Standard signals
  573. faux_eloop_signal_t *sig = faux_list_kfind(eloop->signals, &signo);
  574. sigaction(signo, &sig->oldact, NULL);
  575. #endif
  576. }
  577. faux_list_kdel(eloop->signals, &signo);
  578. return BOOL_TRUE;
  579. }
  580. /** @brief Unregisters all signals to wait for.
  581. *
  582. * @param [in] eloop Allocated and initialized event loop object.
  583. * @return BOOL_TRUE - success, BOOL_FALSE - error.
  584. */
  585. bool_t faux_eloop_del_signal_all(faux_eloop_t *eloop)
  586. {
  587. faux_list_node_t *iter = NULL;
  588. if (!eloop)
  589. return BOOL_FALSE;
  590. // "Del all" function is so complex because signals can be set now
  591. // and deletion is not only removing from list.
  592. // So del all signals one by one.
  593. while ((iter = faux_list_tail(eloop->signals))) {
  594. faux_eloop_signal_t *entry = NULL;
  595. entry = (faux_eloop_signal_t *)faux_list_data(iter);
  596. faux_eloop_del_signal(eloop, entry->signo);
  597. }
  598. return BOOL_TRUE;
  599. }
  600. /** @brief Service function to create new context for event.
  601. *
  602. * @param [in] event_cb Callback for event.
  603. * @param [in] data User data for event.
  604. * @return Allocated context structure or NULL on error.
  605. */
  606. static faux_eloop_context_t *faux_eloop_new_context(
  607. faux_eloop_cb_fn event_cb, void *data)
  608. {
  609. faux_eloop_context_t *context = NULL;
  610. context = faux_zmalloc(sizeof(*context));
  611. assert(context);
  612. if (!context)
  613. return NULL;
  614. context->event_cb = event_cb;
  615. context->user_data = data;
  616. return context;
  617. }
  618. /** @brief Registers scheduled time event. See faux_sched_once().
  619. *
  620. * @param [in] eloop Allocated and initialized event loop object.
  621. * @param [in] time See faux_sched_once().
  622. * @param [in] ev_id See faux_sched_once().
  623. * @param [in] event_cb See faux_sched_once().
  624. * @param [in] data See faux_sched_once().
  625. * @return Pointer to created faux_ev_t object or NULL on error.
  626. */
  627. faux_ev_t *faux_eloop_add_sched_once(faux_eloop_t *eloop, const struct timespec *time,
  628. int ev_id, faux_eloop_cb_fn event_cb, void *data)
  629. {
  630. faux_eloop_context_t *context = NULL;
  631. faux_ev_t *ev = NULL;
  632. assert(eloop);
  633. if (!eloop)
  634. return NULL;
  635. context = faux_eloop_new_context(event_cb, data);
  636. assert(context);
  637. if (!context)
  638. return NULL;
  639. if (!(ev = faux_sched_once(eloop->sched, time, ev_id, context))) {
  640. faux_free(context);
  641. return NULL;
  642. }
  643. faux_ev_set_free_data_cb(ev, faux_free);
  644. return ev;
  645. }
  646. /** @brief Registers scheduled time event. See faux_sched_once_delayed().
  647. *
  648. * @param [in] eloop Allocated and initialized event loop object.
  649. * @param [in] interval See faux_sched_once_delayed().
  650. * @param [in] ev_id See faux_sched_once_delayed().
  651. * @param [in] event_cb See faux_sched_once_delayed().
  652. * @param [in] data See faux_sched_once_delayed().
  653. * @return Pointer to created faux_ev_t object or NULL on error.
  654. */
  655. faux_ev_t *faux_eloop_add_sched_once_delayed(faux_eloop_t *eloop, const struct timespec *interval,
  656. int ev_id, faux_eloop_cb_fn event_cb, void *data)
  657. {
  658. faux_eloop_context_t *context = NULL;
  659. faux_ev_t *ev = NULL;
  660. assert(eloop);
  661. if (!eloop)
  662. return NULL;
  663. context = faux_eloop_new_context(event_cb, data);
  664. assert(context);
  665. if (!context)
  666. return NULL;
  667. if (!(ev = faux_sched_once_delayed(eloop->sched, interval, ev_id, context))) {
  668. faux_free(context);
  669. return NULL;
  670. }
  671. faux_ev_set_free_data_cb(ev, faux_free);
  672. return ev;
  673. }
  674. /** @brief Registers scheduled time event. See faux_sched_periodic().
  675. *
  676. * @param [in] eloop Allocated and initialized event loop object.
  677. * @param [in] time See faux_sched_periodic().
  678. * @param [in] ev_id See faux_sched_periodic().
  679. * @param [in] event_cb See faux_sched_periodic().
  680. * @param [in] data See faux_sched_periodic().
  681. * @param [in] period See faux_sched_periodic().
  682. * @param [in] cycle_num See faux_sched_periodic().
  683. * @return Pointer to created faux_ev_t object or NULL on error.
  684. */
  685. faux_ev_t *faux_eloop_add_sched_periodic(faux_eloop_t *eloop, const struct timespec *time,
  686. int ev_id, faux_eloop_cb_fn event_cb, void *data,
  687. const struct timespec *period, unsigned int cycle_num)
  688. {
  689. faux_eloop_context_t *context = NULL;
  690. faux_ev_t *ev = NULL;
  691. assert(eloop);
  692. if (!eloop)
  693. return NULL;
  694. context = faux_eloop_new_context(event_cb, data);
  695. assert(context);
  696. if (!context)
  697. return NULL;
  698. if (!(ev = faux_sched_periodic(eloop->sched, time, ev_id, context,
  699. period, cycle_num))) {
  700. faux_free(context);
  701. return NULL;
  702. }
  703. faux_ev_set_free_data_cb(ev, faux_free);
  704. return ev;
  705. }
  706. /** @brief Registers scheduled time event. See faux_sched_periodic_delayed().
  707. *
  708. * @param [in] eloop Allocated and initialized event loop object.
  709. * @param [in] ev_id See faux_sched_periodic_delayed().
  710. * @param [in] event_cb See faux_sched_periodic_delayed().
  711. * @param [in] data See faux_sched_periodic_delayed().
  712. * @param [in] period See faux_sched_periodic_delayed().
  713. * @param [in] cycle_num See faux_sched_periodic_delayed().
  714. * @return Pointer to created faux_ev_t object or NULL on error.
  715. */
  716. faux_ev_t *faux_eloop_add_sched_periodic_delayed(faux_eloop_t *eloop,
  717. int ev_id, faux_eloop_cb_fn event_cb, void *data,
  718. const struct timespec *period, unsigned int cycle_num)
  719. {
  720. faux_eloop_context_t *context = NULL;
  721. faux_ev_t *ev = NULL;
  722. assert(eloop);
  723. if (!eloop)
  724. return NULL;
  725. context = faux_eloop_new_context(event_cb, data);
  726. assert(context);
  727. if (!context)
  728. return NULL;
  729. if (!(ev = faux_sched_periodic_delayed(eloop->sched, ev_id, context,
  730. period, cycle_num))) {
  731. faux_free(context);
  732. return NULL;
  733. }
  734. faux_ev_set_free_data_cb(ev, faux_free);
  735. return ev;
  736. }
  737. /** @brief Unregisters scheduled time event.
  738. *
  739. * @param [in] eloop Allocated and initialized event loop object.
  740. * @param [in] ev Event object to unregister.
  741. * @return Number of unregistered entries or < 0 on error.
  742. */
  743. ssize_t faux_eloop_del_sched(faux_eloop_t *eloop, faux_ev_t *ev)
  744. {
  745. assert(eloop);
  746. if (!eloop)
  747. return -1;
  748. return faux_sched_del(eloop->sched, ev);
  749. }
  750. /** @brief Unregisters all scheduled time events.
  751. *
  752. * @param [in] eloop Allocated and initialized event loop object.
  753. * @return BOOL_TRUE - success, BOOL_FALSE - error.
  754. */
  755. bool_t faux_eloop_del_sched_all(faux_eloop_t *eloop)
  756. {
  757. assert(eloop);
  758. if (!eloop)
  759. return BOOL_FALSE;
  760. faux_sched_del_all(eloop->sched);
  761. return BOOL_TRUE;
  762. }
  763. /** @brief Unregisters scheduled time event by event ID.
  764. *
  765. * @param [in] eloop Allocated and initialized event loop object.
  766. * @param [in] ev_id Event ID to unregister.
  767. * @return Number of unregistered entries or < 0 on error.
  768. */
  769. ssize_t faux_eloop_del_sched_by_id(faux_eloop_t *eloop, int ev_id)
  770. {
  771. assert(eloop);
  772. if (!eloop)
  773. return -1;
  774. return faux_sched_del_by_id(eloop->sched, ev_id);
  775. }