r929 - trunk/varnish-cache/bin/varnishd

phk at projects.linpro.no phk at projects.linpro.no
Wed Sep 6 21:35:33 CEST 2006


Author: phk
Date: 2006-09-06 21:35:33 +0200 (Wed, 06 Sep 2006)
New Revision: 929

Modified:
   trunk/varnish-cache/bin/varnishd/cache.h
   trunk/varnish-cache/bin/varnishd/cache_pool.c
Log:
Reduce traffic on the wrk_mtx, saving some syscalls along the way:

Make a thread-reaper-thread which examines the tail end of the queue
and kicks threads which are too old so the wake up and die.

This allows us to assume that a thread on the free queue is always
waiting on its condvar, so we don't need to hold the mutex when we
signal the condvar.

As a result, the woken thread stands a chance to grab the mutex
and a little song and dance between the two threads is avoided.



Modified: trunk/varnish-cache/bin/varnishd/cache.h
===================================================================
--- trunk/varnish-cache/bin/varnishd/cache.h	2006-09-06 19:08:06 UTC (rev 928)
+++ trunk/varnish-cache/bin/varnishd/cache.h	2006-09-06 19:35:33 UTC (rev 929)
@@ -99,7 +99,8 @@
 	struct objhead		*nobjhead;
 	struct object		*nobj;
 
-	unsigned		nbr;
+	time_t			idle;
+
 	pthread_cond_t		cv;
 	TAILQ_ENTRY(worker)	list;
 	struct workreq		*wrq;

Modified: trunk/varnish-cache/bin/varnishd/cache_pool.c
===================================================================
--- trunk/varnish-cache/bin/varnishd/cache_pool.c	2006-09-06 19:08:06 UTC (rev 928)
+++ trunk/varnish-cache/bin/varnishd/cache_pool.c	2006-09-06 19:35:33 UTC (rev 929)
@@ -25,8 +25,10 @@
 /* Number of work requests queued in excess of worker threads available */
 static unsigned		wrk_overflow;
 
-static TAILQ_HEAD(, worker) wrk_idle = TAILQ_HEAD_INITIALIZER(wrk_idle);
-static TAILQ_HEAD(, worker) wrk_busy = TAILQ_HEAD_INITIALIZER(wrk_busy);
+TAILQ_HEAD(workerhead, worker);
+
+static struct workerhead wrk_idle = TAILQ_HEAD_INITIALIZER(wrk_idle);
+static struct workerhead wrk_busy = TAILQ_HEAD_INITIALIZER(wrk_busy);
 static TAILQ_HEAD(, workreq) wrk_reqhead = TAILQ_HEAD_INITIALIZER(wrk_reqhead);
 
 /*--------------------------------------------------------------------
@@ -150,6 +152,7 @@
 	if (w->nobjhead != NULL)
 		CHECK_OBJ(w->nobjhead, OBJHEAD_MAGIC);
 	w->wrq = NULL;
+	w->idle = time(NULL);
 	LOCK(&wrk_mtx);
 	VSL_stats->n_wrk_busy--;
 }
@@ -158,19 +161,17 @@
 wrk_thread(void *priv)
 {
 	struct worker *w, ww;
-	struct timespec ts;
 
 	(void)priv;
 	w = &ww;
 	memset(w, 0, sizeof *w);
 	w->magic = WORKER_MAGIC;
-
+	w->idle = time(NULL);
 	AZ(pthread_cond_init(&w->cv, NULL));
 
+	VSL(SLT_WorkThread, 0, "%p start", w);
 	LOCK(&wrk_mtx);
-	w->nbr = VSL_stats->n_wrk;
 	VSL_stats->n_wrk_create++;
-	VSL(SLT_WorkThread, 0, "%u born", w->nbr);
 	TAILQ_INSERT_HEAD(&wrk_busy, w, list);
 	while (1) {
 		CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
@@ -184,27 +185,17 @@
 		
 		TAILQ_REMOVE(&wrk_busy, w, list);
 		TAILQ_INSERT_HEAD(&wrk_idle, w, list);
-
-		/* If we are a reserved thread we don't die */
-		if (w->nbr < params->wthread_min) {
-			AZ(pthread_cond_wait(&w->cv, &wrk_mtx));
-		} else {
-			/* If we are a dynamic thread, time out and die */
-			AZ(clock_gettime(CLOCK_REALTIME, &ts));
-			ts.tv_sec += params->wthread_timeout;
-			if (pthread_cond_timedwait(&w->cv, &wrk_mtx, &ts)) {
-				VSL_stats->n_wrk--;
-				TAILQ_REMOVE(&wrk_idle, w, list);
-				UNLOCK(&wrk_mtx);
-				VSL(SLT_WorkThread, 0, "%u suicide", w->nbr);
-				AZ(pthread_cond_destroy(&w->cv));
-				return (NULL);
-			}
-		}
-
-		/* we are already removed from wrk_idle */
+		assert(w->idle != 0);
+		AZ(pthread_cond_wait(&w->cv, &wrk_mtx));
+		if (w->idle == 0)
+			break;
 		wrk_do_one(w);
 	}
