diff --git a/components/pthreads/pthread.c b/components/pthreads/pthread.c index e02a174f4ef2efd0ef5ce8777821ec44d35ebe32..646727f85449bc84c1aae211f89dfb001bcd95f7 100644 --- a/components/pthreads/pthread.c +++ b/components/pthreads/pthread.c @@ -57,6 +57,9 @@ int pthread_create (pthread_t *tid, const pthread_attr_t *attr, if (ptd == RT_NULL) return ENOMEM; /* clean posix thread data memory */ rt_memset(ptd, 0, sizeof(_pthread_data_t)); + ptd->canceled = 0; + ptd->cancelstate = PTHREAD_CANCEL_DISABLE; + ptd->canceltype = PTHREAD_CANCEL_DEFERRED; if (attr != RT_NULL) ptd->attr = *attr; else @@ -204,23 +207,54 @@ int pthread_join (pthread_t thread, void **value_ptr) else return ESRCH; } -int pthread_cancel (pthread_t thread) -{ - _pthread_data_t* ptd; - - ptd = _pthread_get_data(thread); - - /* check cancel point */ -} - void pthread_exit (void* value) { _pthread_data_t* ptd; + _pthread_cleanup_t* cleanup; + _pthread_key_data_t* key; + extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX]; ptd = _pthread_get_data(rt_thread_self()); + rt_enter_critical(); + /* disable cancel */ + ptd->cancelstate = PTHREAD_CANCEL_DISABLE; /* set return value */ ptd->return_value = value; + rt_exit_critical(); + + /* invoke pushed cleanup */ + while (ptd->cleanup != RT_NULL) + { + cleanup = ptd->cleanup; + ptd->cleanup = cleanup->next; + + cleanup->cleanup_func(cleanup->parameter); + /* release this cleanup function */ + rt_free(cleanup); + } + + /* destruct thread local key */ + if (ptd->tls != RT_NULL) + { + void* data; + rt_uint32_t index; + + for (index = 0; index < PTHREAD_KEY_MAX; index ++) + { + if (_thread_keys[index].is_used) + { + data = ptd->tls[index]; + if (data) + _thread_keys[index].destructor(data); + } + } + + /* release tls area */ + rt_free(ptd->tls); + ptd->tls = RT_NULL; + } + if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE) { /* release the joinable pthread */ @@ -312,14 +346,71 @@ void pthread_cleanup_push(void (*routine)(void*), void *arg) int pthread_setcancelstate(int state, int *oldstate) { + _pthread_data_t* ptd; + + /* get posix thread data */ + ptd = _pthread_get_data(rt_thread_self()); + RT_ASSERT(ptd != RT_NULL); + + if ((state == PTHREAD_CANCEL_ENABLE) || (state == PTHREAD_CANCEL_DISABLE)) + { + if (oldstate) *oldstate = ptd->cancelstate; + ptd->cancelstate = state; + + return 0; + } + + return EINVAL; } int pthread_setcanceltype(int type, int *oldtype) { + _pthread_data_t* ptd; + + /* get posix thread data */ + ptd = _pthread_get_data(rt_thread_self()); + RT_ASSERT(ptd != RT_NULL); + + if ((type != PTHREAD_CANCEL_DEFERRED) && (type != PTHREAD_CANCEL_ASYNCHRONOUS)) + return EINVAL; + + if (oldtype) *oldtype = ptd->canceltype; + ptd->canceltype = type; + return 0; } void pthread_testcancel(void) { + int cancel=0; + _pthread_data_t* ptd; + + /* get posix thread data */ + ptd = _pthread_get_data(rt_thread_self()); + RT_ASSERT(ptd != RT_NULL); + + if (ptd->cancelstate == PTHREAD_CANCEL_ENABLE) cancel = ptd->canceled; + if (cancel) pthread_exit((void*)PTHREAD_CANCELED); +} + +int pthread_cancel(pthread_t thread) +{ + _pthread_data_t* ptd; + + /* get posix thread data */ + ptd = _pthread_get_data(thread); + RT_ASSERT(ptd != RT_NULL); + + /* set canceled */ + if (ptd->cancelstate == PTHREAD_CANCEL_ENABLE) + { + ptd->canceled = 1; + if (ptd->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) + { + /* TODO: need cancel thread */ + } + } + + return 0; } diff --git a/components/pthreads/pthread_internal.h b/components/pthreads/pthread_internal.h index 33ecfb8d0d0ffd635a00315a38e92c217d6de163..9f32105694da7e8cd54f4336b3616ccf151628a0 100644 --- a/components/pthreads/pthread_internal.h +++ b/components/pthreads/pthread_internal.h @@ -13,6 +13,13 @@ struct _pthread_cleanup }; typedef struct _pthread_cleanup _pthread_cleanup_t; +struct _pthread_key_data +{ + int is_used; + void (*destructor)(void* parameter); +}; +typedef struct _pthread_key_data _pthread_key_data_t; + #define PTHREAD_MAGIC 0x70746873 struct _pthread_data { @@ -29,6 +36,11 @@ struct _pthread_data /* semaphore for joinable thread */ rt_sem_t joinable_sem; + /* cancel state and type */ + rt_uint8_t cancelstate; + volatile rt_uint8_t canceltype; + volatile rt_uint8_t canceled; + _pthread_cleanup_t* cleanup; void** tls; /* thread-local storage area */ }; diff --git a/components/pthreads/pthread_tls.c b/components/pthreads/pthread_tls.c index 5dacc1e1f2aff0498b538df552cbecf9ed25c9cf..0fda158a3958d96bceb8d53fe95b4460b9e7dcc0 100644 --- a/components/pthreads/pthread_tls.c +++ b/components/pthreads/pthread_tls.c @@ -1,13 +1,7 @@ #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]; +_pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX]; void pthread_key_system_init() { @@ -82,3 +76,4 @@ int pthread_key_delete(pthread_key_t key) return 0; } +