您的位置:首页 > 其它

SylixOS线程私有数据浅析

2017-05-19 14:15 148 查看
目录
1.
线程私有数据概述    1

2.
线程私有数据的相关API函数流程浅析    1

2.1    加入线程私有变量    1
2.2    删除线程私有变量    3
2.3    设置私有线程变量    6
2.4    获得线程私有变量值    8
3.
总结    10

4.
参考文献    10

 

线程私有数据概述

在SylixOS中为了满足多线程安全的要求,使得一种资源可以安全的被多个线程使用,采用了包括代码临界区保护和可重入性等方法。本文描述实现可重入的一种方法:线程私有数据。值得注意的是这种保护方式牺牲了系统的实时性并且只针对单CPU系统有效,若非必要,SylixOS不推荐使用此方式。

线程私有数据的相关API函数流程浅析

加入线程私有变量

加入线程私有变量的流程如图 2-1所示。



图 2-1
加入线程私有变量

输入

在调用API_ThreadVarAdd函数时,我们需要输入线程ID以及私有变量地址。具体实现如程序清单 2-1所示。

程序清单 2-1
加入线程私有变量输入

ULONGAPI_ThreadVarAdd (LW_OBJECT_HANDLEulId,
ULONG *pulAddr)

{

REGISTERUINT16usIndex;

REGISTERPLW_CLASS_TCBptcb;

REGISTERPLW_CLASS_THREADVARpthreadvar;

 

usIndex =
_ObjectGetIndex(ulId);

...

}

判断是否在中断

获取CPU当前的中断嵌套值,判断是否在中断,该函数不能在中断中调用。具体实现如程序清单 2-2所示。

程序清单 2-2
判断是否在中断

if (LW_CPU_GET_CUR_NESTING()) {
/* 不能在中断中调用 */

_DebugHandle(__ERRORMESSAGE_LEVEL,
"called from ISR.\r\n");

_ErrorHandle(ERROR_KERNEL_IN_ISR);

return (ERROR_KERNEL_IN_ISR);

}

检查线
4000
程的有效性

在进入内核态之前,检查当前线程ID是否符合线程规范,以判断该线程是否有效。具体实现如程序清单 2-3所示。

程序清单 2-3
检查线程有效性

#if LW_CFG_ARG_CHK_EN > 0

if (!_ObjectClassOK(ulId,
_OBJECT_THREAD)) {

_DebugHandle(__ERRORMESSAGE_LEVEL,
"thread handle invalidate.\r\n");

_ErrorHandle(ERROR_KERNEL_HANDLE_NULL);

return (ERROR_KERNEL_HANDLE_NULL);

}

if (_Thread_Index_Invalid(usIndex))
{ /* 检查线程有效性 */

_DebugHandle(__ERRORMESSAGE_LEVEL,
"thread handle invalidate.\r\n");

_ErrorHandle(ERROR_THREAD_NULL);

return (ERROR_THREAD_NULL);

}

#endif

进入内核态

进入内核态进行操作。

检查线程的有效性

进入内核态以后,通过检查对应的线程TCB地址表来判断线程是否有效。具体实现如程序清单 2-4所示。

程序清单 2-4
检查线程有效性

if (_Thread_Invalid(usIndex)) {

__KERNEL_EXIT();
/* 退出内核 */

_DebugHandle(__ERRORMESSAGE_LEVEL,
"thread handle invalidate.\r\n");

_ErrorHandle(ERROR_THREAD_NULL);

return (ERROR_THREAD_NULL);

}

分配控制块

为当前的线程分配一个私有数据控制块,通过Allocate_ThreadVar_Object函数从空闲ThreadVar 控件池中取出一个空闲 ThreadVar。具体实现如程序清单 2-5所示。

程序清单 2-5
分配控制块

pthreadvar =
_Allocate_ThreadVar_Object();
/* 分配一个控制块 */

检查控制块的有效性

判断获得的控制器是否有效。具体实现如程序清单 2-6所示。

