From 37e2a417a6cb6a981c85dfdcd3245a48f99a4165 Mon Sep 17 00:00:00 2001
From: Guillaume Nault <g.nault@alphalink.fr>
Date: Wed, 24 Jul 2013 20:27:45 +0200
Subject: triton: Fix race upon termination

The triton_terminate() function works by setting the need_close flag
of each triton context, then queues this context for execution by a
triton thread if not already running. But if the context is already
being run by a triton thread, it may not notice that its need_close
flag has been updated (this flag is only checked at the beginning
of ctx_thread()). So if no other event wakes up that context (i.e.
if ctx_thread() isn't run again), it will never terminate.

This patch moves the need_close flag check at the end of ctx_thread()
so that a triton context can take the need_close flag into account
event if it's updated while running.

The context spinlock is also used to protect the need_close flag as
it is concurrently updated by triton_terminate().

Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
---
 accel-pppd/triton/triton.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/accel-pppd/triton/triton.c b/accel-pppd/triton/triton.c
index 267cc2bc..d4c21e2f 100644
--- a/accel-pppd/triton/triton.c
+++ b/accel-pppd/triton/triton.c
@@ -185,11 +185,6 @@ static void ctx_thread(struct _triton_context_t *ctx)
 	uint64_t tt;
 
 	log_debug2("ctx %p %p: enter\n", ctx, ctx->thread);
-	if (ctx->need_close) {
-		if (ctx->ud->close)
-			ctx->ud->close(ctx->ud);
-		ctx->need_close = 0;
-	}
 
 	while (1) {
 		spin_lock(&ctx->lock);
@@ -234,6 +229,17 @@ static void ctx_thread(struct _triton_context_t *ctx)
 		break;	
 	}
 
+	spin_lock(&ctx->lock);
+	if (ctx->need_close) {
+		spin_unlock(&ctx->lock);
+		if (ctx->ud->close) {
+			ctx->ud->close(ctx->ud);
+		}
+		spin_lock(&ctx->lock);
+		ctx->need_close = 0;
+	}
+	spin_unlock(&ctx->lock);
+
 	log_debug2("ctx %p %p: exit\n", ctx, ctx->thread);
 }
 
-- 
cgit v1.2.3