From c17843a200ffd70903d3f7170883d671bafc80af Mon Sep 17 00:00:00 2001
From: Jan Vcelak <jan.vcelak@nic.cz>
Date: Fri, 12 Sep 2014 13:33:15 +0200
Subject: [PATCH] suspend background workers during reload

refs #296
---
 src/knot/server/server.c |  8 +++++---
 src/knot/worker/pool.c   | 30 +++++++++++++++++++++++++++++-
 src/knot/worker/pool.h   | 10 ++++++++++
 src/knot/zone/events.c   |  2 +-
 4 files changed, 45 insertions(+), 5 deletions(-)

diff --git a/src/knot/server/server.c b/src/knot/server/server.c
index d36ddd57a..a165b5a77 100644
--- a/src/knot/server/server.c
+++ b/src/knot/server/server.c
@@ -588,12 +588,13 @@ int server_update_zones(const struct conf_t *conf, void *data)
 {
 	server_t *server = (server_t *)data;
 
-	/* Prevent new events on zones waiting to be replaced. */
+	/* Prevent emitting of new zone events. */
 	if (server->zone_db) {
 		knot_zonedb_foreach(server->zone_db, zone_events_freeze);
 	}
 
-	/* Finish operations already in the queue. */
+	/* Suspend workers, clear wating events, finish running events. */
+	worker_pool_suspend(server->workers);
 	worker_pool_clear(server->workers);
 	worker_pool_wait(server->workers);
 
@@ -603,7 +604,8 @@ int server_update_zones(const struct conf_t *conf, void *data)
 	/* Trim extra heap. */
 	mem_trim();
 
-	/* Plan events on new zones. */
+	/* Resume workers and allow events on new zones. */
+	worker_pool_resume(server->workers);
 	if (server->zone_db) {
 		knot_zonedb_foreach(server->zone_db, zone_events_start);
 	}
diff --git a/src/knot/worker/pool.c b/src/knot/worker/pool.c
index aede4e9aa..ac71deadf 100644
--- a/src/knot/worker/pool.c
+++ b/src/knot/worker/pool.c
@@ -35,6 +35,7 @@ struct worker_pool {
 	pthread_cond_t wake;
 
 	bool terminating;	/*!< Is the pool terminating? .*/
+	bool suspended;		/*!< Is execution temporarily suspended? .*/
 	int running;		/*!< Number of running threads. */
 	worker_queue_t tasks;
 };
@@ -61,7 +62,11 @@ static int worker_main(dthread_t *thread)
 			break;
 		}
 
-		task_t *task = worker_queue_dequeue(&pool->tasks);
+		task_t *task = NULL;
+		if (!pool->suspended) {
+			task = worker_queue_dequeue(&pool->tasks);
+		}
+
 		if (task == NULL) {
 			pthread_cond_wait(&pool->wake, &pool->lock);
 			continue;
@@ -162,6 +167,29 @@ void worker_pool_stop(worker_pool_t *pool)
 	dt_stop(pool->threads);
 }
 
+void worker_pool_suspend(worker_pool_t *pool)
+{
+	if (!pool) {
+		return;
+	}
+
+	pthread_mutex_lock(&pool->lock);
+	pool->suspended = true;
+	pthread_mutex_unlock(&pool->lock);
+}
+
+void worker_pool_resume(worker_pool_t *pool)
+{
+	if (!pool) {
+		return;
+	}
+
+	pthread_mutex_lock(&pool->lock);
+	pool->suspended = false;
+	pthread_cond_broadcast(&pool->wake);
+	pthread_mutex_unlock(&pool->lock);
+}
+
 void worker_pool_join(worker_pool_t *pool)
 {
 	if (!pool) {
diff --git a/src/knot/worker/pool.h b/src/knot/worker/pool.h
index fcaae2880..424b5b11c 100644
--- a/src/knot/worker/pool.h
+++ b/src/knot/worker/pool.h
@@ -45,6 +45,16 @@ void worker_pool_start(worker_pool_t *pool);
  */
 void worker_pool_stop(worker_pool_t *pool);
 
+/*!
+ * \brief Temporarily suspend the execution of worker pool.
+ */
+void worker_pool_suspend(worker_pool_t *pool);
+
+/*!
+ * \brief Resume the execution of worker pool.
+ */
+void worker_pool_resume(worker_pool_t *pool);
+
 /*!
  * \brief Wait for all threads to terminate.
  */
diff --git a/src/knot/zone/events.c b/src/knot/zone/events.c
index 1235dad54..0252eeb77 100644
--- a/src/knot/zone/events.c
+++ b/src/knot/zone/events.c
@@ -921,7 +921,7 @@ void zone_events_enqueue(zone_t *zone, zone_event_type_t type)
 
 	pthread_mutex_lock(&events->mx);
 
-	/* Possible only if no event is running at the moment. */
+	/* Bypass scheduler if no event is running. */
 	if (!events->running && !events->frozen) {
 		events->running = true;
 		event_set_time(events, type, ZONE_EVENT_IMMEDIATE);
-- 
GitLab