From 56b361a0a764d10fdd07d1d4cc31a93e883a0f91 Mon Sep 17 00:00:00 2001
From: Sebastian Reimers <hallo@studio-link.de>
Date: Thu, 11 Jan 2024 18:04:43 +0100
Subject: [PATCH] tmr: lock new and old list on timer migration

Fixes posible tmr_cancel race conditions
---
 src/tmr/tmr.c | 35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/src/tmr/tmr.c b/src/tmr/tmr.c
index 3c1bdc780..2896f4c9c 100644
--- a/src/tmr/tmr.c
+++ b/src/tmr/tmr.c
@@ -375,10 +375,14 @@ void tmr_debug(void)
  */
 void tmr_init(struct tmr *tmr)
 {
-	if (!tmr)
+	struct tmrl *tmrl = re_tmrl_get();
+
+	if (!tmr || !tmrl)
 		return;
 
 	memset(tmr, 0, sizeof(*tmr));
+
+	tmr->lock = tmrl->lock;
 }
 
 
@@ -388,36 +392,33 @@ static void tmr_startcont_dbg(struct tmr *tmr, uint64_t delay, bool syncnow,
 {
 	struct tmrl *tmrl = re_tmrl_get();
 	struct le *le;
-	mtx_t *lock;
+	mtx_t *old_lock = NULL;
 
 	if (!tmr || !tmrl)
 		return;
 
-	if (!tmr->lock || !tmr->le.list)
-		lock = tmrl->lock;
-	else
-		lock = tmr->lock; /* use old lock for unlinking */
+	mtx_lock(tmr->lock);
 
-	mtx_lock(lock);
+	/* Lock both old and new list */
+	if (tmr->lock != tmrl->lock) {
+		mtx_lock(tmrl->lock);
+		old_lock  = tmr->lock;
+		tmr->lock = tmrl->lock;
+	}
 
 	if (tmr->th)
 		list_unlink(&tmr->le);
 
-	mtx_unlock(lock);
-
-	lock = tmrl->lock;
-
-	mtx_lock(lock);
-
 	tmr->th	  = th;
 	tmr->arg  = arg;
 	tmr->file = file;
 	tmr->line = line;
-	tmr->lock = tmrl->lock;
+
+	if (old_lock)
+		mtx_unlock(old_lock);
 
 	if (!th) {
-		tmr->lock = NULL;
-		mtx_unlock(lock);
+		mtx_unlock(tmr->lock);
 		return;
 	}
 
@@ -445,7 +446,7 @@ static void tmr_startcont_dbg(struct tmr *tmr, uint64_t delay, bool syncnow,
 		}
 	}
 
-	mtx_unlock(lock);
+	mtx_unlock(tmr->lock);
 }