From 25f50375ef71f2aa4928fbf814973f118ed1fadd Mon Sep 17 00:00:00 2001 From: "bernard.xiong" Date: Fri, 12 Nov 2010 10:26:36 +0000 Subject: [PATCH] add initial pthread implementation. git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1044 bbd45198-f89e-11dd-88c7-29a3b14d5316 --- components/pthreads/pthread.c | 276 ++++++++++++++++++++++++++ components/pthreads/pthread.h | 114 +++++++++++ components/pthreads/pthread_attr.c | 161 +++++++++++++++ components/pthreads/pthread_attr.h | 20 ++ components/pthreads/pthread_barrier.c | 0 components/pthreads/pthread_barrier.h | 0 components/pthreads/pthread_cond.c | 57 ++++++ components/pthreads/pthread_cond.h | 23 +++ components/pthreads/pthread_mutex.c | 193 ++++++++++++++++++ components/pthreads/pthread_mutex.h | 25 +++ components/pthreads/pthread_rwlock.c | 0 components/pthreads/pthread_rwlock.h | 21 ++ components/pthreads/pthread_spin.c | 26 +++ components/pthreads/pthread_spin.h | 18 ++ components/pthreads/pthread_test.c | 127 ++++++++++++ components/pthreads/pthread_tls.c | 0 components/pthreads/pthread_tls.h | 0 components/pthreads/sem.c | 98 +++++++++ components/pthreads/sem.h | 20 ++ 19 files changed, 1179 insertions(+) create mode 100644 components/pthreads/pthread.c create mode 100644 components/pthreads/pthread.h create mode 100644 components/pthreads/pthread_attr.c create mode 100644 components/pthreads/pthread_attr.h create mode 100644 components/pthreads/pthread_barrier.c create mode 100644 components/pthreads/pthread_barrier.h create mode 100644 components/pthreads/pthread_cond.c create mode 100644 components/pthreads/pthread_cond.h create mode 100644 components/pthreads/pthread_mutex.c create mode 100644 components/pthreads/pthread_mutex.h create mode 100644 components/pthreads/pthread_rwlock.c create mode 100644 components/pthreads/pthread_rwlock.h create mode 100644 components/pthreads/pthread_spin.c create mode 100644 components/pthreads/pthread_spin.h create mode 100644 components/pthreads/pthread_test.c create mode 100644 components/pthreads/pthread_tls.c create mode 100644 components/pthreads/pthread_tls.h create mode 100644 components/pthreads/sem.c create mode 100644 components/pthreads/sem.h diff --git a/components/pthreads/pthread.c b/components/pthreads/pthread.c new file mode 100644 index 0000000000..8200b471ec --- /dev/null +++ b/components/pthreads/pthread.c @@ -0,0 +1,276 @@ +#include "pthread.h" + +#define PTHREAD_MAGIC 0x70746873 +struct _pthread_data +{ + rt_uint32_t magic; + pthread_attr_t attr; + rt_thread_t tid; + + void* (*thread_entry)(void* parameter); + void* thread_parameter; + + /* return value */ + void* return_value; + + /* semaphore for joinable thread */ + rt_sem_t joinable_sem; + + void** tls; /* thread-local storage area */ +}; +typedef struct _pthread_data _pthread_data_t; + +rt_inline _pthread_data_t* get_pthread_data(pthread_t thread) +{ + RT_ASSERT(thread != RT_NULL); + + return (_pthread_data_t*)thread->user_data; +} + +int pthread_system_init(void) +{ + return 0; +} + +static void _pthread_cleanup(rt_thread_t tid) +{ + _pthread_data_t *ptd; + ptd = get_pthread_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 pthread data */ + ptd = (_pthread_data_t*)rt_malloc(sizeof(_pthread_data_t)); + if (ptd == RT_NULL) return ENOMEM; + /* clean memory */ + rt_memset(ptd, 0, sizeof(_pthread_data_t)); + + 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; +} + +int pthread_detach(pthread_t thread) +{ + _pthread_data_t* ptd; + + ptd = get_pthread_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); + } + rt_free(ptd->tid); + rt_free(ptd); + } + else + { + rt_enter_critical(); + /* change to detach state */ + ptd->attr.detachstate = PTHREAD_CREATE_DETACHED; + rt_exit_critical(); + + /* detach joinable semaphore */ + rt_sem_delete(ptd->joinable_sem); + } + + return 0; +} + +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 = get_pthread_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; +} + +int pthread_cancel (pthread_t thread) +{ + _pthread_data_t* ptd; + + ptd = get_pthread_data(thread); + + /* check cancel point */ +} + +void pthread_exit (void* value) +{ + _pthread_data_t* ptd; + + ptd = get_pthread_data(rt_thread_self()); + + /* set return value */ + ptd->return_value = value; + 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(); +} + +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; +} + +int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) +{ + return ENOTSUP; +} + diff --git a/components/pthreads/pthread.h b/components/pthreads/pthread.h new file mode 100644 index 0000000000..dfa3c11050 --- /dev/null +++ b/components/pthreads/pthread.h @@ -0,0 +1,114 @@ +/* + * File : pthread.h + * 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-10-26 Bernard the first version + */ +#ifndef __PTHREAD_H__ +#define __PTHREAD_H__ + +#include +#include + +#include "pthread_attr.h" +#include "pthread_mutex.h" + +typedef rt_thread_t pthread_t; + +typedef long pthread_condattr_t; +typedef int pthread_key_t; +typedef int pthread_once_t; + +enum { + PTHREAD_CANCEL_ASYNCHRONOUS = 0, + PTHREAD_CANCEL_ENABLE, + PTHREAD_CANCEL_DEFERRED, + PTHREAD_CANCEL_DISABLE, + PTHREAD_CANCELED +}; + +#define PTHREAD_COND_INITIALIZER +#define PTHREAD_RWLOCK_INITIALIZER +#define PTHREAD_MUTEX_INITIALIZER {-1, 0} + +#define PTHREAD_CREATE_JOINABLE 0x00 +#define PTHREAD_CREATE_DETACHED 0x01 + +#define PTHREAD_EXPLICIT_SCHED 0 +#define PTHREAD_INHERIT_SCHED 1 + +enum { + PTHREAD_MUTEX_NORMAL = 0, + PTHREAD_MUTEX_RECURSIVE = 1, + 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 sched_param { + int sched_priority; +}; + +/* + * Scheduling policies required by IEEE Std 1003.1-2001 + */ +#define SCHED_OTHER 0 /* Behavior can be FIFO or RR, or not */ +#define SCHED_FIFO 1 +#define SCHED_RR 2 + +int pthread_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 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)); + +#endif + diff --git a/components/pthreads/pthread_attr.c b/components/pthreads/pthread_attr.c new file mode 100644 index 0000000000..02b9ec6cdd --- /dev/null +++ b/components/pthreads/pthread_attr.c @@ -0,0 +1,161 @@ +#include +#include "pthread.h" +#include + +#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; +} + +int pthread_attr_destroy(pthread_attr_t *attr) +{ + RT_ASSERT(attr != RT_NULL); + + memset(attr, 0, sizeof(pthread_attr_t)); + return 0; +} + +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; +} + +int pthread_attr_getdetachstate(pthread_attr_t const * attr, int *state) +{ + RT_ASSERT(attr != RT_NULL); + + *state = (int)attr->detachstate; + + return 0; +} + +int pthread_attr_setschedpolicy(pthread_attr_t * attr, int policy) +{ + RT_ASSERT(attr != RT_NULL); + + attr->policy = policy; + return 0; +} + +int pthread_attr_getschedpolicy(pthread_attr_t const *attr, int *policy) +{ + RT_ASSERT(attr != RT_NULL); + + *policy = (int)attr->policy; + return 0; +} + +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; +} + +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; +} + +int pthread_attr_setstacksize(pthread_attr_t * attr, size_t stack_size) +{ + RT_ASSERT(attr != RT_NULL); + + attr->stack_size = stack_size; + return 0; +} + +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; +} + +int pthread_attr_setstackaddr(pthread_attr_t * attr, void * stack_addr) +{ + RT_ASSERT(attr != RT_NULL); + return ENOTSUP; +} + +int pthread_attr_getstackaddr(pthread_attr_t const * attr, void ** stack_addr) +{ + RT_ASSERT(attr != RT_NULL); + return ENOTSUP; +} + +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; +} + +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; +} + +int pthread_attr_setguardsize(pthread_attr_t * attr, size_t guard_size) +{ + return ENOTSUP; +} + +int pthread_attr_getguardsize(pthread_attr_t const * attr, size_t *guard_size) +{ + return ENOTSUP; +} + +int pthread_attr_setscope(pthread_attr_t *attr, int scope) +{ + if (scope == PTHREAD_SCOPE_SYSTEM) + return 0; + if (scope == PTHREAD_SCOPE_PROCESS) + return ENOTSUP; + + return EINVAL; +} + +int pthread_attr_getscope(pthread_attr_t const *attr) +{ + return PTHREAD_SCOPE_SYSTEM; +} + diff --git a/components/pthreads/pthread_attr.h b/components/pthreads/pthread_attr.h new file mode 100644 index 0000000000..f4950e20bf --- /dev/null +++ b/components/pthreads/pthread_attr.h @@ -0,0 +1,20 @@ +#ifndef __PTHREAD_ATTR_H__ +#define __PTHREAD_ATTR_H__ + +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; +extern const pthread_attr_t pthread_default_attr; + +int pthread_attr_destroy(pthread_attr_t *attr); +int pthread_attr_init(pthread_attr_t *attr); + +#endif diff --git a/components/pthreads/pthread_barrier.c b/components/pthreads/pthread_barrier.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/components/pthreads/pthread_barrier.h b/components/pthreads/pthread_barrier.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/components/pthreads/pthread_cond.c b/components/pthreads/pthread_cond.c new file mode 100644 index 0000000000..b0c85aefc0 --- /dev/null +++ b/components/pthreads/pthread_cond.c @@ -0,0 +1,57 @@ +#include "pthread_cond.h" + +int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *pshared) +{ + if (!attr || !pshared) return EINVAL; + + *pshared = PTHREAD_PROCESS_PRIVATE; + return 0; +} + +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; +} + +int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) +{ + /* parameter check */ + if (cond == RT_NULL) return EINVAL; + if ((attr != RT_NULL) && (*attr != PTHREAD_PROCESS_PRIVATE)) return EINVAL; + + return 0; +} + +int pthread_cond_destroy(pthread_cond_t *cond) +{ + return 0; +} + +int pthread_cond_broadcast(pthread_cond_t *cond) +{ + return 0; +} + +int pthread_cond_signal(pthread_cond_t *cond) +{ + return 0; +} + +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + return 0; +} + +int pthread_cond_timedwait(pthread_cond_t *cond, + pthread_mutex_t * mutex, + const struct timespec *abstime) +{ + return 0; +} + diff --git a/components/pthreads/pthread_cond.h b/components/pthreads/pthread_cond.h new file mode 100644 index 0000000000..02b0412a9e --- /dev/null +++ b/components/pthreads/pthread_cond.h @@ -0,0 +1,23 @@ +#ifndef __PTHREAD_COND_H__ +#define __PTHREAD_COND_H__ + +#include +#include + +struct pthread_cond +{ + pthread_mutex_t *mutex; +}; +typedef struct pthread_cond pthread_cond_t; + +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); + +#endif diff --git a/components/pthreads/pthread_mutex.c b/components/pthreads/pthread_mutex.c new file mode 100644 index 0000000000..4e244cee9e --- /dev/null +++ b/components/pthreads/pthread_mutex.c @@ -0,0 +1,193 @@ +#include +#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; +} + +int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) +{ + if (attr) + { + *attr = -1; + return 0; + } + + return EINVAL; +} + +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; +} + +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; +} + +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; +} + +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; +} + +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; +} + +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; +} + +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; +} + +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; +} + +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; +} + diff --git a/components/pthreads/pthread_mutex.h b/components/pthreads/pthread_mutex.h new file mode 100644 index 0000000000..c12e9df0cc --- /dev/null +++ b/components/pthreads/pthread_mutex.h @@ -0,0 +1,25 @@ +#ifndef __PTHREAD_MUTEX_H__ +#define __PTHREAD_MUTEX_H__ + +typedef long pthread_mutexattr_t; +struct pthread_mutex +{ + pthread_mutexattr_t attr; + struct rt_mutex lock; +}; +typedef struct pthread_mutex pthread_mutex_t; + +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); + +#endif diff --git a/components/pthreads/pthread_rwlock.c b/components/pthreads/pthread_rwlock.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/components/pthreads/pthread_rwlock.h b/components/pthreads/pthread_rwlock.h new file mode 100644 index 0000000000..ee7dfaa91c --- /dev/null +++ b/components/pthreads/pthread_rwlock.h @@ -0,0 +1,21 @@ +#ifndef __PTHREAD_RWLOCK_H__ +#define __PTHREAD_RWLOCK_H__ + +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_trywrlock (pthread_rwlock_t * rwlock); +int pthread_rwlock_unlock (pthread_rwlock_t * rwlock); +int pthread_rwlock_wrlock (pthread_rwlock_t * rwlock); + +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); + +#endif diff --git a/components/pthreads/pthread_spin.c b/components/pthreads/pthread_spin.c new file mode 100644 index 0000000000..4332ec1db8 --- /dev/null +++ b/components/pthreads/pthread_spin.c @@ -0,0 +1,26 @@ +#include "pthread_spin.h" + +int pthread_spin_init (pthread_spinlock_t *lock, int pshared) +{ + return 0; +} + +int pthread_spin_destroy (pthread_spinlock_t *lock) +{ + return 0; +} + +int pthread_spin_lock (pthread_spinlock_t * lock) +{ + return 0; +} + +int pthread_spin_trylock (pthread_spinlock_t * lock) +{ + return 0; +} + +int pthread_spin_unlock (pthread_spinlock_t * lock) +{ + return 0; +} diff --git a/components/pthreads/pthread_spin.h b/components/pthreads/pthread_spin.h new file mode 100644 index 0000000000..4b66c8bdc2 --- /dev/null +++ b/components/pthreads/pthread_spin.h @@ -0,0 +1,18 @@ +#ifndef __PTHREAD_SPIN_H__ +#define __PTHREAD_SPIN_H__ +#include + +struct pthread_spinlock +{ + int pshared; +}; +typedef struct pthread_spinlock pthread_spinlock_t; + +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); + +#endif diff --git a/components/pthreads/pthread_test.c b/components/pthreads/pthread_test.c new file mode 100644 index 0000000000..14c07e9249 --- /dev/null +++ b/components/pthreads/pthread_test.c @@ -0,0 +1,127 @@ +#include +#include + +#define _die_(x) do { rt_kprintf(x); RT_ASSERT(0); } while (0) +#define pr(x) do { rt_kprintf(x); } while (0) +#define sleep(n) rt_thread_sleep((n * RT_TICK_PER_SECOND)/1000) +#define alarm(n) + +/* (0) once test */ +void test0_ok() { pr("(once called) "); } +void test0_failed() { _die_("failed...\n"); } +void pth_t0() { + pthread_once_t v_once=PTHREAD_ONCE_INIT; + pr("\nTEST 0: once test:\n\n"); + pr("testing once function... "); + pthread_once(&v_once,test0_ok); + pthread_once(&v_once,test0_failed); + pr("OK.\n"); +} +FINSH_FUNCTION_EXPORT(pth_t0, pthread testcase0); + +/* (1) mutex tests */ +void test_rec_mutex() { + pthread_mutex_t tm; + pthread_mutexattr_t ta; + pthread_mutexattr_settype(&ta, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&tm, &ta); + pr("testing recursive mutex... "); + alarm(5); + if (pthread_mutex_lock(&tm) != 0) _die_("failed... mutex_lock on unused rec-mutex (c=0)...\n"); + if (tm.lock.owner!=pthread_self()) _die_("failed.. wrong owner....\n"); + if (tm.lock.hold!=1) _die_("failed... wrong counting (c!=1)....\n"); + if (pthread_mutex_lock(&tm) != 0) _die_("failed... mutex_lock on taken rec-mutex (c=1)...\n"); + if (tm.lock.hold!=2) _die_("failed... wrong counting (c!=2)....\n"); + if (pthread_mutex_lock(&tm) != 0) _die_("failed... mutex_lock on taken rec-mutex (c=2)...\n"); + if (tm.lock.hold!=3) _die_("failed... wrong counting (c!=3)....\n"); + if (pthread_mutex_unlock(&tm) != 0) _die_("failed... mutex_unlock on taken rec-mutex (c=3)...\n"); + if (tm.lock.hold!=2) _die_("failed... wrong counting (c!=2)....\n"); + if (tm.lock.owner==0) _die_("failed... mutex has no owner?!?!\n"); + if (pthread_mutex_unlock(&tm) != 0) _die_("failed... mutex_unlock on taken rec-mutex (c=2)...\n"); + if (tm.lock.hold!=1) _die_("failed... wrong counting (c!=1)....\n"); + if (tm.lock.owner==0) _die_("failed... mutex has no owner?!?!\n"); + if (pthread_mutex_unlock(&tm) != 0) _die_("failed... mutex_unlock on taken rec-mutex (c=1)...\n"); + if (tm.lock.hold!=0) _die_("failed... wrong counting (c!=0)....\n"); + if (tm.lock.owner!=0) _die_("failed... mutex still owned ?!?!\n"); + if (pthread_mutex_unlock(&tm) != 0) _die_("failed... mutex_unlock on free rec-mutex (c=0)...\n"); + alarm(0); + pr("OK.\n"); +} + +void test_err_mutex() { + pthread_mutex_t tm; + pthread_mutexattr_t ta; + + pthread_mutexattr_settype(&ta, PTHREAD_MUTEX_ERRORCHECK); + pthread_mutex_init(&tm, &ta); + pr("testing errorcheck mutex... "); + alarm(5); + if (pthread_mutex_lock(&tm) != 0) _die_("failed... mutex_lock on unused errchk-mutex...\n"); + if (tm.lock.owner!=pthread_self()) _die_("failed.. wrong owner....\n"); + if (pthread_mutex_lock(&tm) != EDEADLK) _die_("failed... mutex_lock on taken errchk-mutex...\n"); + if (pthread_mutex_unlock(&tm) != 0) _die_("failed... mutex_unlock on taken errchk-mutex...\n"); + if (tm.lock.owner!=0) _die_("failed... mutex still owned ?!?!\n"); + if (pthread_mutex_unlock(&tm) != EPERM) _die_("failed... mutex_unlock on free errchk-mutex...\n"); + alarm(0); + pr("OK.\n"); +} + +void pth_t1() { + pr("\nTEST 1: mutex test:\n\n"); + test_rec_mutex(); + test_err_mutex(); +} +FINSH_FUNCTION_EXPORT(pth_t1, pthread testcase0); + +void* thread(void*arg) +{ + if (0) { arg=0; } + pr("(thread created) "); + sleep(1); + pr("(thread exit) "); + return 0; +} + +void test_thread() { + pthread_t t; + pr("testing basic thread creation and join... "); + if ((pthread_create(&t,0,thread,0))!=0) _die_("failed...\n"); + if (pthread_join(t,0) != 0) _die_("failed... joining thread\n"); + pr("OK.\n"); +} + +void test_thread_join_detached() { + pthread_t t; + pthread_attr_t attr; + pr("testing for failing join of a detached thread... "); + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); + if ((pthread_create(&t,&attr,thread,0))!=0) _die_("failed...\n"); + if (pthread_join(t,0) == 0) _die_("failed... I had joined a detached thread !\n"); + sleep(2); + pr("OK.\n"); +} + +static char alt_stack[4096]; +void test_thread_alt_stack() { + pthread_t t; + pthread_attr_t attr; + pr("testing alternate thread stack... "); + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr,sizeof(alt_stack)); + if ((pthread_create(&t,&attr,thread,0))!=0) _die_("failed... creating thread\n"); + if (pthread_join(t,0) != 0) _die_("failed... joining thread\n"); + pthread_attr_setstackaddr(&attr,alt_stack); + if ((pthread_create(&t,&attr,thread,0))!=0) _die_("failed... creating thread\n"); + if (pthread_join(t,0) != 0) _die_("failed... joining thread\n"); + pr("OK.\n"); +} + +void pth_t2() +{ + pr("\nTEST 2: thread creation & attributes:\n\n"); + test_thread(); + test_thread_join_detached(); + test_thread_alt_stack(); +} +FINSH_FUNCTION_EXPORT(pth_t2, pthread testcase1); diff --git a/components/pthreads/pthread_tls.c b/components/pthreads/pthread_tls.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/components/pthreads/pthread_tls.h b/components/pthreads/pthread_tls.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/components/pthreads/sem.c b/components/pthreads/sem.c new file mode 100644 index 0000000000..e4cecab69a --- /dev/null +++ b/components/pthreads/sem.c @@ -0,0 +1,98 @@ +#include +#include + +#include "sem.h" + +int sem_close(sem_t *sem) +{ +} + +int sem_destroy(sem_t *sem) +{ +} + +int sem_unlink(const char *name) +{ + return EACCES; +} + +int sem_getvalue(sem_t *sem, int *sval) +{ + RT_ASSERT(sem != RT_NULL); + if (sval) *sval = sem->value; +} + +int sem_init(sem_t *sem, int pshared, unsigned int value) +{ + RT_ASSERT(sem != RT_NULL); +} + +sem_t *sem_open(const char *name, int oflag, ...) +{ + rt_sem_t sem; + + sem = RT_NULL; + if (oflag == O_CREAT) + { + sem = rt_sem_create(name, 1, RT_IPC_FLAG_FIFO); + if (sem == RT_NULL) + rt_set_errno(ENOSPC); + } + + if (oflag == O_EXCL) + { + rt_enter_critical(); + /* find semaphore object */ + rt_exit_critical(); + + if (sem == RT_NULL) rt_set_errno(ENOENT); + } + + return sem; +} + +int sem_post(sem_t *sem) +{ + rt_sem_release(sem); +} + +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 = abs_timeout->tv_sec/RT_TICK_PER_SECOND + (abs_timeout->tv_nsec/1000) * (1000/RT_TICK_PER_SECOND); + + result = rt_sem_take(sem, tick); + if (result == -RT_ETIMEOUT) return ETIMEDOUT; + if (result == RT_EOK) return 0; + + return EINTR; +} + +int sem_trywait(sem_t *sem) +{ + rt_err_t result; + + if (!sem) return EINVAL; + + result = rt_sem_take(sem, RT_WAITING_FOREVER); + if (result == -RT_ETIMEOUT) return EAGAIN; + if (result == RT_EOK) return 0; + + return EINTR; +} + +int sem_wait(sem_t *sem) +{ + rt_err_t result; + + result = rt_sem_take(sem, RT_WAITING_FOREVER); + if (result == RT_EOK) return 0; + + return EINTR; +} + diff --git a/components/pthreads/sem.h b/components/pthreads/sem.h new file mode 100644 index 0000000000..29e2911a54 --- /dev/null +++ b/components/pthreads/sem.h @@ -0,0 +1,20 @@ +#ifndef __POSIX_SEMAPHORE_H__ +#define __POSIX_SEMAPHORE_H__ + +#include +#include + +typedef struct rt_semaphore 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 -- GitLab