summaryrefslogtreecommitdiffstats
path: root/src/shared
diff options
context:
space:
mode:
authorSimon Rettberg2016-02-05 15:05:30 +0100
committerSimon Rettberg2016-02-05 15:05:30 +0100
commit627645acc074eab7a3694a267bc2a643d8b3e57a (patch)
tree5f61225803c369ab1295ce0ee36a33ae6cb51eb8 /src/shared
parent[SERVER] BREAKING: Get rid of pseudo case-insensitivity (diff)
downloaddnbd3-627645acc074eab7a3694a267bc2a643d8b3e57a.tar.gz
dnbd3-627645acc074eab7a3694a267bc2a643d8b3e57a.tar.xz
dnbd3-627645acc074eab7a3694a267bc2a643d8b3e57a.zip
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
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/signal.c42
-rw-r--r--src/shared/signal.h31
2 files changed, 52 insertions, 21 deletions
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 <errno.h>
#include <unistd.h>
-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