diff --git a/components/pthreads/pthread.c b/components/pthreads/pthread.c index 964f57ad29c1d3d801f290707f6ba881b6570fe0..e02a174f4ef2efd0ef5ce8777821ec44d35ebe32 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 bd112b503f958599f322feb46c2b65c431e829ad..5dab979c4efc8d83686031f3ea4e8a0960a836b0 100644 --- a/components/pthreads/pthread.h +++ b/components/pthreads/pthread.h @@ -18,6 +18,18 @@ #include #include +#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); diff --git a/components/pthreads/pthread_internal.h b/components/pthreads/pthread_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..33ecfb8d0d0ffd635a00315a38e92c217d6de163 --- /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 7efb0b325526306e1128163a62e368eff87b6224..5dacc1e1f2aff0498b538df552cbecf9ed25c9cf 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; }