xref: /kernel/liteos_a/compat/posix/src/pthread.c (revision 0d163575)
1/*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 *    conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 *    of conditions and the following disclaimer in the documentation and/or other materials
13 *    provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 *    to endorse or promote products derived from this software without specific prior written
17 *    permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "pprivate.h"
33#include "pthread.h"
34#include "sched.h"
35
36#include "stdio.h"
37#include "map_error.h"
38#include "los_process_pri.h"
39#include "los_sched_pri.h"
40
41
42/*
43 * Array of pthread control structures. A pthread_t object is
44 * "just" an index into this array.
45 */
46STATIC _pthread_data g_pthreadData[LOSCFG_BASE_CORE_TSK_LIMIT + 1];
47
48/* Count of number of threads that have exited and not been reaped. */
49STATIC INT32 g_pthreadsExited = 0;
50
51/* this is to protect the pthread data */
52STATIC pthread_mutex_t g_pthreadsDataMutex = PTHREAD_MUTEX_INITIALIZER;
53
54/* pointed to by PTHREAD_CANCELED */
55UINTPTR g_pthreadCanceledDummyVar;
56
57/*
58 * Private version of pthread_self() that returns a pointer to our internal
59 * control structure.
60 */
61_pthread_data *pthread_get_self_data(void)
62{
63    UINT32 runningTaskPID = ((LosTaskCB *)(OsCurrTaskGet()))->taskID;
64    _pthread_data *data = &g_pthreadData[runningTaskPID];
65
66    return data;
67}
68
69_pthread_data *pthread_get_data(pthread_t id)
70{
71    _pthread_data *data = NULL;
72
73    if (OS_TID_CHECK_INVALID(id)) {
74        return NULL;
75    }
76
77    data = &g_pthreadData[id];
78    /* Check that this is a valid entry */
79    if ((data->state == PTHREAD_STATE_FREE) || (data->state == PTHREAD_STATE_EXITED)) {
80        return NULL;
81    }
82
83    /* Check that the entry matches the id */
84    if (data->id != id) {
85        return NULL;
86    }
87
88    /* Return the pointer */
89    return data;
90}
91
92/*
93 * Check whether there is a cancel pending and if so, whether
94 * cancellations are enabled. We do it in this order to reduce the
95 * number of tests in the common case - when no cancellations are
96 * pending. We make this inline so it can be called directly below for speed
97 */
98STATIC INT32 CheckForCancel(VOID)
99{
100    _pthread_data *self = pthread_get_self_data();
101    if (self->canceled && (self->cancelstate == PTHREAD_CANCEL_ENABLE)) {
102        return 1;
103    }
104    return 0;
105}
106
107STATIC VOID ProcessUnusedStatusTask(_pthread_data *data)
108{
109    data->state = PTHREAD_STATE_FREE;
110    (VOID)memset_s(data, sizeof(_pthread_data), 0, sizeof(_pthread_data));
111}
112
113/*
114 * This function is called to tidy up and dispose of any threads that have
115 * exited. This work must be done from a thread other than the one exiting.
116 * Note: this function must be called with pthread_mutex locked.
117 */
118STATIC VOID PthreadReap(VOID)
119{
120    UINT32 i;
121    _pthread_data *data = NULL;
122    /*
123     * Loop over the thread table looking for exited threads. The
124     * g_pthreadsExited counter springs us out of this once we have
125     * found them all (and keeps us out if there are none to do).
126     */
127    for (i = 0; g_pthreadsExited && (i < g_taskMaxNum); i++) {
128        data = &g_pthreadData[i];
129        if (data->state == PTHREAD_STATE_EXITED) {
130            /* the Huawei LiteOS not delete the dead TCB,so need to delete the TCB */
131            (VOID)LOS_TaskDelete(data->task->taskID);
132            if (data->task->taskStatus & OS_TASK_STATUS_UNUSED) {
133                ProcessUnusedStatusTask(data);
134                g_pthreadsExited--;
135            }
136        }
137    }
138}
139
140STATIC VOID SetPthreadAttr(const _pthread_data *self, const pthread_attr_t *attr, pthread_attr_t *outAttr)
141{
142    /*
143     * Set use_attr to the set of attributes we are going to
144     * actually use. Either those passed in, or the default set.
145     */
146    if (attr == NULL) {
147        (VOID)pthread_attr_init(outAttr);
148    } else {
149        (VOID)memcpy_s(outAttr, sizeof(pthread_attr_t), attr, sizeof(pthread_attr_t));
150    }
151
152    /*
153     * If the stack size is not valid, we can assume that it is at
154     * least PTHREAD_STACK_MIN bytes.
155     */
156    if (!outAttr->stacksize_set) {
157        outAttr->stacksize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
158    }
159    if (outAttr->inheritsched == PTHREAD_INHERIT_SCHED) {
160        if (self->task == NULL) {
161            outAttr->schedparam.sched_priority = LOS_TaskPriGet(OsCurrTaskGet()->taskID);
162        } else {
163            outAttr->schedpolicy = self->attr.schedpolicy;
164            outAttr->schedparam  = self->attr.schedparam;
165            outAttr->scope       = self->attr.scope;
166        }
167    }
168}
169
170STATIC VOID SetPthreadDataAttr(const pthread_attr_t *userAttr, const pthread_t threadID,
171                               LosTaskCB *taskCB, _pthread_data *created)
172{
173    created->attr         = *userAttr;
174    created->id           = threadID;
175    created->task         = taskCB;
176    created->state        = (userAttr->detachstate == PTHREAD_CREATE_JOINABLE) ?
177                            PTHREAD_STATE_RUNNING : PTHREAD_STATE_DETACHED;
178    /* need to confirmation */
179    created->cancelstate  = PTHREAD_CANCEL_ENABLE;
180    created->canceltype   = PTHREAD_CANCEL_DEFERRED;
181    created->cancelbuffer = NULL;
182    created->canceled     = 0;
183    created->freestack    = 0; /* no use default : 0 */
184    created->stackmem     = taskCB->topOfStack;
185    created->thread_data  = NULL;
186}
187
188STATIC UINT32 InitPthreadData(pthread_t threadID, pthread_attr_t *userAttr,
189                              const CHAR name[], size_t len)
190{
191    errno_t err;
192    UINT32 ret = LOS_OK;
193    LosTaskCB *taskCB = OS_TCB_FROM_TID(threadID);
194    _pthread_data *created = &g_pthreadData[threadID];
195
196    err = strncpy_s(created->name, sizeof(created->name), name, len);
197    if (err != EOK) {
198        PRINT_ERR("%s: %d, err: %d\n", __FUNCTION__, __LINE__, err);
199        return LOS_NOK;
200    }
201    userAttr->stacksize   = taskCB->stackSize;
202    err = OsSetTaskName(taskCB, created->name, FALSE);
203    if (err != LOS_OK) {
204        PRINT_ERR("%s: %d, err: %d\n", __FUNCTION__, __LINE__, err);
205        return LOS_NOK;
206    }
207#ifdef LOSCFG_KERNEL_SMP
208    if (userAttr->cpuset.__bits[0] > 0) {
209        taskCB->cpuAffiMask = (UINT16)userAttr->cpuset.__bits[0];
210    }
211#endif
212
213    SetPthreadDataAttr(userAttr, threadID, taskCB, created);
214    return ret;
215}
216
217int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
218                   void *(*startRoutine)(void *), void *arg)
219{
220    pthread_attr_t userAttr;
221    UINT32 ret;
222    CHAR name[PTHREAD_DATA_NAME_MAX] = {0};
223    STATIC UINT16 pthreadNumber = 1;
224    TSK_INIT_PARAM_S taskInitParam = {0};
225    UINT32 taskHandle;
226    _pthread_data *self = pthread_get_self_data();
227
228    if ((thread == NULL) || (startRoutine == NULL)) {
229        return EINVAL;
230    }
231
232    SetPthreadAttr(self, attr, &userAttr);
233
234    (VOID)snprintf_s(name, sizeof(name), sizeof(name) - 1, "pth%02d", pthreadNumber);
235    pthreadNumber++;
236
237    taskInitParam.pcName       = name;
238    taskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)startRoutine;
239    taskInitParam.auwArgs[0]   = (UINTPTR)arg;
240    taskInitParam.usTaskPrio   = (UINT16)userAttr.schedparam.sched_priority;
241    taskInitParam.uwStackSize  = userAttr.stacksize;
242    if (OsProcessIsUserMode(OsCurrProcessGet())) {
243        taskInitParam.processID = (UINTPTR)OsGetKernelInitProcess();
244    } else {
245        taskInitParam.processID = (UINTPTR)OsCurrProcessGet();
246    }
247    if (userAttr.detachstate == PTHREAD_CREATE_DETACHED) {
248        taskInitParam.uwResved = LOS_TASK_STATUS_DETACHED;
249    } else {
250        /* Set the pthread default joinable */
251        taskInitParam.uwResved = LOS_TASK_ATTR_JOINABLE;
252    }
253
254    PthreadReap();
255    ret = LOS_TaskCreateOnly(&taskHandle, &taskInitParam);
256    if (ret == LOS_OK) {
257        *thread = (pthread_t)taskHandle;
258        ret = InitPthreadData(*thread, &userAttr, name, PTHREAD_DATA_NAME_MAX);
259        if (ret != LOS_OK) {
260            goto ERROR_OUT_WITH_TASK;
261        }
262        (VOID)LOS_SetTaskScheduler(taskHandle, SCHED_RR, taskInitParam.usTaskPrio);
263    }
264
265    if (ret == LOS_OK) {
266        return ENOERR;
267    } else {
268        goto ERROR_OUT;
269    }
270
271ERROR_OUT_WITH_TASK:
272    (VOID)LOS_TaskDelete(taskHandle);
273ERROR_OUT:
274    *thread = (pthread_t)-1;
275
276    return map_errno(ret);
277}
278
279void pthread_exit(void *retVal)
280{
281    _pthread_data *self = pthread_get_self_data();
282    UINT32 intSave;
283
284    if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, (int *)0) != ENOERR) {
285        PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
286    }
287
288    if (pthread_mutex_lock(&g_pthreadsDataMutex) != ENOERR) {
289        PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
290    }
291
292    self->task->joinRetval = retVal;
293    /*
294     * If we are already detached, go to EXITED state, otherwise
295     * go into JOIN state.
296     */
297    if (self->state == PTHREAD_STATE_DETACHED) {
298        self->state = PTHREAD_STATE_EXITED;
299        g_pthreadsExited++;
300    } else {
301        self->state = PTHREAD_STATE_JOIN;
302    }
303
304    if (pthread_mutex_unlock(&g_pthreadsDataMutex) != ENOERR) {
305        PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
306    }
307    SCHEDULER_LOCK(intSave);
308    /* If the thread is the highest thread,it can't schedule in LOS_SemPost. */
309    OsTaskJoinPostUnsafe(self->task);
310    if (self->task->taskStatus & OS_TASK_STATUS_RUNNING) {
311        OsSchedResched();
312    }
313    SCHEDULER_UNLOCK(intSave);
314}
315
316STATIC INT32 ProcessByJoinState(_pthread_data *joined)
317{
318    UINT32 intSave;
319    INT32 err = 0;
320    UINT32 ret;
321    switch (joined->state) {
322        case PTHREAD_STATE_RUNNING:
323            /* The thread is still running, we must wait for it. */
324            SCHEDULER_LOCK(intSave);
325            ret = OsTaskJoinPendUnsafe(joined->task);
326            SCHEDULER_UNLOCK(intSave);
327            if (ret != LOS_OK) {
328                err = (INT32)ret;
329                break;
330            }
331
332            joined->state = PTHREAD_STATE_ALRDY_JOIN;
333            break;
334           /*
335            * The thread has become unjoinable while we waited, so we
336            * fall through to complain.
337            */
338        case PTHREAD_STATE_FREE:
339        case PTHREAD_STATE_DETACHED:
340        case PTHREAD_STATE_EXITED:
341            /* None of these may be joined. */
342            err = EINVAL;
343            break;
344        case PTHREAD_STATE_ALRDY_JOIN:
345            err = EINVAL;
346            break;
347        case PTHREAD_STATE_JOIN:
348            break;
349        default:
350            PRINT_ERR("state: %u is not supported\n", (UINT32)joined->state);
351            break;
352    }
353    return err;
354}
355
356int pthread_join(pthread_t thread, void **retVal)
357{
358    INT32 err;
359    UINT8 status;
360    _pthread_data *self = NULL;
361    _pthread_data *joined = NULL;
362
363    /* Check for cancellation first. */
364    pthread_testcancel();
365
366    /* Dispose of any dead threads */
367    (VOID)pthread_mutex_lock(&g_pthreadsDataMutex);
368    PthreadReap();
369    (VOID)pthread_mutex_unlock(&g_pthreadsDataMutex);
370
371    self   = pthread_get_self_data();
372    joined = pthread_get_data(thread);
373    if (joined == NULL) {
374        return ESRCH;
375    }
376    status = joined->state;
377
378    if (joined == self) {
379        return EDEADLK;
380    }
381
382    err = ProcessByJoinState(joined);
383    (VOID)pthread_mutex_lock(&g_pthreadsDataMutex);
384
385    if (!err) {
386        /*
387         * Here, we know that joinee is a thread that has exited and is
388         * ready to be joined.
389         */
390        if (retVal != NULL) {
391            /* Get the retVal */
392            *retVal = joined->task->joinRetval;
393        }
394
395        /* Set state to exited. */
396        joined->state = PTHREAD_STATE_EXITED;
397        g_pthreadsExited++;
398
399        /* Dispose of any dead threads */
400        PthreadReap();
401    } else {
402        joined->state = status;
403    }
404
405    (VOID)pthread_mutex_unlock(&g_pthreadsDataMutex);
406    /* Check for cancellation before returning */
407    pthread_testcancel();
408
409    return err;
410}
411
412/*
413 * Set the detachstate of the thread to "detached". The thread then does not
414 * need to be joined and its resources will be freed when it exits.
415 */
416int pthread_detach(pthread_t thread)
417{
418    int ret = 0;
419    UINT32 intSave;
420
421    _pthread_data *detached = NULL;
422
423    if (pthread_mutex_lock(&g_pthreadsDataMutex) != ENOERR) {
424        ret = ESRCH;
425    }
426    detached = pthread_get_data(thread);
427    if (detached == NULL) {
428        ret = ESRCH; /* No such thread */
429    } else if (detached->state == PTHREAD_STATE_DETACHED) {
430        ret = EINVAL; /* Already detached! */
431    } else if (detached->state == PTHREAD_STATE_JOIN) {
432        detached->state = PTHREAD_STATE_EXITED;
433        g_pthreadsExited++;
434    } else {
435        /* Set state to detached and kick any joinees to make them return. */
436        SCHEDULER_LOCK(intSave);
437        if (!(detached->task->taskStatus & OS_TASK_STATUS_EXIT)) {
438            ret = OsTaskSetDetachUnsafe(detached->task);
439            if (ret == ESRCH) {
440                ret = LOS_OK;
441            } else if (ret == LOS_OK) {
442                detached->state = PTHREAD_STATE_DETACHED;
443            }
444        } else {
445            detached->state = PTHREAD_STATE_EXITED;
446            g_pthreadsExited++;
447        }
448        SCHEDULER_UNLOCK(intSave);
449    }
450
451    /* Dispose of any dead threads */
452    PthreadReap();
453    if (pthread_mutex_unlock(&g_pthreadsDataMutex) != ENOERR) {
454        ret = ESRCH;
455    }
456
457    return ret;
458}
459
460int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param)
461{
462    _pthread_data *data = NULL;
463    int ret;
464
465    if ((param == NULL) || (param->sched_priority > OS_TASK_PRIORITY_LOWEST)) {
466        return EINVAL;
467    }
468
469    if (policy != SCHED_RR) {
470        return EINVAL;
471    }
472
473    /* The parameters seem OK, change the thread. */
474    ret = pthread_mutex_lock(&g_pthreadsDataMutex);
475    if (ret != ENOERR) {
476        return ret;
477    }
478
479    data = pthread_get_data(thread);
480    if (data == NULL) {
481        ret = pthread_mutex_unlock(&g_pthreadsDataMutex);
482        if (ret != ENOERR) {
483            return ret;
484        }
485        return ESRCH;
486    }
487
488    /* Only support one policy now */
489    data->attr.schedpolicy = SCHED_RR;
490    data->attr.schedparam  = *param;
491
492    ret = pthread_mutex_unlock(&g_pthreadsDataMutex);
493    if (ret != ENOERR) {
494        return ret;
495    }
496    (VOID)LOS_TaskPriSet((UINT32)thread, (UINT16)param->sched_priority);
497
498    return ENOERR;
499}
500
501int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param)
502{
503    _pthread_data *data = NULL;
504    int ret;
505
506    if ((policy == NULL) || (param == NULL)) {
507        return EINVAL;
508    }
509
510    ret = pthread_mutex_lock(&g_pthreadsDataMutex);
511    if (ret != ENOERR) {
512        return ret;
513    }
514
515    data = pthread_get_data(thread);
516    if (data == NULL) {
517        goto ERR_OUT;
518    }
519
520    *policy = data->attr.schedpolicy;
521    *param = data->attr.schedparam;
522
523    ret = pthread_mutex_unlock(&g_pthreadsDataMutex);
524    return ret;
525ERR_OUT:
526    ret = pthread_mutex_unlock(&g_pthreadsDataMutex);
527    if (ret != ENOERR) {
528        return ret;
529    }
530    return ESRCH;
531}
532
533/* Call initRoutine just the once per control variable. */
534int pthread_once(pthread_once_t *onceControl, void (*initRoutine)(void))
535{
536    pthread_once_t old;
537    int ret;
538
539    if ((onceControl == NULL) || (initRoutine == NULL)) {
540        return EINVAL;
541    }
542
543    /* Do a test and set on the onceControl object. */
544    ret = pthread_mutex_lock(&g_pthreadsDataMutex);
545    if (ret != ENOERR) {
546        return ret;
547    }
548
549    old = *onceControl;
550    *onceControl = 1;
551
552    ret = pthread_mutex_unlock(&g_pthreadsDataMutex);
553    if (ret != ENOERR) {
554        return ret;
555    }
556    /* If the onceControl was zero, call the initRoutine(). */
557    if (!old) {
558        initRoutine();
559    }
560
561    return ENOERR;
562}
563
564/* Thread specific data */
565int pthread_key_create(pthread_key_t *key, void (*destructor)(void *))
566{
567    (VOID)key;
568    (VOID)destructor;
569    PRINT_ERR("[%s] is not support.\n", __FUNCTION__);
570    return 0;
571}
572
573/* Store the pointer value in the thread-specific data slot addressed by the key. */
574int pthread_setspecific(pthread_key_t key, const void *pointer)
575{
576    (VOID)key;
577    (VOID)pointer;
578    PRINT_ERR("[%s] is not support.\n", __FUNCTION__);
579    return 0;
580}
581
582/* Retrieve the pointer value in the thread-specific data slot addressed by the key. */
583void *pthread_getspecific(pthread_key_t key)
584{
585    (VOID)key;
586    PRINT_ERR("[%s] is not support.\n", __FUNCTION__);
587    return NULL;
588}
589
590/*
591 * Set cancel state of current thread to ENABLE or DISABLE.
592 * Returns old state in *oldState.
593 */
594int pthread_setcancelstate(int state, int *oldState)
595{
596    _pthread_data *self = NULL;
597    int ret;
598
599    if ((state != PTHREAD_CANCEL_ENABLE) && (state != PTHREAD_CANCEL_DISABLE)) {
600        return EINVAL;
601    }
602
603    ret = pthread_mutex_lock(&g_pthreadsDataMutex);
604    if (ret != ENOERR) {
605        return ret;
606    }
607
608    self = pthread_get_self_data();
609
610    if (oldState != NULL) {
611        *oldState = self->cancelstate;
612    }
613
614    self->cancelstate = (UINT8)state;
615
616    ret = pthread_mutex_unlock(&g_pthreadsDataMutex);
617    if (ret != ENOERR) {
618        return ret;
619    }
620
621    return ENOERR;
622}
623
624/*
625 * Set cancel type of current thread to ASYNCHRONOUS or DEFERRED.
626 * Returns old type in *oldType.
627 */
628int pthread_setcanceltype(int type, int *oldType)
629{
630    _pthread_data *self = NULL;
631    int ret;
632
633    if ((type != PTHREAD_CANCEL_ASYNCHRONOUS) && (type != PTHREAD_CANCEL_DEFERRED)) {
634        return EINVAL;
635    }
636
637    ret = pthread_mutex_lock(&g_pthreadsDataMutex);
638    if (ret != ENOERR) {
639        return ret;
640    }
641
642    self = pthread_get_self_data();
643    if (oldType != NULL) {
644        *oldType = self->canceltype;
645    }
646
647    self->canceltype = (UINT8)type;
648
649    ret = pthread_mutex_unlock(&g_pthreadsDataMutex);
650    if (ret != ENOERR) {
651        return ret;
652    }
653
654    return ENOERR;
655}
656
657STATIC UINT32 DoPthreadCancel(_pthread_data *data)
658{
659    UINT32 ret = LOS_OK;
660    UINT32 intSave;
661    LOS_TaskLock();
662    data->canceled = 0;
663    if ((data->task->taskStatus & OS_TASK_STATUS_EXIT) || (LOS_TaskSuspend(data->task->taskID) != ENOERR)) {
664        ret = LOS_NOK;
665        goto OUT;
666    }
667
668    if (data->task->taskStatus & OS_TASK_FLAG_PTHREAD_JOIN) {
669        SCHEDULER_LOCK(intSave);
670        OsTaskJoinPostUnsafe(data->task);
671        SCHEDULER_UNLOCK(intSave);
672        g_pthreadCanceledDummyVar = (UINTPTR)PTHREAD_CANCELED;
673        data->task->joinRetval = (VOID *)g_pthreadCanceledDummyVar;
674    } else if (data->state && !(data->task->taskStatus & OS_TASK_STATUS_UNUSED)) {
675        data->state = PTHREAD_STATE_EXITED;
676        g_pthreadsExited++;
677        PthreadReap();
678    } else {
679        ret = LOS_NOK;
680    }
681OUT:
682    LOS_TaskUnlock();
683    return ret;
684}
685
686int pthread_cancel(pthread_t thread)
687{
688    _pthread_data *data = NULL;
689
690    if (pthread_mutex_lock(&g_pthreadsDataMutex) != ENOERR) {
691        PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
692    }
693
694    data = pthread_get_data(thread);
695    if (data == NULL) {
696        if (pthread_mutex_unlock(&g_pthreadsDataMutex) != ENOERR) {
697            PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
698        }
699        return ESRCH;
700    }
701
702    data->canceled = 1;
703
704    if ((data->cancelstate == PTHREAD_CANCEL_ENABLE) &&
705        (data->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)) {
706        /*
707         * If the thread has cancellation enabled, and it is in
708         * asynchronous mode, suspend it and set corresponding thread's status.
709         * We also release the thread out of any current wait to make it wake up.
710         */
711        if (DoPthreadCancel(data) == LOS_NOK) {
712            goto ERROR_OUT;
713        }
714    }
715
716    /*
717     * Otherwise the thread has cancellation disabled, in which case
718     * it is up to the thread to enable cancellation
719     */
720    if (pthread_mutex_unlock(&g_pthreadsDataMutex) != ENOERR) {
721        PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
722    }
723
724    return ENOERR;
725ERROR_OUT:
726    if (pthread_mutex_unlock(&g_pthreadsDataMutex) != ENOERR) {
727        PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
728    }
729    return ESRCH;
730}
731
732/*
733 * Test for a pending cancellation for the current thread and terminate
734 * the thread if there is one.
735 */
736void pthread_testcancel(void)
737{
738    if (CheckForCancel()) {
739        /*
740         * If we have cancellation enabled, and there is a cancellation
741         * pending, then go ahead and do the deed.
742         * Exit now with special retVal. pthread_exit() calls the
743         * cancellation handlers implicitly.
744         */
745        pthread_exit((void *)PTHREAD_CANCELED);
746    }
747}
748
749/* Get current thread id. */
750pthread_t pthread_self(void)
751{
752    _pthread_data *data = pthread_get_self_data();
753
754    return data->id;
755}
756
757/* Compare two thread identifiers. */
758int pthread_equal(pthread_t thread1, pthread_t thread2)
759{
760    return thread1 == thread2;
761}
762
763void pthread_cleanup_push_inner(struct pthread_cleanup_buffer *buffer,
764                                void (*routine)(void *), void *arg)
765{
766    (VOID)buffer;
767    (VOID)routine;
768    (VOID)arg;
769    PRINT_ERR("[%s] is not support.\n", __FUNCTION__);
770    return;
771}
772
773void pthread_cleanup_pop_inner(struct pthread_cleanup_buffer *buffer, int execute)
774{
775    (VOID)buffer;
776    (VOID)execute;
777    PRINT_ERR("[%s] is not support.\n", __FUNCTION__);
778    return;
779}
780
781/*
782 * Set the cpu affinity mask for the thread
783 */
784int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t* cpuset)
785{
786    INT32 ret = sched_setaffinity(thread, cpusetsize, cpuset);
787    if (ret == -1) {
788        return errno;
789    } else {
790        return ENOERR;
791    }
792}
793
794/*
795 * Get the cpu affinity mask from the thread
796 */
797int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t* cpuset)
798{
799    INT32 ret = sched_getaffinity(thread, cpusetsize, cpuset);
800    if (ret == -1) {
801        return errno;
802    } else {
803        return ENOERR;
804    }
805}
806
807