程序清单 2-6
检查控制块的有效性

if (!pthreadvar) {

__KERNEL_EXIT();
/* 退出内核 */

_ErrorHandle(ERROR_THREAD_VAR_FULL);

return (ERROR_THREAD_VAR_FULL);

}

链接控制块

将获得的私有数据控制块加入TCB的上下文。具体实现如程序清单 2-7所示。

程序清单 2-7
链接控制块

pthreadvar->PRIVATEVAR_pulAddress =
pulAddr;

pthreadvar->PRIVATEVAR_ulValueSave = *pulAddr;

ptcb =
_K_ptcbTCBIdTable[usIndex];

/*
加入TCB上下文 */

_List_Line_Add_Ahead(&pthreadvar->PRIVATEVAR_lineVarList,
&ptcb->TCB_plinePrivateVars);

退出内核

退出内核态。

删除线程私有变量

删除线程私有变量的流程如图 2-2所示。



图 2-2
删除线程私有变量

输入

在调用API_ThreadVarDelete函数时,我们需要输入线程ID以及私有变量地址。具体实现如程序清单 2-8所示。

程序清单 2-8
删除线程私有数据输入

ULONGAPI_ThreadVarDelete (LW_OBJECT_HANDLEulId,
ULONG *pulAddr)

{

REGISTERUINT16usIndex;

REGISTERPLW_CLASS_TCBptcbCur;

REGISTERPLW_CLASS_TCBptcb;

REGISTERPLW_LIST_LINEplineVar;

REGISTERPLW_CLASS_THREADVARpthreadvar;

usIndex =
_ObjectGetIndex(ulId);



}

判断是否在中断

获取CPU当前的中断嵌套值,判断是否在中断,该函数不能在中断中调用。

检查线程的有效性

在进入内核态之前,检查当前线程ID是否符合线程规范,以判断该线程是否有效。

进入内核态

进入内核态进行操作。

检查线程的有效性

进入内核态以后,通过检查对应的线程TCB地址表来判断线程是否有效。

查找私有数据控制块并解链

通过全局变量私有化线表查找控制块,将私有数据控制块从TCB中解链并释放控制块。具体实现如程序清单 2-9所示。

程序清单 2-9
查找控制块并解链

for (plineVar =
ptcb->TCB_plinePrivateVars;
/* 查找 */

plineVar !=
LW_NULL;

plineVar =
_list_line_get_next(plineVar)) {

 

pthreadvar =
_LIST_ENTRY(plineVar,
LW_CLASS_THREADVAR, PRIVATEVAR_lineVarList);

if (pthreadvar->PRIVATEVAR_pulAddress ==
pulAddr) {

if (ptcb ==
ptcbCur) {

*pulAddr =
pthreadvar->PRIVATEVAR_ulValueSave;

}

_List_Line_Del(plineVar, &ptcb->TCB_plinePrivateVars);
/* 从 TCB
中解链 */

_Free_ThreadVar_Object(pthreadvar);
/* 释放控制块 */

 

__KERNEL_EXIT();
/* 退出内核 */

return (ERROR_NONE);

}

}

 

退出内核

退出内核态。

设置私有线程变量

设置线程私有变量的流程如图 2-3所示。



图 2-3
设置线程私有变量

输入

在调用API_ThreadVarSet函数时,我们需要输入线程ID以及私有变量地址。具体实现如程序清单 2-10所示。

程序清单 2-10
设置线程私有变量的值输入

ULONG API_ThreadVarSet
(LW_OBJECT_HANDLEulId,
ULONG *pulAddr,
ULONGulValue)

{

REGISTERUINT16usIndex;

REGISTERPLW_CLASS_TCBptcbCur;

REGISTERPLW_CLASS_TCBptcb;

REGISTERPLW_LIST_LINEplineVar;

REGISTERPLW_CLASS_THREADVARpthreadvar;

usIndex =
_ObjectGetIndex(ulId);



}

判断是否在中断

获取CPU当前的中断嵌套值,判断是否在中断,该函数不能在中断中调用。

