Fruit's git repositories f00f / presence event.c
presence

Tree @presence (Download .tar.gz)

event.c @presenceraw · history · blame

#include <stdlib.h>
#include <inttypes.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/poll.h>

#include "error.h"
#include "event.h"
#include "hook.h"
#include "safeio.h"
#include "tab.h"
#include "worker.h"

extern int eventfd(unsigned int initval, int flags);

HOOK_USE(event);

static void event_run(const char *event, const char *type) {
	event_t e;

	e.event = event;
	e.type = type;

	hook_call(event_hook, &e);
}

static int fd = -1;

static void *event_worker(void *_) {
	mpool_t *p;
	s64 delay;
	struct db *db;
	char *event, *type;
	s64 pause = 0;
	uint64_t num = 0;

	p = mpool_new(NULL);
	worker_tmp_set(p);

	for(;;) {
		delay = INT64_MIN;

		db = db_begin(p);
		db_event_timetonext(db, &delay);
		mpool_clear(p);

		if(delay < 0)
			delay = 0;
		else if(delay > 60000000)
			delay = 60000000;

		if(safepoll(fd, POLLIN, delay) && read(fd, &num, sizeof num) == -1) {
			if(errno != EINTR)
				break;
			sleep(++pause);
			continue;
		}

		db = db_begin(p);
		while(db_event_nextexpired(db, &event, &type) && event) {
			event_run(event, type);
			if(!db_event_del(db, event))
				break;
		}

		if(db_commit(db)) {
			mpool_clear(p);
			pause = 0;
		} else {
			eputs("event transaction failed, sleeping");
			mpool_clear(p);
			sleep(++pause);
		}
	}

	worker_tmp_del();

	return NULL;
}

static void event_notify(void) {
	uint64_t een = 1;
	write(fd, &een, sizeof een);
}

static pthread_t draadje;

__attribute__((constructor))
static void event_init(void) {
	fd = eventfd(0, 0);
	if(fd == -1)
		perror_exit("eventfd()");

	pthread_create(&draadje, NULL, event_worker, NULL);
}

__attribute__((destructor))
static void event_exit(void) {
	int i = fd;
	if(i != -1) {
		fd = -1;
		close(i);
		pthread_join(draadje, NULL);
	}
}

static tab_entry_t notify_tab_entries[] = {
	{"events", event_notify},
};

TAB_REGISTER(notify);