summaryrefslogblamecommitdiffstats
path: root/src/shared/signal.inc/eventfd.c
blob: b4d4d6e34e804ba06da1c2bea24192115344c38a (plain) (tree)









































































                                                                                            
#include <sys/eventfd.h>
#include <poll.h>
#include <inttypes.h>
#include <errno.h>
#include <unistd.h>

/*
 * Linux implementation of signals.
 * Internally, eventfds are used for signalling, as they
 * provide the least overhead. We don't allocate any struct
 * ever, but cast the event fd+1 to dnbd3_signal_t*
 * to save all the malloc() and free() calls.
 */

dnbd3_signal_t* signal_new()
{
	// On error, eventfd() returns -1, so essentially we return NULL on error.
	// (Yes, NULL doesn't have to be 0 everywhere, but cmon)
	return (dnbd3_signal_t*)(intptr_t)( eventfd( 0, EFD_NONBLOCK ) + 1 );
}

dnbd3_signal_t* signal_newBlocking()
{
	return (dnbd3_signal_t*)(intptr_t)( eventfd( 0, 0 ) + 1 );
}

int signal_call(const dnbd3_signal_t* const signal)
{
	if ( signal == NULL ) return SIGNAL_ERROR;
	static uint64_t one = 1;
	const int signalFd = ( (int)(intptr_t)signal ) - 1;
	return write( signalFd, &one, sizeof one ) == sizeof one ? SIGNAL_OK : SIGNAL_ERROR;
}

int signal_wait(const dnbd3_signal_t* const signal, int timeoutMs)
{
	if ( signal == NULL ) return SIGNAL_ERROR;
	const int signalFd = ( (int)(intptr_t)signal ) - 1;
	struct pollfd ps = {
		.fd = signalFd,
		.events = POLLIN
	};
	int ret = poll( &ps, 1, timeoutMs );
	if ( ret == 0 ) return SIGNAL_TIMEOUT;
	if ( ret == -1 ) return SIGNAL_ERROR;
	if ( ps.revents & ( POLLERR | POLLNVAL ) ) return SIGNAL_ERROR;
	return signal_clear( signal );
}

int signal_clear(const dnbd3_signal_t* const signal)
{
	if ( signal == NULL ) return SIGNAL_ERROR;
	uint64_t ret;
	const int signalFd = ( (int)(intptr_t)signal ) - 1;
	if ( read( signalFd, &ret, sizeof ret ) != sizeof ret ) {
		if ( errno == EAGAIN ) return 0;
		return SIGNAL_ERROR;
	}
	return (int)ret;
}

void signal_close(const dnbd3_signal_t* const signal)
{
	const int signalFd = ( (int)(intptr_t)signal ) - 1;
	close( signalFd );
}

int signal_getWaitFd(const dnbd3_signal_t* const signal)
{
	if ( signal == NULL ) return -1;
	const int signalFd = ( (int)(intptr_t)signal ) - 1;
	return signalFd;
}