检查线程的有效性

在进入内核态之前,检查当前线程ID是否符合线程规范,以判断该线程是否有效。

进入内核态

进入内核态进行操作。

检查线程的有效性

进入内核态以后,通过检查对应的线程TCB地址表来判断线程是否有效。

查找私有数据控制块同时判断是否为当前线程

通过全局变量私有化线表查找控制块,然后检查线程控制块的相关信息判断是否为当前线程,是则赋值,不是则将值保存。具体实现如程序清单 2-11所示。

程序清单 2-11
查找控制块并判断是否为当前线程

ptcb =
_K_ptcbTCBIdTable[usIndex];

 

for (plineVar =
ptcb->TCB_plinePrivateVars;
/* 查找 */

plineVar !=
LW_NULL;

plineVar =
_list_line_get_next(plineVar)) {

 

pthreadvar =
_LIST_ENTRY(plineVar,
LW_CLASS_THREADVAR, PRIVATEVAR_lineVarList);

if (pthreadvar->PRIVATEVAR_pulAddress ==
pulAddr) {

if (ptcb ==
ptcbCur) {
/* 是不是当前线程 */

*pulAddr =
ulValue;

 

}
else {

pthreadvar->PRIVATEVAR_ulValueSave =
ulValue;

}

退出内核

退出内核态。

获得线程私有变量值

获得线程私有变量值的流程如图 2-4所示。



图 2-4
获得线程私有变量值

输入

我们需要输入线程ID以及私有变量地址。具体实现如程序清单 2-12所示。

程序清单 2-12
私有线程变量值获取

ULONG API_ThreadVarGet (LW_OBJECT_HANDLE ulId, ULONG *pulAddr)

{

REGISTERUINT16usIndex;

REGISTERPLW_CLASS_TCBptcbCur;

REGISTERPLW_CLASS_TCBptcb;

REGISTERPLW_LIST_LINEplineVar;

REGISTERULONGulValue;

REGISTERPLW_CLASS_THREADVARpthreadvar;

usIndex =
_ObjectGetIndex(ulId);



}

判断是否在中断

获取CPU当前的中断嵌套值,判断是否在中断,该函数不能在中断中调用。

检查线程的有效性

在进入内核态之前,检查当前线程ID是否符合线程规范,以判断该线程是否有效。

进入内核态

进入内核态进行操作。

检查线程的有效性

进入内核态以后,通过检查对应的线程TCB地址表来判断线程是否有效。

查找私有数据控制块同时判断是否为当前线程

通过全局变量私有化线表查找控制块,然后检查线程控制块的相关信息判断是否为当前线程,是获取线程私有变量的值,不是则获得保存的变量值。实现如程序清单 2-13所示。

程序清单 2-13
查找控制块并判断是否为当前线程

ptcb =
_K_ptcbTCBIdTable[usIndex];

for (plineVar =
ptcb->TCB_plinePrivateVars;
/* 查找 */

plineVar !=
LW_NULL;

plineVar =
_list_line_get_next(plineVar)) {

pthreadvar =
_LIST_ENTRY(plineVar,
LW_CLASS_THREADVAR, PRIVATEVAR_lineVarList);

if (pthreadvar->PRIVATEVAR_pulAddress ==
pulAddr) {

if (ptcb ==
ptcbCur) {
/* 是不是当前线程 */

ulValue = *pulAddr;

}
else {

ulValue =
pthreadvar->PRIVATEVAR_ulValueSave;

}

退出内核

退出内核态。

 

总结

线程私有数据是线程上下文记录的一个unsigned long型数值(可以将其看成一个指向一个全局变量的指针)和保存全局变量值的临时变量(用来恢复线程上下文中全局变量的值)。每次线程被调入处理器时,系统根据该指针自动从线程上下文装入全局变量的值。相应地,任务被调出处理器时,系统根据该指针自动将全局变量的值保存到线程的上下文。

参考文献

1.《SylixOS应用开发手册》

2. SylixOS源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: