mirror of https://github.com/RT-Thread/rt-thread
add thread local storage feature.
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1049 bbd45198-f89e-11dd-88c7-29a3b14d5316
This commit is contained in:
parent
aca1628a31
commit
1c67fc851a
|
@ -1,41 +1,18 @@
|
||||||
#include "pthread.h"
|
#include <pthread.h>
|
||||||
|
#include "pthread_internal.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pthread_system_init(void)
|
int pthread_system_init(void)
|
||||||
{
|
{
|
||||||
|
/* initialize key area */
|
||||||
|
pthread_key_system_init();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _pthread_cleanup(rt_thread_t tid)
|
static void _pthread_cleanup(rt_thread_t tid)
|
||||||
{
|
{
|
||||||
_pthread_data_t *ptd;
|
_pthread_data_t *ptd;
|
||||||
ptd = get_pthread_data(tid);
|
ptd = _pthread_get_data(tid);
|
||||||
|
|
||||||
/* clear cleanup function */
|
/* clear cleanup function */
|
||||||
tid->cleanup = RT_NULL;
|
tid->cleanup = RT_NULL;
|
||||||
|
@ -75,10 +52,10 @@ int pthread_create (pthread_t *tid, const pthread_attr_t *attr,
|
||||||
/* tid shall be provided */
|
/* tid shall be provided */
|
||||||
RT_ASSERT(tid != RT_NULL);
|
RT_ASSERT(tid != RT_NULL);
|
||||||
|
|
||||||
/* allocate pthread data */
|
/* allocate posix thread data */
|
||||||
ptd = (_pthread_data_t*)rt_malloc(sizeof(_pthread_data_t));
|
ptd = (_pthread_data_t*)rt_malloc(sizeof(_pthread_data_t));
|
||||||
if (ptd == RT_NULL) return ENOMEM;
|
if (ptd == RT_NULL) return ENOMEM;
|
||||||
/* clean memory */
|
/* clean posix thread data memory */
|
||||||
rt_memset(ptd, 0, sizeof(_pthread_data_t));
|
rt_memset(ptd, 0, sizeof(_pthread_data_t));
|
||||||
|
|
||||||
if (attr != RT_NULL) ptd->attr = *attr;
|
if (attr != RT_NULL) ptd->attr = *attr;
|
||||||
|
@ -161,7 +138,7 @@ int pthread_detach(pthread_t thread)
|
||||||
{
|
{
|
||||||
_pthread_data_t* ptd;
|
_pthread_data_t* ptd;
|
||||||
|
|
||||||
ptd = get_pthread_data(thread);
|
ptd = _pthread_get_data(thread);
|
||||||
|
|
||||||
if (thread->stat == RT_THREAD_CLOSE)
|
if (thread->stat == RT_THREAD_CLOSE)
|
||||||
{
|
{
|
||||||
|
@ -177,6 +154,12 @@ int pthread_detach(pthread_t thread)
|
||||||
/* release thread allocated stack */
|
/* release thread allocated stack */
|
||||||
rt_free(ptd->tid->stack_addr);
|
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->tid);
|
||||||
rt_free(ptd);
|
rt_free(ptd);
|
||||||
}
|
}
|
||||||
|
@ -205,7 +188,7 @@ int pthread_join (pthread_t thread, void **value_ptr)
|
||||||
return EDEADLK;
|
return EDEADLK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptd = get_pthread_data(thread);
|
ptd = _pthread_get_data(thread);
|
||||||
if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED)
|
if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED)
|
||||||
return EINVAL; /* join on a detached pthread */
|
return EINVAL; /* join on a detached pthread */
|
||||||
|
|
||||||
|
@ -225,7 +208,7 @@ int pthread_cancel (pthread_t thread)
|
||||||
{
|
{
|
||||||
_pthread_data_t* ptd;
|
_pthread_data_t* ptd;
|
||||||
|
|
||||||
ptd = get_pthread_data(thread);
|
ptd = _pthread_get_data(thread);
|
||||||
|
|
||||||
/* check cancel point */
|
/* check cancel point */
|
||||||
}
|
}
|
||||||
|
@ -234,7 +217,7 @@ void pthread_exit (void* value)
|
||||||
{
|
{
|
||||||
_pthread_data_t* ptd;
|
_pthread_data_t* ptd;
|
||||||
|
|
||||||
ptd = get_pthread_data(rt_thread_self());
|
ptd = _pthread_get_data(rt_thread_self());
|
||||||
|
|
||||||
/* set return value */
|
/* set return value */
|
||||||
ptd->return_value = value;
|
ptd->return_value = value;
|
||||||
|
@ -281,10 +264,50 @@ int pthread_kill(pthread_t thread, int sig)
|
||||||
|
|
||||||
void pthread_cleanup_pop(int execute)
|
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)
|
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)
|
int pthread_setcancelstate(int state, int *oldstate)
|
||||||
|
|
|
@ -18,22 +18,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
typedef rt_thread_t pthread_t;
|
#define PTHREAD_KEY_MAX 8
|
||||||
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_COND_INITIALIZER {-1, 0}
|
#define PTHREAD_COND_INITIALIZER {-1, 0}
|
||||||
#define PTHREAD_RWLOCK_INITIALIZER {-1, 0}
|
#define PTHREAD_RWLOCK_INITIALIZER {-1, 0}
|
||||||
|
@ -45,6 +30,30 @@ enum {
|
||||||
#define PTHREAD_EXPLICIT_SCHED 0
|
#define PTHREAD_EXPLICIT_SCHED 0
|
||||||
#define PTHREAD_INHERIT_SCHED 1
|
#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 {
|
enum {
|
||||||
PTHREAD_MUTEX_NORMAL = 0,
|
PTHREAD_MUTEX_NORMAL = 0,
|
||||||
PTHREAD_MUTEX_RECURSIVE = 1,
|
PTHREAD_MUTEX_RECURSIVE = 1,
|
||||||
|
@ -66,7 +75,6 @@ enum {
|
||||||
#define PTHREAD_PROCESS_PRIVATE 0
|
#define PTHREAD_PROCESS_PRIVATE 0
|
||||||
#define PTHREAD_PROCESS_SHARED 1
|
#define PTHREAD_PROCESS_SHARED 1
|
||||||
|
|
||||||
|
|
||||||
#define PTHREAD_SCOPE_PROCESS 0
|
#define PTHREAD_SCOPE_PROCESS 0
|
||||||
#define PTHREAD_SCOPE_SYSTEM 1
|
#define PTHREAD_SCOPE_SYSTEM 1
|
||||||
|
|
||||||
|
@ -129,13 +137,6 @@ struct pthread_barrier
|
||||||
};
|
};
|
||||||
typedef struct pthread_barrier pthread_barrier_t;
|
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 */
|
/* pthread thread interface */
|
||||||
int pthread_attr_destroy(pthread_attr_t *attr);
|
int pthread_attr_destroy(pthread_attr_t *attr);
|
||||||
int pthread_attr_init(pthread_attr_t *attr);
|
int pthread_attr_init(pthread_attr_t *attr);
|
||||||
|
|
|
@ -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
|
|
@ -1,19 +1,84 @@
|
||||||
#include <pthread.h>
|
#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)
|
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)
|
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*))
|
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)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue