Async linux demo¶
This example showcases a number of different things:
Emitting signals
Using a state condition guard
De-coupling the state machine with a thread safe queue
Timer events using linux’s timerfd
Event queue using linux’s signalfd
epoll -based main event loop
This example uses a ‘private context’ for the machine:
struct private_ctx {
struct ufsm_queue *q;
struct ufsm_timer tmr, tmr_exit;
int epoll_fd;
bool run;
};
This is passed to all action functions through the ‘context’ parameter.
Main loop:
/* Initialize the queue to hold 128 int's */
q = ufsm_queue_init(priv.epoll_fd, 128);
priv.q = q;
ufsm_timer_init(&priv.tmr, priv.epoll_fd, q, 1500, eEnable);
ufsm_timer_init(&priv.tmr_exit, priv.epoll_fd, q, 5000, eExitTimerExpired);
linux_async_init(&m, &priv);
linux_async_process(&m, UFSM_RESET);
for (;;) {
int no_of_fds = epoll_wait(priv.epoll_fd, events, MAX_EVENTS, -1);
if (no_of_fds == -1) {
fprintf(stderr, "epoll_wait failed\n");
rc = -1;
goto err_free_timers_out;
}
for (int n = 0; n < no_of_fds; n++) {
int fd = events[n].data.fd;
if (ufsm_timer_get_fd(&priv.tmr) == fd) {
ufsm_timer_handle(&priv.tmr);
} else if (ufsm_timer_get_fd(&priv.tmr_exit) == fd) {
ufsm_timer_handle(&priv.tmr_exit);
} else if (ufsm_queue_get_fd(q) == fd) {
uint64_t no_of_queue_events;
if (ufsm_queue_handle(q, &no_of_queue_events) != 0) {
fprintf(stderr, "Failed to read queue events\n");
priv.run = false;
rc = -1;
break;
}
for (int i = 0; i < no_of_queue_events; i++) {
assert(linux_async_process(&m, ufsm_queue_pop(q)) == 0);
}
}
}
if (!priv.run) {
printf("Exiting...\n");
break;
}
}
The queue, timers and the state machine are initialized. The ‘tmr’ timer is used to send the event ‘eEnable’ after 1500 ms.
The ‘tmr_exit’ timer will send ‘eExitTimerExpired’ after 5000ms and terminating the program.
The queue uses a signalfd ‘object’ to wake up the epoll when there are new events in the queue.
Source code: examples/linux