From 35881fb690c341f53ea3fb969e8d87b69401e49c Mon Sep 17 00:00:00 2001
From: Zheng Da <zhengda1936@gmail.com>
Date: Wed, 18 Nov 2009 01:45:36 +0100
Subject: Adapt the implementation of DDEKit threads.

---
 libddekit/include/ddekit/thread.h |  19 ----
 libddekit/thread.c                | 213 +++++++++++++++++---------------------
 2 files changed, 97 insertions(+), 135 deletions(-)

diff --git a/libddekit/include/ddekit/thread.h b/libddekit/include/ddekit/thread.h
index ecd399d9..6e505818 100644
--- a/libddekit/include/ddekit/thread.h
+++ b/libddekit/include/ddekit/thread.h
@@ -3,8 +3,6 @@
 
 /** \defgroup DDEKit_threads */
 
-#include <l4/dde/ddekit/lock.h>
-
 struct ddekit_thread;
 typedef struct ddekit_thread ddekit_thread_t;
 
@@ -118,29 +116,12 @@ void  ddekit_thread_wakeup(ddekit_thread_t *thread);
  */
 void  ddekit_thread_exit(void) __attribute__((noreturn));
 
-/** Terminate a thread 
- *
- * \ingroup DDEKit_threads
- */
-void  ddekit_thread_terminate(ddekit_thread_t *thread);
-
 /** Get the name, a thread registered with DDEKit. 
  *
  * \ingroup DDEKit_threads
  */
 const char *ddekit_thread_get_name(ddekit_thread_t *thread);
 
-/** Get unique ID of a DDEKit thread.
- *
- * \ingroup DDEKit_threads
- *
- *  DDEKit does not allow direct access to the thread data
- *  structure, since this struct contains L4-specific data types.
- *  However, applications might want to get some kind of ID related
- *  to a ddekit_thread, for instance to use it as a Linux-like PID.
- */
-int ddekit_thread_get_id(ddekit_thread_t *thread);
-
 /** Hint that this thread is done and may be scheduled somehow. 
  *
  * \ingroup DDEKit_threads
diff --git a/libddekit/thread.c b/libddekit/thread.c
index db767dc9..a4566d77 100644
--- a/libddekit/thread.c
+++ b/libddekit/thread.c
@@ -1,114 +1,68 @@
-#include <l4/dde/ddekit/thread.h>
-#include <l4/dde/ddekit/condvar.h>
-#include <l4/dde/ddekit/panic.h>
-#include <l4/dde/ddekit/memory.h>
-#include <l4/dde/ddekit/printf.h>
-
-#include <l4/dde/dde.h>
-#include <l4/thread/thread.h>
-#include <l4/log/l4log.h>
-#include <l4/sys/syscalls.h>
-#include <l4/util/rdtsc.h>
-
 #include <stdio.h>
 #include <string.h>
+#include <cthreads.h>
+#include <time.h>
+#include <error.h>
+
+#include "ddekit/thread.h"
 
 #define DDEKIT_THREAD_STACK_SIZE 0x2000 /* 8 KB */
 
 static struct ddekit_slab *ddekit_stack_slab = NULL;
 
 struct ddekit_thread {
-	l4thread_t l4thread;
-	void *data;
-	void *stack;
-	ddekit_condvar_t *sleep_cv;
-	const char *name;
+	struct cthread thread;
 };
 
