You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
807 lines
22 KiB
807 lines
22 KiB
/*
|
|
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
|
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
* conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
|
* provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
|
|
* to endorse or promote products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "pprivate.h"
|
|
#include "pthread.h"
|
|
#include "sched.h"
|
|
|
|
#include "stdio.h"
|
|
#include "map_error.h"
|
|
#include "los_process_pri.h"
|
|
#include "los_sched_pri.h"
|
|
|
|
|
|
/*
|
|
* Array of pthread control structures. A pthread_t object is
|
|
* "just" an index into this array.
|
|
*/
|
|
STATIC _pthread_data g_pthreadData[LOSCFG_BASE_CORE_TSK_LIMIT + 1];
|
|
|
|
/* Count of number of threads that have exited and not been reaped. */
|
|
STATIC INT32 g_pthreadsExited = 0;
|
|
|
|
/* this is to protect the pthread data */
|
|
STATIC pthread_mutex_t g_pthreadsDataMutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
/* pointed to by PTHREAD_CANCELED */
|
|
UINTPTR g_pthreadCanceledDummyVar;
|
|
|
|
/*
|
|
* Private version of pthread_self() that returns a pointer to our internal
|
|
* control structure.
|
|
*/
|
|
_pthread_data *pthread_get_self_data(void)
|
|
{
|
|
UINT32 runningTaskPID = ((LosTaskCB *)(OsCurrTaskGet()))->taskID;
|
|
_pthread_data *data = &g_pthreadData[runningTaskPID];
|
|
|
|
return data;
|
|
}
|
|
|
|
_pthread_data *pthread_get_data(pthread_t id)
|
|
{
|
|
_pthread_data *data = NULL;
|
|
|
|
if (OS_TID_CHECK_INVALID(id)) {
|
|
return NULL;
|
|
}
|
|
|
|
data = &g_pthreadData[id];
|
|
/* Check that this is a valid entry */
|
|
if ((data->state == PTHREAD_STATE_FREE) || (data->state == PTHREAD_STATE_EXITED)) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Check that the entry matches the id */
|
|
if (data->id != id) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Return the pointer */
|
|
return data;
|
|
}
|
|
|
|
/*
|
|
* Check whether there is a cancel pending and if so, whether
|
|
* cancellations are enabled. We do it in this order to reduce the
|
|
* number of tests in the common case - when no cancellations are
|
|
* pending. We make this inline so it can be called directly below for speed
|
|
*/
|
|
STATIC INT32 CheckForCancel(VOID)
|
|
{
|
|
_pthread_data *self = pthread_get_self_data();
|
|
if (self->canceled && (self->cancelstate == PTHREAD_CANCEL_ENABLE)) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
STATIC VOID ProcessUnusedStatusTask(_pthread_data *data)
|
|
{
|
|
data->state = PTHREAD_STATE_FREE;
|
|
(VOID)memset_s(data, sizeof(_pthread_data), 0, sizeof(_pthread_data));
|
|
}
|
|
|
|
/*
|
|
* This function is called to tidy up and dispose of any threads that have
|
|
* exited. This work must be done from a thread other than the one exiting.
|
|
* Note: this function must be called with pthread_mutex locked.
|
|
*/
|
|
STATIC VOID PthreadReap(VOID)
|
|
{
|
|
UINT32 i;
|
|
_pthread_data *data = NULL;
|
|
/*
|
|
* Loop over the thread table looking for exited threads. The
|
|
* g_pthreadsExited counter springs us out of this once we have
|
|
* found them all (and keeps us out if there are none to do).
|
|
*/
|
|
for (i = 0; g_pthreadsExited && (i < g_taskMaxNum); i++) {
|
|
data = &g_pthreadData[i];
|
|
if (data->state == PTHREAD_STATE_EXITED) {
|
|
/* the Huawei LiteOS not delete the dead TCB,so need to delete the TCB */
|
|
(VOID)LOS_TaskDelete(data->task->taskID);
|
|
if (data->task->taskStatus & OS_TASK_STATUS_UNUSED) {
|
|
ProcessUnusedStatusTask(data);
|
|
g_pthreadsExited--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
STATIC VOID SetPthreadAttr(const _pthread_data *self, const pthread_attr_t *attr, pthread_attr_t *outAttr)
|
|
{
|
|
/*
|
|
* Set use_attr to the set of attributes we are going to
|
|
* actually use. Either those passed in, or the default set.
|
|
*/
|
|
if (attr == NULL) {
|
|
(VOID)pthread_attr_init(outAttr);
|
|
} else {
|
|
(VOID)memcpy_s(outAttr, sizeof(pthread_attr_t), attr, sizeof(pthread_attr_t));
|
|
}
|
|
|
|
/*
|
|
* If the stack size is not valid, we can assume that it is at
|
|
* least PTHREAD_STACK_MIN bytes.
|
|
*/
|
|
if (!outAttr->stacksize_set) {
|
|
outAttr->stacksize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
|
|
}
|
|
if (outAttr->inheritsched == PTHREAD_INHERIT_SCHED) {
|
|
if (self->task == NULL) {
|
|
outAttr->schedparam.sched_priority = ((LosTaskCB *)(OsCurrTaskGet()))->priority;
|
|
} else {
|
|
outAttr->schedpolicy = self->attr.schedpolicy;
|
|
outAttr->schedparam = self->attr.schedparam;
|
|
outAttr->scope = self->attr.scope;
|
|
}
|
|
}
|
|
}
|
|
|
|
STATIC VOID SetPthreadDataAttr(const pthread_attr_t *userAttr, const pthread_t threadID,
|
|
LosTaskCB *taskCB, _pthread_data *created)
|
|
{
|
|
created->attr = *userAttr;
|
|
created->id = threadID;
|
|
created->task = taskCB;
|
|
created->state = (userAttr->detachstate == PTHREAD_CREATE_JOINABLE) ?
|
|
PTHREAD_STATE_RUNNING : PTHREAD_STATE_DETACHED;
|
|
/* need to confirmation */
|
|
created->cancelstate = PTHREAD_CANCEL_ENABLE;
|
|
created->canceltype = PTHREAD_CANCEL_DEFERRED;
|
|
created->cancelbuffer = NULL;
|
|
created->canceled = 0;
|
|
created->freestack = 0; /* no use default : 0 */
|
|
created->stackmem = taskCB->topOfStack;
|
|
created->thread_data = NULL;
|
|
}
|
|
|
|
STATIC UINT32 InitPthreadData(pthread_t threadID, pthread_attr_t *userAttr,
|
|
const CHAR name[], size_t len)
|
|
{
|
|
errno_t err;
|
|
UINT32 ret = LOS_OK;
|
|
LosTaskCB *taskCB = OS_TCB_FROM_TID(threadID);
|
|
_pthread_data *created = &g_pthreadData[threadID];
|
|
|
|
err = strncpy_s(created->name, sizeof(created->name), name, len);
|
|
if (err != EOK) {
|
|
PRINT_ERR("%s: %d, err: %d\n", __FUNCTION__, __LINE__, err);
|
|
return LOS_NOK;
|
|
}
|
|
userAttr->stacksize = taskCB->stackSize;
|
|
err = OsSetTaskName(taskCB, created->name, FALSE);
|
|
if (err != LOS_OK) {
|
|
PRINT_ERR("%s: %d, err: %d\n", __FUNCTION__, __LINE__, err);
|
|
return LOS_NOK;
|
|
}
|
|
#ifdef LOSCFG_KERNEL_SMP
|
|
if (userAttr->cpuset.__bits[0] > 0) {
|
|
taskCB->cpuAffiMask = (UINT16)userAttr->cpuset.__bits[0];
|
|
}
|
|
#endif
|
|
|
|
SetPthreadDataAttr(userAttr, threadID, taskCB, created);
|
|
return ret;
|
|
}
|
|
|
|
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
|
void *(*startRoutine)(void *), void *arg)
|
|
{
|
|
pthread_attr_t userAttr;
|
|
UINT32 ret;
|
|
CHAR name[PTHREAD_DATA_NAME_MAX] = {0};
|
|
STATIC UINT16 pthreadNumber = 1;
|
|
TSK_INIT_PARAM_S taskInitParam = {0};
|
|
UINT32 taskHandle;
|
|
_pthread_data *self = pthread_get_self_data();
|
|
|
|
if ((thread == NULL) || (startRoutine == NULL)) {
|
|
return EINVAL;
|
|
}
|
|
|
|
SetPthreadAttr(self, attr, &userAttr);
|
|
|
|
(VOID)snprintf_s(name, sizeof(name), sizeof(name) - 1, "pth%02d", pthreadNumber);
|
|
pthreadNumber++;
|
|
|
|
taskInitParam.pcName = name;
|
|
taskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)startRoutine;
|
|
taskInitParam.auwArgs[0] = (UINTPTR)arg;
|
|
taskInitParam.usTaskPrio = (UINT16)userAttr.schedparam.sched_priority;
|
|
taskInitParam.uwStackSize = userAttr.stacksize;
|
|
if (OsProcessIsUserMode(OsCurrProcessGet())) {
|
|
taskInitParam.processID = OsGetKernelInitProcessID();
|
|
} else {
|
|
taskInitParam.processID = OsCurrProcessGet()->processID;
|
|
}
|
|
if (userAttr.detachstate == PTHREAD_CREATE_DETACHED) {
|
|
taskInitParam.uwResved = LOS_TASK_STATUS_DETACHED;
|
|
} else {
|
|
/* Set the pthread default joinable */
|
|
taskInitParam.uwResved = LOS_TASK_ATTR_JOINABLE;
|
|
}
|
|
|
|
PthreadReap();
|
|
ret = LOS_TaskCreateOnly(&taskHandle, &taskInitParam);
|
|
if (ret == LOS_OK) {
|
|
*thread = (pthread_t)taskHandle;
|
|
ret = InitPthreadData(*thread, &userAttr, name, PTHREAD_DATA_NAME_MAX);
|
|
if (ret != LOS_OK) {
|
|
goto ERROR_OUT_WITH_TASK;
|
|
}
|
|
(VOID)LOS_SetTaskScheduler(taskHandle, SCHED_RR, taskInitParam.usTaskPrio);
|
|
}
|
|
|
|
if (ret == LOS_OK) {
|
|
return ENOERR;
|
|
} else {
|
|
goto ERROR_OUT;
|
|
}
|
|
|
|
ERROR_OUT_WITH_TASK:
|
|
(VOID)LOS_TaskDelete(taskHandle);
|
|
ERROR_OUT:
|
|
*thread = (pthread_t)-1;
|
|
|
|
return map_errno(ret);
|
|
}
|
|
|
|
void pthread_exit(void *retVal)
|
|
{
|
|
_pthread_data *self = pthread_get_self_data();
|
|
UINT32 intSave;
|
|
|
|
if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, (int *)0) != ENOERR) {
|
|
PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
|
|
}
|
|
|
|
if (pthread_mutex_lock(&g_pthreadsDataMutex) != ENOERR) {
|
|
PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
|
|
}
|
|
|
|
self->task->joinRetval = retVal;
|
|
/*
|
|
* If we are already detached, go to EXITED state, otherwise
|
|
* go into JOIN state.
|
|
*/
|
|
if (self->state == PTHREAD_STATE_DETACHED) {
|
|
self->state = PTHREAD_STATE_EXITED;
|
|
g_pthreadsExited++;
|
|
} else {
|
|
self->state = PTHREAD_STATE_JOIN;
|
|
}
|
|
|
|
if (pthread_mutex_unlock(&g_pthreadsDataMutex) != ENOERR) {
|
|
PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
|
|
}
|
|
SCHEDULER_LOCK(intSave);
|
|
/* If the thread is the highest thread,it can't schedule in LOS_SemPost. */
|
|
OsTaskJoinPostUnsafe(self->task);
|
|
if (self->task->taskStatus & OS_TASK_STATUS_RUNNING) {
|
|
OsSchedResched();
|
|
}
|
|
SCHEDULER_UNLOCK(intSave);
|
|
}
|
|
|
|
STATIC INT32 ProcessByJoinState(_pthread_data *joined)
|
|
{
|
|
UINT32 intSave;
|
|
INT32 err = 0;
|
|
UINT32 ret;
|
|
switch (joined->state) {
|
|
case PTHREAD_STATE_RUNNING:
|
|
/* The thread is still running, we must wait for it. */
|
|
SCHEDULER_LOCK(intSave);
|
|
ret = OsTaskJoinPendUnsafe(joined->task);
|
|
SCHEDULER_UNLOCK(intSave);
|
|
if (ret != LOS_OK) {
|
|
err = (INT32)ret;
|
|
break;
|
|
}
|
|
|
|
joined->state = PTHREAD_STATE_ALRDY_JOIN;
|
|
break;
|
|
/*
|
|
* The thread has become unjoinable while we waited, so we
|
|
* fall through to complain.
|
|
*/
|
|
case PTHREAD_STATE_FREE:
|
|
case PTHREAD_STATE_DETACHED:
|
|
case PTHREAD_STATE_EXITED:
|
|
/* None of these may be joined. */
|
|
err = EINVAL;
|
|
break;
|
|
case PTHREAD_STATE_ALRDY_JOIN:
|
|
err = EINVAL;
|
|
break;
|
|
case PTHREAD_STATE_JOIN:
|
|
break;
|
|
default:
|
|
PRINT_ERR("state: %u is not supported\n", (UINT32)joined->state);
|
|
break;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int pthread_join(pthread_t thread, void **retVal)
|
|
{
|
|
INT32 err;
|
|
UINT8 status;
|
|
_pthread_data *self = NULL;
|
|
_pthread_data *joined = NULL;
|
|
|
|
/* Check for cancellation first. */
|
|
pthread_testcancel();
|
|
|
|
/* Dispose of any dead threads */
|
|
(VOID)pthread_mutex_lock(&g_pthreadsDataMutex);
|
|
PthreadReap();
|
|
(VOID)pthread_mutex_unlock(&g_pthreadsDataMutex);
|
|
|
|
self = pthread_get_self_data();
|
|
joined = pthread_get_data(thread);
|
|
if (joined == NULL) {
|
|
return ESRCH;
|
|
}
|
|
status = joined->state;
|
|
|
|
if (joined == self) {
|
|
return EDEADLK;
|
|
}
|
|
|
|
err = ProcessByJoinState(joined);
|
|
(VOID)pthread_mutex_lock(&g_pthreadsDataMutex);
|
|
|
|
if (!err) {
|
|
/*
|
|
* Here, we know that joinee is a thread that has exited and is
|
|
* ready to be joined.
|
|
*/
|
|
if (retVal != NULL) {
|
|
/* Get the retVal */
|
|
*retVal = joined->task->joinRetval;
|
|
}
|
|
|
|
/* Set state to exited. */
|
|
joined->state = PTHREAD_STATE_EXITED;
|
|
g_pthreadsExited++;
|
|
|
|
/* Dispose of any dead threads */
|
|
PthreadReap();
|
|
} else {
|
|
joined->state = status;
|
|
}
|
|
|
|
(VOID)pthread_mutex_unlock(&g_pthreadsDataMutex);
|
|
/* Check for cancellation before returning */
|
|
pthread_testcancel();
|
|
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Set the detachstate of the thread to "detached". The thread then does not
|
|
* need to be joined and its resources will be freed when it exits.
|
|
*/
|
|
int pthread_detach(pthread_t thread)
|
|
{
|
|
int ret = 0;
|
|
UINT32 intSave;
|
|
|
|
_pthread_data *detached = NULL;
|
|
|
|
if (pthread_mutex_lock(&g_pthreadsDataMutex) != ENOERR) {
|
|
ret = ESRCH;
|
|
}
|
|
detached = pthread_get_data(thread);
|
|
if (detached == NULL) {
|
|
ret = ESRCH; /* No such thread */
|
|
} else if (detached->state == PTHREAD_STATE_DETACHED) {
|
|
ret = EINVAL; /* Already detached! */
|
|
} else if (detached->state == PTHREAD_STATE_JOIN) {
|
|
detached->state = PTHREAD_STATE_EXITED;
|
|
g_pthreadsExited++;
|
|
} else {
|
|
/* Set state to detached and kick any joinees to make them return. */
|
|
SCHEDULER_LOCK(intSave);
|
|
if (!(detached->task->taskStatus & OS_TASK_STATUS_EXIT)) {
|
|
ret = OsTaskSetDetachUnsafe(detached->task);
|
|
if (ret == ESRCH) {
|
|
ret = LOS_OK;
|
|
} else if (ret == LOS_OK) {
|
|
detached->state = PTHREAD_STATE_DETACHED;
|
|
}
|
|
} else {
|
|
detached->state = PTHREAD_STATE_EXITED;
|
|
g_pthreadsExited++;
|
|
}
|
|
SCHEDULER_UNLOCK(intSave);
|
|
}
|
|
|
|
/* Dispose of any dead threads */
|
|
PthreadReap();
|
|
if (pthread_mutex_unlock(&g_pthreadsDataMutex) != ENOERR) {
|
|
ret = ESRCH;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param)
|
|
{
|
|
_pthread_data *data = NULL;
|
|
int ret;
|
|
|
|
if ((param == NULL) || (param->sched_priority > OS_TASK_PRIORITY_LOWEST)) {
|
|
return EINVAL;
|
|
}
|
|
|
|
if (policy != SCHED_RR) {
|
|
return EINVAL;
|
|
}
|
|
|
|
/* The parameters seem OK, change the thread. */
|
|
ret = pthread_mutex_lock(&g_pthreadsDataMutex);
|
|
if (ret != ENOERR) {
|
|
return ret;
|
|
}
|
|
|
|
data = pthread_get_data(thread);
|
|
if (data == NULL) {
|
|
ret = pthread_mutex_unlock(&g_pthreadsDataMutex);
|
|
if (ret != ENOERR) {
|
|
return ret;
|
|
}
|
|
return ESRCH;
|
|
}
|
|
|
|
/* Only support one policy now */
|
|
data->attr.schedpolicy = SCHED_RR;
|
|
data->attr.schedparam = *param;
|
|
|
|
ret = pthread_mutex_unlock(&g_pthreadsDataMutex);
|
|
if (ret != ENOERR) {
|
|
return ret;
|
|
}
|
|
(VOID)LOS_TaskPriSet((UINT32)thread, (UINT16)param->sched_priority);
|
|
|
|
return ENOERR;
|
|
}
|
|
|
|
int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param)
|
|
{
|
|
_pthread_data *data = NULL;
|
|
int ret;
|
|
|
|
if ((policy == NULL) || (param == NULL)) {
|
|
return EINVAL;
|
|
}
|
|
|
|
ret = pthread_mutex_lock(&g_pthreadsDataMutex);
|
|
if (ret != ENOERR) {
|
|
return ret;
|
|
}
|
|
|
|
data = pthread_get_data(thread);
|
|
if (data == NULL) {
|
|
goto ERR_OUT;
|
|
}
|
|
|
|
*policy = data->attr.schedpolicy;
|
|
*param = data->attr.schedparam;
|
|
|
|
ret = pthread_mutex_unlock(&g_pthreadsDataMutex);
|
|
return ret;
|
|
ERR_OUT:
|
|
ret = pthread_mutex_unlock(&g_pthreadsDataMutex);
|
|
if (ret != ENOERR) {
|
|
return ret;
|
|
}
|
|
return ESRCH;
|
|
}
|
|
|
|
/* Call initRoutine just the once per control variable. */
|
|
int pthread_once(pthread_once_t *onceControl, void (*initRoutine)(void))
|
|
{
|
|
pthread_once_t old;
|
|
int ret;
|
|
|
|
if ((onceControl == NULL) || (initRoutine == NULL)) {
|
|
return EINVAL;
|
|
}
|
|
|
|
/* Do a test and set on the onceControl object. */
|
|
ret = pthread_mutex_lock(&g_pthreadsDataMutex);
|
|
if (ret != ENOERR) {
|
|
return ret;
|
|
}
|
|
|
|
old = *onceControl;
|
|
*onceControl = 1;
|
|
|
|
ret = pthread_mutex_unlock(&g_pthreadsDataMutex);
|
|
if (ret != ENOERR) {
|
|
return ret;
|
|
}
|
|
/* If the onceControl was zero, call the initRoutine(). */
|
|
if (!old) {
|
|
initRoutine();
|
|
}
|
|
|
|
return ENOERR;
|
|
}
|
|
|
|
/* Thread specific data */
|
|
int pthread_key_create(pthread_key_t *key, void (*destructor)(void *))
|
|
{
|
|
(VOID)key;
|
|
(VOID)destructor;
|
|
PRINT_ERR("[%s] is not support.\n", __FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
/* Store the pointer value in the thread-specific data slot addressed by the key. */
|
|
int pthread_setspecific(pthread_key_t key, const void *pointer)
|
|
{
|
|
(VOID)key;
|
|
(VOID)pointer;
|
|
PRINT_ERR("[%s] is not support.\n", __FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
/* Retrieve the pointer value in the thread-specific data slot addressed by the key. */
|
|
void *pthread_getspecific(pthread_key_t key)
|
|
{
|
|
(VOID)key;
|
|
PRINT_ERR("[%s] is not support.\n", __FUNCTION__);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Set cancel state of current thread to ENABLE or DISABLE.
|
|
* Returns old state in *oldState.
|
|
*/
|
|
int pthread_setcancelstate(int state, int *oldState)
|
|
{
|
|
_pthread_data *self = NULL;
|
|
int ret;
|
|
|
|
if ((state != PTHREAD_CANCEL_ENABLE) && (state != PTHREAD_CANCEL_DISABLE)) {
|
|
return EINVAL;
|
|
}
|
|
|
|
ret = pthread_mutex_lock(&g_pthreadsDataMutex);
|
|
if (ret != ENOERR) {
|
|
return ret;
|
|
}
|
|
|
|
self = pthread_get_self_data();
|
|
|
|
if (oldState != NULL) {
|
|
*oldState = self->cancelstate;
|
|
}
|
|
|
|
self->cancelstate = (UINT8)state;
|
|
|
|
ret = pthread_mutex_unlock(&g_pthreadsDataMutex);
|
|
if (ret != ENOERR) {
|
|
return ret;
|
|
}
|
|
|
|
return ENOERR;
|
|
}
|
|
|
|
/*
|
|
* Set cancel type of current thread to ASYNCHRONOUS or DEFERRED.
|
|
* Returns old type in *oldType.
|
|
*/
|
|
int pthread_setcanceltype(int type, int *oldType)
|
|
{
|
|
_pthread_data *self = NULL;
|
|
int ret;
|
|
|
|
if ((type != PTHREAD_CANCEL_ASYNCHRONOUS) && (type != PTHREAD_CANCEL_DEFERRED)) {
|
|
return EINVAL;
|
|
}
|
|
|
|
ret = pthread_mutex_lock(&g_pthreadsDataMutex);
|
|
if (ret != ENOERR) {
|
|
return ret;
|
|
}
|
|
|
|
self = pthread_get_self_data();
|
|
if (oldType != NULL) {
|
|
*oldType = self->canceltype;
|
|
}
|
|
|
|
self->canceltype = (UINT8)type;
|
|
|
|
ret = pthread_mutex_unlock(&g_pthreadsDataMutex);
|
|
if (ret != ENOERR) {
|
|
return ret;
|
|
}
|
|
|
|
return ENOERR;
|
|
}
|
|
|
|
STATIC UINT32 DoPthreadCancel(_pthread_data *data)
|
|
{
|
|
UINT32 ret = LOS_OK;
|
|
UINT32 intSave;
|
|
LOS_TaskLock();
|
|
data->canceled = 0;
|
|
if ((data->task->taskStatus & OS_TASK_STATUS_EXIT) || (LOS_TaskSuspend(data->task->taskID) != ENOERR)) {
|
|
ret = LOS_NOK;
|
|
goto OUT;
|
|
}
|
|
|
|
if (data->task->taskStatus & OS_TASK_FLAG_PTHREAD_JOIN) {
|
|
SCHEDULER_LOCK(intSave);
|
|
OsTaskJoinPostUnsafe(data->task);
|
|
SCHEDULER_UNLOCK(intSave);
|
|
g_pthreadCanceledDummyVar = (UINTPTR)PTHREAD_CANCELED;
|
|
data->task->joinRetval = (VOID *)g_pthreadCanceledDummyVar;
|
|
} else if (data->state && !(data->task->taskStatus & OS_TASK_STATUS_UNUSED)) {
|
|
data->state = PTHREAD_STATE_EXITED;
|
|
g_pthreadsExited++;
|
|
PthreadReap();
|
|
} else {
|
|
ret = LOS_NOK;
|
|
}
|
|
OUT:
|
|
LOS_TaskUnlock();
|
|
return ret;
|
|
}
|
|
|
|
int pthread_cancel(pthread_t thread)
|
|
{
|
|
_pthread_data *data = NULL;
|
|
|
|
if (pthread_mutex_lock(&g_pthreadsDataMutex) != ENOERR) {
|
|
PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
|
|
}
|
|
|
|
data = pthread_get_data(thread);
|
|
if (data == NULL) {
|
|
if (pthread_mutex_unlock(&g_pthreadsDataMutex) != ENOERR) {
|
|
PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
|
|
}
|
|
return ESRCH;
|
|
}
|
|
|
|
data->canceled = 1;
|
|
|
|
if ((data->cancelstate == PTHREAD_CANCEL_ENABLE) &&
|
|
(data->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)) {
|
|
/*
|
|
* If the thread has cancellation enabled, and it is in
|
|
* asynchronous mode, suspend it and set corresponding thread's status.
|
|
* We also release the thread out of any current wait to make it wake up.
|
|
*/
|
|
if (DoPthreadCancel(data) == LOS_NOK) {
|
|
goto ERROR_OUT;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Otherwise the thread has cancellation disabled, in which case
|
|
* it is up to the thread to enable cancellation
|
|
*/
|
|
if (pthread_mutex_unlock(&g_pthreadsDataMutex) != ENOERR) {
|
|
PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
|
|
}
|
|
|
|
return ENOERR;
|
|
ERROR_OUT:
|
|
if (pthread_mutex_unlock(&g_pthreadsDataMutex) != ENOERR) {
|
|
PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
|
|
}
|
|
return ESRCH;
|
|
}
|
|
|
|
/*
|
|
* Test for a pending cancellation for the current thread and terminate
|
|
* the thread if there is one.
|
|
*/
|
|
void pthread_testcancel(void)
|
|
{
|
|
if (CheckForCancel()) {
|
|
/*
|
|
* If we have cancellation enabled, and there is a cancellation
|
|
* pending, then go ahead and do the deed.
|
|
* Exit now with special retVal. pthread_exit() calls the
|
|
* cancellation handlers implicitly.
|
|
*/
|
|
pthread_exit((void *)PTHREAD_CANCELED);
|
|
}
|
|
}
|
|
|
|
/* Get current thread id. */
|
|
pthread_t pthread_self(void)
|
|
{
|
|
_pthread_data *data = pthread_get_self_data();
|
|
|
|
return data->id;
|
|
}
|
|
|
|
/* Compare two thread identifiers. */
|
|
int pthread_equal(pthread_t thread1, pthread_t thread2)
|
|
{
|
|
return thread1 == thread2;
|
|
}
|
|
|
|
void pthread_cleanup_push_inner(struct pthread_cleanup_buffer *buffer,
|
|
void (*routine)(void *), void *arg)
|
|
{
|
|
(VOID)buffer;
|
|
(VOID)routine;
|
|
(VOID)arg;
|
|
PRINT_ERR("[%s] is not support.\n", __FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
void pthread_cleanup_pop_inner(struct pthread_cleanup_buffer *buffer, int execute)
|
|
{
|
|
(VOID)buffer;
|
|
(VOID)execute;
|
|
PRINT_ERR("[%s] is not support.\n", __FUNCTION__);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Set the cpu affinity mask for the thread
|
|
*/
|
|
int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t* cpuset)
|
|
{
|
|
INT32 ret = sched_setaffinity(thread, cpusetsize, cpuset);
|
|
if (ret == -1) {
|
|
return errno;
|
|
} else {
|
|
return ENOERR;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Get the cpu affinity mask from the thread
|
|
*/
|
|
int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t* cpuset)
|
|
{
|
|
INT32 ret = sched_getaffinity(thread, cpusetsize, cpuset);
|
|
if (ret == -1) {
|
|
return errno;
|
|
} else {
|
|
return ENOERR;
|
|
}
|
|
}
|
|
|