!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"
|
#include "los_task.h"
|
||||||
|
|
||||||
#define PTHREAD_NAMELEN 16
|
#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 {
|
typedef struct {
|
||||||
void *(*startRoutine)(void *);
|
void *(*startRoutine)(void *);
|
||||||
void *param;
|
void *param;
|
||||||
char name[PTHREAD_NAMELEN];
|
char name[PTHREAD_NAMELEN];
|
||||||
|
uintptr_t *key;
|
||||||
|
LOS_DL_LIST threadList;
|
||||||
} PthreadData;
|
} PthreadData;
|
||||||
|
|
||||||
|
static void PthreadExitKeyDtor(PthreadData *pthreadData);
|
||||||
|
|
||||||
static void *PthreadEntry(UINT32 param)
|
static void *PthreadEntry(UINT32 param)
|
||||||
{
|
{
|
||||||
PthreadData *pthreadData = (PthreadData *)(UINTPTR)param;
|
PthreadData *pthreadData = (PthreadData *)(UINTPTR)param;
|
||||||
void *(*startRoutine)(void *) = pthreadData->startRoutine;
|
void *(*startRoutine)(void *) = pthreadData->startRoutine;
|
||||||
void *ret = startRoutine(pthreadData->param);
|
void *ret = startRoutine(pthreadData->param);
|
||||||
free(pthreadData);
|
pthread_exit(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +80,6 @@ static int PthreadCreateAttrInit(const pthread_attr_t *attr, void *(*startRoutin
|
||||||
{
|
{
|
||||||
const pthread_attr_t *threadAttr = attr;
|
const pthread_attr_t *threadAttr = attr;
|
||||||
struct sched_param schedParam = { 0 };
|
struct sched_param schedParam = { 0 };
|
||||||
PthreadData *pthreadData = NULL;
|
|
||||||
INT32 policy = 0;
|
INT32 policy = 0;
|
||||||
pthread_attr_t attrTmp;
|
pthread_attr_t attrTmp;
|
||||||
INT32 ret;
|
INT32 ret;
|
||||||
|
@ -92,13 +106,14 @@ static int PthreadCreateAttrInit(const pthread_attr_t *attr, void *(*startRoutin
|
||||||
taskInitParam->usTaskPrio = (UINT16)schedParam.sched_priority;
|
taskInitParam->usTaskPrio = (UINT16)schedParam.sched_priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthreadData = (PthreadData *)malloc(sizeof(PthreadData));
|
PthreadData *pthreadData = (PthreadData *)malloc(sizeof(PthreadData));
|
||||||
if (pthreadData == NULL) {
|
if (pthreadData == NULL) {
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthreadData->startRoutine = startRoutine;
|
pthreadData->startRoutine = startRoutine;
|
||||||
pthreadData->param = arg;
|
pthreadData->param = arg;
|
||||||
|
pthreadData->key = NULL;
|
||||||
taskInitParam->pcName = pthreadData->name;
|
taskInitParam->pcName = pthreadData->name;
|
||||||
taskInitParam->pfnTaskEntry = PthreadEntry;
|
taskInitParam->pfnTaskEntry = PthreadEntry;
|
||||||
taskInitParam->uwArg = (UINT32)(UINTPTR)pthreadData;
|
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 };
|
TSK_INIT_PARAM_S taskInitParam = { 0 };
|
||||||
UINT32 taskID;
|
UINT32 taskID;
|
||||||
UINT32 ret;
|
UINT32 ret;
|
||||||
|
UINT32 intSave;
|
||||||
|
|
||||||
if ((thread == NULL) || (startRoutine == NULL)) {
|
if ((thread == NULL) || (startRoutine == NULL)) {
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
@ -129,6 +145,15 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
|
||||||
return EINVAL;
|
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 */
|
/* set pthread default name */
|
||||||
(void)sprintf_s(taskInitParam.pcName, PTHREAD_NAMELEN, "pthread%u", taskID);
|
(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)
|
void pthread_exit(void *retVal)
|
||||||
{
|
{
|
||||||
|
UINT32 intSave;
|
||||||
|
|
||||||
LosTaskCB *tcb = OS_TCB_FROM_TID(LOS_CurTaskIDGet());
|
LosTaskCB *tcb = OS_TCB_FROM_TID(LOS_CurTaskIDGet());
|
||||||
tcb->joinRetval = (UINTPTR)retVal;
|
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);
|
(void)LOS_TaskDelete(tcb->taskID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,3 +303,162 @@ int pthread_getname_np(pthread_t thread, char *buf, size_t buflen)
|
||||||
}
|
}
|
||||||
return ERANGE;
|
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;
|
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);
|
RUN_TEST_SUITE(PthreadFuncTestSuite);
|
||||||
|
|
Loading…
Reference in New Issue