text: /*----------------------------------------------------------------------------
   * 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;
  
      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();
  }
  
  