summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2019-08-27 23:20:20 +0200
committerSimon Rettberg2019-08-27 23:20:20 +0200
commitff228ee519c27bb80234e6eadbf9cbe1adda4318 (patch)
treeea8b66f2ec6c6bab0f7cd5fdab30ab60fa9a6214
parent[SERVER] Fix swapped assignment (diff)
downloaddnbd3-ff228ee519c27bb80234e6eadbf9cbe1adda4318.tar.gz
dnbd3-ff228ee519c27bb80234e6eadbf9cbe1adda4318.tar.xz
dnbd3-ff228ee519c27bb80234e6eadbf9cbe1adda4318.zip
[SERVER] Add timer infrastructure
To be used by "close unused fd" checks, and others...
-rw-r--r--src/server/server.c142
-rw-r--r--src/server/server.h2
2 files changed, 134 insertions, 10 deletions
diff --git a/src/server/server.c b/src/server/server.c
index 922740a..1cdd2ab 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -45,6 +45,25 @@
#define LONGOPT_SIZE 1004
#define LONGOPT_ERRORMSG 1005
+typedef struct _job job_t;
+
+struct _job {
+ job_t *next;
+ void *(*startRoutine)(void *);
+ void *arg;
+ ticks dueDate;
+ int intervalSecs;
+};
+
+static job_t *jobHead;
+static _Atomic(job_t *) newJob;
+static bool hasTimerThread = false;
+static pthread_t timerThread;
+
+static pthread_t mainThread;
+
+#define DEFAULT_TIMER_TIMEOUT (60)
+
static poll_list_t *listeners = NULL;
/**
@@ -71,6 +90,12 @@ static void dnbd3_handleSignal2(int signum, siginfo_t *info, void *data);
static void* server_asyncImageListLoad(void *data);
+static void* timerMainloop(void*);
+
+static int handlePendingJobs(void);
+
+static void queueJobInternal(job_t *job);
+
/**
* Print help text for usage instructions
*/
@@ -105,14 +130,21 @@ void dnbd3_printVersion()
/**
* Clean up structs, connections, write out data, then exit
*/
-void dnbd3_cleanup()
+_Noreturn static void dnbd3_cleanup()
{
int retries;
_shutdown = true;
logadd( LOG_INFO, "Cleanup..." );
- if ( listeners != NULL ) sock_destroyPollList( listeners );
+ if ( hasTimerThread ) {
+ pthread_kill( timerThread, SIGHUP );
+ thread_join( timerThread, NULL );
+ }
+
+ if ( listeners != NULL ) {
+ sock_destroyPollList( listeners );
+ }
listeners = NULL;
// Kill connection to all clients
@@ -172,6 +204,7 @@ int main(int argc, char *argv[])
{ 0, 0, 0, 0 }
};
+ mainThread = pthread_self();
opt = getopt_long( argc, argv, optString, longOpts, &longIndex );
while ( opt != -1 ) {
@@ -195,8 +228,12 @@ int main(int argc, char *argv[])
case LONGOPT_CRC4:
return image_generateCrcFile( optarg ) ? 0 : EXIT_FAILURE;
case LONGOPT_ASSERT:
+ printf( "Now leaking memory:\n" );
+ char *bla = malloc( 10 );
+ bla[2] = 3;
+ bla = NULL;
printf( "Testing use after free:\n" );
- volatile char * volatile test = malloc( 10 );
+ char *test = malloc( 10 );
test[0] = 1;
free( (void*)test );
test[1] = 2;
@@ -303,11 +340,10 @@ int main(int argc, char *argv[])
}
// setup signal handler
- struct sigaction sa;
- memset( &sa, 0, sizeof(sa) );
- sa.sa_sigaction = dnbd3_handleSignal2;
- sa.sa_flags = SA_SIGINFO;
- //sa.sa_mask = ;
+ struct sigaction sa = {
+ .sa_sigaction = dnbd3_handleSignal2,
+ .sa_flags = SA_SIGINFO,
+ };
sigaction( SIGTERM, &sa, NULL );
sigaction( SIGINT, &sa, NULL );
sigaction( SIGUSR1, &sa, NULL );
@@ -342,6 +378,10 @@ int main(int argc, char *argv[])
logadd( LOG_INFO, "Server is ready. (%s)", VERSION_STRING );
+ if ( thread_create( &timerThread, NULL, &timerMainloop, NULL ) == 0 ) {
+ hasTimerThread = true;
+ }
+
// +++++++++++++++++++++++++++++++++++++++++++++++++++ main loop
struct sockaddr_storage client;
socklen_t len;
@@ -365,7 +405,7 @@ int main(int argc, char *argv[])
//
len = sizeof(client);
fd = sock_accept( listeners, &client, &len );
- if ( fd < 0 ) {
+ if ( fd == -1 ) {
const int err = errno;
if ( err == EINTR || err == EAGAIN ) continue;
logadd( LOG_ERROR, "Client accept failure (err=%d)", err );
@@ -469,6 +509,8 @@ static void dnbd3_handleSignal(int signum)
static void dnbd3_handleSignal2(int signum, siginfo_t *info, void *data UNUSED)
{
+ if ( !pthread_equal( pthread_self(), mainThread ) )
+ return;
memcpy( &lastSignal, info, sizeof(siginfo_t) );
dnbd3_handleSignal( signum );
}
@@ -488,3 +530,85 @@ static void* server_asyncImageListLoad(void *data UNUSED)
return NULL;
}
+static void* timerMainloop(void* stuff UNUSED)
+{
+ setThreadName( "timer" );
+ while ( !_shutdown ) {
+ // Handle jobs/timer events; returns timeout until next event
+ int to = handlePendingJobs();
+ sleep( MIN( MAX( 1, to ), DEFAULT_TIMER_TIMEOUT ) );
+ }
+ logadd( LOG_DEBUG1, "Timer thread done" );
+ return NULL;
+}
+
+static int handlePendingJobs(void)
+{
+ declare_now;
+ job_t *todo, **temp, *old;
+ int diff;
+ todo = jobHead;
+ for ( temp = &todo; *temp != NULL; temp = &(*temp)->next ) {
+ diff = (int)timing_diff( &now, &(*temp)->dueDate );
+ if ( diff > 0 ) // Found one that's in the future
+ break;
+ }
+ jobHead = *temp; // Make it list head
+ *temp = NULL; // Split off part before that
+ while ( todo != NULL ) {
+ threadpool_run( todo->startRoutine, todo->arg );
+ old = todo;
+ todo = todo->next;
+ if ( old->intervalSecs == 0 ) {
+ free( old ); // oneshot
+ } else {
+ timing_set( &old->dueDate, &now, old->intervalSecs );
+ queueJobInternal( old ); // repeated
+ }
+ }
+ // See if any new jobs have been queued
+ while ( newJob != NULL ) {
+ todo = newJob;
+ // NULL should never happen since we're the only consumer
+ assert( todo != NULL );
+ if ( !atomic_compare_exchange_weak( &newJob, &todo, NULL ) )
+ continue;
+ do {
+ old = todo;
+ todo = todo->next;
+ queueJobInternal( old );
+ } while ( todo != NULL );
+ }
+ // Return new timeout
+ if ( jobHead == NULL )
+ return DEFAULT_TIMER_TIMEOUT;
+ return (int)timing_diff( &now, &jobHead->dueDate );
+}
+
+static void queueJobInternal(job_t *job)
+{
+ assert( job != NULL );
+ job_t **it;
+ for ( it = &jobHead; *it != NULL; it = &(*it)->next ) {
+ if ( timing_1le2( &job->dueDate, &(*it)->dueDate ) )
+ break;
+ }
+ job->next = *it;
+ *it = job;
+}
+
+void server_addJob(void *(*startRoutine)(void *), void *arg, int delaySecs, int intervalSecs)
+{
+ declare_now;
+ job_t *new = malloc( sizeof(*new) );
+ new->startRoutine = startRoutine;
+ new->arg = arg;
+ new->intervalSecs = intervalSecs;
+ timing_set( &new->dueDate, &now, delaySecs );
+ for ( ;; ) {
+ new->next = newJob;
+ if ( atomic_compare_exchange_weak( &newJob, &new->next, new ) )
+ break;
+ }
+}
+
diff --git a/src/server/server.h b/src/server/server.h
index bab8421..a026eb6 100644
--- a/src/server/server.h
+++ b/src/server/server.h
@@ -24,8 +24,8 @@
#include "globals.h"
#include "../types.h"
-void dnbd3_cleanup();
uint32_t dnbd3_serverUptime();
+void server_addJob(void *(*startRoutine)(void *), void *arg, int delaySecs, int intervalSecs);
#if !defined(_FILE_OFFSET_BITS) || _FILE_OFFSET_BITS != 64
#error Please set _FILE_OFFSET_BITS to 64 in your makefile/configuration