diff options
author | Simon Rettberg | 2016-02-10 14:26:54 +0100 |
---|---|---|
committer | Simon Rettberg | 2016-02-10 14:26:54 +0100 |
commit | d50c437a65028f95aa72162004f2b61f64131a50 (patch) | |
tree | fa52c4e0a79e01795a8fc547b83084a5c2941b52 /src/shared/fdsignal.inc/eventfd.c | |
parent | dfskljgdslkfsdklgj (diff) | |
download | dnbd3-d50c437a65028f95aa72162004f2b61f64131a50.tar.gz dnbd3-d50c437a65028f95aa72162004f2b61f64131a50.tar.xz dnbd3-d50c437a65028f95aa72162004f2b61f64131a50.zip |
[SHARED] signal.h -> fdsignal.h
Diffstat (limited to 'src/shared/fdsignal.inc/eventfd.c')
-rw-r--r-- | src/shared/fdsignal.inc/eventfd.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/shared/fdsignal.inc/eventfd.c b/src/shared/fdsignal.inc/eventfd.c new file mode 100644 index 0000000..b4d4d6e --- /dev/null +++ b/src/shared/fdsignal.inc/eventfd.c @@ -0,0 +1,74 @@ +#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; +} + |