diff options
| author | Bernard Xiong <[email protected]> | 2016-05-10 09:22:01 +0800 |
|---|---|---|
| committer | Bernard Xiong <[email protected]> | 2016-05-10 09:22:01 +0800 |
| commit | 64feef0dde9d8353ffe4a3f257ab17848ccf6f53 (patch) | |
| tree | dd3f096b8a3c249e5327cc34a0c105c5125099e1 /components/libc | |
| parent | eb320a0104bbaa6c1235fe899b6d099fdabe8c25 (diff) | |
[LIBC] mv pthreads/libdl to libc and rename dfs_lwip to dfs_net
Diffstat (limited to 'components/libc')
27 files changed, 3705 insertions, 1 deletions
diff --git a/components/libc/SConscript b/components/libc/SConscript index 4ed1dde123..a7913ed744 100644 --- a/components/libc/SConscript +++ b/components/libc/SConscript @@ -17,4 +17,7 @@ else: if rtconfig.PLATFORM == 'gcc' and rtconfig.ARCH != 'sim': objs = objs + SConscript('minilibc/SConscript') +objs = objs + SConscript('pthreads/SConscript') +objs = objs + SConscript('libdl/SConscript') + Return('objs') diff --git a/components/libc/libdl/SConscript b/components/libc/libdl/SConscript new file mode 100644 index 0000000000..f7f588858a --- /dev/null +++ b/components/libc/libdl/SConscript @@ -0,0 +1,9 @@ +from building import * + +src = Glob('*.c') +cwd = GetCurrentDir() +CPPPATH = [cwd] + +group = DefineGroup('libdl', src, depend = ['RT_USING_MODULE', 'RT_USING_LIBDL'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/libc/libdl/dlclose.c b/components/libc/libdl/dlclose.c new file mode 100644 index 0000000000..af070891fc --- /dev/null +++ b/components/libc/libdl/dlclose.c @@ -0,0 +1,36 @@ +/* + * File : dlclose.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2010-11-17 yi.qiu first version + */ + +#include <rtthread.h> +#include <rtm.h> + +int dlclose (void *handle) +{ + rt_module_t module; + + RT_ASSERT(handle != RT_NULL); + + module = (rt_module_t)handle; + module->nref--; + + if(module->nref <= 0) + { + rt_module_unload(module); + } + + return RT_TRUE; +} + +RTM_EXPORT(dlclose) + diff --git a/components/libc/libdl/dlerror.c b/components/libc/libdl/dlerror.c new file mode 100644 index 0000000000..dd076412fe --- /dev/null +++ b/components/libc/libdl/dlerror.c @@ -0,0 +1,24 @@ +/* + * File : dlerror.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2010-11-17 yi.qiu first version + */ + +#include <rtthread.h> +#include <rtm.h> + +const char *dlerror(void) +{ + return "TODO"; +} + +RTM_EXPORT(dlerror) + diff --git a/components/libc/libdl/dlfcn.h b/components/libc/libdl/dlfcn.h new file mode 100644 index 0000000000..069f0d9c46 --- /dev/null +++ b/components/libc/libdl/dlfcn.h @@ -0,0 +1,18 @@ +#ifndef __DLFCN_H_ +#define __DLFCN_H_ + +#define RTLD_LAZY 0x00000 +#define RTLD_NOW 0x00001 + +#define RTLD_LOCAL 0x00000 +#define RTLD_GLOBAL 0x10000 + +#define RTLD_DEFAULT ((void*)1) +#define RTLD_NEXT ((void*)2) + +void *dlopen (const char *filename, int flag); +const char *dlerror(void); +void *dlsym(void *handle, const char *symbol); +int dlclose (void *handle); + +#endif diff --git a/components/libc/libdl/dlopen.c b/components/libc/libdl/dlopen.c new file mode 100644 index 0000000000..5e063eed96 --- /dev/null +++ b/components/libc/libdl/dlopen.c @@ -0,0 +1,55 @@ +/* + * File : dlopen.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2010-11-17 yi.qiu first version + */ + +#include <rtthread.h> +#include <rtm.h> +#include <string.h> + +#define MODULE_ROOT_DIR "/module/lib" + +void* dlopen(const char *filename, int flags) +{ + rt_module_t module; + char *fullpath; + const char*def_path = MODULE_ROOT_DIR; + + /* check parameters */ + RT_ASSERT(filename != RT_NULL); + + if (filename[0] != '/') /* it's a absolute path, use it directly */ + { + fullpath = rt_malloc(strlen(def_path) + strlen(filename) + 2); + + /* join path and file name */ + rt_snprintf(fullpath, strlen(def_path) + strlen(filename) + 2, + "%s/%s", def_path, filename); + } + else + { + rt_kprintf("use absolute path\n"); + return RT_NULL; + } + + /* find in module list */ + module = rt_module_find(fullpath); + + if(module != RT_NULL) module->nref++; + else module = rt_module_open(fullpath); + + rt_free(fullpath); + return (void*)module; +} + +RTM_EXPORT(dlopen) + diff --git a/components/libc/libdl/dlsym.c b/components/libc/libdl/dlsym.c new file mode 100644 index 0000000000..36c7b01fce --- /dev/null +++ b/components/libc/libdl/dlsym.c @@ -0,0 +1,37 @@ +/* + * File : dlsym.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2010-11-17 yi.qiu first version + */ + +#include <rtthread.h> +#include <rtm.h> + +void* dlsym(void *handle, const char* symbol) +{ + int i; + rt_module_t module; + + RT_ASSERT(handle != RT_NULL); + + module = (rt_module_t)handle; + + for(i=0; i<module->nsym; i++) + { + if (rt_strcmp(module->symtab[i].name, symbol) == 0) + return (void*)module->symtab[i].addr; + } + + return RT_NULL; +} + +RTM_EXPORT(dlsym) + diff --git a/components/libc/newlib/syscalls.c b/components/libc/newlib/syscalls.c index b5d4ec5bf6..55c19ccee9 100644 --- a/components/libc/newlib/syscalls.c +++ b/components/libc/newlib/syscalls.c @@ -450,5 +450,15 @@ void __libc_init_array(void) void abort(void) { - return ; + if (rt_thread_self()) + { + rt_thread_t self = rt_thread_self(); + + rt_kprintf("thread:%-8.*s abort!\n", RT_NAME_MAX, self->name); + rt_thread_suspend(self); + + rt_schedule(); + } + + while (1); } diff --git a/components/libc/pthreads/SConscript b/components/libc/pthreads/SConscript new file mode 100644 index 0000000000..9023e12c13 --- /dev/null +++ b/components/libc/pthreads/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +group = DefineGroup('pthreads', src, depend = ['RT_USING_PTHREADS', 'RT_USING_LIBC'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/libc/pthreads/clock_time.c b/components/libc/pthreads/clock_time.c new file mode 100644 index 0000000000..06227e17e7 --- /dev/null +++ b/components/libc/pthreads/clock_time.c @@ -0,0 +1,155 @@ +/* + * File : clock_time.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 + * 2012-12-08 Bernard fix the issue of _timevalue.tv_usec initialization, + * which found by Rob <[email protected]> + */ + +#include <rtthread.h> +#include <pthread.h> + +struct timeval _timevalue; +void clock_time_system_init() +{ + time_t time; + rt_tick_t tick; + rt_device_t device; + + time = 0; + device = rt_device_find("rtc"); + if (device != RT_NULL) + { + /* get realtime seconds */ + rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time); + } + + /* get tick */ + tick = rt_tick_get(); + + _timevalue.tv_usec = (tick%RT_TICK_PER_SECOND) * MICROSECOND_PER_TICK; + _timevalue.tv_sec = time - tick/RT_TICK_PER_SECOND - 1; +} + +int clock_time_to_tick(const struct timespec *time) +{ + int tick; + int nsecond, second; + struct timespec tp; + + RT_ASSERT(time != RT_NULL); + + tick = RT_WAITING_FOREVER; + if (time != NULL) + { + /* get current tp */ + clock_gettime(CLOCK_REALTIME, &tp); + + if ((time->tv_nsec - tp.tv_nsec) < 0) + { + nsecond = NANOSECOND_PER_SECOND - (tp.tv_nsec - time->tv_nsec); + second = time->tv_sec - tp.tv_sec - 1; + } + else + { + nsecond = time->tv_nsec - tp.tv_nsec; + second = time->tv_sec - tp.tv_sec; + } + + tick = second * RT_TICK_PER_SECOND + nsecond * RT_TICK_PER_SECOND / NANOSECOND_PER_SECOND; + if (tick < 0) tick = 0; + } + + return tick; +} +RTM_EXPORT(clock_time_to_tick); + +int clock_getres(clockid_t clockid, struct timespec *res) +{ + if ((clockid != CLOCK_REALTIME) || (res == RT_NULL)) + { + rt_set_errno(EINVAL); + + return -1; + } + + res->tv_sec = 0; + res->tv_nsec = NANOSECOND_PER_SECOND/RT_TICK_PER_SECOND; + + return 0; +} +RTM_EXPORT(clock_getres); + +int clock_gettime(clockid_t clockid, struct timespec *tp) +{ + rt_tick_t tick; + + if ((clockid != CLOCK_REALTIME) || (tp == RT_NULL)) + { + rt_set_errno(EINVAL); + + return -1; + } + + /* get tick */ + tick = rt_tick_get(); + + tp->tv_sec = _timevalue.tv_sec + tick / RT_TICK_PER_SECOND; + tp->tv_nsec = (_timevalue.tv_usec + (tick % RT_TICK_PER_SECOND) * NANOSECOND_PER_TICK) * 1000; + + return 0; +} +RTM_EXPORT(clock_gettime); + +int clock_settime(clockid_t clockid, const struct timespec *tp) +{ + int second; + rt_tick_t tick; + rt_device_t device; + + if ((clockid != CLOCK_REALTIME) || (tp == RT_NULL)) + { + rt_set_errno(EINVAL); + + return -1; + } + + /* get second */ + second = tp->tv_sec; + /* get tick */ + tick = rt_tick_get(); + + /* update timevalue */ + _timevalue.tv_usec = MICROSECOND_PER_SECOND - (tick % RT_TICK_PER_SECOND) * MICROSECOND_PER_TICK; + _timevalue.tv_sec = second - tick/RT_TICK_PER_SECOND - 1; + + /* update for RTC device */ + device = rt_device_find("rtc"); + if (device != RT_NULL) + { + /* set realtime seconds */ + rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &second); + } + else + return -1; + + return 0; +} +RTM_EXPORT(clock_settime); diff --git a/components/libc/pthreads/mqueue.c b/components/libc/pthreads/mqueue.c new file mode 100644 index 0000000000..7b669dc367 --- /dev/null +++ b/components/libc/pthreads/mqueue.c @@ -0,0 +1,344 @@ +/* + * File : mqueue.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 <string.h> +#include "mqueue.h" +#include "pthread_internal.h" + +static mqd_t posix_mq_list = RT_NULL; +static struct rt_semaphore posix_mq_lock; +void posix_mq_system_init() +{ + rt_sem_init(&posix_mq_lock, "pmq", 1, RT_IPC_FLAG_FIFO); +} + +rt_inline void posix_mq_insert(mqd_t pmq) +{ + pmq->next = posix_mq_list; + posix_mq_list = pmq; +} + +static void posix_mq_delete(mqd_t pmq) +{ + mqd_t iter; + if (posix_mq_list == pmq) + { + posix_mq_list = pmq->next; + + rt_mq_delete(pmq->mq); + rt_free(pmq); + + return; + } + for (iter = posix_mq_list; iter->next != RT_NULL; iter = iter->next) + { + if (iter->next == pmq) + { + /* delete this mq */ + if (pmq->next != RT_NULL) + iter->next = pmq->next; + else + iter->next = RT_NULL; + + /* delete RT-Thread mqueue */ + rt_mq_delete(pmq->mq); + rt_free(pmq); + + return ; + } + } +} + +static mqd_t posix_mq_find(const char* name) +{ + mqd_t iter; + rt_object_t object; + + for (iter = posix_mq_list; iter != RT_NULL; iter = iter->next) + { + object = (rt_object_t)(iter->mq); + + if (strncmp(object->name, name, RT_NAME_MAX) == 0) + { + return iter; + } + } + + return RT_NULL; +} + +int mq_setattr(mqd_t mqdes, + const struct mq_attr *mqstat, + struct mq_attr *omqstat) +{ + rt_set_errno(-RT_ERROR); + + return -1; +} +RTM_EXPORT(mq_setattr); + +int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat) +{ + if ((mqdes == RT_NULL) || mqstat == RT_NULL) + { + rt_set_errno(EBADF); + + return -1; + } + + mqstat->mq_maxmsg = mqdes->mq->max_msgs; + mqstat->mq_msgsize = mqdes->mq->msg_size; + mqstat->mq_curmsgs = 0; + mqstat->mq_flags = 0; + + return 0; +} +RTM_EXPORT(mq_getattr); + +mqd_t mq_open(const char *name, int oflag, ...) +{ + mqd_t mqdes; + va_list arg; + mode_t mode; + struct mq_attr *attr = RT_NULL; + + /* lock posix mqueue list */ + rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER); + + mqdes = RT_NULL; + if (oflag & O_CREAT) + { + va_start(arg, oflag); + mode = (mode_t)va_arg(arg, unsigned int); + mode = mode; + attr = (struct mq_attr *)va_arg(arg, struct mq_attr *); + va_end(arg); + + if (oflag & O_EXCL) + { + if (posix_mq_find(name) != RT_NULL) + { + rt_set_errno(EEXIST); + goto __return; + } + } + mqdes = (mqd_t) rt_malloc (sizeof(struct mqdes)); + if (mqdes == RT_NULL) + { + rt_set_errno(ENFILE); + goto __return; + } + + /* create RT-Thread message queue */ + mqdes->mq = rt_mq_create(name, attr->mq_msgsize, attr->mq_maxmsg, RT_IPC_FLAG_FIFO); + if (mqdes->mq == RT_NULL) /* create failed */ + { + rt_set_errno(ENFILE); + goto __return; + } + /* initialize reference count */ + mqdes->refcount = 1; + mqdes->unlinked = 0; + + /* insert mq to posix mq list */ + posix_mq_insert(mqdes); + } + else + { + /* find mqueue */ + mqdes = posix_mq_find(name); + if (mqdes != RT_NULL) + { + mqdes->refcount ++; /* increase reference count */ + } + else + { + rt_set_errno(ENOENT); + goto __return; + } + } + rt_sem_release(&posix_mq_lock); + + return mqdes; + +__return: + /* release lock */ + rt_sem_release(&posix_mq_lock); + + /* release allocated memory */ + if (mqdes != RT_NULL) + { + if (mqdes->mq != RT_NULL) + { + /* delete RT-Thread message queue */ + rt_mq_delete(mqdes->mq); + } + rt_free(mqdes); + } + return RT_NULL; +} +RTM_EXPORT(mq_open); + +ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio) +{ + rt_err_t result; + + if ((mqdes == RT_NULL) || (msg_ptr == RT_NULL)) + { + rt_set_errno(EINVAL); + + return -1; + } + + result = rt_mq_recv(mqdes->mq, msg_ptr, msg_len, RT_WAITING_FOREVER); + if (result == RT_EOK) + return msg_len; + + rt_set_errno(EBADF); + return -1; +} +RTM_EXPORT(mq_receive); + +int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio) +{ + rt_err_t result; + + if ((mqdes == RT_NULL) || (msg_ptr == RT_NULL)) + { + rt_set_errno(EINVAL); + + return -1; + } + + result = rt_mq_send(mqdes->mq, (void*)msg_ptr, msg_len); + if (result == RT_EOK) + return 0; + + rt_set_errno(EBADF); + + return -1; +} +RTM_EXPORT(mq_send); + +ssize_t mq_timedreceive(mqd_t mqdes, + char *msg_ptr, + size_t msg_len, + unsigned *msg_prio, + const struct timespec *abs_timeout) +{ + int tick; + rt_err_t result; + + /* parameters check */ + if ((mqdes == RT_NULL) || (msg_ptr == RT_NULL)) + { + rt_set_errno(EINVAL); + + return -1; + } + + tick = clock_time_to_tick(abs_timeout); + + result = rt_mq_recv(mqdes->mq, msg_ptr, msg_len, tick); + if (result == RT_EOK) + return msg_len; + + if (result == -RT_ETIMEOUT) + rt_set_errno(ETIMEDOUT); + else + rt_set_errno(EBADMSG); + + return -1; +} +RTM_EXPORT(mq_timedreceive); + +int mq_timedsend(mqd_t mqdes, + const char *msg_ptr, + size_t msg_len, + unsigned msg_prio, + const struct timespec *abs_timeout) +{ + /* RT-Thread does not support timed send */ + return mq_send(mqdes, msg_ptr, msg_len, msg_prio); +} +RTM_EXPORT(mq_timedsend); + +int mq_notify(mqd_t mqdes, const struct sigevent *notification) +{ + rt_set_errno(-RT_ERROR); + + return -1; +} +RTM_EXPORT(mq_notify); + +int mq_close(mqd_t mqdes) +{ + if (mqdes == RT_NULL) + { + rt_set_errno(EINVAL); + + return -1; + } + + /* lock posix mqueue list */ + rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER); + mqdes->refcount --; + if (mqdes->refcount == 0) + { + /* delete from posix mqueue list */ + if (mqdes->unlinked) + posix_mq_delete(mqdes); + } + rt_sem_release(&posix_mq_lock); + + return 0; +} +RTM_EXPORT(mq_close); + +int mq_unlink(const char *name) +{ + mqd_t pmq; + + /* lock posix mqueue list */ + rt_sem_take(&posix_mq_lock, RT_WAITING_FOREVER); + pmq = posix_mq_find(name); + if (pmq != RT_NULL) + { + pmq->unlinked = 1; + if (pmq->refcount == 0) + { + /* remove this mqueue */ + posix_mq_delete(pmq); + } + rt_sem_release(&posix_mq_lock); + + return 0; + } + rt_sem_release(&posix_mq_lock); + + /* no this entry */ + rt_set_errno(ENOENT); + + return -1; +} +RTM_EXPORT(mq_unlink); diff --git a/components/libc/pthreads/mqueue.h b/components/libc/pthreads/mqueue.h new file mode 100644 index 0000000000..de2925837f --- /dev/null +++ b/components/libc/pthreads/mqueue.h @@ -0,0 +1,73 @@ +/* + * File : mqueue.h + * 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 + */ + +#ifndef __MQUEUE_H__ +#define __MQUEUE_H__ + +#include <rtthread.h> +#include <pthread.h> + +struct mqdes +{ + /* reference count and unlinked */ + rt_uint16_t refcount; + rt_uint16_t unlinked; + + /* RT-Thread message queue */ + rt_mq_t mq; + /* next posix mqueue */ + struct mqdes* next; +}; +typedef struct mqdes* mqd_t; + +struct mq_attr +{ + long mq_flags; /* Message queue flags. */ + long mq_maxmsg; /* Maximum number of messages. */ + long mq_msgsize; /* Maximum message size. */ + long mq_curmsgs; /* Number of messages currently queued. */ +}; + +int mq_close(mqd_t mqdes); +int mq_getattr(mqd_t mqdes, struct mq_attr *mqstat); +int mq_notify(mqd_t mqdes, const struct sigevent *notification); +mqd_t mq_open(const char *name, int oflag, ...); +ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio); +int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio); +int mq_setattr(mqd_t mqdes, + const struct mq_attr *mqstat, + struct mq_attr *omqstat); +ssize_t mq_timedreceive(mqd_t mqdes, + char *msg_ptr, + size_t msg_len, + unsigned *msg_prio, + const struct timespec *abs_timeout); +int mq_timedsend(mqd_t mqdes, + const char *msg_ptr, + size_t msg_len, + unsigned msg_prio, + const struct timespec *abs_timeout); + +int mq_unlink(const char *name); + +#endif diff --git a/components/libc/pthreads/posix_types.h b/components/libc/pthreads/posix_types.h new file mode 100644 index 0000000000..1e401e2de3 --- /dev/null +++ b/components/libc/pthreads/posix_types.h @@ -0,0 +1,48 @@ +/* + * File : posix_types.h + * 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 + * 2013-12-23 Bernard Add the checking for ESHUTDOWN + */ + +#ifndef __POSIX_TYPES_H__ +#define __POSIX_TYPES_H__ + +#include <rtthread.h> + +#include <stddef.h> +#include <stdarg.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/time.h> + +/* errno for Keil MDK */ +#if defined(__CC_ARM) || defined(__IAR_SYSTEMS_ICC__) +#include <sys/errno.h> +#include <sys/unistd.h> +#else +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#endif + +#endif + diff --git a/components/libc/pthreads/pthread.c b/components/libc/pthreads/pthread.c new file mode 100644 index 0000000000..41432f760f --- /dev/null +++ b/components/libc/pthreads/pthread.c @@ -0,0 +1,526 @@ +/* + * 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 key area */ + pthread_key_system_init(); + /* initialize posix mqueue */ + posix_mq_system_init(); + /* initialize posix semaphore */ + posix_sem_system_init(); + + return 0; +} + +static void _pthread_cleanup(rt_thread_t 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); + } +} + +static void pthread_entry_stub(void *parameter) +{ + _pthread_data_t *ptd; + void *value; + + ptd = (_pthread_data_t*)parameter; + + /* 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 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); + + return ENOMEM; + } + + /* 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; + } + + 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; + + /* set parameter */ + ptd->thread_entry = start; + ptd->thread_parameter = parameter; + + /* 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 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 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); + + return EINVAL; +} +RTM_EXPORT(pthread_create); + +int pthread_detach(pthread_t thread) +{ + _pthread_data_t* ptd; + + 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); + + /* 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; + + /* detach joinable semaphore */ + rt_sem_delete(ptd->joinable_sem); + ptd->joinable_sem = RT_NULL; + rt_exit_critical(); + } + + return 0; +} +RTM_EXPORT(pthread_detach); + +int pthread_join (pthread_t thread, void **value_ptr) +{ + _pthread_data_t* ptd; + rt_err_t result; + + 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 */ + + 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; +} +RTM_EXPORT(pthread_join); + +void pthread_exit (void *value) +{ + _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()); + + 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 */ + rt_sem_release(ptd->joinable_sem); + } + + /* 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)) +{ + 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(); + + init_routine(); + } + rt_exit_critical(); + + return 0; +} +RTM_EXPORT(pthread_once); + +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) +{ + return EOPNOTSUPP; +} +RTM_EXPORT(pthread_atfork); + +int pthread_kill(pthread_t thread, int sig) +{ + return EOPNOTSUPP; +} +RTM_EXPORT(pthread_kill); + +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); + } + } +} +RTM_EXPORT(pthread_cleanup_pop); + +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(); + } +} +RTM_EXPORT(pthread_cleanup_push); + +/* + * According to IEEE Std 1003.1, 2004 Edition , following pthreads + * interface support cancellation point: + * mq_receive() + * mq_send() + * mq_timedreceive() + * mq_timedsend() + * msgrcv() + * msgsnd() + * msync() + * pthread_cond_timedwait() + * pthread_cond_wait() + * pthread_join() + * pthread_testcancel() + * sem_timedwait() + * sem_wait() + * + * A cancellation point may also occur when a thread is + * executing the following functions: + * pthread_rwlock_rdlock() + * pthread_rwlock_timedrdlock() + * pthread_rwlock_timedwrlock() + * pthread_rwlock_wrlock() + * + * The pthread_cancel(), pthread_setcancelstate(), and pthread_setcanceltype() + * functions are defined to be async-cancel safe. + */ + +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; +} +RTM_EXPORT(pthread_setcancelstate); + +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; +} +RTM_EXPORT(pthread_setcanceltype); + +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); +} +RTM_EXPORT(pthread_testcancel); + +int pthread_cancel(pthread_t thread) +{ + _pthread_data_t *ptd; + + /* cancel self */ + if (thread == rt_thread_self()) + return 0; + + /* 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); + } + } + + return 0; +} +RTM_EXPORT(pthread_cancel); + diff --git a/components/libc/pthreads/pthread.h b/components/libc/pthreads/pthread.h new file mode 100644 index 0000000000..7481595682 --- /dev/null +++ b/components/libc/pthreads/pthread.h @@ -0,0 +1,305 @@ +/* + * File : pthread.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, 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 + * 2010-10-26 Bernard the first version + */ + +#ifndef __PTHREAD_H__ +#define __PTHREAD_H__ + +#include <rtthread.h> +#include <posix_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; +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 +}; + +enum +{ + PTHREAD_MUTEX_NORMAL = 0, + PTHREAD_MUTEX_RECURSIVE = 1, + PTHREAD_MUTEX_ERRORCHECK = 2, + PTHREAD_MUTEX_ERRORCHECK_NP = PTHREAD_MUTEX_ERRORCHECK, + PTHREAD_MUTEX_RECURSIVE_NP = PTHREAD_MUTEX_RECURSIVE, + PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL +}; + +/* init value for pthread_once_t */ +#define PTHREAD_ONCE_INIT 0 + +enum +{ + PTHREAD_PRIO_INHERIT =0, + PTHREAD_PRIO_NONE, + PTHREAD_PRIO_PROTECT, +}; + +#define PTHREAD_PROCESS_PRIVATE 0 +#define PTHREAD_PROCESS_SHARED 1 + +#define PTHREAD_SCOPE_PROCESS 0 +#define PTHREAD_SCOPE_SYSTEM 1 + +struct pthread_attr +{ + void* stack_base; + rt_uint16_t stack_size; /* stack size of thread */ + + rt_uint8_t priority; /* priority of thread */ + rt_uint8_t detachstate; /* detach state */ + rt_uint8_t policy; /* scheduler policy */ + rt_uint8_t inheritsched; /* Inherit parent prio/policy */ +}; +typedef struct pthread_attr pthread_attr_t; + +struct pthread_mutex +{ + pthread_mutexattr_t attr; + struct rt_mutex lock; +}; +typedef struct pthread_mutex pthread_mutex_t; + +struct pthread_cond +{ + pthread_condattr_t attr; + struct rt_semaphore sem; +}; +typedef struct pthread_cond pthread_cond_t; + +struct pthread_rwlock +{ + pthread_rwlockattr_t attr; + + pthread_mutex_t rw_mutex; /* basic lock on this struct */ + pthread_cond_t rw_condreaders; /* for reader threads waiting */ + pthread_cond_t rw_condwriters; /* for writer threads waiting */ + + int rw_nwaitreaders; /* the number of reader threads waiting */ + int rw_nwaitwriters; /* the number of writer threads waiting */ + int rw_refcount; /* 0: unlocked, -1: locked by writer, > 0 locked by n readers */ +}; +typedef struct pthread_rwlock pthread_rwlock_t; + +/* spinlock implementation, (ADVANCED REALTIME THREADS)*/ +struct pthread_spinlock +{ + int lock; +}; +typedef struct pthread_spinlock pthread_spinlock_t; + +struct pthread_barrier +{ + int count; + pthread_cond_t cond; + pthread_mutex_t mutex; +}; +typedef struct pthread_barrier pthread_barrier_t; + +/* pthread thread interface */ +int pthread_attr_destroy(pthread_attr_t *attr); +int pthread_attr_init(pthread_attr_t *attr); +int pthread_attr_setdetachstate(pthread_attr_t *attr, int state); +int pthread_attr_getdetachstate(pthread_attr_t const *attr, int *state); +int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); +int pthread_attr_getschedpolicy(pthread_attr_t const *attr, int *policy); +int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stack_size); +int pthread_attr_getstacksize(pthread_attr_t const *attr, size_t *stack_size); +int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack_addr); +int pthread_attr_getstackaddr(pthread_attr_t const *attr, void **stack_addr); +int pthread_attr_setstack(pthread_attr_t *attr, + void *stack_base, + size_t stack_size); +int pthread_attr_getstack(pthread_attr_t const *attr, + void **stack_base, + size_t *stack_size); + +int pthread_system_init(void); +int pthread_create (pthread_t *tid, const pthread_attr_t *attr, + void *(*start) (void *), void *arg); + +int pthread_detach (pthread_t thread); +int pthread_join (pthread_t thread, void **value_ptr); + +rt_inline int pthread_equal (pthread_t t1, pthread_t t2) +{ + return t1 == t2; +} + +rt_inline pthread_t pthread_self (void) +{ + return rt_thread_self(); +} + +void pthread_exit (void *value_ptr); +int pthread_once(pthread_once_t * once_control, void (*init_routine) (void)); + +/* pthread cleanup */ +void pthread_cleanup_pop(int execute); +void pthread_cleanup_push(void (*routine)(void*), void *arg); + +/* pthread cancel */ +int pthread_cancel(pthread_t thread); +void pthread_testcancel(void); +int pthread_setcancelstate(int state, int *oldstate); +int pthread_setcanceltype(int type, int *oldtype); + +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)); +int pthread_kill(pthread_t thread, int sig); + +/* pthread mutex interface */ +int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); +int pthread_mutex_destroy(pthread_mutex_t *mutex); +int pthread_mutex_lock(pthread_mutex_t *mutex); +int pthread_mutex_unlock(pthread_mutex_t *mutex); +int pthread_mutex_trylock(pthread_mutex_t *mutex); + +int pthread_mutexattr_init(pthread_mutexattr_t *attr); +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); +int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type); +int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type); +int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared); +int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared); + +/* pthread condition interface */ +int pthread_condattr_destroy(pthread_condattr_t *attr); +int pthread_condattr_init(pthread_condattr_t *attr); + +/* ADVANCED REALTIME feature in IEEE Std 1003.1, 2004 Edition */ +int pthread_condattr_getclock(const pthread_condattr_t *attr, + clockid_t *clock_id); +int pthread_condattr_setclock(pthread_condattr_t *attr, + clockid_t clock_id); + +int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); +int pthread_cond_destroy(pthread_cond_t *cond); +int pthread_cond_broadcast(pthread_cond_t *cond); +int pthread_cond_signal(pthread_cond_t *cond); + +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); +int pthread_cond_timedwait(pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime); + +/* pthread rwlock interface */ +int pthread_rwlockattr_init (pthread_rwlockattr_t *attr); +int pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr); +int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared); +int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared); + +int pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); +int pthread_rwlock_destroy (pthread_rwlock_t *rwlock); + +int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock); +int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock); + +int pthread_rwlock_timedrdlock (pthread_rwlock_t *rwlock, const struct timespec *abstime); +int pthread_rwlock_timedwrlock (pthread_rwlock_t *rwlock, const struct timespec *abstime); + +int pthread_rwlock_unlock (pthread_rwlock_t *rwlock); + +int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock); +int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock); + +/* pthread spinlock interface */ +int pthread_spin_init (pthread_spinlock_t *lock, int pshared); +int pthread_spin_destroy (pthread_spinlock_t *lock); + +int pthread_spin_lock (pthread_spinlock_t * lock); +int pthread_spin_trylock (pthread_spinlock_t * lock); +int pthread_spin_unlock (pthread_spinlock_t * lock); + +/* pthread barrier interface */ +int pthread_barrierattr_destroy(pthread_barrierattr_t *attr); +int pthread_barrierattr_init(pthread_barrierattr_t *attr); +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, int *pshared); +int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared); + +int pthread_barrier_destroy(pthread_barrier_t *barrier); +int pthread_barrier_init(pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, + unsigned count); + +int pthread_barrier_wait(pthread_barrier_t *barrier); + +/* Signal Generation and Delivery, P1003.1b-1993, p. 63 + NOTE: P1003.1c/D10, p. 34 adds sigev_notify_function and + sigev_notify_attributes to the sigevent structure. */ +union sigval +{ + int sival_int; /* Integer signal value */ + void *sival_ptr; /* Pointer signal value */ +}; + +struct sigevent +{ + int sigev_notify; /* Notification type */ + int sigev_signo; /* Signal number */ + union sigval sigev_value; /* Signal value */ + void (*sigev_notify_function)( union sigval ); + /* Notification function */ + pthread_attr_t *sigev_notify_attributes; /* Notification Attributes */ +}; + +/* posix clock and timer */ +#define MILLISECOND_PER_SECOND 1000UL +#define MICROSECOND_PER_SECOND 1000000UL +#define NANOSECOND_PER_SECOND 1000000000UL + +#define MILLISECOND_PER_TICK (MILLISECOND_PER_SECOND / RT_TICK_PER_SECOND) +#define MICROSECOND_PER_TICK (MICROSECOND_PER_SECOND / RT_TICK_PER_SECOND) +#define NANOSECOND_PER_TICK (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND) + +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 0 +#endif + +int clock_getres (clockid_t clockid, struct timespec *res); +int clock_gettime (clockid_t clockid, struct timespec *tp); +int clock_settime (clockid_t clockid, const struct timespec *tp); + +#endif + diff --git a/components/libc/pthreads/pthread_attr.c b/components/libc/pthreads/pthread_attr.c new file mode 100644 index 0000000000..3e0f7b1e4c --- /dev/null +++ b/components/libc/pthreads/pthread_attr.c @@ -0,0 +1,218 @@ +/* + * File : pthread_attr.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, 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 + * 2010-10-26 Bernard the first version + */ + +#include <rtthread.h> +#include "pthread.h" +#include "sched.h" +#include <string.h> + +#define DEFAULT_STACK_SIZE 2048 +#define DEFAULT_PRIORITY (RT_THREAD_PRIORITY_MAX/2 + RT_THREAD_PRIORITY_MAX/4) + +const pthread_attr_t pthread_default_attr = +{ + 0, /* stack base */ + DEFAULT_STACK_SIZE, /* stack size */ + DEFAULT_PRIORITY, /* priority */ + PTHREAD_CREATE_JOINABLE, /* detach state */ + SCHED_FIFO, /* scheduler policy */ + PTHREAD_INHERIT_SCHED /* Inherit parent prio/policy */ +}; + +int pthread_attr_init(pthread_attr_t *attr) +{ + RT_ASSERT(attr != RT_NULL); + + *attr = pthread_default_attr; + + return 0; +} +RTM_EXPORT(pthread_attr_init); + +int pthread_attr_destroy(pthread_attr_t *attr) +{ + RT_ASSERT(attr != RT_NULL); + + memset(attr, 0, sizeof(pthread_attr_t)); + + return 0; +} +RTM_EXPORT(pthread_attr_destroy); + +int pthread_attr_setdetachstate(pthread_attr_t *attr, int state) +{ + RT_ASSERT(attr != RT_NULL); + + if (state != PTHREAD_CREATE_JOINABLE && state != PTHREAD_CREATE_DETACHED) + return EINVAL; + + attr->detachstate = state; + + return 0; +} +RTM_EXPORT(pthread_attr_setdetachstate); + +int pthread_attr_getdetachstate(pthread_attr_t const *attr, int *state) +{ + RT_ASSERT(attr != RT_NULL); + + *state = (int)attr->detachstate; + + return 0; +} +RTM_EXPORT(pthread_attr_getdetachstate); + +int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) +{ + RT_ASSERT(attr != RT_NULL); + + attr->policy = policy; + + return 0; +} +RTM_EXPORT(pthread_attr_setschedpolicy); + +int pthread_attr_getschedpolicy(pthread_attr_t const *attr, int *policy) +{ + RT_ASSERT(attr != RT_NULL); + + *policy = (int)attr->policy; + + return 0; +} +RTM_EXPORT(pthread_attr_getschedpolicy); + +int pthread_attr_setschedparam(pthread_attr_t *attr, + struct sched_param const *param) +{ + RT_ASSERT(attr != RT_NULL); + RT_ASSERT(param != RT_NULL); + + attr->priority = param->sched_priority; + + return 0; +} +RTM_EXPORT(pthread_attr_setschedparam); + +int pthread_attr_getschedparam(pthread_attr_t const *attr, + struct sched_param *param) +{ + RT_ASSERT(attr != RT_NULL); + RT_ASSERT(param != RT_NULL); + + param->sched_priority = attr->priority; + + return 0; +} +RTM_EXPORT(pthread_attr_getschedparam); + +int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stack_size) +{ + RT_ASSERT(attr != RT_NULL); + + attr->stack_size = stack_size; + + return 0; +} +RTM_EXPORT(pthread_attr_setstacksize); + +int pthread_attr_getstacksize(pthread_attr_t const *attr, size_t *stack_size) +{ + RT_ASSERT(attr != RT_NULL); + + *stack_size = attr->stack_size; + + return 0; +} +RTM_EXPORT(pthread_attr_getstacksize); + +int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stack_addr) +{ + RT_ASSERT(attr != RT_NULL); + + return EOPNOTSUPP; +} +RTM_EXPORT(pthread_attr_setstackaddr); + +int pthread_attr_getstackaddr(pthread_attr_t const *attr, void **stack_addr) +{ + RT_ASSERT(attr != RT_NULL); + + return EOPNOTSUPP; +} +RTM_EXPORT(pthread_attr_getstackaddr); + +int pthread_attr_setstack(pthread_attr_t *attr, + void *stack_base, + size_t stack_size) +{ + RT_ASSERT(attr != RT_NULL); + + attr->stack_base = stack_base; + attr->stack_size = RT_ALIGN_DOWN(stack_size, RT_ALIGN_SIZE); + + return 0; +} +RTM_EXPORT(pthread_attr_setstack); + +int pthread_attr_getstack(pthread_attr_t const *attr, + void **stack_base, + size_t *stack_size) +{ + RT_ASSERT(attr != RT_NULL); + + *stack_base = attr->stack_base; + *stack_size = attr->stack_size; + + return 0; +} +RTM_EXPORT(pthread_attr_getstack); + +int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guard_size) +{ + return EOPNOTSUPP; +} + +int pthread_attr_getguardsize(pthread_attr_t const *attr, size_t *guard_size) +{ + return EOPNOTSUPP; +} +RTM_EXPORT(pthread_attr_getguardsize); + +int pthread_attr_setscope(pthread_attr_t *attr, int scope) +{ + if (scope == PTHREAD_SCOPE_SYSTEM) + return 0; + if (scope == PTHREAD_SCOPE_PROCESS) + return EOPNOTSUPP; + + return EINVAL; +} +RTM_EXPORT(pthread_attr_setscope); + +int pthread_attr_getscope(pthread_attr_t const *attr) +{ + return PTHREAD_SCOPE_SYSTEM; +} +RTM_EXPORT(pthread_attr_getscope); diff --git a/components/libc/pthreads/pthread_barrier.c b/components/libc/pthreads/pthread_barrier.c new file mode 100644 index 0000000000..c39a45586e --- /dev/null +++ b/components/libc/pthreads/pthread_barrier.c @@ -0,0 +1,124 @@ +/* + * File : pthread_barrier.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, 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 + * 2010-10-26 Bernard the first version + */ + +#include <pthread.h> + +int pthread_barrierattr_destroy(pthread_barrierattr_t *attr) +{ + if (!attr) + return EINVAL; + + return 0; +} +RTM_EXPORT(pthread_barrierattr_destroy); + +int pthread_barrierattr_init(pthread_barrierattr_t *attr) +{ + if (!attr) + return EINVAL; + *attr = PTHREAD_PROCESS_PRIVATE; + + return 0; +} +RTM_EXPORT(pthread_barrierattr_init); + +int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, + int *pshared) +{ + if (!attr) + return EINVAL; + *pshared = (int)*attr; + + return 0; +} +RTM_EXPORT(pthread_barrierattr_getpshared); + +int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) +{ + if (!attr) + return EINVAL; + if (pshared == PTHREAD_PROCESS_PRIVATE) + attr = PTHREAD_PROCESS_PRIVATE; + + return EINVAL; +} +RTM_EXPORT(pthread_barrierattr_setpshared); + +int pthread_barrier_destroy(pthread_barrier_t *barrier) +{ + rt_err_t result; + + if (!barrier) + return EINVAL; + + result = pthread_cond_destroy(&(barrier->cond)); + + return result; +} +RTM_EXPORT(pthread_barrier_destroy); + +int pthread_barrier_init(pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, + unsigned count) +{ + if (!barrier) + return EINVAL; + if (attr && (*attr != PTHREAD_PROCESS_PRIVATE)) + return EINVAL; + + barrier->count = count; + pthread_cond_init(&(barrier->cond), NULL); + pthread_mutex_init(&(barrier->mutex), NULL); + + return 0; +} +RTM_EXPORT(pthread_barrier_init); + +int pthread_barrier_wait(pthread_barrier_t *barrier) +{ + rt_err_t result; + if (!barrier) + return EINVAL; + + result = pthread_mutex_lock(&(barrier->mutex)); + if (result != 0) + return EINVAL; + + if (barrier->count == 0) + result = EINVAL; + else + { + barrier->count -= 1; + if (barrier->count == 0) /* broadcast condition */ + pthread_cond_broadcast(&(barrier->cond)); + else + pthread_cond_wait(&(barrier->cond), &(barrier->mutex)); + } + + pthread_mutex_unlock(&(barrier->mutex)); + + return result; +} +RTM_EXPORT(pthread_barrier_wait); + diff --git a/components/libc/pthreads/pthread_cond.c b/components/libc/pthreads/pthread_cond.c new file mode 100644 index 0000000000..25628fc2b3 --- /dev/null +++ b/components/libc/pthreads/pthread_cond.c @@ -0,0 +1,243 @@ +/* + * File : pthread_cond.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, 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 + * 2010-10-26 Bernard the first version + */ + +#include <pthread.h> +#include "pthread_internal.h" + +int pthread_condattr_destroy(pthread_condattr_t *attr) +{ + if (!attr) + return EINVAL; + + return 0; +} +RTM_EXPORT(pthread_condattr_destroy); + +int pthread_condattr_init(pthread_condattr_t *attr) +{ + if (!attr) + return EINVAL; + *attr = PTHREAD_PROCESS_PRIVATE; + + return 0; +} +RTM_EXPORT(pthread_condattr_init); + +int pthread_condattr_getclock(const pthread_condattr_t *attr, + clockid_t *clock_id) +{ + return 0; +} +RTM_EXPORT(pthread_condattr_getclock); + +int pthread_condattr_setclock(pthread_condattr_t *attr, + clockid_t clock_id) +{ + return 0; +} +RTM_EXPORT(pthread_condattr_setclock); + +int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *pshared) +{ + if (!attr || !pshared) + return EINVAL; + + *pshared = PTHREAD_PROCESS_PRIVATE; + + return 0; +} +RTM_EXPORT(pthread_condattr_getpshared); + +int pthread_condattr_setpshared(pthread_condattr_t*attr, int pshared) +{ + if ((pshared != PTHREAD_PROCESS_PRIVATE) && + (pshared != PTHREAD_PROCESS_SHARED)) + { + return EINVAL; + } + + if (pshared != PTHREAD_PROCESS_PRIVATE) + return ENOSYS; + + return 0; +} +RTM_EXPORT(pthread_condattr_setpshared); + +int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) +{ + rt_err_t result; + char cond_name[RT_NAME_MAX]; + static rt_uint16_t cond_num = 0; + + /* parameter check */ + if (cond == RT_NULL) + return EINVAL; + if ((attr != RT_NULL) && (*attr != PTHREAD_PROCESS_PRIVATE)) + return EINVAL; + + rt_snprintf(cond_name, sizeof(cond_name), "cond%02d", cond_num++); + + if (attr == RT_NULL) /* use default value */ + cond->attr = PTHREAD_PROCESS_PRIVATE; + else + cond->attr = *attr; + + result = rt_sem_init(&cond->sem, cond_name, 0, RT_IPC_FLAG_FIFO); + if (result != RT_EOK) + return EINVAL; + + /* detach the object from system object container */ + rt_object_detach(&(cond->sem.parent.parent)); + + return 0; +} +RTM_EXPORT(pthread_cond_init); + +int pthread_cond_destroy(pthread_cond_t *cond) +{ + rt_err_t result; + if (cond == RT_NULL) + return EINVAL; + if (cond->attr == -1) + return 0; /* which is not initialized */ + + result = rt_sem_trytake(&(cond->sem)); + if (result != RT_EOK) + return EBUSY; + + /* clean condition */ + rt_memset(cond, 0, sizeof(pthread_cond_t)); + cond->attr = -1; + + return 0; +} +RTM_EXPORT(pthread_cond_destroy); + +int pthread_cond_broadcast(pthread_cond_t *cond) +{ + rt_err_t result; + if (cond->attr == -1) + pthread_cond_init(cond, RT_NULL); + + rt_enter_critical(); + while (1) + { + /* try to take condition semaphore */ + result = rt_sem_trytake(&(cond->sem)); + if (result == -RT_ETIMEOUT) + { + /* it's timeout, release this semaphore */ + rt_sem_release(&(cond->sem)); + } + else if (result == RT_EOK) + { + /* has taken this semaphore, release it */ + rt_sem_release(&(cond->sem)); + break; + } + else + { + rt_exit_critical(); + + return EINVAL; + } + } + rt_exit_critical(); + + return 0; +} +RTM_EXPORT(pthread_cond_broadcast); + +int pthread_cond_signal(pthread_cond_t *cond) +{ + rt_err_t result; + + if (cond->attr == -1) + pthread_cond_init(cond, RT_NULL); + + result = rt_sem_release(&(cond->sem)); + if (result == RT_EOK) + return 0; + + return 0; +} +RTM_EXPORT(pthread_cond_signal); + +rt_err_t _pthread_cond_timedwait(pthread_cond_t *cond, + pthread_mutex_t *mutex, + rt_int32_t timeout) +{ + rt_err_t result; + + if (!cond || !mutex) + return -RT_ERROR; + /* check whether initialized */ + if (cond->attr == -1) + pthread_cond_init(cond, RT_NULL); + + /* The mutex was not owned by the current thread at the time of the call. */ + if (mutex->lock.owner != pthread_self()) + return -RT_ERROR; + /* unlock a mutex failed */ + if (pthread_mutex_unlock(mutex) != 0) + return -RT_ERROR; + + result = rt_sem_take(&(cond->sem), timeout); + /* lock mutex again */ + pthread_mutex_lock(mutex); + + return result; +} +RTM_EXPORT(_pthread_cond_timedwait); + +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + rt_err_t result; + + result = _pthread_cond_timedwait(cond, mutex, RT_WAITING_FOREVER); + if (result == RT_EOK) + return 0; + + return EINVAL; +} +RTM_EXPORT(pthread_cond_wait); + +int pthread_cond_timedwait(pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + int timeout; + rt_err_t result; + + timeout = clock_time_to_tick(abstime); + result = _pthread_cond_timedwait(cond, mutex, timeout); + if (result == RT_EOK) + return 0; + if (result == -RT_ETIMEOUT) + return ETIMEDOUT; + + return EINVAL; +} +RTM_EXPORT(pthread_cond_timedwait); + diff --git a/components/libc/pthreads/pthread_internal.h b/components/libc/pthreads/pthread_internal.h new file mode 100644 index 0000000000..0a21fccb13 --- /dev/null +++ b/components/libc/pthreads/pthread_internal.h @@ -0,0 +1,91 @@ +/* + * File : pthread_internal.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, 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 + * 2010-10-26 Bernard the first version + */ + +#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; + +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 +{ + 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; + + /* 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 */ +}; +typedef struct _pthread_data _pthread_data_t; + +rt_inline _pthread_data_t *_pthread_get_data(pthread_t thread) +{ + _pthread_data_t *ptd; + RT_ASSERT(thread != RT_NULL); + + ptd = (_pthread_data_t *)thread->user_data; + RT_ASSERT(ptd != RT_NULL); + RT_ASSERT(ptd->magic == PTHREAD_MAGIC); + + return ptd; +} + +int clock_time_to_tick(const struct timespec *time); +void clock_time_system_init(void); +void posix_mq_system_init(void); +void posix_sem_system_init(void); +void pthread_key_system_init(void); + +#endif diff --git a/components/libc/pthreads/pthread_mutex.c b/components/libc/pthreads/pthread_mutex.c new file mode 100644 index 0000000000..40fd870e81 --- /dev/null +++ b/components/libc/pthreads/pthread_mutex.c @@ -0,0 +1,251 @@ +/* + * File : pthread_mutex.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, 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 + * 2010-10-26 Bernard the first version + */ + +#include <rtthread.h> +#include "pthread.h" + +#define MUTEXATTR_SHARED_MASK 0x0010 +#define MUTEXATTR_TYPE_MASK 0x000f + +const pthread_mutexattr_t pthread_default_mutexattr = PTHREAD_PROCESS_PRIVATE; + +int pthread_mutexattr_init(pthread_mutexattr_t *attr) +{ + if (attr) + { + *attr = pthread_default_mutexattr; + + return 0; + } + + return EINVAL; +} +RTM_EXPORT(pthread_mutexattr_init); + +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) +{ + if (attr) + { + *attr = -1; + + return 0; + } + + return EINVAL; +} +RTM_EXPORT(pthread_mutexattr_destroy); + +int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type) +{ + if (attr && type) + { + int atype = (*attr & MUTEXATTR_TYPE_MASK); + + if (atype >= PTHREAD_MUTEX_NORMAL && atype <= PTHREAD_MUTEX_ERRORCHECK) + { + *type = atype; + + return 0; + } + } + + return EINVAL; +} +RTM_EXPORT(pthread_mutexattr_gettype); + +int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) +{ + if (attr && type >= PTHREAD_MUTEX_NORMAL && type <= PTHREAD_MUTEX_ERRORCHECK) + { + *attr = (*attr & ~MUTEXATTR_TYPE_MASK) | type; + + return 0; + } + + return EINVAL; +} +RTM_EXPORT(pthread_mutexattr_settype); + +int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared) +{ + if (!attr) + return EINVAL; + + switch (pshared) + { + case PTHREAD_PROCESS_PRIVATE: + *attr &= ~MUTEXATTR_SHARED_MASK; + return 0; + + case PTHREAD_PROCESS_SHARED: + *attr |= MUTEXATTR_SHARED_MASK; + return 0; + } + + return EINVAL; +} +RTM_EXPORT(pthread_mutexattr_setpshared); + +int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared) +{ + if (!attr || !pshared) + return EINVAL; + + *pshared = (*attr & MUTEXATTR_SHARED_MASK) ? PTHREAD_PROCESS_SHARED + : PTHREAD_PROCESS_PRIVATE; + return 0; +} +RTM_EXPORT(pthread_mutexattr_getpshared); + +int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) +{ + rt_err_t result; + char name[RT_NAME_MAX]; + static rt_uint16_t pthread_mutex_number = 0; + + if (!mutex) + return EINVAL; + + /* build mutex name */ + rt_snprintf(name, sizeof(name), "pmtx%02d", pthread_mutex_number ++); + if (attr == RT_NULL) + mutex->attr = pthread_default_mutexattr; + else + mutex->attr = *attr; + + /* init mutex lock */ + result = rt_mutex_init(&(mutex->lock), name, RT_IPC_FLAG_FIFO); + if (result != RT_EOK) + return EINVAL; + + /* detach the object from system object container */ + rt_object_detach(&(mutex->lock.parent.parent)); + + return 0; +} +RTM_EXPORT(pthread_mutex_init); + +int pthread_mutex_destroy(pthread_mutex_t *mutex) +{ + if (!mutex || mutex->attr == -1) + return EINVAL; + + /* it's busy */ + if (mutex->lock.owner != RT_NULL) + return EBUSY; + + rt_memset(mutex, 0, sizeof(pthread_mutex_t)); + mutex->attr = -1; + + return 0; +} +RTM_EXPORT(pthread_mutex_destroy); + +int pthread_mutex_lock(pthread_mutex_t *mutex) +{ + int mtype; + rt_err_t result; + + if (!mutex) + return EINVAL; + + if (mutex->attr == -1) + { + /* init mutex */ + pthread_mutex_init(mutex, RT_NULL); + } + + mtype = mutex->attr & MUTEXATTR_TYPE_MASK; + rt_enter_critical(); + if (mutex->lock.owner == rt_thread_self() && + mtype != PTHREAD_MUTEX_RECURSIVE) + { + rt_exit_critical(); + + return EDEADLK; + } + rt_exit_critical(); + + result = rt_mutex_take(&(mutex->lock), RT_WAITING_FOREVER); + if (result == RT_EOK) + return 0; + + return EINVAL; +} +RTM_EXPORT(pthread_mutex_lock); + +int pthread_mutex_unlock(pthread_mutex_t *mutex) +{ + rt_err_t result; + + if (!mutex) + return EINVAL; + if (mutex->attr == -1) + { + /* init mutex */ + pthread_mutex_init(mutex, RT_NULL); + } + + if (mutex->lock.owner != rt_thread_self()) + { + int mtype; + mtype = mutex->attr & MUTEXATTR_TYPE_MASK; + + /* error check, return EPERM */ + if (mtype == PTHREAD_MUTEX_ERRORCHECK) + return EPERM; + + /* no thread waiting on this mutex */ + if (mutex->lock.owner == RT_NULL) + return 0; + } + + result = rt_mutex_release(&(mutex->lock)); + if (result == RT_EOK) + return 0; + + return EINVAL; +} +RTM_EXPORT(pthread_mutex_unlock); + +int pthread_mutex_trylock(pthread_mutex_t *mutex) +{ + rt_err_t result; + + if (!mutex) + return EINVAL; + if (mutex->attr == -1) + { + /* init mutex */ + pthread_mutex_init(mutex, RT_NULL); + } + + result = rt_mutex_take(&(mutex->lock), 0); + if (result == RT_EOK) + return 0; + + return EBUSY; +} +RTM_EXPORT(pthread_mutex_trylock); + diff --git a/components/libc/pthreads/pthread_rwlock.c b/components/libc/pthreads/pthread_rwlock.c new file mode 100644 index 0000000000..3e009034cc --- /dev/null +++ b/components/libc/pthreads/pthread_rwlock.c @@ -0,0 +1,354 @@ +/* + * File : pthread_rwlock.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, 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 + * 2010-10-26 Bernard the first version + */ + +#include <pthread.h> + +int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) +{ + if (!attr) + return EINVAL; + *attr = PTHREAD_PROCESS_PRIVATE; + + return 0; +} +RTM_EXPORT(pthread_rwlockattr_init); + +int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr) +{ + if (!attr) + return EINVAL; + + return 0; +} +RTM_EXPORT(pthread_rwlockattr_destroy); + +int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, + int *pshared) +{ + if (!attr || !pshared) + return EINVAL; + + *pshared = PTHREAD_PROCESS_PRIVATE; + + return 0; +} +RTM_EXPORT(pthread_rwlockattr_getpshared); + +int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared) +{ + if (!attr || pshared != PTHREAD_PROCESS_PRIVATE) + return EINVAL; + + return 0; +} +RTM_EXPORT(pthread_rwlockattr_setpshared); + +int pthread_rwlock_init(pthread_rwlock_t *rwlock, + const pthread_rwlockattr_t *attr) +{ + if (!rwlock) + return EINVAL; + + rwlock->attr = PTHREAD_PROCESS_PRIVATE; + pthread_mutex_init(&(rwlock->rw_mutex), NULL); + pthread_cond_init(&(rwlock->rw_condreaders), NULL); + pthread_cond_init(&(rwlock->rw_condwriters), NULL); + + rwlock->rw_nwaitwriters = 0; + rwlock->rw_nwaitreaders = 0; + rwlock->rw_refcount = 0; + + return 0; +} +RTM_EXPORT(pthread_rwlock_init); + +int pthread_rwlock_destroy (pthread_rwlock_t *rwlock) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + return 0; /* rwlock is not initialized */ + + if ( (result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + if (rwlock->rw_refcount != 0 || + rwlock->rw_nwaitreaders != 0 || + rwlock->rw_nwaitwriters != 0) + { + result = EBUSY; + + return result; + } + else + { + /* check whether busy */ + result = rt_sem_trytake(&(rwlock->rw_condreaders.sem)); + if (result == RT_EOK) + { + result = rt_sem_trytake(&(rwlock->rw_condwriters.sem)); + if (result == RT_EOK) + { + rt_sem_release(&(rwlock->rw_condreaders.sem)); + rt_sem_release(&(rwlock->rw_condwriters.sem)); + + pthread_cond_destroy(&rwlock->rw_condreaders); + pthread_cond_destroy(&rwlock->rw_condwriters); + } + else + { + rt_sem_release(&(rwlock->rw_condreaders.sem)); + result = EBUSY; + } + } + else + result = EBUSY; + } + + pthread_mutex_unlock(&rwlock->rw_mutex); + if (result == 0) + pthread_mutex_destroy(&rwlock->rw_mutex); + + return result; +} +RTM_EXPORT(pthread_rwlock_destroy); + +int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + pthread_rwlock_init(rwlock, NULL); + + if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + /* give preference to waiting writers */ + while (rwlock->rw_refcount < 0 || rwlock->rw_nwaitwriters > 0) + { + rwlock->rw_nwaitreaders++; + /* rw_mutex will be released when waiting for rw_condreaders */ + result = pthread_cond_wait(&rwlock->rw_condreaders, &rwlock->rw_mutex); + /* rw_mutex should have been taken again when returned from waiting */ + rwlock->rw_nwaitreaders--; + if (result != 0) /* wait error */ + break; + } + + /* another reader has a read lock */ + if (result == 0) + rwlock->rw_refcount++; + + pthread_mutex_unlock(&rwlock->rw_mutex); + + return (result); +} +RTM_EXPORT(pthread_rwlock_rdlock); + +int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + pthread_rwlock_init(rwlock, NULL); + + if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + if (rwlock->rw_refcount < 0 || rwlock->rw_nwaitwriters > 0) + result = EBUSY; /* held by a writer or waiting writers */ + else + rwlock->rw_refcount++; /* increment count of reader locks */ + + pthread_mutex_unlock(&rwlock->rw_mutex); + + return(result); +} +RTM_EXPORT(pthread_rwlock_tryrdlock); + +int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, + const struct timespec *abstime) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + pthread_rwlock_init(rwlock, NULL); + + if ( (result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + /* give preference to waiting writers */ + while (rwlock->rw_refcount < 0 || rwlock->rw_nwaitwriters > 0) + { + rwlock->rw_nwaitreaders++; + /* rw_mutex will be released when waiting for rw_condreaders */ + result = pthread_cond_timedwait(&rwlock->rw_condreaders, &rwlock->rw_mutex, abstime); + /* rw_mutex should have been taken again when returned from waiting */ + rwlock->rw_nwaitreaders--; + if (result != 0) + break; + } + + /* another reader has a read lock */ + if (result == 0) + rwlock->rw_refcount++; + + pthread_mutex_unlock(&rwlock->rw_mutex); + + return (result); +} +RTM_EXPORT(pthread_rwlock_timedrdlock); + +int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, + const struct timespec *abstime) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + pthread_rwlock_init(rwlock, NULL); + + if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + while (rwlock->rw_refcount != 0) + { + rwlock->rw_nwaitwriters++; + /* rw_mutex will be released when waiting for rw_condwriters */ + result = pthread_cond_timedwait(&rwlock->rw_condwriters, &rwlock->rw_mutex, abstime); + /* rw_mutex should have been taken again when returned from waiting */ + rwlock->rw_nwaitwriters--; + + if (result != 0) + break; + } + + if (result == 0) + rwlock->rw_refcount = -1; + + pthread_mutex_unlock(&rwlock->rw_mutex); + + return(result); +} +RTM_EXPORT(pthread_rwlock_timedwrlock); + +int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + pthread_rwlock_init(rwlock, NULL); + + if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + if (rwlock->rw_refcount != 0) + result = EBUSY; /* held by either writer or reader(s) */ + else + rwlock->rw_refcount = -1; /* available, indicate a writer has it */ + + pthread_mutex_unlock(&rwlock->rw_mutex); + + return(result); +} +RTM_EXPORT(pthread_rwlock_trywrlock); + +int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + pthread_rwlock_init(rwlock, NULL); + + if ( (result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + if (rwlock->rw_refcount > 0) + rwlock->rw_refcount--; /* releasing a reader */ + else if (rwlock->rw_refcount == -1) + rwlock->rw_refcount = 0; /* releasing a writer */ + + /* give preference to waiting writers over waiting readers */ + if (rwlock->rw_nwaitwriters > 0) + { + if (rwlock->rw_refcount == 0) + result = pthread_cond_signal(&rwlock->rw_condwriters); + } + else if (rwlock->rw_nwaitreaders > 0) + { + result = pthread_cond_broadcast(&rwlock->rw_condreaders); + } + + pthread_mutex_unlock(&rwlock->rw_mutex); + + return(result); +} +RTM_EXPORT(pthread_rwlock_unlock); + +int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) +{ + int result; + + if (!rwlock) + return EINVAL; + if (rwlock->attr == -1) + pthread_rwlock_init(rwlock, NULL); + + if ((result = pthread_mutex_lock(&rwlock->rw_mutex)) != 0) + return(result); + + while (rwlock->rw_refcount != 0) + { + rwlock->rw_nwaitwriters++; + /* rw_mutex will be released when waiting for rw_condwriters */ + result = pthread_cond_wait(&rwlock->rw_condwriters, &rwlock->rw_mutex); + /* rw_mutex should have been taken again when returned from waiting */ + rwlock->rw_nwaitwriters--; + + if (result != 0) + break; + } + + if (result == 0) + rwlock->rw_refcount = -1; + + pthread_mutex_unlock(&rwlock->rw_mutex); + + return(result); +} +RTM_EXPORT(pthread_rwlock_wrlock); + diff --git a/components/libc/pthreads/pthread_spin.c b/components/libc/pthreads/pthread_spin.c new file mode 100644 index 0000000000..4c4320dda9 --- /dev/null +++ b/components/libc/pthreads/pthread_spin.c @@ -0,0 +1,83 @@ +/* + * File : pthread_spin.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, 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 + * 2010-10-26 Bernard the first version + */ + +#include <pthread.h> + +int pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + if (!lock) + return EINVAL; + + lock->lock = 0; + + return 0; +} + +int pthread_spin_destroy (pthread_spinlock_t *lock) +{ + if (!lock) + return EINVAL; + + return 0; +} + +int pthread_spin_lock (pthread_spinlock_t *lock) +{ + if (!lock) + return EINVAL; + + while (!(lock->lock)) + { + lock->lock = 1; + } + + return 0; +} + +int pthread_spin_trylock (pthread_spinlock_t *lock) +{ + if (!lock) + return EINVAL; + + if (!(lock->lock)) + { + lock->lock = 1; + + return 0; + } + + return EBUSY; +} + +int pthread_spin_unlock (pthread_spinlock_t *lock) +{ + if (!lock) + return EINVAL; + if (!(lock->lock)) + return EPERM; + + lock->lock = 0; + + return 0; +} diff --git a/components/libc/pthreads/pthread_tls.c b/components/libc/pthreads/pthread_tls.c new file mode 100644 index 0000000000..d689f31e47 --- /dev/null +++ b/components/libc/pthreads/pthread_tls.c @@ -0,0 +1,115 @@ +/* + * File : pthread_tls.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, 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 + * 2010-10-26 Bernard the first version + */ + +#include <pthread.h> +#include "pthread_internal.h" + +_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; +} +RTM_EXPORT(pthread_getspecific); + +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 = (void**)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; +} +RTM_EXPORT(pthread_setspecific); + +int pthread_key_create(pthread_key_t *key, void (*destructor)(void*)) +{ + 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; +} +RTM_EXPORT(pthread_key_create); + +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; +} +RTM_EXPORT(pthread_key_delete); + diff --git a/components/libc/pthreads/sched.c b/components/libc/pthreads/sched.c new file mode 100644 index 0000000000..6f75127bf2 --- /dev/null +++ b/components/libc/pthreads/sched.c @@ -0,0 +1,56 @@ +/* + * File : sched.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, 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 <sched.h> + +int sched_yield(void) +{ + rt_thread_yield(); + + return 0; +} +RTM_EXPORT(sched_yield); + +int sched_get_priority_min(int policy) +{ + if (policy != SCHED_FIFO && policy != SCHED_RR) + return EINVAL; + + return 0; +} +RTM_EXPORT(sched_get_priority_min); + +int sched_get_priority_max(int policy) +{ + if (policy != SCHED_FIFO && policy != SCHED_RR) + return EINVAL; + + return RT_THREAD_PRIORITY_MAX - 1; +} +RTM_EXPORT(sched_get_priority_max); + +int sched_setscheduler(pid_t pid, int policy) +{ + return EOPNOTSUPP; +} +RTM_EXPORT(sched_setscheduler); diff --git a/components/libc/pthreads/sched.h b/components/libc/pthreads/sched.h new file mode 100644 index 0000000000..173f3eb2de --- /dev/null +++ b/components/libc/pthreads/sched.h @@ -0,0 +1,59 @@ +/* + * File : sched.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, 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 + */ + +#ifndef __SCHED_H__ +#define __SCHED_H__ + +#include <rtthread.h> +#include <pthread.h> + +/* Thread scheduling policies */ +enum +{ + SCHED_OTHER = 0, + SCHED_FIFO, + SCHED_RR, + SCHED_MIN = SCHED_OTHER, + SCHED_MAX = SCHED_RR +}; + +struct sched_param +{ + int sched_priority; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + +int sched_yield(void); +int sched_get_priority_min(int policy); +int sched_get_priority_max(int policy); +int sched_setscheduler(pid_t pid, int policy); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/libc/pthreads/semaphore.c b/components/libc/pthreads/semaphore.c new file mode 100644 index 0000000000..ae69e0d1bc --- /dev/null +++ b/components/libc/pthreads/semaphore.c @@ -0,0 +1,401 @@ +/* + * File : semaphore.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, 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 + * 2010-10-26 Bernard the first version + */ + +#include <rtthread.h> +#include <string.h> +#include "semaphore.h" +#include "pthread_internal.h" + +static sem_t *posix_sem_list = RT_NULL; +static struct rt_semaphore posix_sem_lock; +void posix_sem_system_init() +{ + rt_sem_init(&posix_sem_lock, "psem", 1, RT_IPC_FLAG_FIFO); +} + +rt_inline void posix_sem_insert(sem_t *psem) +{ + psem->next = posix_sem_list; + posix_sem_list = psem; +} + +static void posix_sem_delete(sem_t *psem) +{ + sem_t *iter; + if (posix_sem_list == psem) + { + posix_sem_list = psem->next; + + rt_sem_delete(psem->sem); + rt_free(psem); + + return; + } + for (iter = posix_sem_list; iter->next != RT_NULL; iter = iter->next) + { + if (iter->next == psem) + { + /* delete this mq */ + if (psem->next != RT_NULL) + iter->next = psem->next; + else + iter->next = RT_NULL; + + /* delete RT-Thread mqueue */ + rt_sem_delete(psem->sem); + rt_free(psem); + + return ; + } + } +} + +static sem_t *posix_sem_find(const char* name) +{ + sem_t *iter; + rt_object_t object; + + for (iter = posix_sem_list; iter != RT_NULL; iter = iter->next) + { + object = (rt_object_t)&(iter->sem); + + if (strncmp(object->name, name, RT_NAME_MAX) == 0) + { + return iter; + } + } + + return RT_NULL; +} + +int sem_close(sem_t *sem) +{ + if (sem == RT_NULL) + { + rt_set_errno(EINVAL); + + return -1; + } + + /* lock posix semaphore list */ + rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); + sem->refcount --; + if (sem->refcount == 0) + { + /* delete from posix semaphore list */ + if (sem->unlinked) + posix_sem_delete(sem); + sem = RT_NULL; + } + rt_sem_release(&posix_sem_lock); + + return 0; +} +RTM_EXPORT(sem_close); + +int sem_destroy(sem_t *sem) +{ + rt_err_t result; + + if ((!sem) || !(sem->unamed)) + { + rt_set_errno(EINVAL); + + return -1; + } + + /* lock posix semaphore list */ + rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); + result = rt_sem_trytake(sem->sem); + if (result != RT_EOK) + { + rt_sem_release(&posix_sem_lock); + rt_set_errno(EBUSY); + + return -1; + } + + /* destroy an unamed posix semaphore */ + posix_sem_delete(sem); + rt_sem_release(&posix_sem_lock); + + return 0; +} +RTM_EXPORT(sem_destroy); + +int sem_unlink(const char *name) +{ + sem_t *psem; + + /* lock posix semaphore list */ + rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); + psem = posix_sem_find(name); + if (psem != RT_NULL) + { + psem->unlinked = 1; + if (psem->refcount == 0) + { + /* remove this semaphore */ + posix_sem_delete(psem); + } + rt_sem_release(&posix_sem_lock); + + return 0; + } + rt_sem_release(&posix_sem_lock); + + /* no this entry */ + rt_set_errno(ENOENT); + + return -1; +} +RTM_EXPORT(sem_unlink); + +int sem_getvalue(sem_t *sem, int *sval) +{ + if (!sem || !sval) + { + rt_set_errno(EINVAL); + + return -1; + } + *sval = sem->sem->value; + + return 0; +} +RTM_EXPORT(sem_getvalue); + +int sem_init(sem_t *sem, int pshared, unsigned int value) +{ + char name[RT_NAME_MAX]; + static rt_uint16_t psem_number = 0; + + if (sem == RT_NULL) + { + rt_set_errno(EINVAL); + + return -1; + } + + rt_snprintf(name, sizeof(name), "psem%02d", psem_number++); + sem->sem = rt_sem_create(name, value, RT_IPC_FLAG_FIFO); + if (sem == RT_NULL) + { + rt_set_errno(ENOMEM); + + return -1; + } + + /* initialize posix semaphore */ + sem->refcount = 1; + sem->unlinked = 0; + sem->unamed = 1; + /* lock posix semaphore list */ + rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); + posix_sem_insert(sem); + rt_sem_release(&posix_sem_lock); + + return 0; +} +RTM_EXPORT(sem_init); + +sem_t *sem_open(const char *name, int oflag, ...) +{ + sem_t* sem; + va_list arg; + mode_t mode; + unsigned int value; + + sem = RT_NULL; + + /* lock posix semaphore list */ + rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); + if (oflag & O_CREAT) + { + va_start(arg, oflag); + mode = (mode_t) va_arg( arg, unsigned int); mode = mode; + value = va_arg( arg, unsigned int); + va_end(arg); + + if (oflag & O_EXCL) + { + if (posix_sem_find(name) != RT_NULL) + { + rt_set_errno(EEXIST); + goto __return; + } + } + sem = (sem_t*) rt_malloc (sizeof(struct posix_sem)); + if (sem == RT_NULL) + { + rt_set_errno(ENFILE); + goto __return; + } + + /* create RT-Thread semaphore */ + sem->sem = rt_sem_create(name, value, RT_IPC_FLAG_FIFO); + if (sem->sem == RT_NULL) /* create failed */ + { + rt_set_errno(ENFILE); + goto __return; + } + /* initialize reference count */ + sem->refcount = 1; + sem->unlinked = 0; + sem->unamed = 0; + + /* insert semaphore to posix semaphore list */ + posix_sem_insert(sem); + } + else + { + /* find semaphore */ + sem = posix_sem_find(name); + if (sem != RT_NULL) + { + sem->refcount ++; /* increase reference count */ + } + else + { + rt_set_errno(ENOENT); + goto __return; + } + } + rt_sem_release(&posix_sem_lock); + + return sem; + +__return: + /* release lock */ + rt_sem_release(&posix_sem_lock); + + /* release allocated memory */ + if (sem != RT_NULL) + { + /* delete RT-Thread semaphore */ + if (sem->sem != RT_NULL) + rt_sem_delete(sem->sem); + rt_free(sem); + } + + return RT_NULL; +} +RTM_EXPORT(sem_open); + +int sem_post(sem_t *sem) +{ + rt_err_t result; + + if (!sem) + { + rt_set_errno(EINVAL); + + return -1; + } + + result = rt_sem_release(sem->sem); + if (result == RT_EOK) + return 0; + + rt_set_errno(EINVAL); + + return -1; +} +RTM_EXPORT(sem_post); + +int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout) +{ + rt_err_t result; + rt_int32_t tick; + + if (!sem || !abs_timeout) + return EINVAL; + + /* calculate os tick */ + tick = clock_time_to_tick(abs_timeout); + + result = rt_sem_take(sem->sem, tick); + if (result == -RT_ETIMEOUT) + { + rt_set_errno(ETIMEDOUT); + + return -1; + } + if (result == RT_EOK) + return 0; + + rt_set_errno(EINTR); + + return -1; +} +RTM_EXPORT(sem_timedwait); + +int sem_trywait(sem_t *sem) +{ + rt_err_t result; + + if (!sem) + { + rt_set_errno(EINVAL); + + return -1; + } + + result = rt_sem_take(sem->sem, RT_WAITING_FOREVER); + if (result == -RT_ETIMEOUT) + { + rt_set_errno(EAGAIN); + + return -1; + } + if (result == RT_EOK) + return 0; + + rt_set_errno(EINTR); + + return -1; +} +RTM_EXPORT(sem_trywait); + +int sem_wait(sem_t *sem) +{ + rt_err_t result; + + if (!sem) + { + rt_set_errno(EINVAL); + + return -1; + } + + result = rt_sem_take(sem->sem, RT_WAITING_FOREVER); + if (result == RT_EOK) + return 0; + + rt_set_errno(EINTR); + + return -1; +} +RTM_EXPORT(sem_wait); + diff --git a/components/libc/pthreads/semaphore.h b/components/libc/pthreads/semaphore.h new file mode 100644 index 0000000000..664c15ee2e --- /dev/null +++ b/components/libc/pthreads/semaphore.h @@ -0,0 +1,57 @@ +/* + * File : semaphore.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2010, 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 + * 2010-10-26 Bernard the first version + */ + +#ifndef __POSIX_SEMAPHORE_H__ +#define __POSIX_SEMAPHORE_H__ + +#include <rtthread.h> +#include <pthread.h> + +struct posix_sem +{ + /* reference count and unlinked */ + rt_uint16_t refcount; + rt_uint8_t unlinked; + rt_uint8_t unamed; + + /* RT-Thread semaphore */ + rt_sem_t sem; + + /* next posix semaphore */ + struct posix_sem* next; +}; +typedef struct posix_sem sem_t; + +int sem_close(sem_t *sem); +int sem_destroy(sem_t *sem); +int sem_getvalue(sem_t *sem, int *sval); +int sem_init(sem_t *sem, int pshared, unsigned int value); +sem_t *sem_open(const char *name, int oflag, ...); +int sem_post(sem_t *sem); +int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); +int sem_trywait(sem_t *sem); +int sem_unlink(const char *name); +int sem_wait(sem_t *sem); + +#endif |
