Преглед изворни кода

add thread local storage feature.

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1049 bbd45198-f89e-11dd-88c7-29a3b14d5316
bernard.xiong@gmail.com пре 14 година
родитељ
комит
1c67fc851a

+ 58 - 35
components/pthreads/pthread.c

@@ -1,41 +1,18 @@
-#include "pthread.h"
-
-#define PTHREAD_MAGIC	0x70746873
-struct _pthread_data
-{
-	rt_uint32_t magic;
-	pthread_attr_t attr;
-	rt_thread_t tid;
-
-	void* (*thread_entry)(void* parameter);
-	void* thread_parameter;
-
-	/* return value */
-	void* return_value;
-
-	/* semaphore for joinable thread */
-	rt_sem_t joinable_sem;
-
-	void** tls; /* thread-local storage area */
-};
-typedef struct _pthread_data _pthread_data_t;
-
-rt_inline _pthread_data_t* get_pthread_data(pthread_t thread)
-{
-	RT_ASSERT(thread != RT_NULL);
-
-	return (_pthread_data_t*)thread->user_data;
-}
+#include <pthread.h>
+#include "pthread_internal.h"
 
 int pthread_system_init(void)
 {
+	/* initialize key area */
+	pthread_key_system_init();
+
 	return 0;
 }
 
 static void _pthread_cleanup(rt_thread_t tid)
 {
 	_pthread_data_t *ptd;
-	ptd = get_pthread_data(tid);
+	ptd = _pthread_get_data(tid);
 
 	/* clear cleanup function */
 	tid->cleanup = RT_NULL;
@@ -75,10 +52,10 @@ int pthread_create (pthread_t *tid, const pthread_attr_t *attr,
 	/* tid shall be provided */
 	RT_ASSERT(tid != RT_NULL);
 
-	/* allocate pthread data */
+	/* allocate posix thread data */
 	ptd = (_pthread_data_t*)rt_malloc(sizeof(_pthread_data_t));
 	if (ptd == RT_NULL) return ENOMEM;
-	/* clean memory */
+	/* clean posix thread data memory */
 	rt_memset(ptd, 0, sizeof(_pthread_data_t));
 
 	if (attr != RT_NULL) ptd->attr = *attr;
@@ -161,7 +138,7 @@ int pthread_detach(pthread_t thread)
 {
 	_pthread_data_t* ptd;
 
-	ptd = get_pthread_data(thread);
+	ptd = _pthread_get_data(thread);
 
 	if (thread->stat == RT_THREAD_CLOSE)
 	{
@@ -177,6 +154,12 @@ int pthread_detach(pthread_t thread)
 			/* release thread allocated stack */
 			rt_free(ptd->tid->stack_addr);
 		}
+
+		/*
+		 * if this thread create the local thread data,
+		 * delete it
+		 */
+		if (ptd->tls != RT_NULL) rt_free(ptd->tls);
 		rt_free(ptd->tid);
 		rt_free(ptd);
 	}
@@ -205,7 +188,7 @@ int pthread_join (pthread_t thread, void **value_ptr)
 		return EDEADLK;
 	}
 
-	ptd = get_pthread_data(thread);
+	ptd = _pthread_get_data(thread);
 	if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED)
 		return EINVAL; /* join on a detached pthread */
 
@@ -225,7 +208,7 @@ int pthread_cancel (pthread_t thread)
 {
 	_pthread_data_t* ptd;
 
-	ptd = get_pthread_data(thread);
+	ptd = _pthread_get_data(thread);
 
 	/* check cancel point */
 }
