thread_create 和 thread_resume

2023-10-30

在lk中我们一般通过thread_create 来新建一个thread,但这个thread 是THREAD_SUSPENDED,必须要调用thread_resume
才能开始运行
enum thread_state {
THREAD_SUSPENDED = 0,
THREAD_READY,
THREAD_RUNNING,
THREAD_BLOCKED,
THREAD_SLEEPING,
THREAD_DEATH,
};
thread_resume(thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
我们来看看thread_create的实现
thread_t *thread_create(const char *name, thread_start_routine entry, void *arg, int priority, size_t stack_size)
{
thread_t *t;


t = malloc(sizeof(thread_t));
if (!t)
return NULL;


init_thread_struct(t, name);


t->entry = entry;
t->arg = arg;
t->priority = priority;
t->saved_critical_section_count = 1; /* we always start inside a critical section */
t->state = THREAD_SUSPENDED;
t->blocking_wait_queue = NULL;
t->wait_queue_block_ret = NO_ERROR;


/* create the stack */
t->stack = malloc(stack_size);
if (!t->stack) {
free(t);
return NULL;
}


t->stack_size = stack_size;


/* inheirit thread local storage from the parent */
int i;
for (i=0; i < MAX_TLS_ENTRY; i++)
t->tls[i] = current_thread->tls[i];


/* set up the initial stack frame */
arch_thread_initialize(t);


/* add it to the global thread list */
enter_critical_section();
list_add_head(&thread_list, &t->thread_list_node);
exit_critical_section();


return t;
}
这个函数但大部分在做新thread_t结构体的初始化。在最后调用list_add_head将这个新建的thread加入到thread_list 中.
/* global thread list */
static struct list_node thread_list;
所有的thread 都是放在这个全局的thread_list 中
现在为止我们的thread 已经建好了,但是其状态是t->state = THREAD_SUSPENDED;我们需要调用thread_resume来让其运行
status_t thread_resume(thread_t *t)
{
#if THREAD_CHECKS
ASSERT(t->magic == THREAD_MAGIC);
ASSERT(t->state != THREAD_DEATH);
#endif


if (t->state == THREAD_READY || t->state == THREAD_RUNNING)
return ERR_NOT_SUSPENDED;


enter_critical_section();
t->state = THREAD_READY;
insert_in_run_queue_head(t);
thread_yield();
exit_critical_section();


return NO_ERROR;
}
这个函数会先判断t->state 是不是THREAD_READY 或者 THREAD_RUNNING,如果是的话就退出,说明出错了,由于我们是
新建一个thread,其状态是THREAD_SUSPENDED,所以继续往下走
将thread的状态设成THREAD_READY。
然后调用insert_in_run_queue_head 插入到将要运行thread的list中
/* run queue manipulation */
static void insert_in_run_queue_head(thread_t *t)
{
#if THREAD_CHECKS
ASSERT(t->magic == THREAD_MAGIC);
ASSERT(t->state == THREAD_READY);
ASSERT(!list_in_list(&t->queue_node));
ASSERT(in_critical_section());
#endif


list_add_head(&run_queue[t->priority], &t->queue_node);
run_queue_bitmap |= (1<<t->priority);
}
其中static struct list_node run_queue[NUM_PRIORITIES];  #define NUM_PRIORITIES 32
可以run_queue是一个数组,每个优先级对应数组中的一样。其中每一项又是一个list.
thread_resume 在把这个thread 放到run_queue后,继续调用thread_yield 来运行
void thread_yield(void)
{
#if THREAD_CHECKS
ASSERT(current_thread->magic == THREAD_MAGIC);
ASSERT(current_thread->state == THREAD_RUNNING);
#endif


enter_critical_section();


#if THREAD_STATS
thread_stats.yields++;
#endif


/* we are yielding the cpu, so stick ourselves into the tail of the run queue and reschedule */
current_thread->state = THREAD_READY;
current_thread->remaining_quantum = 0;
insert_in_run_queue_tail(current_thread);
thread_resched();


exit_critical_section();
}
这个函数将当前正在运行的thread的状态设成THREAD_READY,然后调用insert_in_run_queue_tail将
当前thread 插入到run_queue 的最后面
然后调用thread_resched 来进程thread 切换
void thread_resched(void)
{
thread_t *oldthread;
thread_t *newthread;


oldthread = current_thread;


int next_queue = HIGHEST_PRIORITY - __builtin_clz(run_queue_bitmap) - (32 - NUM_PRIORITIES);
//dprintf(SPEW, "bitmap 0x%x, next %d\n", run_queue_bitmap, next_queue);


newthread = list_remove_head_type(&run_queue[next_queue], thread_t, queue_node);


if (list_is_empty(&run_queue[next_queue]))
run_queue_bitmap &= ~(1<<next_queue);


newthread->state = THREAD_RUNNING;


if (newthread == oldthread)
return;


/* set up quantum for the new thread if it was consumed */
if (newthread->remaining_quantum <= 0) {
newthread->remaining_quantum = 5; // XXX make this smarter
}




/* do the switch */
oldthread->saved_critical_section_count = critical_section_count;
current_thread = newthread;
critical_section_count = newthread->saved_critical_section_count;
arch_context_switch(oldthread, newthread);
}


通过list_remove_head_type 异常并返回在run_queue 头部的thread,由于这次切换的时候是找
优先级高的thread的运行,因此如果当前还有比我们优先级高的thread,可能这次运行的不是我们前面
新建的thread
int next_queue = HIGHEST_PRIORITY - __builtin_clz(run_queue_bitmap) - (32 - NUM_PRIORITIES);
将这个thread的状态切换成newthread->state = THREAD_RUNNING
最后调用arch_context_switch 来进行thread 切换
void arch_context_switch(thread_t *oldthread, thread_t *newthread)
{
// dprintf("arch_context_switch: old %p (%s), new %p (%s)\n", oldthread, oldthread->name, newthread, newthread->name);
arm_context_switch(&oldthread->arch.sp, newthread->arch.sp);
}
由于当前cpu是arm,因此调用arm_context_switch来切换
/* context switch frame is as follows:
* ulr
* usp
* lr
* r11
* r10
* r9
* r8
* r7
* r6
* r5
* r4
*/
/* arm_context_switch(addr_t *old_sp, addr_t new_sp) */
FUNCTION(arm_context_switch)
/* save all the usual registers + user regs */
/* the spsr is saved and restored in the iframe by exceptions.S */
sub r3, sp, #(11*4) /* can't use sp in user mode stm */
mov r12, lr
stmia r3, { r4-r11, r12, r13, r14 }^

/* save old sp */
str r3, [r0] 


/* clear any exlusive locks that the old thread holds */
#if ARM_ISA_ARMV7
/* can clear it directly */
.word 0xf57ff01f // clrex
#elif ARM_ISA_ARMV6
/* have to do a fake strex to clear it */
ldr r0, =strex_spot
strex r3, r2, [r0]
#endif


/* load new regs */
ldmia r1, { r4-r11, r12, r13, r14 }^
mov lr, r12 /* restore lr */
add sp, r1, #(11*4)     /* restore sp */
bx lr

其实现比较简单就是保存当前thread的寄存器,然后将新thread的寄存器从stack中load到寄存器中,并执行bx lr 跳到新thread来运行

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

thread_create 和 thread_resume 的相关文章

  • python稳健性检验_有哪些比较好的做异常值检测的方法?

    最近很多小伙伴都比较关注异常值检测的方法 接下来小编就为大家介绍几种 希望能帮到大家 摘要 本文介绍了异常值检测的常见四种方法 分别为Numeric Outlier Z Score DBSCA以及Isolation Forest 在训练机器
  • 算法导论 第三节 分治法

    分治法 1 分 把一个大问题分成若干个小问题 即原问题的n变小 2 治 递归的解决每一个子问题 然后把这些子问题的解合并成整个大问题的解 归并排序 1 一分为二 2 递归的对每一个子数组进行排序 3 合并 线性的n时间内就可以完成 归并排序
  • vscode修改npm镜像源

    npm install g cnpm registry https registry npm taobao orgnpm install g cnpm registry https registry npm taobao org npm c
  • 内核空间和应用空间的数据拷贝(copy_to_user & copy_from_user)

    1 copy to user copy from user long copy to user void user to const void from unsigned long n long copy from user void to
  • 【C++学习笔记(五十一)】之Qt中的信号和槽机制

    一 信号和槽机制 信号和槽机制分为信号和槽函数 用于处理事件 当某个事件发生时 比如说某个按钮被点击后 它就会发出一个信号 signal 如果有对象对这个信号感兴趣 那么它就会使用连接 connect 函数 将该信号与自己的一个槽函数 sl
  • ubuntu 18.04安装pycharm及编译环境配置

    PyCharm介绍 PyCharm是一种Python IDE 其带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具 比如 调试 语法高亮 Project管理 代码跳转 智能提示 自动完成 单元测试 版本控制等等 此外 该ID
  • 网络编程六--UDP服务器客户端

    写在前面 UDP User Datagram Protocol 称为用户数据报协议 是一种无连接的传输协议 UDP的主要应用在即使丢失部分数据 也不影响整体效果的场景 例实时传输视频或音频时 即使丢失部分数据 也不会影响整体效果 只是会有轻
  • 74-Maven的简单介绍和使用(70-73是项目的修改和创建)

    Maven 专家 管理项目 1 理解Maven 在以前的项目编写中 jar包管理令人头疼 SSM框架 30 的jar包 所以在项目的发展中 产生一系列的新技术Maven Gradle 高新 Maven项目对象模型 可以通过一小段的描述信息来
  • 【Python】数据加密解密技术

    Python如何加密解密 感兴趣的小伙伴可以举一下脚 我看看有多少 咳咳咳 正式开始了 今天给大家分享的是Python如何加密解密 感兴趣的小伙伴要认真学起来 前言 加密算法主要分为 哈希算法 对称加密算法 非对称加密算法 哈希算法 MD5
  • Hostname/IP doesn't match certificate's altnames

    背景 一直用Docker Toolbox on VirtualBox在Windows上开发 创建的boot2docker镜像IP地址是192 168 99 100 这两天因为工作需要 想装一个minikube 安装的时候没有启动Docker
  • JavaSE复习:集合

    一方面 面向对象语言对事物的体现都是以对象的形式 为了方便对多个对象的操作 就要对对象进行存储 另一方面 使用Array存储对象方面具有一些弊端 而Java 集合就像一种容器 可以动态地把多个对象的引用放入容器中 集合与数组的比较 首先说下
  • Web3.0是什么?带你解析Web3.0

    有人还在研究什么是元宇宙和NFT 那个概念已经过时了 据说现在流行的是Web3 0和DAO 如果你只想了解关于Web3 0的观点 那么先简明扼要的告诉你 Web3 0是未来 但就2022年人类科技水平的发展来看 你目前接触到的 向你兜售通过
  • Ubuntu最大连接数

    使用ulimit n查看连接数或ulimit a查看详细信息 1 配置 etc security limits conf sudo vim etc security limits conf 文件尾追加 hard nofile 40960 s
  • pagehelper源码分析

    pagehelper不用说 只要是用过的就会爱上他 Maven依赖
  • 最大降雨量

    import os import sys 请在此输入您的代码 第四周的降雨量最大 1 2 3 46 47 48 49 4 5 6 42 43 44 45 7 8 9 38 39 40 41 10 11 12 34 35 36 37 13 1
  • C#与C++数据类型对应表

    C 调用DLL文件时参数对应表 Wtypes h 中的非托管类型 非托管 C 语言类型 托管类名 说明 HANDLE void System IntPtr 32 位 BYTE unsigned char System Byte 8 位 SH
  • Shopify开发入门-前端保姆级教程

    Shopify开发入门 前端保姆级教程 本文旨在介绍Shopify开发入门 环境 配置等 帮助开发者配置环境 了解各个开发模式的区别及用途 已有Shopify开发经验者可退出 以免浪费你的宝贵时间 本文5k字 图片 链接 代码块较多 请耐心
  • OSPF的防环机制

    文章目录 域间防环 域内防环 有向图转化 有向图的画法 示例 SPF算法 OSPF将整个OSPF域划分为多个区域 区域内部通过拓扑信息计算路由 区域间传递路由信息 实现全网可达 OSPF防环机制主要是体现在域内防环和域间防环 域间防环 OS
  • 并发锁分析

    锁 为什么加锁 并发会造成数据混乱 事务 原子性a 一致性c 隔离性i 持久性d 加锁的影响和优化点 线程切换的开销 缓存命中率 加锁失败会进行线程切换 用户态和内核态的切换开销 栈的切换 寄存器切换 synchronized重量锁的实现是

随机推荐

  • 管螺纹如何标注_螺纹基础知识,搞机械的必须懂这些

    螺纹是零件上常见的一种结构 它被广泛地用于零件之间的连接 也可以起传递运动和动力的作用 主要介绍国家标准对螺纹的结构 尺寸 画法和标注的规定 一 螺纹种类 按牙型可分为三角形 梯形 矩形 锯齿形和圆弧螺纹 按螺纹旋向可分为左旋和右旋 按螺旋
  • 基于CEEMDAN集合经验模态分解算法Python程序

    基于CEEMDAN集合经验模态分解算法Python程序 可用于时间序列和其他领域 特色 1 基于Python 2 数据从excel文件中读取 更换简单 全部完整的代码 保证可以运行的代码看这里 http t csdn cn obJlChtt
  • springboot整合quartz项目使用(含完整代码)

    前言 quartz是一个定时调度的框架 就目前市场上来说 其实有比quartz更优秀的一些定时调度框架 不但性能比quartz好 学习成本更低 而且还提供可视化操作定时任务 例如xxl Job elastic Job这两个算是目前工作中使用
  • 高并发情况下修改系统参数

    单进程最大打开文件数限制 一般的发行版 限制单进程最大可以打开1024个文件 这是远远不能满足高并发需求的 调整过程如下 在 号提示符下敲入 ulimit n 65535 限制修改失败了 会显示 Operationnotpermitted
  • pandas DataFrame数据转为list

    首先使用np array 函数把DataFrame转化为np ndarray 再利用tolist 函数把np ndarray 转为list 示例代码如下 coding utf 8 import numpy as np import pand
  • 仪表识别之数字表识别

    转自 https blog csdn net huneng1991 article details 82049207 这篇文章讲述了仪表上的数字表的识别 看图片效果还是挺好的 这里记录一下备用 2 识别检测方法 这篇文章主要用的方法是机器学
  • “猜数字“游戏,系统随机生成一个[1,100]的数字,由用户输入数字后,计算机提示输入数字“偏大”、“偏小”,并记录猜数次数

    import java util Scanner public class Demo public static void main String args TODO Auto generated method stub Scanner i
  • [C语言]分支语句:if语句、switch语句

    分支语句也称为选择结构 条件判断语句 顾名思义 要么选择A 要么选择B 或选择其他的一种结构 在c语言中 常见的分支语句分别有 if语句和switch语句 目录 1 if语句 1 1if语句的结构 1 2if语句的注意点 2 switch语
  • 【MATLAB】rem和mod函数的区别

    求整数x y的余数 rem x y 求模 mod x y 如果x和y的符号相同 同为 同为 那么rem x y mod x y 正数与正数 负数与负数 取整结果两个函数效果一样 如果x和y的符号相反 那么mod x y rem x y y
  • 存储过程的概念,函数与存储过程的区别

    存储过程 为了完成特定功能的sql语句集进行编译优化后 存储在数据库服务器中 用户通过指定存储过程的名字来调用执行 区别 本质上没有区别 1 存储过程作为一个独立部分 函数可以作为查询语句的一个部分 2 存储过程功能较为复杂 函数功能针对性
  • Linux系统下安装Python爬虫环境+模拟浏览器插件

    一 服务器版本 Centos7以上版本 二 配置python环境 1 安装依赖包 yum y install gcc gcc c yum y install zlib zlib devel yum y install bzip2 bzip2
  • 如何通过gradle来导入jar包

    很多android项目在lib文件夹下看不到任何的jar包 但是项目中确实导入了很多的第三方jar包 这里我们来看看androidstudio通过gradle来导入jar包的方法 首先我们需要进入ProjectStructure界面 打开这
  • C8051 不能写数据

    问题 使用C8051f520芯片 在线调试发现不能给变量赋值 解决 芯片ram只有256B 我在keil设置了pdata 改成data就行了 网友资料显示 pdATa 外部扩展RAM的低256个字节 地址出现在A0 A7的上时读写 用mov
  • ipad未能与itunes连接到服务器,为什么无法连接到iTunes Store?iPhone/iPad解决方法

    一些用户在使用iPhone时 偶尔会发现在登录Apple ID或者是在Apple Store中下载软件时 会显示无法连接到iTunes Store 出现这个提示 也就无法在Apple Store中进行相关操作了 那么 大家知道为什么无法连接
  • Eigen库中vector.transpose()函数什么意思

    在使用Eigen库时 我们阅读源码的时候可能看到在输出 显示 一个向量时 有如下表示形式 定义一个向量 Vector3d p2 打印该向量 cout lt lt p2 lt lt endl 列向量显示 cout lt lt p2 trans
  • 【2D标注】cvat-canvas添加标尺线

    一 场景概述 在使用cvat canvas做2D标注开发时 有时我们需要对2D图形添加一些标尺线 例如前方距离当前摄像头的距离标尺 这时候我们需要添加标尺线 基于cvat canvas现有的框架设计模式 实现逻辑如下 在canvasView
  • 16-4_Qt 5.9 C++开发指南_Qt 应用程序的发布

    文章目录 1 应用程序发布方式 2 Windows 平台上的应用程序发布 1 应用程序发布方式 用 Qt 开发一个应用程序后 将应用程序提供给用户在其他计算机上使用就是应用程序的发布 应用程序发布一般会提供一个安装程序 将应用程序的可执行文
  • 取消idea双击shift时出现的搜索框

    快捷键 Ctrl Shift A 有可能没反应 Help gt Find Action 输入registry 选择第一个 找到ide suppress double click handler 勾选它 双击shift不会再弹出搜索框
  • reportlab 使用中文报错 reportlab.pdfbase.ttfonts.TTFError: Not a recognized TrueType font

    使用reportlab 使用中文报错过程中 注册了 simsun 字体 然后就报这个错误 reportlab pdfbase ttfonts TTFError Not a recognized TrueType font version 0
  • thread_create 和 thread_resume

    在lk中我们一般通过thread create 来新建一个thread 但这个thread 是THREAD SUSPENDED 必须要调用thread resume 才能开始运行 enum thread state THREAD SUSPE