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