diff options
| author | yiyue.fang <[email protected]> | 2013-06-26 23:18:30 +0800 |
|---|---|---|
| committer | yiyue.fang <[email protected]> | 2013-06-26 23:18:30 +0800 |
| commit | 8ab2b287b813edc1cdbe8bba430a2593e5fc3e8a (patch) | |
| tree | 1f8534cb1927cb82e38563a26739cc653104c59f /components/pthreads/pthread.c | |
| parent | 773990abdb90078839ea0834fc15539e94a04fdf (diff) | |
Embedded GPLv2 license in pthreads
Diffstat (limited to 'components/pthreads/pthread.c')
| -rw-r--r-- | components/pthreads/pthread.c | 672 |
1 files changed, 360 insertions, 312 deletions
diff --git a/components/pthreads/pthread.c b/components/pthreads/pthread.c index 4455885652..a823253d48 100644 --- a/components/pthreads/pthread.c +++ b/components/pthreads/pthread.c @@ -1,366 +1,409 @@ +/* + * File : pthread.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + */ + #include <pthread.h> #include <sched.h> #include "pthread_internal.h" int pthread_system_init(void) { - /* initialize clock and time */ - clock_time_system_init(); + /* initialize clock and time */ + clock_time_system_init(); - /* initialize key area */ - pthread_key_system_init(); - /* initialize posix mqueue */ - posix_mq_system_init(); - /* initialize posix semaphore */ - posix_sem_system_init(); + /* initialize key area */ + pthread_key_system_init(); + /* initialize posix mqueue */ + posix_mq_system_init(); + /* initialize posix semaphore */ + posix_sem_system_init(); - return 0; + return 0; } static void _pthread_cleanup(rt_thread_t tid) { - _pthread_data_t *ptd; - ptd = _pthread_get_data(tid); + _pthread_data_t *ptd; + ptd = _pthread_get_data(tid); - /* clear cleanup function */ - tid->cleanup = RT_NULL; - if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE) - { - rt_sem_release(ptd->joinable_sem); - } - else - { - /* release pthread resource */ - pthread_detach(tid); - } + /* clear cleanup function */ + tid->cleanup = RT_NULL; + if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE) + { + rt_sem_release(ptd->joinable_sem); + } + else + { + /* release pthread resource */ + pthread_detach(tid); + } } -static void pthread_entry_stub(void* parameter) +static void pthread_entry_stub(void *parameter) { - _pthread_data_t *ptd; - void* value; + _pthread_data_t *ptd; + void *value; - ptd = (_pthread_data_t*)parameter; + ptd = (_pthread_data_t*)parameter; - /* execute pthread entry */ - value = ptd->thread_entry(ptd->thread_parameter); - /* set value */ - ptd->return_value = value; + /* execute pthread entry */ + value = ptd->thread_entry(ptd->thread_parameter); + /* set value */ + ptd->return_value = value; } -int pthread_create (pthread_t *tid, const pthread_attr_t *attr, - void *(*start) (void *), void *parameter) +int pthread_create(pthread_t *tid, + const pthread_attr_t *attr, + void *(*start) (void *), void *parameter) { - int result; - void* stack; - char name[RT_NAME_MAX]; - static rt_uint16_t pthread_number = 0; - _pthread_data_t *ptd; + int result; + void *stack; + char name[RT_NAME_MAX]; + static rt_uint16_t pthread_number = 0; + _pthread_data_t *ptd; + + /* tid shall be provided */ + RT_ASSERT(tid != RT_NULL); + + /* allocate posix thread data */ + ptd = (_pthread_data_t*)rt_malloc(sizeof(_pthread_data_t)); + 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; + ptd->magic = PTHREAD_MAGIC; + + if (attr != RT_NULL) + ptd->attr = *attr; + else + { + /* use default attribute */ + pthread_attr_init(&ptd->attr); + } + + rt_snprintf(name, sizeof(name), "pth%02d", pthread_number ++); + if (ptd->attr.stack_base == 0) + { + stack = (void*)rt_malloc(ptd->attr.stack_size); + } + else + stack = (void*)(ptd->attr.stack_base); + + if (stack == RT_NULL) + { + rt_free(ptd); - /* tid shall be provided */ - RT_ASSERT(tid != RT_NULL); + return ENOMEM; + } - /* allocate posix thread data */ - ptd = (_pthread_data_t*)rt_malloc(sizeof(_pthread_data_t)); - 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; - ptd->magic = PTHREAD_MAGIC; + /* pthread is a static thread object */ + ptd->tid = (rt_thread_t) rt_malloc(sizeof(struct rt_thread)); + if (ptd->tid == RT_NULL) + { + if (ptd->attr.stack_base == 0) + rt_free(stack); + rt_free(ptd); - if (attr != RT_NULL) ptd->attr = *attr; - else - { - /* use default attribute */ - pthread_attr_init(&ptd->attr); - } + return ENOMEM; + } - rt_snprintf(name, sizeof(name), "pth%02d", pthread_number ++); - if (ptd->attr.stack_base == 0) - { - stack = (void*)rt_malloc(ptd->attr.stack_size); - } - else stack = (void*)(ptd->attr.stack_base); + if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE) + { + ptd->joinable_sem = rt_sem_create(name, 0, RT_IPC_FLAG_FIFO); + if (ptd->joinable_sem == RT_NULL) + { + if (ptd->attr.stack_base != 0) + rt_free(stack); + rt_free(ptd); - if (stack == RT_NULL) - { - rt_free(ptd); - return ENOMEM; - } + return ENOMEM; + } + } + else + ptd->joinable_sem = RT_NULL; - /* pthread is a static thread object */ - ptd->tid = (rt_thread_t) rt_malloc(sizeof(struct rt_thread)); - if (ptd->tid == RT_NULL) - { - if (ptd->attr.stack_base ==0) rt_free(stack); - rt_free(ptd); - return ENOMEM; - } + /* set parameter */ + ptd->thread_entry = start; + ptd->thread_parameter = parameter; - if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE) - { - ptd->joinable_sem = rt_sem_create(name, 0, RT_IPC_FLAG_FIFO); - if (ptd->joinable_sem == RT_NULL) - { - if (ptd->attr.stack_base !=0) rt_free(stack); - rt_free(ptd); - return ENOMEM; - } - } - else ptd->joinable_sem = RT_NULL; + /* initial this pthread to system */ + if (rt_thread_init(ptd->tid, name, pthread_entry_stub, ptd, + stack, ptd->attr.stack_size, + ptd->attr.priority, 5) != RT_EOK) + { + if (ptd->attr.stack_base == 0) + rt_free(stack); + if (ptd->joinable_sem != RT_NULL) + rt_sem_delete(ptd->joinable_sem); + rt_free(ptd); - /* set parameter */ - ptd->thread_entry = start; - ptd->thread_parameter = parameter; + return EINVAL; + } - /* initial this pthread to system */ - if (rt_thread_init(ptd->tid, name, pthread_entry_stub, ptd, - stack, ptd->attr.stack_size, - ptd->attr.priority, 5) != RT_EOK) - { - if (ptd->attr.stack_base ==0) rt_free(stack); - if (ptd->joinable_sem != RT_NULL) rt_sem_delete(ptd->joinable_sem); - rt_free(ptd); - return EINVAL; - } + /* set pthread id */ + *tid = ptd->tid; - /* set pthread id */ - *tid = ptd->tid; + /* set pthread cleanup function and ptd data */ + (*tid)->cleanup = _pthread_cleanup; + (*tid)->user_data = (rt_uint32_t)ptd; - /* set pthread cleanup function and ptd data */ - (*tid)->cleanup = _pthread_cleanup; - (*tid)->user_data = (rt_uint32_t)ptd; + /* start thread */ + result = rt_thread_startup(*tid); + if (result == RT_EOK) + return 0; - /* start thread */ - result = rt_thread_startup(*tid); - if (result == RT_EOK) return 0; + /* start thread failed */ + rt_thread_detach(ptd->tid); + if (ptd->attr.stack_base == 0) + rt_free(stack); + if (ptd->joinable_sem != RT_NULL) + rt_sem_delete(ptd->joinable_sem); - /* start thread failed */ - rt_thread_detach(ptd->tid); - if (ptd->attr.stack_base ==0) rt_free(stack); - if (ptd->joinable_sem != RT_NULL) rt_sem_delete(ptd->joinable_sem); + rt_free(ptd); - rt_free(ptd); - return EINVAL; + return EINVAL; } RTM_EXPORT(pthread_create); int pthread_detach(pthread_t thread) { - _pthread_data_t* ptd; + _pthread_data_t* ptd; - ptd = _pthread_get_data(thread); + ptd = _pthread_get_data(thread); - if (thread->stat == RT_THREAD_CLOSE) - { - /* delete joinable semaphore */ - if (ptd->joinable_sem != RT_NULL) - rt_sem_delete(ptd->joinable_sem); - /* detach thread object */ - rt_thread_detach(ptd->tid); + if (thread->stat == RT_THREAD_CLOSE) + { + /* delete joinable semaphore */ + if (ptd->joinable_sem != RT_NULL) + rt_sem_delete(ptd->joinable_sem); + /* detach thread object */ + rt_thread_detach(ptd->tid); - /* release thread resource */ - if (ptd->attr.stack_base == RT_NULL) - { - /* release thread allocated stack */ - rt_free(ptd->tid->stack_addr); - } + /* release thread resource */ + if (ptd->attr.stack_base == RT_NULL) + { + /* 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); - } - else - { - rt_enter_critical(); - /* change to detach state */ - ptd->attr.detachstate = PTHREAD_CREATE_DETACHED; + /* + * 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); + } + else + { + rt_enter_critical(); + /* change to detach state */ + ptd->attr.detachstate = PTHREAD_CREATE_DETACHED; - /* detach joinable semaphore */ - rt_sem_delete(ptd->joinable_sem); - ptd->joinable_sem = RT_NULL; - rt_exit_critical(); - } + /* detach joinable semaphore */ + rt_sem_delete(ptd->joinable_sem); + ptd->joinable_sem = RT_NULL; + rt_exit_critical(); + } - return 0; + return 0; } RTM_EXPORT(pthread_detach); int pthread_join (pthread_t thread, void **value_ptr) { - _pthread_data_t* ptd; - rt_err_t result; + _pthread_data_t* ptd; + rt_err_t result; - if (thread == rt_thread_self()) - { - /* join self */ - return EDEADLK; - } + if (thread == rt_thread_self()) + { + /* join self */ + return EDEADLK; + } - ptd = _pthread_get_data(thread); - if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED) - return EINVAL; /* join on a detached pthread */ + ptd = _pthread_get_data(thread); + if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED) + return EINVAL; /* join on a detached pthread */ - result = rt_sem_take(ptd->joinable_sem, RT_WAITING_FOREVER); - if (result == RT_EOK) - { - /* get return value */ - if (value_ptr != RT_NULL) *value_ptr = ptd->return_value; + result = rt_sem_take(ptd->joinable_sem, RT_WAITING_FOREVER); + if (result == RT_EOK) + { + /* get return value */ + if (value_ptr != RT_NULL) + *value_ptr = ptd->return_value; - /* release resource */ - pthread_detach(thread); - } - else return ESRCH; - - return 0; + /* release resource */ + pthread_detach(thread); + } + else + return ESRCH; + + return 0; } RTM_EXPORT(pthread_join); -void pthread_exit (void* value) +void pthread_exit (void *value) { - _pthread_data_t* ptd; - _pthread_cleanup_t* cleanup; - extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX]; + _pthread_data_t *ptd; + _pthread_cleanup_t *cleanup; + extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX]; - ptd = _pthread_get_data(rt_thread_self()); + 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(); + 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; + /* 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); - } + 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); - } - } + /* 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; - } + /* release tls area */ + rt_free(ptd->tls); + ptd->tls = RT_NULL; + } - if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE) - { - /* release the joinable pthread */ - rt_sem_release(ptd->joinable_sem); - } + if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE) + { + /* release the joinable pthread */ + rt_sem_release(ptd->joinable_sem); + } - /* detach thread */ - rt_thread_detach(ptd->tid); - /* reschedule thread */ - rt_schedule(); + /* detach thread */ + rt_thread_detach(ptd->tid); + /* reschedule thread */ + rt_schedule(); } RTM_EXPORT(pthread_exit); -int pthread_once(pthread_once_t * once_control, void (*init_routine) (void)) +int pthread_once(pthread_once_t *once_control, void (*init_routine) (void)) { - RT_ASSERT(once_control != RT_NULL); - RT_ASSERT(init_routine != RT_NULL); + RT_ASSERT(once_control != RT_NULL); + RT_ASSERT(init_routine != RT_NULL); - rt_enter_critical(); - if (!(*once_control)) - { - /* call routine once */ - *once_control = 1; - rt_exit_critical(); + rt_enter_critical(); + if (!(*once_control)) + { + /* call routine once */ + *once_control = 1; + rt_exit_critical(); - init_routine(); - } - rt_exit_critical(); + init_routine(); + } + rt_exit_critical(); - return 0; + return 0; } RTM_EXPORT(pthread_once); int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) { - return ENOTSUP; + return ENOTSUP; } RTM_EXPORT(pthread_atfork); int pthread_kill(pthread_t thread, int sig) { - return ENOTSUP; + return ENOTSUP; } RTM_EXPORT(pthread_kill); void pthread_cleanup_pop(int execute) { - _pthread_data_t* ptd; - _pthread_cleanup_t* cleanup; + _pthread_data_t *ptd; + _pthread_cleanup_t *cleanup; - /* get posix thread data */ - ptd = _pthread_get_data(rt_thread_self()); - RT_ASSERT(ptd != RT_NULL); + /* 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 (execute) + { + rt_enter_critical(); + cleanup = ptd->cleanup; + if (cleanup) + ptd->cleanup = cleanup->next; + rt_exit_critical(); - if (cleanup) - { - cleanup->cleanup_func(cleanup->parameter); + if (cleanup) + { + cleanup->cleanup_func(cleanup->parameter); - rt_free(cleanup); - } - } + rt_free(cleanup); + } + } } RTM_EXPORT(pthread_cleanup_pop); void pthread_cleanup_push(void (*routine)(void*), void *arg) { - _pthread_data_t* ptd; - _pthread_cleanup_t* cleanup; + _pthread_data_t *ptd; + _pthread_cleanup_t *cleanup; - /* get posix thread data */ - ptd = _pthread_get_data(rt_thread_self()); - RT_ASSERT(ptd != RT_NULL); + /* 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; + 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(); - } + rt_enter_critical(); + cleanup->next = ptd->cleanup; + ptd->cleanup = cleanup; + rt_exit_critical(); + } } RTM_EXPORT(pthread_cleanup_push); @@ -394,85 +437,90 @@ RTM_EXPORT(pthread_cleanup_push); int pthread_setcancelstate(int state, int *oldstate) { - _pthread_data_t* ptd; + _pthread_data_t *ptd; - /* get posix thread data */ - ptd = _pthread_get_data(rt_thread_self()); - RT_ASSERT(ptd != RT_NULL); + /* 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; + if ((state == PTHREAD_CANCEL_ENABLE) || (state == PTHREAD_CANCEL_DISABLE)) + { + if (oldstate) + *oldstate = ptd->cancelstate; + ptd->cancelstate = state; - return 0; - } + return 0; + } - return EINVAL; + return EINVAL; } RTM_EXPORT(pthread_setcancelstate); int pthread_setcanceltype(int type, int *oldtype) { - _pthread_data_t* ptd; + _pthread_data_t *ptd; - /* get posix thread data */ - ptd = _pthread_get_data(rt_thread_self()); - RT_ASSERT(ptd != RT_NULL); + /* 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 ((type != PTHREAD_CANCEL_DEFERRED) && (type != PTHREAD_CANCEL_ASYNCHRONOUS)) + return EINVAL; - if (oldtype) *oldtype = ptd->canceltype; - ptd->canceltype = type; + if (oldtype) + *oldtype = ptd->canceltype; + ptd->canceltype = type; - return 0; + return 0; } RTM_EXPORT(pthread_setcanceltype); void pthread_testcancel(void) { - int cancel=0; - _pthread_data_t* ptd; + int cancel=0; + _pthread_data_t* ptd; - /* get posix thread data */ - ptd = _pthread_get_data(rt_thread_self()); - RT_ASSERT(ptd != RT_NULL); + /* 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); + if (ptd->cancelstate == PTHREAD_CANCEL_ENABLE) + cancel = ptd->canceled; + if (cancel) + pthread_exit((void*)PTHREAD_CANCELED); } RTM_EXPORT(pthread_testcancel); int pthread_cancel(pthread_t thread) { - _pthread_data_t* ptd; + _pthread_data_t *ptd; - /* cancel self */ - if (thread == rt_thread_self()) return 0; + /* cancel self */ + if (thread == rt_thread_self()) + return 0; - /* get posix thread data */ - ptd = _pthread_get_data(thread); - RT_ASSERT(ptd != RT_NULL); + /* 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) - { - /* - * to detach thread. - * this thread will be removed from scheduler list - * and because there is a cleanup function in the - * thread (pthread_cleanup), it will move to defunct - * thread list and wait for handling in idle thread. - */ - rt_thread_detach(thread); - } - } + /* set canceled */ + if (ptd->cancelstate == PTHREAD_CANCEL_ENABLE) + { + ptd->canceled = 1; + if (ptd->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) + { + /* + * to detach thread. + * this thread will be removed from scheduler list + * and because there is a cleanup function in the + * thread (pthread_cleanup), it will move to defunct + * thread list and wait for handling in idle thread. + */ + rt_thread_detach(thread); + } + } - return 0; + return 0; } RTM_EXPORT(pthread_cancel); |
