diff options
| author | [email protected] <[email protected]> | 2010-11-15 15:36:54 +0000 |
|---|---|---|
| committer | [email protected] <[email protected]> | 2010-11-15 15:36:54 +0000 |
| commit | 1c67fc851a0773dda7363065d13aa4ddf1330d38 (patch) | |
| tree | 5560f59e07094d2bf0fe5d5acda069fa4c8e529f | |
| parent | aca1628a31c2acca262a90af921501368f8cfcc2 (diff) | |
add thread local storage feature.
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1049 bbd45198-f89e-11dd-88c7-29a3b14d5316
| -rw-r--r-- | components/pthreads/pthread.c | 93 | ||||
| -rw-r--r-- | components/pthreads/pthread.h | 37 | ||||
| -rw-r--r-- | components/pthreads/pthread_internal.h | 44 | ||||
| -rw-r--r-- | components/pthreads/pthread_tls.c | 67 |
4 files changed, 187 insertions, 54 deletions
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 <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)
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,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);
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 <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
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 <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;
}
|