-/**
- * The thread-local-storage key for the BSD struct thread.
- */
-static int tlskey_thread;
-
-struct startup_args {
-	void (*fun)(void *);
-	void *arg;
-	const char *name;
-};
-
-ddekit_thread_t *ddekit_thread_setup_myself(const char *name) {
-	ddekit_thread_t *td;
-	int namelen = strlen(name);
-	char *pname;
-	
-	td = ddekit_simple_malloc(sizeof(*td) + (namelen+1));
-	pname = (char *) td + sizeof(*td);
+static void setup_thread (cthread_t *t, const char *name) {
+	if (name) {
+		const char *cpy = NULL;
 
-	td->data=NULL;
-	td->sleep_cv = ddekit_condvar_init();
-	td->l4thread = l4thread_myself();
-	td->name = pname;
+		cpy = malloc (strlen (name) + 1);
+		if (cpy == NULL)
+			error (0, 0, "fail to allocate memory");
+		else 
+			strcpy (cpy, name);
 
-	strcpy(pname, name);
+		cthread_set_name (t, name);
+	}
 
-	l4thread_data_set_current(tlskey_thread, td);
-
-	return td;
+	/*
+	 * ldata isn't used by cthread. Since cthread isn't exposed to 
+	 * the user of this library. It's very safe to store
+	 * the condition variable in ldata.
+	 */
+	sleep_cond = condition_alloc ();
+	condition_init (sleep_cond);
+	cthread_set_ldata (t, sleep_cond);
 }
 
-static void ddekit_thread_startup(void *arg) {
-	struct startup_args su;
-	ddekit_thread_t *td;
-
-	/* copy arg to su so that it can bee freed by caller */
-	su = *((struct startup_args*)arg);
-
-	/* init dde thread structure */
-	td = ddekit_thread_setup_myself(su.name);
-	/* inform caller of initialization */
-	l4thread_started(td);
+ddekit_thread_t *ddekit_thread_setup_myself(const char *name) {
+	ddekit_thread_t *td = ddekit_thread_myself();
 
-	/* call thread routine */
-	su.fun(su.arg);
+	setup_thread (&td->thread, name);
+	return td;
 }
 
 ddekit_thread_t *ddekit_thread_create(void (*fun)(void *), void *arg, const char *name) {
-	struct startup_args su;
 	ddekit_thread_t *td;
-	l4thread_t l4td;
-	char l4name[20];
-	void *stack;
-	
-	su.fun  = fun;
-	su.arg  = arg;
-	su.name = name;
-	
-	snprintf(l4name, 20, ".%s", name);
-	
-	stack  = ddekit_slab_alloc(ddekit_stack_slab);
-	
-	
-	l4td = l4thread_create_long(L4THREAD_INVALID_ID, ddekit_thread_startup, l4name,
-                                    (l4_addr_t) stack + (DDEKIT_THREAD_STACK_SIZE-1 )* sizeof (void *),
-                                    DDEKIT_THREAD_STACK_SIZE,
-                                    L4THREAD_DEFAULT_PRIO, &su, L4THREAD_CREATE_SYNC);
-			
-	if (l4td < 0)
-		ddekit_panic("error creating thread");
-
-	td = (ddekit_thread_t*) l4thread_startup_return(l4td);
-	
-	td->stack = stack;
-	
+	condition_t sleep_cond;
+
+	// TODO not very sure whether I should let the thread suspend
+	// before initialization is completed.
+	td = (ddekit_thread_t *) cthread_fork (fun, arg);
+	setup_thread (&td->thread, name);
 	return td;
 }
 
 ddekit_thread_t *ddekit_thread_myself(void) {
-	return (ddekit_thread_t *) l4thread_data_get_current(tlskey_thread);
+	return (ddekit_thread_t *) cthread_self ();
 }
 
 void ddekit_thread_set_data(ddekit_thread_t *thread, void *data) {
-	thread->data = data;
+	// TODO not very sure whether I should call cthread_set_ldata
+	// or cthread_set_data.
+	cthread_set_data ((cthread_t) thread, data);
 }
 
 void ddekit_thread_set_my_data(void *data) {
@@ -116,7 +70,7 @@ void ddekit_thread_set_my_data(void *data) {
 }
 
 void *ddekit_thread_get_data(ddekit_thread_t *thread) {
-	return thread->data;
+	return cthread_data ((cthread_t) thread);
 }
 
 void *ddekit_thread_get_my_data() {
@@ -124,72 +78,99 @@ void *ddekit_thread_get_my_data() {
 }
 
 void ddekit_thread_msleep(unsigned long msecs) {
-	l4thread_sleep(msecs);
+	int ret;
+	struct timespec rgt;
+
+	rgt.tv_sec = (time_t) (msecs / 1000);
+	rgt.tv_nsec = (msecs % 1000) * 1000 * 1000;
+	ret = nanosleep (&rgt , NULL);
+	if (ret < 0)
+		error (0, errno, "nanosleep");
 }
 
 void ddekit_thread_usleep(unsigned long usecs) {
-	l4_busy_wait_us(usecs);
+	int ret;
+	struct timespec rgt;
+
+	rgt.tv_sec = (time_t) (usecs / 1000 / 1000);
+	rgt.tv_nsec = (usecs % (1000 * 1000)) * 1000;
+	ret = nanosleep (&rgt , NULL);
+	if (ret < 0)
+		error (0, errno, "nanosleep");
 }
 
 
 void ddekit_thread_nsleep(unsigned long nsecs) {
-	l4_busy_wait_ns(nsecs);
+	int ret;
+	struct timespec rgt;
+
+	rgt.tv_sec = (time_t) (nsecs / 1000 / 1000 / 1000);
+	rgt.tv_nsec = nsecs % (1000 * 1000 * 1000);
+	ret = nanosleep (&rgt , NULL);
+	if (ret < 0)
+		error (0, errno, "nanosleep");
 }
 
 void ddekit_thread_sleep(ddekit_lock_t *lock) {
 	ddekit_thread_t *td;
+	condition_t sleep_cond;
 
 	td = ddekit_thread_myself();
+	sleep_cond = ddekit_thread_get_data (&td->thread);
 
-	ddekit_condvar_wait(td->sleep_cv, lock);
+	mutex_lock (lock);
+	// TODO condition_wait cannot guarantee that the thread is 
+	// woke up by another thread, maybe by signals.
+	// Does it matter here?
+	condition_wait (sleep_cond, lock);
+	mutex_unlock (lock);
 }
 
 void  ddekit_thread_wakeup(ddekit_thread_t *td) {
-	ddekit_condvar_signal(td->sleep_cv);
-}
-
-void  ddekit_thread_exit() {
 	ddekit_thread_t *td;
+	condition_t sleep_cond;
 
 	td = ddekit_thread_myself();
-	
-	l4thread_exit();
+	sleep_cond = ddekit_thread_get_data (&td->thread);
 
-	ddekit_slab_free(ddekit_stack_slab ,td->stack);
-	
+	condition_signal (sleep_cond);
 }
 
-void ddekit_thread_terminate(ddekit_thread_t *t)
-{
-	l4thread_shutdown(t->l4thread);
-}
+void  ddekit_thread_exit() {
+	const char *name;
+	condition_t sleep_cond;
+	cthread_t t = cthread_self ();
 
-const char *ddekit_thread_get_name(ddekit_thread_t *thread) {
-	return thread->name;
+	// TODO I hope I don't need a lock to protect ldata and name.
+
+	/* I have to free the sleep condition variable
+	 * before the thread exits. */
+	sleep_cond = cthread_ldata (t);
+	cthread_set_ldata (t, NULL);
+	condition_free (sleep_cond);
+
+	name = cthread_name (t);
+	cthread_set_name (t, NULL);
+	free (name);
+
+	cthread_exit (0);
 }
 
-int ddekit_thread_get_id(ddekit_thread_t *t)
-{
-	return t->l4thread;
+const char *ddekit_thread_get_name(ddekit_thread_t *thread) {
+	return cthread_name ((cthread_t) thread);
 }
 
 void ddekit_thread_schedule(void)
 {
-	l4_yield();
+	cthread_yield();
 }
 
 void ddekit_yield(void)
 {
-	l4_yield();
+	cthread_yield();
 }
 
 void ddekit_init_threads() {
-	/* register TLS key for pointer to dde thread structure */
-	tlskey_thread = l4thread_data_allocate_key();
-	
-	/* setup dde part of thread data */
-	ddekit_thread_setup_myself("main");
-	
- 	/* create slab for stacks */
-	ddekit_stack_slab = ddekit_slab_init(DDEKIT_THREAD_STACK_SIZE, 1);
+	// TODO maybe the name has already been set.
+	cthread_set_name (cthread_self (), "main");
 }
-- 
cgit v1.2.3