From a856303b9cdadcfade33de0d3a335db0332f5761 Mon Sep 17 00:00:00 2001 From: zhushengle Date: Tue, 28 Dec 2021 11:28:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81posix=E7=BA=BF?= =?UTF-8?q?=E7=A8=8B=E7=A7=81=E6=9C=89=E6=95=B0=E6=8D=AE=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BREAKING CHANGE: int pthread_key_create(pthread_key_t *k, void (*dtor)(void *)) int pthread_key_delete(pthread_key_t k) int pthread_setspecific(pthread_key_t k, const void *x) void *pthread_getspecific(pthread_key_t k) Close #I4ODEB Signed-off-by: zhushengle Change-Id: I60ce26c20d1e2033922d2d1b01d73fc8938c8019 --- kal/posix/src/pthread.c | 204 +++++++++++++++++- .../src/pthread/pthread_cond_func_test.c | 111 ++++++++++ 2 files changed, 311 insertions(+), 4 deletions(-) diff --git a/kal/posix/src/pthread.c b/kal/posix/src/pthread.c index e1263921..aa2e142d 100644 --- a/kal/posix/src/pthread.c +++ b/kal/posix/src/pthread.c @@ -39,19 +39,34 @@ #include "los_task.h" #define PTHREAD_NAMELEN 16 +#define PTHREAD_KEY_UNUSED 0 +#define PTHREAD_KEY_USED 1 + +typedef void (*PthreadKeyDtor)(void *); +typedef struct { + int flag; + PthreadKeyDtor destructor; +} PthreadKey; +static unsigned int g_pthreadkeyCount = 0; +static PthreadKey g_pthreadKeyData[PTHREAD_KEYS_MAX]; +static LOS_DL_LIST g_pthreadListHead; typedef struct { void *(*startRoutine)(void *); void *param; char name[PTHREAD_NAMELEN]; + uintptr_t *key; + LOS_DL_LIST threadList; } PthreadData; +static void PthreadExitKeyDtor(PthreadData *pthreadData); + static void *PthreadEntry(UINT32 param) { PthreadData *pthreadData = (PthreadData *)(UINTPTR)param; void *(*startRoutine)(void *) = pthreadData->startRoutine; void *ret = startRoutine(pthreadData->param); - free(pthreadData); + pthread_exit(ret); return ret; } @@ -65,7 +80,6 @@ static int PthreadCreateAttrInit(const pthread_attr_t *attr, void *(*startRoutin { const pthread_attr_t *threadAttr = attr; struct sched_param schedParam = { 0 }; - PthreadData *pthreadData = NULL; INT32 policy = 0; pthread_attr_t attrTmp; INT32 ret; @@ -92,13 +106,14 @@ static int PthreadCreateAttrInit(const pthread_attr_t *attr, void *(*startRoutin taskInitParam->usTaskPrio = (UINT16)schedParam.sched_priority; } - pthreadData = (PthreadData *)malloc(sizeof(PthreadData)); + PthreadData *pthreadData = (PthreadData *)malloc(sizeof(PthreadData)); if (pthreadData == NULL) { return ENOMEM; } pthreadData->startRoutine = startRoutine; pthreadData->param = arg; + pthreadData->key = NULL; taskInitParam->pcName = pthreadData->name; taskInitParam->pfnTaskEntry = PthreadEntry; taskInitParam->uwArg = (UINT32)(UINTPTR)pthreadData; @@ -114,6 +129,7 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr, TSK_INIT_PARAM_S taskInitParam = { 0 }; UINT32 taskID; UINT32 ret; + UINT32 intSave; if ((thread == NULL) || (startRoutine == NULL)) { return EINVAL; @@ -129,6 +145,15 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr, return EINVAL; } + PthreadData *pthreadData = (PthreadData *)taskInitParam.uwArg; + intSave = LOS_IntLock(); + if (g_pthreadListHead.pstNext == NULL) { + LOS_ListInit(&g_pthreadListHead); + } + + LOS_ListAdd(&g_pthreadListHead, &pthreadData->threadList); + LOS_IntRestore(intSave); + /* set pthread default name */ (void)sprintf_s(taskInitParam.pcName, PTHREAD_NAMELEN, "pthread%u", taskID); @@ -219,9 +244,21 @@ int pthread_detach(pthread_t thread) void pthread_exit(void *retVal) { + UINT32 intSave; + LosTaskCB *tcb = OS_TCB_FROM_TID(LOS_CurTaskIDGet()); tcb->joinRetval = (UINTPTR)retVal; - free((PthreadData *)(UINTPTR)tcb->arg); + PthreadData *pthreadData = (PthreadData *)(UINTPTR)tcb->arg; + + if (pthreadData->key != NULL) { + PthreadExitKeyDtor(pthreadData); + } + + intSave = LOS_IntLock(); + LOS_ListDelete(&pthreadData->threadList); + LOS_IntRestore(intSave); + free(pthreadData); + (void)LOS_TaskDelete(tcb->taskID); } @@ -266,3 +303,162 @@ int pthread_getname_np(pthread_t thread, char *buf, size_t buflen) } return ERANGE; } + +static void PthreadExitKeyDtor(PthreadData *pthreadData) +{ + PthreadKey *keys = NULL; + unsigned int intSave; + + intSave = LOS_IntLock(); + for (unsigned int count = 0; count < PTHREAD_KEYS_MAX; count++) { + keys = &g_pthreadKeyData[count]; + if (keys->flag == PTHREAD_KEY_UNUSED) { + continue; + } + PthreadKeyDtor dtor = keys->destructor; + LOS_IntRestore(intSave); + + if ((dtor != NULL) && (pthreadData->key[count] != 0)) { + dtor((void *)pthreadData->key[count]); + } + + intSave = LOS_IntLock(); + } + LOS_IntRestore(intSave); + + free((void *)pthreadData->key); +} + +int pthread_key_create(pthread_key_t *k, void (*dtor)(void *)) +{ + unsigned int intSave; + unsigned int count = 0; + PthreadKey *keys = NULL; + + if (k == NULL) { + return EINVAL; + } + + intSave = LOS_IntLock(); + if (g_pthreadkeyCount >= PTHREAD_KEYS_MAX) { + LOS_IntRestore(intSave); + return EAGAIN; + } + + do { + keys = &g_pthreadKeyData[count]; + if (keys->flag == PTHREAD_KEY_UNUSED) { + break; + } + count++; + } while (count < PTHREAD_KEYS_MAX); + + keys->destructor = dtor; + keys->flag = PTHREAD_KEY_USED; + g_pthreadkeyCount++; + LOS_IntRestore(intSave); + + *k = count; + return 0; +} + +int pthread_key_delete(pthread_key_t k) +{ + unsigned int intSave; + + if (k >= PTHREAD_KEYS_MAX) { + return EINVAL; + } + + intSave = LOS_IntLock(); + if ((g_pthreadkeyCount == 0) || (g_pthreadKeyData[k].flag == PTHREAD_KEY_UNUSED)) { + LOS_IntRestore(intSave); + return EAGAIN; + } + + LOS_DL_LIST *list = g_pthreadListHead.pstNext; + while (list != &g_pthreadListHead) { + PthreadData *pthreadData = (PthreadData *)LOS_DL_LIST_ENTRY(list, PthreadData, threadList); + if (pthreadData->key != NULL) { + if ((g_pthreadKeyData[k].destructor != NULL) && (pthreadData->key[k] != 0)) { + g_pthreadKeyData[k].destructor((void *)pthreadData->key[k]); + } + pthreadData->key[k] = 0; + } + list = list->pstNext; + } + + g_pthreadKeyData[k].destructor = NULL; + g_pthreadKeyData[k].flag = PTHREAD_KEY_UNUSED; + g_pthreadkeyCount--; + LOS_IntRestore(intSave); + return 0; +} + +int pthread_setspecific(pthread_key_t k, const void *x) +{ + pthread_t self = pthread_self(); + unsigned int intSave; + uintptr_t *key = NULL; + + if (k >= PTHREAD_KEYS_MAX) { + return EINVAL; + } + + if (!IsPthread(self)) { + return EINVAL; + } + + LosTaskCB *taskCB = OS_TCB_FROM_TID((UINT32)self); + PthreadData *pthreadData = (PthreadData *)taskCB->arg; + if (pthreadData->key == NULL) { + key = (uintptr_t *)malloc(sizeof(uintptr_t) * PTHREAD_KEYS_MAX); + if (key == NULL) { + return ENOMEM; + } + (void)memset_s(key, sizeof(uintptr_t) * PTHREAD_KEYS_MAX, 0, sizeof(uintptr_t) * PTHREAD_KEYS_MAX); + } + + intSave = LOS_IntLock(); + if (g_pthreadKeyData[k].flag == PTHREAD_KEY_UNUSED) { + LOS_IntRestore(intSave); + free(key); + return EAGAIN; + } + + if (pthreadData->key == NULL) { + pthreadData->key = key; + } + + pthreadData->key[k] = (uintptr_t)x; + LOS_IntRestore(intSave); + return 0; +} + +void *pthread_getspecific(pthread_key_t k) +{ + unsigned int intSave; + void *key = NULL; + pthread_t self = pthread_self(); + + if (k >= PTHREAD_KEYS_MAX) { + return NULL; + } + + if (!IsPthread(self)) { + return NULL; + } + + LosTaskCB *taskCB = OS_TCB_FROM_TID((UINT32)self); + PthreadData *pthreadData = (PthreadData *)taskCB->arg; + intSave = LOS_IntLock(); + if ((g_pthreadKeyData[k].flag == PTHREAD_KEY_UNUSED) || (pthreadData->key == NULL)) { + LOS_IntRestore(intSave); + return NULL; + } + + key = (void *)pthreadData->key[k]; + LOS_IntRestore(intSave); + return key; +} + diff --git a/testsuites/unittest/posix/src/pthread/pthread_cond_func_test.c b/testsuites/unittest/posix/src/pthread/pthread_cond_func_test.c index fc382e8f..76fa0384 100644 --- a/testsuites/unittest/posix/src/pthread/pthread_cond_func_test.c +++ b/testsuites/unittest/posix/src/pthread/pthread_cond_func_test.c @@ -529,4 +529,115 @@ LITE_TEST_CASE(PthreadFuncTestSuite, testPthread007, Function | MediumTest | Lev return LOS_OK; }; +static int g_pthreadKey1; +static int g_pthreadKey2; +static void pthreadKeyFree(void *data) +{ + if (data != NULL) { + free(data); + } +} + +static void *pthread_f08(void *arg) +{ +#define TEST_KEY_SIZE 0x100 + int *data = (int *)malloc(TEST_KEY_SIZE); + if (data == NULL) { + return (void *)ENOMEM; + } + + (void)memset_s(data, TEST_KEY_SIZE, 0, TEST_KEY_SIZE); + *data = 100 + (int)pthread_self(); /* 100: test data */ + int ret = pthread_setspecific(g_pthreadKey1, (void *)data); + if (ret != 0) { + return (void *)ret; + } + + data = (int *)malloc(TEST_KEY_SIZE); + if (data == NULL) { + return (void *)ENOMEM; + } + + (void)memset_s(data, TEST_KEY_SIZE, 0, TEST_KEY_SIZE); + *data = 200 + (int)pthread_self(); /* 200: test data */ + ret = pthread_setspecific(g_pthreadKey2, (void *)data); + if (ret != 0) { + return (void *)ret; + } + + int *result = (int *)pthread_getspecific(g_pthreadKey1); + if (result == NULL) { + return (void *)EINVAL; + } + + if (*result != (100 + (int)pthread_self())) { /* 100: test data */ + return (void *)EDEADLK; + } + + result = (int *)pthread_getspecific(g_pthreadKey2); + if (result == NULL) { + return (void *)EINVAL; + } + + if (*result != (200 + (int)pthread_self())) { /* 200: test data */ + return (void *)EDEADLK; + } + + return NULL; +} + +/** + * @tc.number : SUB_KERNEL_PTHREAD_OPERATION_008 + * @tc.name : event operation for deatch + * @tc.desc : [C- SOFTWARE -0200] + */ +LITE_TEST_CASE(PthreadFuncTestSuite, testPthread008, Function | MediumTest | Level1) +{ + pthread_attr_t attr; + pthread_t newTh1, newTh2; + struct sched_param schedParam = { 0 }; + int result = 0; + UINT32 ret; + + ret = pthread_key_create(&g_pthreadKey1, pthreadKeyFree); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + ret = pthread_key_create(&g_pthreadKey2, pthreadKeyFree); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + ret = pthread_attr_init(&attr); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + ret = pthread_attr_setstacksize(&attr, OS_TSK_TEST_STACK_SIZE); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + schedParam.sched_priority = TASK_PRIO_TEST - 1; + ret = pthread_attr_setschedparam(&attr, &schedParam); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + ret = pthread_create(&newTh1, &attr, pthread_f08, NULL); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + ret = pthread_create(&newTh2, &attr, pthread_f08, NULL); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + ret = pthread_join(newTh1, (void **)&result); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + ICUNIT_ASSERT_EQUAL(result, 0, result); + + ret = pthread_join(newTh2, (void **)&result); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + ICUNIT_ASSERT_EQUAL(result, 0, result); + + ret = pthread_key_delete(g_pthreadKey1); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + ret = pthread_key_delete(g_pthreadKey2); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + return LOS_OK; +}; + RUN_TEST_SUITE(PthreadFuncTestSuite);