1607 lines
35 KiB
C
1607 lines
35 KiB
C
/*----------------------------------------------------------------------------
|
|
* Tencent is pleased to support the open source community by making TencentOS
|
|
* available.
|
|
*
|
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
|
* If you have downloaded a copy of the TencentOS binary from Tencent, please
|
|
* note that the TencentOS binary is licensed under the BSD 3-Clause License.
|
|
*
|
|
* If you have downloaded a copy of the TencentOS source code from Tencent,
|
|
* please note that TencentOS source code is licensed under the BSD 3-Clause
|
|
* License, except for the third-party components listed below which are
|
|
* subject to different license terms. Your integration of TencentOS into your
|
|
* own projects may require compliance with the BSD 3-Clause License, as well
|
|
* as the other licenses applicable to the third-party components included
|
|
* within TencentOS.
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
#include "private/posix_config.h"
|
|
|
|
#include "errno.h"
|
|
#include "pthread.h"
|
|
#include "private/pthread.h"
|
|
#include "private/time.h"
|
|
|
|
int __pthread_canceled;
|
|
|
|
__STATIC__ int pthreads_ready2reap = 0;
|
|
|
|
__STATIC__ void pthread_dead_reap(void)
|
|
{
|
|
pthreads_ready2reap -= pthread_ctl_reap(pthreads_ready2reap);
|
|
}
|
|
|
|
__STATIC__ void pthread_entry(void *data)
|
|
{
|
|
void *retval;
|
|
pthread_ctl_t *the_ctl;
|
|
|
|
the_ctl = (pthread_ctl_t *)data;
|
|
|
|
retval = the_ctl->start_routine(the_ctl->arg);
|
|
|
|
pthread_exit(retval);
|
|
}
|
|
|
|
__STATIC__ int pthread_is_cancel_pending(void)
|
|
{
|
|
pthread_ctl_t *self_ctl;
|
|
|
|
self_ctl = pthread_ctl_self();
|
|
if (self_ctl &&
|
|
self_ctl->cancelpending &&
|
|
self_ctl->cancelstate == PTHREAD_CANCEL_ENABLE) {
|
|
return K_TRUE;
|
|
}
|
|
|
|
return K_FALSE;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void))
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__API__ int pthread_attr_destroy(pthread_attr_t *attr)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
|
|
memset(attr, 0, sizeof(pthread_attr_t));
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(detachstate, EINVAL);
|
|
|
|
*detachstate = attr->detachstate;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__API__ int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(inheritsched, EINVAL);
|
|
|
|
*inheritsched = attr->inheritsched;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(param, EINVAL);
|
|
|
|
*param = attr->schedparam;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(policy, EINVAL);
|
|
|
|
*policy = attr->schedpolicy;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__API__ int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(stackaddr, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(stacksize, EINVAL);
|
|
|
|
if (!attr->stackaddr_valid || !attr->stacksize_valid) {
|
|
return EINVAL;
|
|
}
|
|
|
|
*stackaddr = attr->stackaddr;
|
|
*stacksize = attr->stacksize;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(stacksize, EINVAL);
|
|
|
|
if (!attr->stacksize_valid) {
|
|
return EINVAL;
|
|
}
|
|
|
|
*stacksize = attr->stacksize;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_attr_init(pthread_attr_t *attr)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
|
|
attr->detachstate = PTHREAD_DEFAULT_DETACH_STATE;
|
|
attr->inheritsched = PTHREAD_DEFAULT_INHERIT_SCHED;
|
|
attr->schedpolicy = PTHREAD_DEFAULT_SCHEDPOLICY;
|
|
attr->schedparam.sched_priority = PTHREAD_DEFAULT_PRIORITY;
|
|
|
|
attr->stackaddr_valid = K_FALSE;
|
|
attr->stacksize_valid = K_FALSE;
|
|
attr->stackaddr = K_NULL;
|
|
attr->stacksize = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
|
|
if (detachstate != PTHREAD_CREATE_JOINABLE &&
|
|
detachstate != PTHREAD_CREATE_DETACHED) {
|
|
return EINVAL;
|
|
}
|
|
|
|
attr->detachstate = detachstate;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__API__ int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(inheritsched, EINVAL);
|
|
|
|
if (inheritsched != PTHREAD_INHERIT_SCHED &&
|
|
inheritsched != PTHREAD_EXPLICIT_SCHED) {
|
|
return EINVAL;
|
|
}
|
|
|
|
attr->inheritsched = inheritsched;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(param, EINVAL);
|
|
|
|
attr->schedparam = *param;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(policy, EINVAL);
|
|
|
|
if (policy != SCHED_OTHER &&
|
|
policy != SCHED_FIFO &&
|
|
policy != SCHED_RR) {
|
|
return EINVAL;
|
|
}
|
|
|
|
attr->schedpolicy = policy;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__API__ int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(stackaddr, EINVAL);
|
|
|
|
if (stacksize < PTHREAD_STK_SIZE_MIN) {
|
|
return EINVAL;
|
|
}
|
|
|
|
attr->stackaddr = stackaddr;
|
|
attr->stackaddr_valid = K_TRUE;
|
|
|
|
attr->stacksize = stacksize;
|
|
attr->stacksize_valid = K_TRUE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
|
|
if (stacksize < PTHREAD_STK_SIZE_MIN) {
|
|
return EINVAL;
|
|
}
|
|
|
|
attr->stacksize = stacksize;
|
|
attr->stacksize_valid = K_TRUE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if POSIX_CFG_PTHREAD_BARRIER_EN > 0u
|
|
|
|
__API__ int pthread_barrier_destroy(pthread_barrier_t *barrier)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(barrier, EINVAL);
|
|
|
|
kerr = tos_barrier_destroy((k_barrier_t *)barrier);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned count)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(barrier, EINVAL);
|
|
|
|
kerr = tos_barrier_create((k_barrier_t *)barrier, (k_barrier_cnt_t)count);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_barrier_wait(pthread_barrier_t *barrier)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(barrier, EINVAL);
|
|
|
|
kerr = tos_barrier_pend((k_barrier_t *)barrier);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, int *pshared)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_barrierattr_init(pthread_barrierattr_t *attr)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
#endif /* POSIX_CFG_PTHREAD_BARRIER_EN */
|
|
|
|
__API__ int pthread_cancel(pthread_t thread)
|
|
{
|
|
pthread_ctl_t *the_ctl;
|
|
|
|
pthread_lock();
|
|
|
|
the_ctl = pthread_ctl_by_id(thread);
|
|
if (!the_ctl) {
|
|
pthread_unlock();
|
|
return ESRCH;
|
|
}
|
|
|
|
the_ctl->cancelpending = K_TRUE;
|
|
|
|
if (the_ctl->cancelstate == PTHREAD_CANCEL_DISABLE) {
|
|
return EPERM;
|
|
}
|
|
|
|
if (the_ctl->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS) {
|
|
tos_task_destroy(the_ctl->the_ktask);
|
|
}
|
|
|
|
pthread_unlock();
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if POSIX_CFG_PTHREAD_COND_EN > 0u
|
|
|
|
__API__ int pthread_cond_broadcast(pthread_cond_t *cond)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(cond, EINVAL);
|
|
|
|
kerr = tos_sem_post_all((k_sem_t *)cond);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_cond_destroy(pthread_cond_t *cond)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(cond, EINVAL);
|
|
|
|
kerr = tos_sem_destroy((k_sem_t *)cond);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(cond, EINVAL);
|
|
|
|
kerr = tos_sem_create((k_sem_t *)cond, 0);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_cond_signal(pthread_cond_t *cond)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(cond, EINVAL);
|
|
|
|
kerr = tos_sem_post((k_sem_t *)cond);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__STATIC__ int pthread_cond_do_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, k_tick_t timeout)
|
|
{
|
|
k_err_t kerr;
|
|
int errcode;
|
|
|
|
if (mutex->kmutex.owner != tos_task_curr_task_get()) {
|
|
return EPERM;
|
|
}
|
|
|
|
errcode = pthread_mutex_unlock(mutex);
|
|
if (errcode != 0) {
|
|
return EINVAL;
|
|
}
|
|
|
|
kerr = tos_sem_pend((k_sem_t *)cond, timeout);
|
|
pthread_mutex_lock(mutex);
|
|
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
if (kerr == K_ERR_PEND_TIMEOUT) {
|
|
return ETIMEDOUT;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
|
|
{
|
|
k_tick_t timeout;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(cond, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(mutex, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(abstime, EINVAL);
|
|
|
|
timeout = timespec_to_ktick(abstime);
|
|
return pthread_cond_do_timedwait(cond, mutex, timeout);
|
|
}
|
|
|
|
__API__ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(cond, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(mutex, EINVAL);
|
|
|
|
return pthread_cond_do_timedwait(cond, mutex, TOS_TIME_FOREVER);
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_condattr_destroy(pthread_condattr_t *attr)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_condattr_getclock(const pthread_condattr_t *attr, clockid_t *clock_id)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *pshared)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_condattr_init(pthread_condattr_t *attr)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
#endif /* POSIX_CFG_PTHREAD_COND_EN */
|
|
|
|
__API__ int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
|
|
{
|
|
k_err_t kerr;
|
|
pthread_t id;
|
|
int errcode;
|
|
int is_stk_need_free = K_FALSE;
|
|
void *stackaddr = K_NULL;
|
|
size_t stacksize;
|
|
char name[K_TASK_NAME_MAX];
|
|
static uint16_t pthrd_id = 0;
|
|
pthread_attr_t the_attr;
|
|
pthread_ctl_t *self_ctl = K_NULL, *the_ctl = K_NULL;
|
|
|
|
TOS_IN_IRQ_CHECK();
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(thread, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(start_routine, EINVAL);
|
|
|
|
id = pthread_id_alloc();
|
|
if (id == -1) {
|
|
return ENOMEM;
|
|
}
|
|
|
|
if (!attr) {
|
|
pthread_attr_init(&the_attr);
|
|
} else {
|
|
the_attr = *attr;
|
|
}
|
|
|
|
self_ctl = pthread_ctl_self();
|
|
|
|
if (the_attr.inheritsched == PTHREAD_INHERIT_SCHED) {
|
|
if (!self_ctl) {
|
|
/* cannot inherit sched policy from non-POSIX thread */
|
|
errcode = EPERM;
|
|
goto errout0;
|
|
}
|
|
|
|
the_attr.schedpolicy = self_ctl->attr.schedpolicy;
|
|
the_attr.schedparam = self_ctl->attr.schedparam;
|
|
}
|
|
|
|
if (the_attr.stackaddr_valid) {
|
|
/* means we called pthread_attr_setstack and returned OK once before*/
|
|
stackaddr = the_attr.stackaddr;
|
|
stacksize = the_attr.stacksize;
|
|
} else if (the_attr.stacksize_valid) {
|
|
/* we called pthread_attr_setstacksize and returned OK once before */
|
|
stacksize = the_attr.stacksize + PTHREAD_INFO_SIZE;
|
|
} else {
|
|
/* neither the pthread_attr_setstack nor pthread_attr_setstacksize has beed called */
|
|
stacksize = PTHREAD_DEFAULT_STACKSIZE;
|
|
}
|
|
|
|
if (!the_attr.stackaddr_valid) {
|
|
stackaddr = tos_mmheap_alloc(stacksize);
|
|
if (!stackaddr) {
|
|
errcode = ENOMEM;
|
|
goto errout0;
|
|
}
|
|
|
|
is_stk_need_free = K_TRUE;
|
|
}
|
|
|
|
/* we keep our little secret onto the bottom of stack, avoiding of multi-times malloc */
|
|
the_ctl = (pthread_ctl_t *)stackaddr;
|
|
the_ctl->stackaddr = (is_stk_need_free ? stackaddr : K_NULL);
|
|
the_ctl->start_routine = start_routine;
|
|
the_ctl->arg = arg;
|
|
memset(&the_ctl->ktask, 0, sizeof(k_task_t));
|
|
|
|
stackaddr = (void *)((cpu_addr_t)stackaddr + PTHREAD_INFO_SIZE);
|
|
stacksize -= PTHREAD_INFO_SIZE;
|
|
snprintf(name, sizeof(name), "pthrd%d", pthrd_id++);
|
|
|
|
if (the_attr.detachstate == PTHREAD_CREATE_JOINABLE) {
|
|
kerr = tos_sem_create(&the_ctl->joinner_sem, 0);
|
|
if (kerr != K_ERR_NONE) {
|
|
errcode = EBUSY;
|
|
goto errout0;
|
|
}
|
|
}
|
|
|
|
tos_knl_sched_lock();
|
|
|
|
pthread_dead_reap();
|
|
|
|
kerr = tos_task_create(&the_ctl->ktask, name,
|
|
pthread_entry, (void *)the_ctl,
|
|
the_attr.schedparam.sched_priority,
|
|
stackaddr, stacksize,
|
|
PTHREAD_DEFAULT_TIMESLICE);
|
|
if (kerr != K_ERR_NONE) {
|
|
errcode = EBUSY;
|
|
tos_knl_sched_unlock();
|
|
goto errout1;
|
|
}
|
|
|
|
the_ctl->threadstate = the_attr.detachstate == PTHREAD_CREATE_JOINABLE ?
|
|
PTHREAD_STATE_RUNNING : PTHREAD_STATE_DETACHED;
|
|
|
|
the_ctl->id = id;
|
|
the_ctl->attr = the_attr;
|
|
the_ctl->retval = K_NULL;
|
|
the_ctl->the_ktask = &the_ctl->ktask;
|
|
|
|
the_ctl->cancelstate = PTHREAD_CANCEL_ENABLE;
|
|
the_ctl->canceltype = PTHREAD_CANCEL_DEFERRED;
|
|
the_ctl->cancelpending = K_FALSE;
|
|
|
|
the_ctl->thread_data = K_NULL;
|
|
tos_slist_init(&the_ctl->cleanup_ctl_list);
|
|
|
|
pthread_id_add(id, the_ctl);
|
|
|
|
*thread = id;
|
|
|
|
tos_knl_sched_unlock();
|
|
|
|
return ENOERR;
|
|
|
|
errout1:
|
|
tos_sem_destroy(&the_ctl->joinner_sem);
|
|
|
|
errout0:
|
|
if (is_stk_need_free) {
|
|
/* stack is allocated by us */
|
|
tos_mmheap_free(stackaddr);
|
|
}
|
|
|
|
return errcode;
|
|
}
|
|
|
|
__API__ int pthread_detach(pthread_t thread)
|
|
{
|
|
int errcode = 0;
|
|
pthread_ctl_t *the_ctl;
|
|
|
|
pthread_lock();
|
|
|
|
the_ctl = pthread_ctl_by_id(thread);
|
|
if (!the_ctl) {
|
|
errcode = ESRCH;
|
|
} else if (the_ctl->threadstate == PTHREAD_STATE_DETACHED) {
|
|
/* already detached */
|
|
errcode = EINVAL;
|
|
} else {
|
|
the_ctl->threadstate = PTHREAD_STATE_DETACHED;
|
|
/* make any who is joining for us wakeup and return(I am detached now!) */
|
|
tos_sem_post_all(&the_ctl->joinner_sem);
|
|
}
|
|
|
|
pthread_dead_reap();
|
|
|
|
pthread_unlock();
|
|
|
|
return errcode;
|
|
}
|
|
|
|
__API__ int pthread_equal(pthread_t t1, pthread_t t2)
|
|
{
|
|
return t1 == t2;
|
|
}
|
|
|
|
__API__ void pthread_exit(void *value_ptr)
|
|
{
|
|
void *value;
|
|
int key = 0;
|
|
int destructor_called = K_FALSE, destructor_iterations = 0;
|
|
key_destructor_t key_destructor = K_NULL;
|
|
pthread_ctl_t *self_ctl;
|
|
pthread_cleanup_ctl_t *cleanup_ctl, *tmp;
|
|
|
|
self_ctl = pthread_ctl_self();
|
|
if (!self_ctl) {
|
|
/* this is a non-POSIX thread */
|
|
return;
|
|
}
|
|
|
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, K_NULL);
|
|
|
|
/* call all the cleanup routine */
|
|
TOS_SLIST_FOR_EACH_ENTRY_SAFE(cleanup_ctl, tmp, pthread_cleanup_ctl_t, list, &self_ctl->cleanup_ctl_list) {
|
|
cleanup_ctl->routine(cleanup_ctl->arg);
|
|
tos_slist_del(&cleanup_ctl->list, &self_ctl->cleanup_ctl_list);
|
|
tos_mmheap_free(cleanup_ctl);
|
|
}
|
|
|
|
/* call destructor for each key */
|
|
do {
|
|
for (key = 0; key < PTHREAD_KEYS_MAX; ++key) {
|
|
/* key is not created */
|
|
if (!pthread_key_is_alloc(key)) {
|
|
continue;
|
|
}
|
|
|
|
/* destrutor is not register-ed */
|
|
key_destructor = pthread_key_destructor_get(key);
|
|
if (!key_destructor) {
|
|
continue;
|
|
}
|
|
|
|
if (self_ctl->thread_data) {
|
|
continue;
|
|
}
|
|
|
|
value = self_ctl->thread_data[key];
|
|
self_ctl->thread_data[key] = K_NULL;
|
|
key_destructor(value);
|
|
|
|
destructor_called = K_TRUE;
|
|
}
|
|
|
|
++destructor_iterations;
|
|
} while (destructor_called && (destructor_iterations <= PTHREAD_DESTRUCTOR_ITERATIONS));
|
|
|
|
/* donot forget this */
|
|
if (self_ctl->thread_data) {
|
|
tos_mmheap_free(self_ctl->thread_data);
|
|
}
|
|
|
|
pthread_lock();
|
|
|
|
self_ctl->retval = value_ptr;
|
|
|
|
if (self_ctl->threadstate == PTHREAD_STATE_DETACHED) {
|
|
/* ready to die totally */
|
|
self_ctl->threadstate = PTHREAD_STATE_EXITED;
|
|
++pthreads_ready2reap;
|
|
} else {
|
|
/* we are dying, but we still waiting for someone to join us(reap for us)*/
|
|
self_ctl->threadstate = PTHREAD_STATE_JOIN;
|
|
}
|
|
|
|
/* wakeup all the joniners */
|
|
tos_sem_post_all(&self_ctl->joinner_sem);
|
|
|
|
pthread_unlock();
|
|
|
|
/* will invoke a knl_sched at last */
|
|
tos_task_destroy(self_ctl->the_ktask);
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_getconcurrency(void)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__API__ int pthread_getcpuclockid(pthread_t thread_id, clockid_t *clock_id)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__API__ int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param)
|
|
{
|
|
pthread_ctl_t *the_ctl;
|
|
|
|
pthread_lock();
|
|
|
|
the_ctl = pthread_ctl_by_id(thread);
|
|
|
|
if (!the_ctl) {
|
|
pthread_unlock();
|
|
return ESRCH;
|
|
}
|
|
|
|
if (policy) {
|
|
*policy = the_ctl->attr.schedpolicy;
|
|
}
|
|
|
|
if (param) {
|
|
*param = the_ctl->attr.schedparam;
|
|
}
|
|
|
|
pthread_unlock();
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ void *pthread_getspecific(pthread_key_t key)
|
|
{
|
|
pthread_ctl_t *self_ctl;
|
|
|
|
if (key >= PTHREAD_KEYS_MAX || key < 0) {
|
|
return K_NULL;
|
|
}
|
|
|
|
self_ctl = pthread_ctl_self();
|
|
if (!self_ctl || !self_ctl->thread_data) {
|
|
/* this is a non-POSIX thread, or thread_data is empty */
|
|
return K_NULL;
|
|
}
|
|
|
|
return self_ctl->thread_data[key];
|
|
}
|
|
|
|
__API__ int pthread_join(pthread_t thread, void **value_ptr)
|
|
{
|
|
k_err_t kerr;
|
|
int errcode = 0;
|
|
pthread_ctl_t *self_ctl, *the_ctl;
|
|
|
|
pthread_testcancel();
|
|
|
|
pthread_lock();
|
|
|
|
pthread_dead_reap();
|
|
|
|
pthread_unlock();
|
|
|
|
self_ctl = pthread_ctl_self();
|
|
if (!self_ctl) {
|
|
/* a non-POSIX thread */
|
|
errcode = EPERM;
|
|
goto errout;
|
|
}
|
|
|
|
the_ctl = pthread_ctl_by_id(thread);
|
|
if (!the_ctl) {
|
|
errcode = ESRCH;
|
|
goto errout;
|
|
}
|
|
|
|
if (the_ctl == self_ctl) {
|
|
errcode = EDEADLK;
|
|
goto errout;
|
|
}
|
|
|
|
if (the_ctl->attr.detachstate == PTHREAD_CREATE_DETACHED) {
|
|
/* the target thread is not joinable */
|
|
errcode = EPERM;
|
|
goto errout;
|
|
}
|
|
|
|
if (the_ctl->threadstate == PTHREAD_STATE_DETACHED &&
|
|
the_ctl->threadstate == PTHREAD_STATE_EXITED) {
|
|
errcode = EINVAL;
|
|
goto errout;
|
|
}
|
|
|
|
if (the_ctl->threadstate == PTHREAD_STATE_JOIN) {
|
|
/* the thread is exit, and waiting to be joined */
|
|
;
|
|
} else if (the_ctl->threadstate == PTHREAD_STATE_RUNNING) {
|
|
while (the_ctl->threadstate == PTHREAD_STATE_RUNNING) {
|
|
kerr = tos_sem_pend(&the_ctl->joinner_sem, TOS_TIME_FOREVER);
|
|
if (kerr != K_ERR_NONE) {
|
|
errcode = ESRCH;
|
|
goto errout;
|
|
}
|
|
|
|
if (pthread_is_cancel_pending()) {
|
|
/* someone cancel us, goto errout and suicide in testcancel */
|
|
errcode = EAGAIN;
|
|
goto errout;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (value_ptr) {
|
|
*value_ptr = the_ctl->retval;
|
|
}
|
|
|
|
/* the guy now happy to die */
|
|
the_ctl->threadstate = PTHREAD_STATE_EXITED;
|
|
|
|
++pthreads_ready2reap;
|
|
|
|
pthread_lock();
|
|
|
|
pthread_dead_reap();
|
|
|
|
pthread_unlock();
|
|
|
|
errout:
|
|
pthread_testcancel();
|
|
return errcode;
|
|
}
|
|
|
|
__API__ int pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
|
|
{
|
|
pthread_key_t the_key;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(key, -1);
|
|
|
|
the_key = pthread_key_alloc();
|
|
if (the_key == -1) {
|
|
*key = -1;
|
|
return EAGAIN;
|
|
}
|
|
|
|
pthread_lock();
|
|
|
|
pthread_key_destructor_register(the_key, destructor);
|
|
|
|
pthread_data_clear(the_key);
|
|
|
|
pthread_unlock();
|
|
|
|
*key = the_key;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_key_delete(pthread_key_t key)
|
|
{
|
|
int rc;
|
|
|
|
pthread_lock();
|
|
|
|
rc = pthread_key_free(key);
|
|
|
|
pthread_unlock();
|
|
|
|
return rc;
|
|
}
|
|
|
|
#if POSIX_CFG_PTHREAD_MUTEX_EN > 0u
|
|
|
|
__NOTSUPP__ int pthread_mutex_consistent(pthread_mutex_t *mutex)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__API__ int pthread_mutex_destroy(pthread_mutex_t *mutex)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(mutex, EINVAL);
|
|
|
|
kerr = tos_mutex_destroy(&mutex->kmutex);
|
|
if (kerr != K_ERR_NONE) {
|
|
return EINVAL;
|
|
}
|
|
|
|
pthread_mutexattr_init(&mutex->attr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_mutex_getprioceiling(const pthread_mutex_t *mutex, int *prioceiling)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__API__ int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(mutex, EINVAL);
|
|
|
|
if (!attr) {
|
|
pthread_mutexattr_init(&mutex->attr);
|
|
attr = &mutex->attr;
|
|
} else {
|
|
mutex->attr = *attr;
|
|
}
|
|
|
|
kerr = tos_mutex_create(&mutex->kmutex);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_mutex_lock(pthread_mutex_t *mutex)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(mutex, EINVAL);
|
|
|
|
if (mutex->attr.type != PTHREAD_MUTEX_RECURSIVE &&
|
|
mutex->kmutex.owner == tos_task_curr_task_get()) {
|
|
/* RECURSIVE is not permitted, and we are the owner */
|
|
return EPERM;
|
|
}
|
|
|
|
/* the k_mutex_t is born to support RECURSIVE */
|
|
kerr = tos_mutex_pend(&mutex->kmutex);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int prioceiling, int *old_ceiling)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__API__ int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime)
|
|
{
|
|
k_err_t kerr;
|
|
k_tick_t ktick;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(mutex, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(abstime, EINVAL);
|
|
|
|
if (mutex->attr.type != PTHREAD_MUTEX_RECURSIVE &&
|
|
mutex->kmutex.owner == tos_task_curr_task_get()) {
|
|
/* RECURSIVE is not permitted, and we are the owner */
|
|
return EPERM;
|
|
}
|
|
|
|
ktick = timespec_to_ktick(abstime);
|
|
kerr = tos_mutex_pend_timed(&mutex->kmutex, ktick);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_mutex_trylock(pthread_mutex_t *mutex)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(mutex, EINVAL);
|
|
|
|
if (mutex->attr.type != PTHREAD_MUTEX_RECURSIVE &&
|
|
mutex->kmutex.owner == tos_task_curr_task_get()) {
|
|
/* RECURSIVE is not permitted, and we are the owner */
|
|
return EPERM;
|
|
}
|
|
|
|
kerr = tos_mutex_pend_timed(&mutex->kmutex, TOS_TIME_NOWAIT);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_mutex_unlock(pthread_mutex_t *mutex)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(mutex, EINVAL);
|
|
|
|
if ((!mutex->kmutex.owner ||
|
|
mutex->kmutex.owner != tos_task_curr_task_get()) &&
|
|
mutex->attr.type == PTHREAD_MUTEX_ERRORCHECK) {
|
|
/* the mutex is not locked or not locked by us, and type is PTHREAD_MUTEX_ERRORCHECK */
|
|
return EPERM;
|
|
}
|
|
|
|
kerr = tos_mutex_post(&mutex->kmutex);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
|
|
attr->type = 0xF;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *mutex, int *prioceiling)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *mutex, int *protocol)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_mutexattr_getpshared(const pthread_mutexattr_t *mutex, int *pshared)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_mutexattr_getrobust(const pthread_mutexattr_t *mutex, int *robust)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__API__ int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(type, EINVAL);
|
|
|
|
*type = attr->type;
|
|
|
|
return 0;
|
|
}
|
|
__API__ int pthread_mutexattr_init(pthread_mutexattr_t *attr)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
|
|
attr->type = PTHREAD_MUTEX_DEFAULT;
|
|
|
|
return 0;
|
|
}
|
|
__NOTSUPP__ int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_mutexattr_setprotocol(pthread_mutexattr_t *mutex, int protocol)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_mutexattr_setpshared(pthread_mutexattr_t *mutex, int pshared)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_mutexattr_setrobust(pthread_mutexattr_t *mutex, int robust)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__API__ int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(attr, EINVAL);
|
|
|
|
if (type < PTHREAD_MUTEX_NORMAL ||
|
|
type > PTHREAD_MUTEX_DEFAULT) {
|
|
return EINVAL;
|
|
}
|
|
|
|
attr->type = type;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* POSIX_CFG_PTHREAD_MUTEX_EN */
|
|
|
|
#if POSIX_CFG_PTHREAD_RWLOCK_EN > 0u
|
|
|
|
__API__ int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
|
|
{
|
|
pthread_once_t old;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(once_control, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(init_routine, EINVAL);
|
|
|
|
pthread_lock();
|
|
|
|
old = *once_control;
|
|
*once_control = 1;
|
|
|
|
pthread_unlock();
|
|
|
|
if (!old) {
|
|
init_routine();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(rwlock, EINVAL);
|
|
|
|
kerr = tos_rwlock_destroy((k_rwlock_t *)rwlock);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(rwlock, EINVAL);
|
|
|
|
kerr = tos_rwlock_create((k_rwlock_t *)rwlock);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(rwlock, EINVAL);
|
|
|
|
kerr = tos_rwlock_rpend((k_rwlock_t *)rwlock);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, const struct timespec *abstime)
|
|
{
|
|
k_err_t kerr;
|
|
k_tick_t ktick;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(rwlock, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(abstime, EINVAL);
|
|
|
|
ktick = timespec_to_ktick(abstime);
|
|
kerr = tos_rwlock_rpend_timed((k_rwlock_t *)rwlock, ktick);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, const struct timespec *abstime)
|
|
{
|
|
k_err_t kerr;
|
|
k_tick_t ktick;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(rwlock, EINVAL);
|
|
TOS_PTR_SANITY_CHECK_RC(abstime, EINVAL);
|
|
|
|
ktick = timespec_to_ktick(abstime);
|
|
kerr = tos_rwlock_wpend_timed((k_rwlock_t *)rwlock, ktick);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
|
|
__API__ int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(rwlock, EINVAL);
|
|
|
|
kerr = tos_rwlock_rpend_try((k_rwlock_t *)rwlock);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(rwlock, EINVAL);
|
|
|
|
kerr = tos_rwlock_wpend_try((k_rwlock_t *)rwlock);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(rwlock, EINVAL);
|
|
|
|
kerr = tos_rwlock_post((k_rwlock_t *)rwlock);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__API__ int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
|
|
{
|
|
k_err_t kerr;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(rwlock, EINVAL);
|
|
|
|
kerr = tos_rwlock_wpend((k_rwlock_t *)rwlock);
|
|
if (kerr == K_ERR_NONE) {
|
|
return 0;
|
|
}
|
|
|
|
return EINVAL;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, int *pshared)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
#endif /* POSIX_CFG_PTHREAD_RWLOCK_EN */
|
|
|
|
__API__ pthread_t pthread_self(void)
|
|
{
|
|
pthread_ctl_t *self_ctl;
|
|
|
|
self_ctl = pthread_ctl_self();
|
|
if (!self_ctl) {
|
|
/* a non-POSIX thread */
|
|
return -1;
|
|
}
|
|
|
|
return self_ctl->id;
|
|
}
|
|
|
|
__API__ int pthread_setcancelstate(int state, int *oldstate)
|
|
{
|
|
pthread_ctl_t *self_ctl;
|
|
|
|
if (state != PTHREAD_CANCEL_ENABLE &&
|
|
state != PTHREAD_CANCEL_DISABLE) {
|
|
return EINVAL;
|
|
}
|
|
|
|
self_ctl = pthread_ctl_self();
|
|
if (!self_ctl) {
|
|
/* this is a non-POSIX thread */
|
|
return EPERM;
|
|
}
|
|
|
|
if (oldstate) {
|
|
*oldstate = self_ctl->cancelstate;
|
|
}
|
|
|
|
self_ctl->cancelstate = state;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_setcanceltype(int type, int *oldtype)
|
|
{
|
|
pthread_ctl_t *self_ctl;
|
|
|
|
if (type != PTHREAD_CANCEL_ASYNCHRONOUS &&
|
|
type != PTHREAD_CANCEL_DEFERRED) {
|
|
return EINVAL;
|
|
}
|
|
|
|
self_ctl = pthread_ctl_self();
|
|
if (!self_ctl) {
|
|
/* this is a non-POSIX thread */
|
|
return EPERM;
|
|
}
|
|
|
|
if (oldtype) {
|
|
*oldtype = self_ctl->canceltype;
|
|
}
|
|
|
|
self_ctl->canceltype = type;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__NOTSUPP__ int pthread_setconcurrency(int new_level)
|
|
{
|
|
return EOPNOTSUPP;
|
|
}
|
|
|
|
__API__ int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param)
|
|
{
|
|
pthread_ctl_t *the_ctl;
|
|
|
|
TOS_PTR_SANITY_CHECK_RC(param, EINVAL);
|
|
|
|
if (policy != SCHED_OTHER &&
|
|
policy != SCHED_FIFO &&
|
|
policy != SCHED_RR) {
|
|
return EINVAL;
|
|
}
|
|
|
|
pthread_lock();
|
|
|
|
the_ctl = pthread_ctl_by_id(thread);
|
|
|
|
if (!the_ctl) {
|
|
pthread_unlock();
|
|
return ESRCH;
|
|
}
|
|
|
|
the_ctl->attr.schedpolicy = policy;
|
|
the_ctl->attr.schedparam = *param;
|
|
|
|
if (the_ctl->the_ktask) {
|
|
tos_task_prio_change(the_ctl->the_ktask, param->sched_priority);
|
|
}
|
|
|
|
pthread_unlock();
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_setschedprio(pthread_t thread, int prio)
|
|
{
|
|
pthread_ctl_t *the_ctl;
|
|
|
|
pthread_lock();
|
|
|
|
the_ctl = pthread_ctl_by_id(thread);
|
|
|
|
if (!the_ctl) {
|
|
pthread_unlock();
|
|
return ESRCH;
|
|
}
|
|
|
|
the_ctl->attr.schedparam.sched_priority = prio;
|
|
|
|
if (the_ctl->the_ktask) {
|
|
tos_task_prio_change(the_ctl->the_ktask, prio);
|
|
}
|
|
|
|
pthread_unlock();
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_setspecific(pthread_key_t key, const void *value)
|
|
{
|
|
int i = 0;
|
|
pthread_ctl_t *self_ctl;
|
|
|
|
if (key >= PTHREAD_KEYS_MAX || key < 0) {
|
|
return EINVAL;
|
|
}
|
|
|
|
self_ctl = pthread_ctl_self();
|
|
if (!self_ctl) {
|
|
/* this is a non-POSIX thread */
|
|
return EPERM;
|
|
}
|
|
|
|
if (!self_ctl->thread_data) {
|
|
self_ctl->thread_data = (void **)tos_mmheap_alloc(sizeof(void *) * PTHREAD_KEYS_MAX);
|
|
if (!self_ctl->thread_data) {
|
|
return ENOMEM;
|
|
}
|
|
|
|
for (i = 0; i < PTHREAD_KEYS_MAX; ++i) {
|
|
self_ctl->thread_data[i] = K_NULL;
|
|
}
|
|
}
|
|
|
|
self_ctl->thread_data[key] = (void *)value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if POSIX_CFG_PTHREAD_SPIN_EN > 0u
|
|
|
|
__API__ int pthread_spin_destroy(pthread_spinlock_t *lock)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(lock, EINVAL);
|
|
|
|
if (lock->is_destroyed) {
|
|
return 0;
|
|
}
|
|
|
|
lock->is_destroyed = K_TRUE;
|
|
lock->is_locked = K_FALSE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_spin_init(pthread_spinlock_t *lock, int pshared)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(lock, EINVAL);
|
|
|
|
lock->is_destroyed = K_FALSE;
|
|
lock->is_locked = K_FALSE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_spin_lock(pthread_spinlock_t *lock)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(lock, EINVAL);
|
|
|
|
if (lock->is_destroyed) {
|
|
return EPERM;
|
|
}
|
|
|
|
while (!lock->is_locked) {
|
|
lock->is_locked = K_TRUE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_spin_trylock(pthread_spinlock_t *lock)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(lock, EINVAL);
|
|
|
|
if (lock->is_destroyed) {
|
|
return EPERM;
|
|
}
|
|
|
|
if (lock->is_locked) {
|
|
return EBUSY;
|
|
}
|
|
|
|
lock->is_locked = K_TRUE;
|
|
return 0;
|
|
}
|
|
|
|
__API__ int pthread_spin_unlock(pthread_spinlock_t *lock)
|
|
{
|
|
TOS_PTR_SANITY_CHECK_RC(lock, EINVAL);
|
|
|
|
if (lock->is_destroyed) {
|
|
return EPERM;
|
|
}
|
|
|
|
if (!lock->is_locked) {
|
|
return EPERM;
|
|
}
|
|
|
|
lock->is_locked = K_FALSE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* POSIX_CFG_PTHREAD_SPIN_EN */
|
|
|
|
__API__ void pthread_testcancel(void)
|
|
{
|
|
if (pthread_is_cancel_pending()) {
|
|
pthread_exit(PTHREAD_CANCELD);
|
|
}
|
|
}
|
|
|
|
__API__ void pthread_cleanup_pop(int execute)
|
|
{
|
|
pthread_ctl_t *self_ctl;
|
|
pthread_cleanup_ctl_t *cleanup_ctl;
|
|
|
|
self_ctl = pthread_ctl_self();
|
|
if (!self_ctl) {
|
|
/* this is a non-POSIX thread */
|
|
return;
|
|
}
|
|
|
|
pthread_lock();
|
|
|
|
if (tos_slist_empty(&self_ctl->cleanup_ctl_list)) {
|
|
pthread_unlock();
|
|
return;
|
|
}
|
|
|
|
cleanup_ctl = TOS_SLIST_FIRST_ENTRY(&self_ctl->cleanup_ctl_list, pthread_cleanup_ctl_t, list);
|
|
tos_slist_del_head(&self_ctl->cleanup_ctl_list);
|
|
|
|
pthread_unlock();
|
|
|
|
if (execute) {
|
|
cleanup_ctl->routine(cleanup_ctl->arg);
|
|
}
|
|
|
|
tos_mmheap_free(cleanup_ctl);
|
|
}
|
|
|
|
__API__ void pthread_cleanup_push(void (*routine)(void*), void *arg)
|
|
{
|
|
pthread_ctl_t *self_ctl;
|
|
pthread_cleanup_ctl_t *cleanup_ctl;
|
|
|
|
if (!routine) {
|
|
return;
|
|
}
|
|
|
|
self_ctl = pthread_ctl_self();
|
|
if (!self_ctl) {
|
|
/* this is a non-POSIX thread */
|
|
return;
|
|
}
|
|
|
|
cleanup_ctl = (pthread_cleanup_ctl_t *)tos_mmheap_alloc(sizeof(pthread_cleanup_ctl_t));
|
|
if (!cleanup_ctl) {
|
|
return;
|
|
}
|
|
|
|
pthread_lock();
|
|
tos_slist_add_head(&cleanup_ctl->list, &self_ctl->cleanup_ctl_list);
|
|
pthread_unlock();
|
|
}
|
|
|