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