+	VSL_stats->n_wrk--;
+	UNLOCK(&wrk_mtx);
+	VSL(SLT_WorkThread, 0, "%p end", w);
+	AZ(pthread_cond_destroy(&w->cv));
+	return (NULL);
 }
 
 /*--------------------------------------------------------------------*/
@@ -224,10 +215,10 @@
 	/* If there are idle threads, we tickle the first one into action */
 	w = TAILQ_FIRST(&wrk_idle);
 	if (w != NULL) {
-		AZ(pthread_cond_signal(&w->cv));
 		TAILQ_REMOVE(&wrk_idle, w, list);
 		TAILQ_INSERT_TAIL(&wrk_busy, w, list);
 		UNLOCK(&wrk_mtx);
+		AZ(pthread_cond_signal(&w->cv));
 		return;
 	}
 	
@@ -258,8 +249,36 @@
 	VSL_stats->n_wrk_failed++;
 	UNLOCK(&wrk_mtx);
 }
+
+/*--------------------------------------------------------------------*/
 	
+static void *
+wrk_reaperthread(void *priv)
+{
+	time_t	now;
+	struct worker *w;
 
+	(void)priv;
+	while (1) {
+		sleep(1);
+		if (VSL_stats->n_wrk <= params->wthread_min)
+			continue; 
+		now = time(NULL);
+		LOCK(&wrk_mtx);
+		w = TAILQ_LAST(&wrk_idle, workerhead);
+		if (w != NULL && w->idle + params->wthread_timeout < now)
+			TAILQ_REMOVE(&wrk_idle, w, list);
+		else 
+			w = NULL;
+		UNLOCK(&wrk_mtx);
+		if (w == NULL)
+			continue;
+		w->idle = 0;
+		AZ(pthread_cond_signal(&w->cv));
+	}
+	INCOMPL();
+}
+
 /*--------------------------------------------------------------------*/
 
 void
@@ -270,6 +289,9 @@
 
 	AZ(pthread_mutex_init(&wrk_mtx, NULL));
 
+	AZ(pthread_create(&tp, NULL, wrk_reaperthread, NULL));
+	AZ(pthread_detach(tp));
+
 	VSL(SLT_Debug, 0, "Starting %u worker threads", params->wthread_min);
 	for (i = 0; i < params->wthread_min; i++) {
 		VSL_stats->n_wrk++;
@@ -295,7 +317,7 @@
 	t = time(NULL);
 	TAILQ_FOREACH(w, &wrk_busy, list) {
 		cli_out(cli, "\n");
-		cli_out(cli, "W %p nbr %d ", w, w->nbr);
+		cli_out(cli, "W %p", w);
 		if (w->wrq == NULL)
 			continue;
 		s = w->wrq->sess;




More information about the varnish-commit mailing list