From 1c67fc851a0773dda7363065d13aa4ddf1330d38 Mon Sep 17 00:00:00 2001 From: "bernard.xiong@gmail.com" Date: Mon, 15 Nov 2010 15:36:54 +0000 Subject: [PATCH] add thread local storage feature. git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1049 bbd45198-f89e-11dd-88c7-29a3b14d5316 --- components/pthreads/pthread.c | 93 ++++++++++++++++---------- components/pthreads/pthread.h | 49 +++++++------- components/pthreads/pthread_internal.h | 44 ++++++++++++ components/pthreads/pthread_tls.c | 67 ++++++++++++++++++- 4 files changed, 193 insertions(+), 60 deletions(-) create mode 100644 components/pthreads/pthread_internal.h diff --git a/components/pthreads/pthread.c b/components/pthreads/pthread.c index 964f57ad29..e02a174f4e 100644 --- a/components/pthreads/pthread.c +++ b/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 +#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) diff --git a/components/pthreads/pthread.h b/components/pthreads/pthread.h index bd112b503f..5dab979c4e 100644 --- a/components/pthreads/pthread.h +++ b/components/pthreads/pthread.h @@ -18,22 +18,7 @@ #include #include -typedef rt_thread_t pthread_t; -typedef long pthread_condattr_t; -typedef long pthread_rwlockattr_t; -typedef long pthread_mutexattr_t; -typedef long pthread_barrierattr_t; - -typedef int pthread_key_t; -typedef int pthread_once_t; - -enum { - PTHREAD_CANCEL_ASYNCHRONOUS = 0, - PTHREAD_CANCEL_ENABLE, - PTHREAD_CANCEL_DEFERRED, - PTHREAD_CANCEL_DISABLE, - PTHREAD_CANCELED -}; +#define PTHREAD_KEY_MAX 8 #define PTHREAD_COND_INITIALIZER {-1, 0} #define PTHREAD_RWLOCK_INITIALIZER {-1, 0} @@ -45,6 +30,30 @@ enum { #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; +typedef long pthread_mutexattr_t; +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, + PTHREAD_CANCEL_DEFERRED, + PTHREAD_CANCEL_DISABLE, + PTHREAD_CANCELED +}; + 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); diff --git a/components/pthreads/pthread_internal.h b/components/pthreads/pthread_internal.h new file mode 100644 index 0000000000..33ecfb8d0d --- /dev/null +++ b/components/pthreads/pthread_internal.h @@ -0,0 +1,44 @@ +#ifndef __PTHREAD_INTERNAL_H__ +#define __PTHREAD_INTERNAL_H__ + +#include +#include + +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 diff --git a/components/pthreads/pthread_tls.c b/components/pthreads/pthread_tls.c index 7efb0b3255..5dacc1e1f2 100644 --- a/components/pthreads/pthread_tls.c +++ b/components/pthreads/pthread_tls.c @@ -1,19 +1,84 @@ #include +#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; }