• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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