diff mbox

linux-generic: thread: reuse thread ids

Message ID 1425306854-10900-1-git-send-email-petri.savolainen@linaro.org
State Accepted
Commit 70bd7de7182eaae5c920979e4d25cb512e6fffb8
Headers show

Commit Message

Petri Savolainen March 2, 2015, 2:34 p.m. UTC
Scheduler validation test failed on a 28 thread machine
since it creates and terminates many threads during a
test run. Linux-generix implementation did not reuse
thread IDs but run out of threads.

Thread ids are protected with a lock and new alloc/free
rutines reuse thread IDs.

Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org>
---
 platform/linux-generic/odp_thread.c | 115 +++++++++++++++++++++++++-----------
 1 file changed, 81 insertions(+), 34 deletions(-)
diff mbox

Patch

diff --git a/platform/linux-generic/odp_thread.c b/platform/linux-generic/odp_thread.c
index c6813f5..bfdaaa2 100644
--- a/platform/linux-generic/odp_thread.c
+++ b/platform/linux-generic/odp_thread.c
@@ -1,3 +1,8 @@ 
+
+
+
+
+
 /* Copyright (c) 2013, Linaro Limited
  * All rights reserved.
  *
@@ -11,7 +16,7 @@ 
 
 #include <odp/thread.h>
 #include <odp_internal.h>
-#include <odp/atomic.h>
+#include <odp/spinlock.h>
 #include <odp/config.h>
 #include <odp_debug_internal.h>
 #include <odp/shared_memory.h>
@@ -22,19 +27,19 @@ 
 #include <stdio.h>
 #include <stdlib.h>
 
+#define MASK_SIZE_16 ((ODP_CONFIG_MAX_THREADS+15)/16)
 
 typedef struct {
-	int thr_id;
+	int thr;
 	int cpu;
-
 } thread_state_t;
 
 
 typedef struct {
-	thread_state_t   thr[ODP_CONFIG_MAX_THREADS];
-	odp_atomic_u32_t num;
-	odp_atomic_u32_t next_id;
-
+	thread_state_t thr[ODP_CONFIG_MAX_THREADS];
+	uint16_t       mask[MASK_SIZE_16];
+	uint32_t       num;
+	odp_spinlock_t lock;
 } thread_globals_t;
 
 
@@ -60,8 +65,7 @@  int odp_thread_init_global(void)
 		return -1;
 
 	memset(thread_globals, 0, sizeof(thread_globals_t));
-	odp_atomic_init_u32(&thread_globals->next_id, 0);
-	odp_atomic_init_u32(&thread_globals->num, 0);
+	odp_spinlock_init(&thread_globals->lock);
 	return 0;
 }
 
@@ -76,19 +80,65 @@  int odp_thread_term_global(void)
 	return ret;
 }
 
+static int alloc_id(void)
+{
+	int i, j;
+	uint16_t *mask = thread_globals->mask;
+
+	if (thread_globals->num >= ODP_CONFIG_MAX_THREADS)
+		return -1;
+
+	for (i = 0; i < MASK_SIZE_16; i++) {
+		if (mask[i] != 0xffff) {
+			for (j = 0; j < 16; j++) {
+				uint16_t bit = 0x1 << j;
+				if ((bit & mask[i]) == 0) {
+					mask[i] |= bit;
+					thread_globals->num++;
+					return i*16 + j;
+				}
+			}
+			return -2;
+		}
+	}
+
+	return -2;
+}
+
+static int free_id(int id)
+{
+	int i, j;
+	uint16_t *mask = thread_globals->mask;
+	uint16_t bit;
+
+	if (id < 0 || id >= ODP_CONFIG_MAX_THREADS)
+		return -1;
+
+	i   = id / 16;
+	j   = id - (i * 16);
+	bit = 0x1 << j;
+
+	if ((bit & mask[i]) == 0)
+		return -1;
+
+	mask[i] &= ~bit;
+	thread_globals->num--;
+	return thread_globals->num;
+}
 
-static int thread_id(void)
+int odp_thread_init_local(void)
 {
-	uint32_t id;
+	int id;
 	int cpu;
 
-	id = odp_atomic_fetch_inc_u32(&thread_globals->next_id);
+	odp_spinlock_lock(&thread_globals->lock);
+	id = alloc_id();
+	odp_spinlock_unlock(&thread_globals->lock);
 
-	if (id >= ODP_CONFIG_MAX_THREADS) {
+	if (id < 0) {
 		ODP_ERR("Too many threads\n");
 		return -1;
 	}
-	odp_atomic_inc_u32(&thread_globals->num);
 
 	cpu = sched_getcpu();
 
@@ -97,20 +147,8 @@  static int thread_id(void)
 		return -1;
 	}
 
-	thread_globals->thr[id].thr_id = id;
-	thread_globals->thr[id].cpu    = cpu;
-
-	return id;
-}
-
-int odp_thread_init_local(void)
-{
-	int id;
-
-	id = thread_id();
-
-	if (id < 0)
-		return -1;
+	thread_globals->thr[id].thr = id;
+	thread_globals->thr[id].cpu = cpu;
 
 	this_thread = &thread_globals->thr[id];
 	return 0;
@@ -118,20 +156,29 @@  int odp_thread_init_local(void)
 
 int odp_thread_term_local(void)
 {
-	uint32_t num;
-	num = odp_atomic_fetch_dec_u32(&thread_globals->num);
-	ODP_ASSERT(num > 0, "Number of threads should be > 0");
-	return num - 1; /* return a number of threads left */
+	int num;
+	int id = this_thread->thr;
+
+	odp_spinlock_lock(&thread_globals->lock);
+	num = free_id(id);
+	odp_spinlock_unlock(&thread_globals->lock);
+
+	if (num < 0) {
+		ODP_ERR("failed to free thread id %i", id);
+		return -1;
+	}
+
+	return num; /* return a number of threads left */
 }
 
 int odp_thread_id(void)
 {
-	return this_thread->thr_id;
+	return this_thread->thr;
 }
 
 int odp_thread_count(void)
 {
-	return odp_atomic_load_u32(&thread_globals->num);
+	return thread_globals->num;
 }
 
 int odp_cpu_id(void)