@@ -234,7 +217,7 @@ void pthread_exit (void* value)
 {
 	_pthread_data_t* ptd;
 
-	ptd = get_pthread_data(rt_thread_self());
+	ptd = _pthread_get_data(rt_thread_self());
 
 	/* set return value */
 	ptd->return_value = value;
@@ -281,10 +264,50 @@ int pthread_kill(pthread_t thread, int sig)
 
 void pthread_cleanup_pop(int execute)
 {
+	_pthread_data_t* ptd;
+	_pthread_cleanup_t* cleanup;
+
+	/* get posix thread data */
+	ptd = _pthread_get_data(rt_thread_self());
+	RT_ASSERT(ptd != RT_NULL);
+
+	if (execute)
+	{
+		rt_enter_critical();
+		cleanup = ptd->cleanup;
+		if (cleanup)
+			ptd->cleanup = cleanup->next;
+		rt_exit_critical();
+
+		if (cleanup)
+		{
+			cleanup->cleanup_func(cleanup->parameter);
+
+			rt_free(cleanup);
+		}
+	}
 }
 
 void pthread_cleanup_push(void (*routine)(void*), void *arg)
 {
+	_pthread_data_t* ptd;
+	_pthread_cleanup_t* cleanup;
+
+	/* get posix thread data */
+	ptd = _pthread_get_data(rt_thread_self());
+	RT_ASSERT(ptd != RT_NULL);
+
+	cleanup = (_pthread_cleanup_t*)rt_malloc(sizeof(_pthread_cleanup_t));
+	if (cleanup != RT_NULL)
+	{
+		cleanup->cleanup_func = routine;
+		cleanup->parameter = arg;
+
+		rt_enter_critical();
+		cleanup->next = ptd->cleanup;
+		ptd->cleanup = cleanup;
+		rt_exit_critical();
+	}
 }
 
 int pthread_setcancelstate(int state, int *oldstate)

+ 19 - 18
components/pthreads/pthread.h

@@ -18,6 +18,18 @@
 #include <errno.h>
 #include <sys/types.h>
 
+#define PTHREAD_KEY_MAX				8
+
+#define PTHREAD_COND_INITIALIZER	{-1, 0}
+#define PTHREAD_RWLOCK_INITIALIZER	{-1, 0}
+#define PTHREAD_MUTEX_INITIALIZER	{-1, 0}
+
+#define PTHREAD_CREATE_JOINABLE		0x00
+#define PTHREAD_CREATE_DETACHED		0x01
+
+#define PTHREAD_EXPLICIT_SCHED		0
+#define PTHREAD_INHERIT_SCHED		1
+
 typedef rt_thread_t pthread_t;
 typedef long pthread_condattr_t;
 typedef long pthread_rwlockattr_t;
@@ -27,6 +39,13 @@ typedef long pthread_barrierattr_t;
 typedef int pthread_key_t;
 typedef int pthread_once_t;
 
+/*
+ * Scheduling policies required by IEEE Std 1003.1-2001
+ */
+#define	SCHED_OTHER	0	/* Behavior can be FIFO or RR, or not */
+#define	SCHED_FIFO	1
+#define	SCHED_RR	2
+
 enum {
 	PTHREAD_CANCEL_ASYNCHRONOUS = 0,
 	PTHREAD_CANCEL_ENABLE,
@@ -35,16 +54,6 @@ enum {
 	PTHREAD_CANCELED
 };
 
-#define PTHREAD_COND_INITIALIZER	{-1, 0}
-#define PTHREAD_RWLOCK_INITIALIZER	{-1, 0}
-#define PTHREAD_MUTEX_INITIALIZER	{-1, 0}
-
-#define PTHREAD_CREATE_JOINABLE		0x00
-#define PTHREAD_CREATE_DETACHED		0x01
-
-#define PTHREAD_EXPLICIT_SCHED		0
-#define PTHREAD_INHERIT_SCHED		1
-
 enum {
     PTHREAD_MUTEX_NORMAL = 0,
     PTHREAD_MUTEX_RECURSIVE = 1,
@@ -66,7 +75,6 @@ enum {
 #define PTHREAD_PROCESS_PRIVATE  0
 #define PTHREAD_PROCESS_SHARED   1
 
-
 #define PTHREAD_SCOPE_PROCESS	0
 #define PTHREAD_SCOPE_SYSTEM	1
 
@@ -129,13 +137,6 @@ struct pthread_barrier
 };
 typedef struct pthread_barrier pthread_barrier_t;
 
-/*
- * Scheduling policies required by IEEE Std 1003.1-2001
- */
-#define	SCHED_OTHER	0	/* Behavior can be FIFO or RR, or not */
-#define	SCHED_FIFO	1
-#define	SCHED_RR	2
-
 /* pthread thread interface */
 int pthread_attr_destroy(pthread_attr_t *attr);
 int pthread_attr_init(pthread_attr_t *attr);

+ 44 - 0
components/pthreads/pthread_internal.h

@@ -0,0 +1,44 @@
+#ifndef __PTHREAD_INTERNAL_H__
+#define __PTHREAD_INTERNAL_H__
+
+#include <rtthread.h>
+#include <pthread.h>
+
+struct _pthread_cleanup
+{
+	void (*cleanup_func)(void* parameter);
+	void* parameter;
+
+	struct _pthread_cleanup* next;
+};
+typedef struct _pthread_cleanup _pthread_cleanup_t;
+
+#define PTHREAD_MAGIC	0x70746873
+struct _pthread_data
+{
+	rt_uint32_t magic;
+	pthread_attr_t attr;
+	rt_thread_t tid;
+
+	void* (*thread_entry)(void* parameter);
+	void* thread_parameter;
+
+	/* return value */
+	void* return_value;
+
+	/* semaphore for joinable thread */
+	rt_sem_t joinable_sem;
+
+	_pthread_cleanup_t* cleanup;
+	void** tls; /* thread-local storage area */
+};
+typedef struct _pthread_data _pthread_data_t;
+
+rt_inline _pthread_data_t* _pthread_get_data(pthread_t thread)
+{
+	RT_ASSERT(thread != RT_NULL);
+
+	return (_pthread_data_t*)thread->user_data;
+}
+
+#endif

+ 66 - 1
components/pthreads/pthread_tls.c

@@ -1,19 +1,84 @@
 #include <pthread.h>
+#include "pthread_internal.h"
+
+struct _pthread_key_data
+{
+	int is_used;
+	void* (*destructor)(void* parameter);
+};
+typedef struct _pthread_key_data _pthread_key_data_t;
+static _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX];
+
+void pthread_key_system_init()
+{
+	rt_memset(&_thread_keys[0], 0, sizeof(_thread_keys));
+}
 
 void *pthread_getspecific(pthread_key_t key)
 {
+	struct _pthread_data* ptd;
+
+	ptd = _pthread_get_data(rt_thread_self());
+	RT_ASSERT(ptd != NULL);
+
+	if (ptd->tls == NULL) return NULL;
+
+	if ((key < PTHREAD_KEY_MAX) && (_thread_keys[key].is_used))
+		return ptd->tls[key];
+
+	return NULL;
 }
 
 int pthread_setspecific(pthread_key_t key, const void *value)
 {
+	struct _pthread_data* ptd;
+
+	ptd = _pthread_get_data(rt_thread_self());
+	RT_ASSERT(ptd != NULL);
+
+	/* check tls area */
+	if (ptd->tls == NULL) ptd->tls = rt_malloc(sizeof(void*) * PTHREAD_KEY_MAX);
+
+	if ((key < PTHREAD_KEY_MAX) && _thread_keys[key].is_used)
+	{
+		ptd->tls[key] = (void *)value;
+		return 0;
+	}
+
+	return EINVAL;
 }
 
 int pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
 {
-	return 0;
+	rt_uint32_t index;
+
+	rt_enter_critical();
+	for (index = 0; index < PTHREAD_KEY_MAX; index ++)
+	{
+		if (_thread_keys[index].is_used == 0)
+		{
+			_thread_keys[index].is_used = 1;
+			_thread_keys[index].destructor = destructor;
+
+			*key = index;
+
+			rt_exit_critical();
+			return 0;
+		}
+	}
+
+	rt_exit_critical();
+	return EAGAIN;
 }
 
 int pthread_key_delete(pthread_key_t key)
 {
+	if (key >= PTHREAD_KEY_MAX) return EINVAL;
+
+	rt_enter_critical();
+	_thread_keys[key].is_used = 0;
+	_thread_keys[key].destructor = 0;
+	rt_exit_critical();
+
 	return 0;
 }