!510 feat: 支持posix线程私有数据能力
Merge pull request !510 from zhushengle/pthread_key
This commit is contained in:
commit
909a18ec8f
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue