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