1 /*
2 * Copyright (c) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved.
3 *
4 * UniProton is licensed under Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 * http://license.coscl.org.cn/MulanPSL2
8 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
9 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
10 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11 * See the Mulan PSL v2 for more details.
12 * Create: 2022-11-15
13 * Description: os内部pthread功能实现
14 */
15 #include "pthread.h"
16 #include "prt_posix_internal.h"
17 #include "../../core/kernel/task/prt_task_internal.h"
18 #include "prt_err_external.h"
19
20 #define PTHREAD_TERMINATED 2
21 #define PTHREAD_EXITED 3
22
23 void (*destor[PTHREAD_KEYS_MAX])(void *) = {0};
24
OsPthreadNotifyParents(struct TagTskCb * tskCb)25 static void OsPthreadNotifyParents(struct TagTskCb *tskCb)
26 {
27 U32 count = tskCb->joinCount;
28
29 while (count--) {
30 PRT_SemPost(tskCb->joinableSem);
31 }
32 }
33
OsPthreadRunDestructor(struct TagTskCb * self)34 static void OsPthreadRunDestructor(struct TagTskCb *self)
35 {
36 int i;
37 void *val;
38 void (*destructor)(void *);
39
40 for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
41 if ((self->tsdUsed & (1U << (U32)i)) != 0) {
42 val = self->tsd[i];
43 destructor = destor[i];
44 destructor(val);
45 }
46 }
47 self->tsdUsed = 0;
48 }
49
PRT_PthreadExit(void * retval)50 void PRT_PthreadExit(void *retval)
51 {
52 U32 ret;
53 uintptr_t intSave;
54 struct TagTskCb *tskCb;
55
56 intSave = OsIntLock();
57
58 tskCb = RUNNING_TASK;
59 while (tskCb->cancelBuf) {
60 void (*f)(void *) = tskCb->cancelBuf->_routine;
61 void *x = tskCb->cancelBuf->_arg;
62 tskCb->cancelBuf = tskCb->cancelBuf->_previous;
63 f(x);
64 }
65
66 tskCb->retval = retval;
67 /* thread is joinable and other threads are waitting */
68 if (tskCb->state == PTHREAD_CREATE_JOINABLE && tskCb->joinCount > 0) {
69 tskCb->state = PTHREAD_EXITED;
70 OsPthreadNotifyParents(tskCb);
71 } else {
72 if (tskCb->state == PTHREAD_CREATE_JOINABLE) {
73 tskCb->state = PTHREAD_EXITED;
74 } else {
75 tskCb->state = PTHREAD_TERMINATED;
76 }
77 if (tskCb->joinableSem != 0) {
78 PRT_SemDelete(tskCb->joinableSem);
79 tskCb->joinableSem = 0;
80 }
81 OsPthreadRunDestructor(tskCb);
82 }
83
84 OsIntRestore(intSave);
85
86 ret = PRT_TaskDelete(tskCb->taskPid);
87 if (ret != OS_OK) {
88 OsErrRecord(ret);
89 }
90 }
91
OsPthreadCreatParaCheck(TskHandle * newthread,const pthread_attr_t * attrp,prt_pthread_startroutine routine,pthread_attr_t * attr)92 static U32 OsPthreadCreatParaCheck(TskHandle *newthread, const pthread_attr_t *attrp,
93 prt_pthread_startroutine routine, pthread_attr_t *attr)
94 {
95 int ret;
96
97 if (newthread == NULL || routine == NULL) {
98 return EINVAL;
99 }
100
101 if (attrp != NULL) {
102 if (attrp->is_initialized == PTHREAD_ATTR_UNINIT) {
103 return EINVAL;
104 }
105 *attr = *attrp;
106 } else {
107 ret = pthread_attr_init(attr);
108 if (ret != OS_OK) {
109 OsErrRecord(ret);
110 }
111 }
112
113 return OS_OK;
114 }
115
OsPthreadWrapper(uintptr_t param1,uintptr_t param2,uintptr_t param3,uintptr_t param4)116 static void OsPthreadWrapper(uintptr_t param1, uintptr_t param2, uintptr_t param3, uintptr_t param4)
117 {
118 void *ret;
119
120 (void)param3;
121 (void)param4;
122 void *(*threadroutine)(void *) = (void *)param1;
123
124 ret = threadroutine((void *)param2);
125 PRT_PthreadExit(ret);
126 }
127
OsPthreadCreateRsrcInit(U32 taskId,pthread_attr_t * attr,struct TagTskCb * tskCb,uintptr_t ** topStackOut,uintptr_t * curStackSize)128 OS_SEC_ALW_INLINE INLINE U32 OsPthreadCreateRsrcInit(U32 taskId, pthread_attr_t *attr,
129 struct TagTskCb *tskCb, uintptr_t **topStackOut, uintptr_t *curStackSize)
130 {
131 U32 ret = OS_OK;
132 uintptr_t *topStack = NULL;
133
134 /* 创建任务线程 */
135 if (g_taskNameAdd != NULL) {
136 ret = g_taskNameAdd(taskId, "pthread");
137 if (ret != OS_OK) {
138 return ret;
139 }
140 }
141
142 /* 查看用户是否配置了任务栈,如没有,则进行内存申请,并标记为系统配置,如有,则标记为用户配置。 */
143 if (attr->stackaddr != 0) {
144 topStack = (void *)(attr->stackaddr);
145 tskCb->stackCfgFlg = OS_TSK_STACK_CFG_BY_USER;
146 } else {
147 topStack = OsTskMemAlloc(attr->stacksize);
148 if (topStack == NULL) {
149 ret = OS_ERRNO_TSK_NO_MEMORY;
150 } else {
151 tskCb->stackCfgFlg = OS_TSK_STACK_CFG_BY_SYS;
152 }
153 }
154 *curStackSize = attr->stacksize;
155 if (ret != OS_OK) {
156 return ret;
157 }
158
159 *topStackOut = topStack;
160 return OS_OK;
161 }
162
OsPthreadCreateTcbInit(uintptr_t stackPtr,pthread_attr_t * attr,uintptr_t topStackAddr,uintptr_t curStackSize,struct TagTskCb * tskCb)163 OS_SEC_ALW_INLINE INLINE void OsPthreadCreateTcbInit(uintptr_t stackPtr, pthread_attr_t *attr,
164 uintptr_t topStackAddr, uintptr_t curStackSize, struct TagTskCb *tskCb)
165 {
166 /* Initialize the task's stack */
167 tskCb->stackPointer = (void *)stackPtr;
168 tskCb->topOfStack = topStackAddr;
169 tskCb->stackSize = curStackSize;
170 tskCb->taskSem = NULL;
171 tskCb->priority = attr->schedparam.sched_priority;
172 tskCb->taskEntry = OsPthreadWrapper;
173 #if defined(OS_OPTION_EVENT)
174 tskCb->event = 0;
175 tskCb->eventMask = 0;
176 #endif
177 tskCb->lastErr = 0;
178 tskCb->taskStatus = OS_TSK_SUSPEND | OS_TSK_INUSE;
179 /* pthread init */
180 tskCb->tsdUsed = 0;
181 tskCb->state = attr->detachstate;
182 tskCb->cancelState = PTHREAD_CANCEL_ENABLE;
183 tskCb->cancelType = PTHREAD_CANCEL_DEFERRED;
184 tskCb->cancelPending = 0;
185 tskCb->cancelBuf = NULL;
186 tskCb->retval = NULL;
187 tskCb->joinCount = 0;
188 tskCb->joinableSem = 0;
189 tskCb->tsdUsed = 0;
190
191 INIT_LIST_OBJECT(&tskCb->pendList);
192 INIT_LIST_OBJECT(&tskCb->timerList);
193 }
194
PRT_PthreadCreate(TskHandle * thread,const pthread_attr_t * attrp,prt_pthread_startroutine routine,void * arg)195 int PRT_PthreadCreate(TskHandle *thread, const pthread_attr_t *attrp,
196 prt_pthread_startroutine routine, void *arg)
197 {
198 U32 ret;
199 U32 taskId;
200 uintptr_t intSave;
201 void *stackPtr = NULL;
202 uintptr_t *topStack = NULL;
203 uintptr_t curStackSize = 0;
204 struct TagTskCb *tskCb = NULL;
205 pthread_attr_t attr = {0};
206
207 ret = OsPthreadCreatParaCheck(thread, attrp, routine, &attr);
208 if (ret != OS_OK) {
209 return ret;
210 }
211
212 intSave = OsIntLock();
213 ret = OsTaskCreateChkAndGetTcb(&tskCb);
214 if (ret != OS_OK) {
215 OsIntRestore(intSave);
216 return ENOMEM;
217 }
218
219 taskId = tskCb->taskPid;
220
221 ret = OsPthreadCreateRsrcInit(taskId, &attr, tskCb, &topStack, &curStackSize);
222 if (ret != OS_OK) {
223 ListAdd(&tskCb->pendList, &g_tskCbFreeList);
224 OsIntRestore(intSave);
225 return ENOMEM;
226 }
227 OsTskStackInit(curStackSize, (uintptr_t)topStack);
228
229 stackPtr = OsTskContextInit(taskId, curStackSize, topStack, (uintptr_t)OsTskEntry);
230
231 OsPthreadCreateTcbInit((uintptr_t)stackPtr, &attr, (uintptr_t)topStack, curStackSize, tskCb);
232 tskCb->args[OS_TSK_PARA_0] = (uintptr_t)routine;
233 tskCb->args[OS_TSK_PARA_1] = (uintptr_t)arg;
234 tskCb->args[OS_TSK_PARA_2] = 0;
235 tskCb->args[OS_TSK_PARA_3] = 0;
236 OsIntRestore(intSave);
237
238 if (tskCb->state == PTHREAD_CREATE_JOINABLE) {
239 ret = PRT_SemCreate(0, &tskCb->joinableSem);
240 if (ret != OS_OK) {
241 return EAGAIN;
242 }
243 }
244
245 ret = PRT_TaskResume(taskId);
246 if (ret != OS_OK) {
247 if (tskCb->state == PTHREAD_CREATE_JOINABLE) {
248 PRT_SemDelete(tskCb->joinableSem);
249 }
250 return EAGAIN;
251 }
252 *thread = taskId;
253
254 return OS_OK;
255 }
256
OsPthreadDestructor(void * arg)257 void OsPthreadDestructor(void *arg)
258 {
259 (void)arg;
260 }
261
PRT_PthreadKeyCreate(pthread_key_t * key,void (* destructor)(void *))262 int PRT_PthreadKeyCreate(pthread_key_t *key, void (*destructor)(void *))
263 {
264 int i;
265
266 for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
267 if (destor[i] == NULL) {
268 *key = (pthread_key_t)i;
269 break;
270 }
271 }
272
273 if (i == PTHREAD_KEYS_MAX) {
274 return EAGAIN;
275 }
276
277 if (destructor != NULL) {
278 destor[i] = destructor;
279 } else {
280 destor[i] = OsPthreadDestructor;
281 }
282
283 return OS_OK;
284 }
285
PRT_PthreadKeyDelete(pthread_key_t key)286 int PRT_PthreadKeyDelete(pthread_key_t key)
287 {
288 U32 i;
289 uintptr_t intSave;
290
291 if ((U32)key >= PTHREAD_KEYS_MAX || destor[key] == NULL) {
292 return EINVAL;
293 }
294
295 intSave = OsIntLock();
296 for (i = 0; i < g_tskMaxNum; i++) {
297 g_tskCbArray[i].tsdUsed = g_tskCbArray[i].tsdUsed & ~(1U << (U32)key);
298 g_tskCbArray[i].tsd[key] = NULL;
299 }
300 destor[key] = NULL;
301 OsIntRestore(intSave);
302
303 return OS_OK;
304 }
305
PRT_PthreadSetSpecific(pthread_key_t key,const void * value)306 int PRT_PthreadSetSpecific(pthread_key_t key, const void *value)
307 {
308 struct TagTskCb *tskCb = RUNNING_TASK;
309
310 if ((U32)key >= PTHREAD_KEYS_MAX || destor[key] == NULL) {
311 return EINVAL;
312 }
313 tskCb->tsd[key] = (void *)(uintptr_t)value;
314 tskCb->tsdUsed |= (1U << (U32)key);
315
316 return OS_OK;
317 }
318
PRT_PthreadGetSpecific(pthread_key_t key)319 void *PRT_PthreadGetSpecific(pthread_key_t key)
320 {
321 struct TagTskCb *tskCb = RUNNING_TASK;
322
323 if ((U32)key >= PTHREAD_KEYS_MAX) {
324 return NULL;
325 }
326 if ((tskCb->tsdUsed & (1U << (U32)key)) == 0) {
327 return NULL;
328 }
329
330 return tskCb->tsd[key];
331 }
332
OsPthreadDoCleanupPush(struct _pthread_cleanup_context * cb)333 static void OsPthreadDoCleanupPush(struct _pthread_cleanup_context *cb)
334 {
335 struct TagTskCb *tskCb = RUNNING_TASK;
336
337 cb->_previous = tskCb->cancelBuf;
338 tskCb->cancelBuf = cb;
339 }
340
OsPthreadDoCleanupPop(struct _pthread_cleanup_context * cb)341 static void OsPthreadDoCleanupPop(struct _pthread_cleanup_context *cb)
342 {
343 struct TagTskCb *tskCb = RUNNING_TASK;
344
345 tskCb->cancelBuf = cb->_previous;
346 }
347
_pthread_cleanup_push(struct _pthread_cleanup_context * cb,void (* f)(void *),void * x)348 void _pthread_cleanup_push(struct _pthread_cleanup_context *cb, void (*f)(void *), void *x)
349 {
350 cb->_routine = f;
351 cb->_arg = x;
352 OsPthreadDoCleanupPush(cb);
353 }
354
_pthread_cleanup_pop(struct _pthread_cleanup_context * cb,int run)355 void _pthread_cleanup_pop(struct _pthread_cleanup_context *cb, int run)
356 {
357 OsPthreadDoCleanupPop(cb);
358 if (run) cb->_routine(cb->_arg);
359 }
360
OsPthreadJoinExit(struct TagTskCb * tskCb,void ** status)361 U32 OsPthreadJoinExit(struct TagTskCb *tskCb, void **status)
362 {
363 switch (tskCb->state) {
364 case PTHREAD_EXITED:
365 if (status != NULL) {
366 *status = tskCb->retval;
367 }
368 /* the last parent frees the resources */
369 if (tskCb->joinCount == 0) {
370 tskCb->state = PTHREAD_TERMINATED;
371 if (tskCb->joinableSem != 0) {
372 PRT_SemDelete(tskCb->joinableSem);
373 tskCb->joinableSem = 0;
374 }
375 OsPthreadRunDestructor(tskCb);
376 }
377 return OS_OK;
378 case PTHREAD_CREATE_JOINABLE:
379 case PTHREAD_CREATE_DETACHED:
380 return EINVAL;
381 case PTHREAD_TERMINATED: /* fall through */
382 default:
383 return ESRCH;
384 }
385 }
386
PRT_PthreadJoin(TskHandle thread,void ** status)387 int PRT_PthreadJoin(TskHandle thread, void **status)
388 {
389 struct TagTskCb *tskCb = RUNNING_TASK;
390 uintptr_t intSave;
391 U32 ret = 0;
392
393 if (thread == tskCb->taskPid) {
394 return EDEADLK;
395 }
396 if (CHECK_TSK_PID_OVERFLOW(thread)) {
397 return ESRCH;
398 }
399
400 intSave = OsIntLock();
401
402 tskCb = GET_TCB_HANDLE(thread);
403 /* the target thread already exited */
404 if (tskCb->taskStatus == OS_TSK_UNUSED) {
405 ret = OsPthreadJoinExit(tskCb, status);
406 OsIntRestore(intSave);
407 return ret;
408 }
409
410 if (tskCb->state == PTHREAD_CREATE_JOINABLE) {
411 /* wait the target thread to finish */
412 tskCb->joinCount++;
413 OsIntRestore(intSave);
414 ret = PRT_SemPend(tskCb->joinableSem, OS_WAIT_FOREVER);
415 if (ret != OS_OK) {
416 tskCb->joinCount--;
417 return EDEADLK;
418 }
419 intSave = OsIntLock();
420 tskCb->joinCount--;
421 }
422
423 ret = OsPthreadJoinExit(tskCb, status);
424 OsIntRestore(intSave);
425
426 return ret;
427 }
428
PRT_PthreadDetach(TskHandle thread)429 int PRT_PthreadDetach(TskHandle thread)
430 {
431 struct TagTskCb *tskCb;
432 uintptr_t intSave;
433 U32 ret = 0;
434
435 if (CHECK_TSK_PID_OVERFLOW(thread)) {
436 return ESRCH;
437 }
438
439 tskCb = GET_TCB_HANDLE(thread);
440 intSave = OsIntLock();
441
442 switch (tskCb->state) {
443 case PTHREAD_CREATE_JOINABLE:
444 tskCb->state = PTHREAD_CREATE_DETACHED;
445 OsPthreadNotifyParents(tskCb);
446 break;
447 case PTHREAD_EXITED:
448 PRT_PthreadJoin(thread, NULL);
449 break;
450 case PTHREAD_TERMINATED:
451 ret = ESRCH;
452 break;
453 default:
454 ret = EINVAL;
455 break;
456 }
457
458 OsIntRestore(intSave);
459
460 return ret;
461 }
462
PRT_PthreadTestCancel(void)463 void PRT_PthreadTestCancel(void)
464 {
465 struct TagTskCb *tskCb = RUNNING_TASK;
466
467 if (tskCb->cancelState == PTHREAD_CANCEL_ENABLE && tskCb->cancelPending) {
468 PRT_PthreadExit(PTHREAD_CANCELED);
469 }
470 }
471
OsPthreadCancelDetachedHandle(struct TagTskCb * tskCb)472 static int OsPthreadCancelDetachedHandle(struct TagTskCb *tskCb)
473 {
474 U32 ret;
475
476 tskCb->state = PTHREAD_TERMINATED;
477 if (tskCb->joinableSem != 0) {
478 ret = PRT_SemDelete(tskCb->joinableSem);
479 if (ret != OS_OK) {
480 return EINVAL;
481 }
482 tskCb->joinableSem = 0;
483 }
484 while (tskCb->cancelBuf) {
485 void (*f)(void *) = tskCb->cancelBuf->_routine;
486 void *x = tskCb->cancelBuf->_arg;
487 tskCb->cancelBuf = tskCb->cancelBuf->_previous;
488 f(x);
489 }
490 OsPthreadRunDestructor(tskCb);
491 ret = PRT_TaskDelete(tskCb->taskPid);
492 if (ret != OS_OK) {
493 return EAGAIN;
494 }
495
496 return OS_OK;
497 }
498
OsPthreadCancelJoinableHandle(struct TagTskCb * tskCb)499 static int OsPthreadCancelJoinableHandle(struct TagTskCb *tskCb)
500 {
501 U32 ret;
502
503 while (tskCb->cancelBuf) {
504 void (*f)(void *) = tskCb->cancelBuf->_routine;
505 void *x = tskCb->cancelBuf->_arg;
506 tskCb->cancelBuf = tskCb->cancelBuf->_previous;
507 f(x);
508 }
509 tskCb->state = PTHREAD_EXITED;
510 if (tskCb->joinCount == 0) {
511 if (tskCb->joinableSem != 0) {
512 ret = PRT_SemDelete(tskCb->joinableSem);
513 if (ret != OS_OK) {
514 return EINVAL;
515 }
516 tskCb->joinableSem = 0;
517 }
518 OsPthreadRunDestructor(tskCb);
519 } else {
520 while (tskCb->joinCount) {
521 tskCb->joinCount--;
522 ret = PRT_SemPost(tskCb->joinableSem);
523 if (ret != OS_OK) {
524 return EINVAL;
525 }
526 }
527 }
528 ret = PRT_TaskDelete(tskCb->taskPid);
529 if (ret != OS_OK) {
530 return EAGAIN;
531 }
532
533 return OS_OK;
534 }
535
PRT_PthreadCancel(TskHandle thread)536 int PRT_PthreadCancel(TskHandle thread)
537 {
538 struct TagTskCb *tskCb;
539 uintptr_t intSave;
540 int ret = OS_OK;
541 struct TagTskCb *curTskCb = RUNNING_TASK;
542
543 if (CHECK_TSK_PID_OVERFLOW(thread)) {
544 return ESRCH;
545 }
546
547 tskCb = GET_TCB_HANDLE(thread);
548 intSave = OsIntLock();
549 if (thread == curTskCb->taskPid) {
550 if (tskCb->cancelState == PTHREAD_CANCEL_ENABLE && tskCb->cancelType == PTHREAD_CANCEL_ASYNCHRONOUS) {
551 PRT_PthreadExit(PTHREAD_CANCELED);
552 }
553 OsIntRestore(intSave);
554 return OS_OK;
555 }
556
557 tskCb->cancelPending = 1;
558 if (tskCb->cancelType == PTHREAD_CANCEL_DEFERRED) {
559 OsIntRestore(intSave);
560 return OS_OK;
561 }
562 if (tskCb->cancelState == PTHREAD_CANCEL_ENABLE) {
563 if (tskCb->state == PTHREAD_CREATE_DETACHED) {
564 ret = OsPthreadCancelDetachedHandle(tskCb);
565 } else if (tskCb->state == PTHREAD_CREATE_JOINABLE) {
566 ret = OsPthreadCancelJoinableHandle(tskCb);
567 }
568 }
569
570 OsIntRestore(intSave);
571
572 return ret;
573 }
574
PRT_PthreadSetCancelState(int state,int * oldstate)575 int PRT_PthreadSetCancelState(int state, int *oldstate)
576 {
577 struct TagTskCb *tskCb = RUNNING_TASK;
578 uintptr_t intSave;
579
580 /* currently, only supports ENABLE and DISABLE */
581 if (state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE) {
582 return EINVAL;
583 }
584
585 intSave = OsIntLock();
586 if (oldstate != NULL) {
587 *oldstate = tskCb->cancelState;
588 }
589 tskCb->cancelState = state;
590 if (state == PTHREAD_CANCEL_ENABLE && tskCb->cancelPending) {
591 PRT_PthreadExit(PTHREAD_CANCELED);
592 }
593 OsIntRestore(intSave);
594
595 return OS_OK;
596 }
597
PRT_PthreadSetCancelType(int type,int * oldType)598 int PRT_PthreadSetCancelType(int type, int *oldType)
599 {
600 struct TagTskCb *tskCb = RUNNING_TASK;
601 uintptr_t intSave;
602
603 if (type != PTHREAD_CANCEL_DEFERRED && type != PTHREAD_CANCEL_ASYNCHRONOUS) {
604 return EINVAL;
605 }
606
607 intSave = OsIntLock();
608 if (oldType != NULL) {
609 *oldType = tskCb->cancelType;
610 }
611 tskCb->cancelType = type;
612 if (type == PTHREAD_CANCEL_ASYNCHRONOUS) {
613 PRT_PthreadTestCancel();
614 }
615 OsIntRestore(intSave);
616
617 return OS_OK;
618 }
619