summaryrefslogblamecommitdiffstats
path: root/src/shared/signal.c
blob: e023c49e3dcd2675f9fbf182a4b50c158d625ca4 (plain) (tree)
1
2
3
4
5
6
7






                        








                                                           
 


                                                                                  

 
                                    
 
                                                                  

 
                                                   
 
                                                  
                                
                                                           


                                                                 
                                                                  
 

                                                           







                                                                       
                                      

 
                                                    
 
                                                  
                     
                                                           






                                                                 
                                                     
 
                                                           


                          





                                                           
#include "signal.h"
#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;
}

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)
{
	const int signalFd = ( (int)(intptr_t)signal ) - 1;
	return signalFd;
}