• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2021 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 "pthread.h"
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <securec.h>
37 #include <limits.h>
38 #include <stdbool.h>
39 #include "los_config.h"
40 #include "los_task.h"
41 #include "los_debug.h"
42 
43 #define PTHREAD_DEFAULT_NAME     "pthread"
44 #define PTHREAD_DEFAULT_NAME_LEN 8
45 #define PTHREAD_NAMELEN 16
46 #define PTHREAD_KEY_UNUSED 0
47 #define PTHREAD_KEY_USED   1
48 #define PTHREAD_TASK_INVAILD 0
49 
50 typedef void (*PthreadKeyDtor)(void *);
51 typedef struct {
52     int flag;
53     PthreadKeyDtor destructor;
54 } PthreadKey;
55 static unsigned int g_pthreadkeyCount = 0;
56 static PthreadKey   g_pthreadKeyData[PTHREAD_KEYS_MAX];
57 static LOS_DL_LIST  g_pthreadListHead;
58 
59 typedef struct {
60     void *(*startRoutine)(void *);
61     void *param;
62     char name[PTHREAD_NAMELEN];
63     uintptr_t *key;
64     LOS_DL_LIST threadList;
65     unsigned char cancelState;
66     unsigned char cancelType;
67     unsigned char canceled;
68 } PthreadData;
69 
70 static void PthreadExitKeyDtor(PthreadData *pthreadData);
71 
PthreadEntry(UINT32 param)72 static void *PthreadEntry(UINT32 param)
73 {
74     PthreadData *pthreadData = (PthreadData *)(UINTPTR)param;
75     void *(*startRoutine)(void *) = pthreadData->startRoutine;
76     void *ret = startRoutine(pthreadData->param);
77     pthread_exit(ret);
78 
79     return ret;
80 }
81 
IsPthread(pthread_t thread)82 static inline bool IsPthread(pthread_t thread)
83 {
84     LosTaskCB *tcb = NULL;
85     if ((UINT32)thread > LOSCFG_BASE_CORE_TSK_LIMIT) {
86         return false;
87     }
88     tcb = OS_TCB_FROM_TID((UINT32)thread);
89     if ((UINTPTR)tcb->taskEntry != (UINTPTR)PthreadEntry) {
90         return false;
91     }
92     return true;
93 }
94 
PthreadAttrCheck(const pthread_attr_t * threadAttr,TSK_INIT_PARAM_S * taskInitParam)95 static int PthreadAttrCheck(const pthread_attr_t *threadAttr, TSK_INIT_PARAM_S *taskInitParam)
96 {
97     INT32 ret;
98     struct sched_param schedParam = { 0 };
99     INT32 policy = 0;
100 
101     if (threadAttr->stacksize < PTHREAD_STACK_MIN) {
102         return EINVAL;
103     }
104     if ((threadAttr->stackaddr_set != 0) && (threadAttr->stacksize_set != 0)) {
105         taskInitParam->stackAddr = (UINTPTR)threadAttr->stackaddr;
106     }
107     if (threadAttr->stacksize_set != 0) {
108         taskInitParam->uwStackSize = threadAttr->stacksize;
109     } else {
110         taskInitParam->uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
111     }
112     if (threadAttr->inheritsched == PTHREAD_EXPLICIT_SCHED) {
113         taskInitParam->usTaskPrio = (UINT16)threadAttr->schedparam.sched_priority;
114     } else if (IsPthread(pthread_self())) {
115         ret = pthread_getschedparam(pthread_self(), &policy, &schedParam);
116         if (ret != 0) {
117             return ret;
118         }
119         taskInitParam->usTaskPrio = (UINT16)schedParam.sched_priority;
120     } else {
121         taskInitParam->usTaskPrio = (UINT16)threadAttr->schedparam.sched_priority;
122     }
123     return 0;
124 }
125 
PthreadCreateAttrInit(const pthread_attr_t * attr,void * (* startRoutine)(void *),void * arg,TSK_INIT_PARAM_S * taskInitParam)126 static int PthreadCreateAttrInit(const pthread_attr_t *attr, void *(*startRoutine)(void *), void *arg,
127     TSK_INIT_PARAM_S *taskInitParam)
128 {
129     const pthread_attr_t *threadAttr = attr;
130     pthread_attr_t attrTmp;
131     INT32 ret;
132 
133     if (attr == NULL) {
134         (VOID)pthread_attr_init(&attrTmp);
135         threadAttr = &attrTmp;
136     }
137 
138     ret = PthreadAttrCheck(threadAttr, taskInitParam);
139     if (ret != 0) {
140         return ret;
141     }
142 
143     PthreadData *pthreadData = (PthreadData *)malloc(sizeof(PthreadData));
144     if (pthreadData == NULL) {
145         return ENOMEM;
146     }
147 
148     errno_t error = memcpy_s(pthreadData->name, PTHREAD_NAMELEN, PTHREAD_DEFAULT_NAME, PTHREAD_DEFAULT_NAME_LEN);
149     if (error != EOK) {
150         free(pthreadData);
151         return error;
152     }
153 
154     pthreadData->cancelState    = PTHREAD_CANCEL_ENABLE;
155     pthreadData->cancelType     = PTHREAD_CANCEL_DEFERRED;
156     pthreadData->canceled       = 0;
157     pthreadData->startRoutine   = startRoutine;
158     pthreadData->param          = arg;
159     pthreadData->key            = NULL;
160     taskInitParam->pcName       = pthreadData->name;
161     taskInitParam->pfnTaskEntry = PthreadEntry;
162     taskInitParam->uwArg        = (UINT32)(UINTPTR)pthreadData;
163     if (threadAttr->detachstate != PTHREAD_CREATE_DETACHED) {
164         taskInitParam->uwResved = LOS_TASK_ATTR_JOINABLE;
165     }
166 
167     return 0;
168 }
169 
CheckForCancel(void)170 static int CheckForCancel(void)
171 {
172     UINT32 intSave;
173     LosTaskCB *tcb = NULL;
174 
175     pthread_t thread = pthread_self();
176     if (!IsPthread(thread)) {
177         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, thread);
178         return 0;
179     }
180 
181     tcb = OS_TCB_FROM_TID((UINT32)thread);
182     intSave = LOS_IntLock();
183     PthreadData *pthreadData = (PthreadData *)(UINTPTR)tcb->arg;
184     if ((pthreadData->canceled) && (pthreadData->cancelState == PTHREAD_CANCEL_ENABLE)) {
185         LOS_IntRestore(intSave);
186         return 1;
187     }
188     LOS_IntRestore(intSave);
189     return 0;
190 }
191 
pthread_create(pthread_t * thread,const pthread_attr_t * attr,void * (* startRoutine)(void *),void * arg)192 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
193     void *(*startRoutine)(void *), void *arg)
194 {
195     TSK_INIT_PARAM_S taskInitParam = { 0 };
196     UINT32 taskID;
197     UINT32 ret;
198     UINT32 intSave;
199 
200     if ((thread == NULL) || (startRoutine == NULL)) {
201         return EINVAL;
202     }
203 
204     ret = PthreadCreateAttrInit(attr, startRoutine, arg, &taskInitParam);
205     if (ret != 0) {
206         return ret;
207     }
208 
209     if (LOS_TaskCreateOnly(&taskID, &taskInitParam) != LOS_OK) {
210         free((VOID *)(UINTPTR)taskInitParam.uwArg);
211         return EINVAL;
212     }
213 
214     PthreadData *pthreadData = (PthreadData *)taskInitParam.uwArg;
215     intSave = LOS_IntLock();
216     if (g_pthreadListHead.pstNext == NULL) {
217         LOS_ListInit(&g_pthreadListHead);
218     }
219 
220     LOS_ListAdd(&g_pthreadListHead, &pthreadData->threadList);
221     LOS_IntRestore(intSave);
222 
223     (void)LOS_TaskResume(taskID);
224 
225     *thread = (pthread_t)taskID;
226 
227     return 0;
228 }
229 
pthread_setschedparam(pthread_t thread,int policy,const struct sched_param * param)230 int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param)
231 {
232     if (!IsPthread(thread)) {
233         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, thread);
234         return EINVAL;
235     }
236 
237     if ((param == NULL) || (param->sched_priority < OS_TASK_PRIORITY_HIGHEST) ||
238         (param->sched_priority >= OS_TASK_PRIORITY_LOWEST)) {
239         return EINVAL;
240     }
241 
242     /* Only support SCHED_RR policy now */
243     if (policy != SCHED_RR) {
244         return ENOTSUP;
245     }
246 
247     if (LOS_TaskPriSet((UINT32)thread, (UINT16)param->sched_priority) != LOS_OK) {
248         return EINVAL;
249     }
250 
251     return 0;
252 }
253 
pthread_setschedprio(pthread_t thread,int prio)254 int pthread_setschedprio(pthread_t thread, int prio)
255 {
256     if (!IsPthread(thread)) {
257         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, thread);
258         return EINVAL;
259     }
260 
261     if (LOS_TaskPriSet((UINT32)thread, (UINT16)prio) != LOS_OK) {
262         return EINVAL;
263     }
264 
265     return 0;
266 }
267 
pthread_once(pthread_once_t * onceControl,void (* initRoutine)(void))268 int pthread_once(pthread_once_t *onceControl, void (*initRoutine)(void))
269 {
270     UINT32 intSave;
271     pthread_once_t old;
272 
273     pthread_t thread = pthread_self();
274     if (!IsPthread(thread)) {
275         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, thread);
276         return EINVAL;
277     }
278 
279     if ((onceControl == NULL) || (initRoutine == NULL)) {
280         return EINVAL;
281     }
282     intSave = LOS_IntLock();
283     old = *onceControl;
284     *onceControl = 1;
285     LOS_IntRestore(intSave);
286 
287     if (!old) {
288         initRoutine();
289     }
290 
291     return 0;
292 }
293 
pthread_equal(pthread_t thread1,pthread_t thread2)294 int pthread_equal(pthread_t thread1, pthread_t thread2)
295 {
296     return (int)(thread1 == thread2);
297 }
298 
pthread_setcancelstate(int state,int * oldState)299 int pthread_setcancelstate(int state, int *oldState)
300 {
301     UINT32 intSave;
302     LosTaskCB *tcb = NULL;
303     PthreadData *pthreadData = NULL;
304     pthread_t thread = pthread_self();
305     if (!IsPthread(thread)) {
306         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, thread);
307         return EINVAL;
308     }
309 
310     if ((state != PTHREAD_CANCEL_ENABLE) && (state != PTHREAD_CANCEL_DISABLE)) {
311         return EINVAL;
312     }
313 
314     tcb = OS_TCB_FROM_TID((UINT32)thread);
315     intSave = LOS_IntLock();
316     pthreadData = (PthreadData *)(UINTPTR)tcb->arg;
317     if (pthreadData == NULL) {
318         LOS_IntRestore(intSave);
319         return EINVAL;
320     }
321 
322     if (oldState != NULL) {
323         *oldState = pthreadData->cancelState;
324     }
325     pthreadData->cancelState = (UINT8)state;
326     LOS_IntRestore(intSave);
327 
328     return 0;
329 }
330 
pthread_setcanceltype(int type,int * oldType)331 int pthread_setcanceltype(int type, int *oldType)
332 {
333     UINT32 intSave;
334     LosTaskCB *tcb = NULL;
335     PthreadData *pthreadData = NULL;
336 
337     pthread_t thread = pthread_self();
338     if (!IsPthread(thread)) {
339         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, thread);
340         return EINVAL;
341     }
342 
343     if ((type != PTHREAD_CANCEL_ASYNCHRONOUS) && (type != PTHREAD_CANCEL_DEFERRED)) {
344         return EINVAL;
345     }
346 
347     tcb = OS_TCB_FROM_TID((UINT32)thread);
348     intSave = LOS_IntLock();
349     pthreadData = (PthreadData *)(UINTPTR)tcb->arg;
350     if (pthreadData == NULL) {
351         LOS_IntRestore(intSave);
352         return EINVAL;
353     }
354 
355     if (oldType != NULL) {
356         *oldType = pthreadData->cancelType;
357     }
358 
359     pthreadData->cancelType = (UINT8)type;
360     LOS_IntRestore(intSave);
361 
362     return 0;
363 }
364 
pthread_getschedparam(pthread_t thread,int * policy,struct sched_param * param)365 int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param)
366 {
367     UINT32 prio;
368 
369     if (!IsPthread(thread)) {
370         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, thread);
371         return EINVAL;
372     }
373 
374     if ((policy == NULL) || (param == NULL)) {
375         return EINVAL;
376     }
377 
378     prio = LOS_TaskPriGet((UINT32)thread);
379     if (prio == OS_INVALID) {
380         return EINVAL;
381     }
382 
383     *policy = SCHED_RR;
384     param->sched_priority = prio;
385 
386     return 0;
387 }
388 
pthread_self(void)389 pthread_t pthread_self(void)
390 {
391     return (pthread_t)LOS_CurTaskIDGet();
392 }
393 
DoPthreadCancel(LosTaskCB * task)394 STATIC UINT32 DoPthreadCancel(LosTaskCB *task)
395 {
396     UINT32 ret = LOS_OK;
397     PthreadData *pthreadData = NULL;
398 
399     LOS_TaskLock();
400     pthreadData = (PthreadData *)(UINTPTR)task->arg;
401     pthreadData->canceled = 0;
402     if ((task->taskStatus == PTHREAD_TASK_INVAILD) || (LOS_TaskSuspend(task->taskID) != LOS_OK)) {
403         ret = LOS_NOK;
404         goto OUT;
405     }
406     free((VOID *)(UINTPTR)task->arg);
407     task->arg = (UINT32)(UINTPTR)NULL;
408     (void)LOS_TaskDelete(task->taskID);
409 
410 OUT:
411     LOS_TaskUnlock();
412     return ret;
413 }
414 
pthread_cancel(pthread_t thread)415 int pthread_cancel(pthread_t thread)
416 {
417     UINT32 intSave;
418     LosTaskCB *tcb = NULL;
419     PthreadData *pthreadData = NULL;
420     if (!IsPthread(thread)) {
421         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, thread);
422         return EINVAL;
423     }
424     intSave = LOS_IntLock();
425     tcb = OS_TCB_FROM_TID((UINT32)thread);
426     pthreadData = (PthreadData *)(UINTPTR)tcb->arg;
427     pthreadData->canceled = 1;
428     if ((pthreadData->cancelState == PTHREAD_CANCEL_ENABLE) &&
429         (pthreadData->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS)) {
430         /*
431          * If the thread has cancellation enabled, and it is in
432          * asynchronous mode, suspend it and set corresponding thread's status.
433          * We also release the thread out of any current wait to make it wake up.
434          */
435         if (DoPthreadCancel(tcb) == LOS_NOK) {
436             LOS_IntRestore(intSave);
437             return ESRCH;
438         }
439     }
440     LOS_IntRestore(intSave);
441 
442     return 0;
443 }
444 
pthread_testcancel(void)445 void pthread_testcancel(void)
446 {
447     if (CheckForCancel()) {
448         /*
449          * If we have cancellation enabled, and there is a cancellation
450          * pending, then go ahead and do the deed.
451          * Exit now with special retVal. pthread_exit() calls the
452          * cancellation handlers implicitly.
453          */
454         pthread_exit((void *)PTHREAD_CANCELED);
455     }
456 }
457 
pthread_join(pthread_t thread,void ** retval)458 int pthread_join(pthread_t thread, void **retval)
459 {
460     UINTPTR result;
461     UINT32 ret;
462     if (!IsPthread(thread)) {
463         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, thread);
464         return EINVAL;
465     }
466 
467     ret = LOS_TaskJoin((UINT32)thread, &result);
468     if (ret == LOS_ERRNO_TSK_NOT_JOIN_SELF) {
469         return EDEADLK;
470     } else if ((ret == LOS_ERRNO_TSK_NOT_CREATED) ||
471                (ret == LOS_ERRNO_TSK_OPERATE_IDLE) ||
472                (ret == LOS_ERRNO_TSK_ID_INVALID) ||
473                (ret == LOS_ERRNO_TSK_SUSPEND_SWTMR_NOT_ALLOWED)) {
474         return ESRCH;
475     } else if (ret != LOS_OK) {
476         return EINVAL;
477     }
478 
479     if (retval != NULL) {
480         *retval = (VOID *)result;
481     }
482 
483     return 0;
484 }
485 
pthread_detach(pthread_t thread)486 int pthread_detach(pthread_t thread)
487 {
488     UINT32 ret;
489     if (!IsPthread(thread)) {
490         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, thread);
491         return EINVAL;
492     }
493 
494     ret = LOS_TaskDetach((UINT32)thread);
495     if (ret == LOS_ERRNO_TSK_NOT_JOIN) {
496         return ESRCH;
497     } else if (ret != LOS_OK) {
498         return EINVAL;
499     }
500 
501     return 0;
502 }
503 
pthread_exit(void * retVal)504 void pthread_exit(void *retVal)
505 {
506     UINT32 intSave;
507 
508     pthread_t thread = pthread_self();
509     if (!IsPthread(thread)) {
510         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, thread);
511         goto EXIT;
512     }
513 
514     LosTaskCB *tcb = OS_TCB_FROM_TID((UINT32)thread);
515     tcb->joinRetval = (UINTPTR)retVal;
516     PthreadData *pthreadData = (PthreadData *)(UINTPTR)tcb->arg;
517     if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0) {
518         PRINT_ERR("%s: %d failed\n", __FUNCTION__, __LINE__);
519     }
520 
521     if (pthreadData->key != NULL) {
522         PthreadExitKeyDtor(pthreadData);
523     }
524 
525     intSave = LOS_IntLock();
526     LOS_ListDelete(&pthreadData->threadList);
527     tcb->taskName = PTHREAD_DEFAULT_NAME;
528     LOS_IntRestore(intSave);
529     free(pthreadData);
530     (void)LOS_TaskDelete(tcb->taskID);
531 EXIT:
532     while (1) {
533     }
534 }
535 
pthread_setname_np(pthread_t thread,const char * name)536 int pthread_setname_np(pthread_t thread, const char *name)
537 {
538     UINT32 intSave;
539     LosTaskCB *taskCB = NULL;
540     char *taskName = NULL;
541 
542     if (!IsPthread(thread)) {
543         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, thread);
544         return EINVAL;
545     }
546 
547     taskName = LOS_TaskNameGet((UINT32)thread);
548     if (taskName == NULL) {
549         return EINVAL;
550     }
551 
552     if (strnlen(name, PTHREAD_NAMELEN) >= PTHREAD_NAMELEN) {
553         return ERANGE;
554     }
555 
556     taskCB = OS_TCB_FROM_TID((UINT32)thread);
557     intSave = LOS_IntLock();
558     if (taskCB->taskStatus & OS_TASK_STATUS_EXIT) {
559         LOS_IntRestore(intSave);
560         return EINVAL;
561     }
562 
563     if (taskCB->taskEntry == PthreadEntry) {
564         (void)strcpy_s(taskName, PTHREAD_NAMELEN, name);
565     } else {
566         LOS_IntRestore(intSave);
567         return EINVAL;
568     }
569     LOS_IntRestore(intSave);
570 
571     return 0;
572 }
573 
pthread_getname_np(pthread_t thread,char * buf,size_t buflen)574 int pthread_getname_np(pthread_t thread, char *buf, size_t buflen)
575 {
576     int ret;
577     const char *name = NULL;
578 
579     if (!IsPthread(thread)) {
580         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, thread);
581         return EINVAL;
582     }
583 
584     name = LOS_TaskNameGet((UINT32)thread);
585     if (name == NULL) {
586         return EINVAL;
587     }
588     if (buflen > strlen(name)) {
589         ret = strcpy_s(buf, buflen, name);
590         if (ret == 0) {
591             return 0;
592         }
593     }
594 
595     return ERANGE;
596 }
597 
PthreadExitKeyDtor(PthreadData * pthreadData)598 static void PthreadExitKeyDtor(PthreadData *pthreadData)
599 {
600     PthreadKey *keys = NULL;
601     unsigned int intSave;
602 
603     intSave = LOS_IntLock();
604     for (unsigned int count = 0; count < PTHREAD_KEYS_MAX; count++) {
605         keys = &g_pthreadKeyData[count];
606         if (keys->flag == PTHREAD_KEY_UNUSED) {
607             continue;
608         }
609         PthreadKeyDtor dtor = keys->destructor;
610         LOS_IntRestore(intSave);
611 
612         if ((dtor != NULL) && (pthreadData->key[count] != 0)) {
613             dtor((void *)pthreadData->key[count]);
614         }
615 
616         intSave = LOS_IntLock();
617     }
618     LOS_IntRestore(intSave);
619 
620     free((void *)pthreadData->key);
621 }
622 
pthread_key_create(pthread_key_t * k,void (* dtor)(void *))623 int pthread_key_create(pthread_key_t *k, void (*dtor)(void *))
624 {
625     unsigned int intSave;
626     unsigned int count = 0;
627     PthreadKey *keys = NULL;
628 
629     pthread_t thread = pthread_self();
630     if (!IsPthread(thread)) {
631         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, thread);
632         return EINVAL;
633     }
634 
635     if (k == NULL) {
636         return EINVAL;
637     }
638 
639     intSave = LOS_IntLock();
640     if (g_pthreadkeyCount >= PTHREAD_KEYS_MAX) {
641         LOS_IntRestore(intSave);
642         return EAGAIN;
643     }
644 
645     do {
646         keys = &g_pthreadKeyData[count];
647         if (keys->flag == PTHREAD_KEY_UNUSED) {
648             break;
649         }
650         count++;
651     } while (count < PTHREAD_KEYS_MAX);
652 
653     keys->destructor = dtor;
654     keys->flag = PTHREAD_KEY_USED;
655     g_pthreadkeyCount++;
656     LOS_IntRestore(intSave);
657 
658     *k = count;
659 
660     return 0;
661 }
662 
pthread_key_delete(pthread_key_t k)663 int pthread_key_delete(pthread_key_t k)
664 {
665     unsigned int intSave;
666 
667     pthread_t thread = pthread_self();
668     if (!IsPthread(thread)) {
669         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, thread);
670         return EINVAL;
671     }
672 
673     if (k >= PTHREAD_KEYS_MAX) {
674         return EINVAL;
675     }
676 
677     intSave = LOS_IntLock();
678     if ((g_pthreadkeyCount == 0) || (g_pthreadKeyData[k].flag == PTHREAD_KEY_UNUSED)) {
679         LOS_IntRestore(intSave);
680         return EAGAIN;
681     }
682 
683     LOS_DL_LIST *list = g_pthreadListHead.pstNext;
684     while (list != &g_pthreadListHead) {
685         PthreadData *pthreadData = (PthreadData *)LOS_DL_LIST_ENTRY(list, PthreadData, threadList);
686         if (pthreadData->key != NULL) {
687             if ((g_pthreadKeyData[k].destructor != NULL) && (pthreadData->key[k] != 0)) {
688                 g_pthreadKeyData[k].destructor((void *)pthreadData->key[k]);
689             }
690             pthreadData->key[k] = 0;
691         }
692         list = list->pstNext;
693     }
694 
695     g_pthreadKeyData[k].destructor = NULL;
696     g_pthreadKeyData[k].flag = PTHREAD_KEY_UNUSED;
697     g_pthreadkeyCount--;
698     LOS_IntRestore(intSave);
699 
700     return 0;
701 }
702 
pthread_setspecific(pthread_key_t k,const void * x)703 int pthread_setspecific(pthread_key_t k, const void *x)
704 {
705     unsigned int intSave;
706     uintptr_t *key = NULL;
707 
708     pthread_t self = pthread_self();
709     if (!IsPthread(self)) {
710         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, self);
711         return EINVAL;
712     }
713 
714     if (k >= PTHREAD_KEYS_MAX) {
715         return EINVAL;
716     }
717 
718     LosTaskCB *taskCB = OS_TCB_FROM_TID((UINT32)self);
719     PthreadData *pthreadData = (PthreadData *)taskCB->arg;
720     if (pthreadData->key == NULL) {
721         key = (uintptr_t *)malloc(sizeof(uintptr_t) * PTHREAD_KEYS_MAX);
722         if (key == NULL) {
723             return ENOMEM;
724         }
725         (void)memset_s(key, sizeof(uintptr_t) * PTHREAD_KEYS_MAX, 0, sizeof(uintptr_t) * PTHREAD_KEYS_MAX);
726     }
727 
728     intSave = LOS_IntLock();
729     if (g_pthreadKeyData[k].flag == PTHREAD_KEY_UNUSED) {
730         LOS_IntRestore(intSave);
731         free(key);
732         return EAGAIN;
733     }
734 
735     if (pthreadData->key == NULL) {
736         pthreadData->key = key;
737     }
738 
739     pthreadData->key[k] = (uintptr_t)x;
740     LOS_IntRestore(intSave);
741 
742     return 0;
743 }
744 
pthread_getspecific(pthread_key_t k)745 void *pthread_getspecific(pthread_key_t k)
746 {
747     unsigned int intSave;
748     void *key = NULL;
749     pthread_t self = pthread_self();
750     if (!IsPthread(self)) {
751         PRINT_ERR("[%s:%d] This task %lu is not a posix thread!!!\n", __FUNCTION__, __LINE__, self);
752         return NULL;
753     }
754 
755     if (k >= PTHREAD_KEYS_MAX) {
756         return NULL;
757     }
758 
759     LosTaskCB *taskCB = OS_TCB_FROM_TID((UINT32)self);
760     PthreadData *pthreadData = (PthreadData *)taskCB->arg;
761     intSave = LOS_IntLock();
762     if ((g_pthreadKeyData[k].flag == PTHREAD_KEY_UNUSED) || (pthreadData->key == NULL)) {
763         LOS_IntRestore(intSave);
764         return NULL;
765     }
766 
767     key = (void *)pthreadData->key[k];
768     LOS_IntRestore(intSave);
769 
770     return key;
771 }
772 
773