Skip to content

Instantly share code, notes, and snippets.

@mppf
Created September 29, 2021 17:17
Show Gist options
  • Save mppf/4bf1c0c78309107b887234986c341d39 to your computer and use it in GitHub Desktop.
Save mppf/4bf1c0c78309107b887234986c341d39 to your computer and use it in GitHub Desktop.
libevent timeout across multiple event_add
/*
Program to demonstrate managing total timeout across many
event_add calls.
It accepts input on stdin for 2 seconds and demonstrates running
for 2 seconds whether there is input or not.
*/
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>
static void callback(evutil_socket_t, short, void *);
struct mystate {
struct event_base *base;
struct event *e;
struct timeval start_time;
struct timeval timeout;
};
void setnonblocking(int fd) {
int opt;
opt = fcntl(fd, F_GETFL);
if (opt < 0) {
printf("fcntl(F_GETFL) fail.");
}
opt |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, opt) < 0) {
printf("fcntl(F_SETFL) fail.");
}
}
int
main(int argc, char **argv)
{
struct mystate s = {0};
setbuf(stdin, NULL);
setnonblocking(0);
s.base = event_base_new();
if (!s.base) {
fprintf(stderr, "Could not initialize libevent!\n");
return 1;
}
s.e = event_new(s.base, /* stdin */ 0, EV_READ, callback, &s);
s.timeout.tv_sec = 2;
event_base_gettimeofday_cached(s.base, &s.start_time);
event_add(s.e, &s.timeout);
event_base_dispatch(s.base);
return 0;
}
static
int timeval_subtract(struct timeval *result,
struct timeval *x,
struct timeval *y)
{
result->tv_sec = x->tv_sec - y->tv_sec;
if ((result->tv_usec = x->tv_usec - y->tv_usec) < 0)
{
result->tv_usec += 1000000;
result->tv_sec--; // borrow
}
return result->tv_sec < 0;
}
static void
callback(evutil_socket_t sig, short events, void *user_data)
{
struct mystate* s = (struct mystate*) user_data;
unsigned char buf[64];
ssize_t got = 0;
struct timeval now = {0};
struct timeval elapsed = {0};
struct timeval remaining = {0};
event_base_gettimeofday_cached(s->base, &now);
if ((events & EV_TIMEOUT) != 0) {
printf("callback for timeout -- breaking\n");
event_base_loopbreak(s->base);
} else {
printf("callback for read\n");
// read some data
got = read(0, buf, sizeof(buf));
// compute how much time is left and schedule an event
timeval_subtract(&elapsed, &now, &s->start_time);
timeval_subtract(&remaining, &s->timeout, &elapsed);
if (remaining.tv_sec < 0) {
remaining.tv_sec = 0;
remaining.tv_usec = 0;
}
printf("remaining usecs: %li\n",
((long int)remaining.tv_sec)*1000000 + remaining.tv_usec);
event_add(s->e, &remaining);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment