SylixOS线程私有数据浅析
目录
-
线程私有数据概述
在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);
}
-
检查线程的有效性
在进入内核态之前,检查当前线程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源码
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
用Heartbeat实现web服务器高可用
用Heartbeat实现web服务器高可用 heartbeat概述: Heartbeat 项目是 Linux-HA 工程的一个组成部分,它实现了一个高可用集群系统。心跳服务和集群通信是高可用集群的两个关键组件,在 Heartbeat 项目里,由 heartbeat 模块实现了这两个功能。 端口号:694 1)heartbeat的工作原理: heartbeat最核心的包括两个。部分,心跳监测部分和资源接管部分,心跳监测可以通过网络链路和串口进行,而且支持冗余链路,它们之间相互发送报文来告诉对方自己当前的状态,如果在指定的时间内未收到对方发送的报文,那就认为对方失效,这时需启动资源接管模块来接管运行在对方主机上的资源或者服务 2)高可用集群 高可用集群是指一组通过硬件和软件连接起来的独立计算机,它们在用户面前表现为一个单一系统,在这样的一组计算机系统内部的一个或者多个节点停止工作,服务会从故障节点切换到正常工作的节点上运行,不会引起服务中断。从这个定义可以看出,集群必须检测节点和服务何时失效,何时恢复为可用。这个任务通常由一组被称为“心跳”的代码完成。在Linux-HA里这个功能由一个叫...
- 下一篇
HP EVA8400删除VDISK后数据恢复过程分步整理
【故障描述】 某地法院一台HP EVA8400存储,2组扩展柜,物理磁盘由12个1T FATA磁盘(AG691A 454414-001)和10个300G 15K FC磁盘(AG690A 454411-001)组成,LUN数量不确定,主机环境为WINDOWS,存储法院历史案例审理材料。 因本案多方转手,所以我们也无法直接得知故障原因。 【初检及分析】 1、电话初检,确定得知,数据出现故障后再未重用。通常按HP-EVA的故障可能推断,数据恢复的可靠性较高。 2、EVA主机及扩展柜正常关机,之后将所有硬盘标好位置序号,拿出。在数据成功恢复之前,不再开启EVA 8400控制器。 3、接手磁盘后,按如下链路对磁盘进行连接。 4、进入WINDOWS环境,用WINHEX查看磁盘情况,发现所有磁盘均可正常识别。 5、查看每个磁盘信息,发现300G FC磁盘存在PV HEAD,而1T FATA磁盘上均无PV HEAD。查看300G磁盘中存储的Metadata,发现仅描述了一个RSS组组成的LUN,大小不足2T,成员为所有300G磁盘。而1T FATA磁盘中残留的LUN信息则至少包括5...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS6,CentOS7官方镜像安装Oracle11G
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Linux系统CentOS6、CentOS7手动修改IP地址