From 627645acc074eab7a3694a267bc2a643d8b3e57a Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Fri, 5 Feb 2016 15:05:30 +0100 Subject: First steps in make signals more abstract from the underlying mechanism; replace epoll with poll. We now don't assume that a signal equals a single fd (eventfd on Linux). The next step would be to create a version of signal.c that uses a pipe internally, so it can be used on other platforms, like *BSD. This is also the reason epoll was replaced with poll in uplink.c --- src/shared/signal.c | 42 ++++++++++++++++++++++++++++++++---------- src/shared/signal.h | 31 ++++++++++++++++++++----------- 2 files changed, 52 insertions(+), 21 deletions(-) (limited to 'src/shared') diff --git a/src/shared/signal.c b/src/shared/signal.c index a0697f8..e023c49 100644 --- a/src/shared/signal.c +++ b/src/shared/signal.c @@ -5,25 +5,38 @@ #include #include -int signal_new() +/* + * 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() { - return eventfd( 0, EFD_NONBLOCK ); + // 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 ); } -int signal_newBlocking() +dnbd3_signal_t* signal_newBlocking() { - return eventfd( 0, 0 ); + return (dnbd3_signal_t*)(intptr_t)( eventfd( 0, 0 ) + 1 ); } -int signal_call(int signalFd) +int signal_call(const dnbd3_signal_t* const signal) { - if ( signalFd < 0 ) return 0; + 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(int signalFd, int timeoutMs) +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 @@ -32,12 +45,14 @@ int signal_wait(int signalFd, int timeoutMs) if ( ret == 0 ) return SIGNAL_TIMEOUT; if ( ret == -1 ) return SIGNAL_ERROR; if ( ps.revents & ( POLLERR | POLLNVAL ) ) return SIGNAL_ERROR; - return signal_clear( signalFd ); + return signal_clear( signal ); } -int signal_clear(int signalFd) +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; @@ -45,8 +60,15 @@ int signal_clear(int signalFd) return (int)ret; } -void signal_close(int signalFd) +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; +} + diff --git a/src/shared/signal.h b/src/shared/signal.h index 6fd2765..3eea6fb 100644 --- a/src/shared/signal.h +++ b/src/shared/signal.h @@ -5,23 +5,25 @@ #define SIGNAL_TIMEOUT (-2) #define SIGNAL_ERROR (-1) +typedef struct _dnbd3_signal dnbd3_signal_t; + /** - * Create a new signal fd (eventfd), nonblocking. - * @return >= 0 on success, which is the fd; < 0 on error + * Create a new signal, nonblocking. + * @return NULL on error, pointer to dnbd3_signal_t on success. */ -int signal_new(); +dnbd3_signal_t* signal_new(); /** - * Create a new signal fd (eventfd), blocking. - * @return >= 0 on success, which is the fd; < 0 on error + * Create a new signal, blocking. + * @return NULL on error, pointer to dnbd3_signal_t on success. */ -int signal_newBlocking(); +dnbd3_signal_t* signal_newBlocking(); /** * Trigger the given signal, so a wait or clear call will succeed. * @return SIGNAL_OK on success, SIGNAL_ERROR on error */ -int signal_call(int signalFd); +int signal_call(const dnbd3_signal_t* const signal); /** * Wait for given signal, with an optional timeout. @@ -31,18 +33,25 @@ int signal_call(int signalFd); * SIGNAL_TIMEOUT if the timeout was reached, * SIGNAL_ERROR if some error occured */ -int signal_wait(int signalFd, int timeoutMs); +int signal_wait(const dnbd3_signal_t* const signal, int timeoutMs); /** - * Clears any pending signals on this signal fd. + * Clears any pending signals on this signal. * @return number of signals that were pending, * SIGNAL_ERROR if some error occured */ -int signal_clear(int signalFd); +int signal_clear(const dnbd3_signal_t* const signal); /** * Close the given signal. */ -void signal_close(int signalFd); +void signal_close(const dnbd3_signal_t* const signal); + +/** + * Get a file descriptor for the given signal that can be + * waited on using poll or similar. + * @return -1 if the signal is invalid + */ +int signal_getWaitFd(const dnbd3_signal_t* const signal); #endif -- cgit v1.2.3-55-g7522