linux 3.10中完成量的使用
完成量是基于等待队列设计的,所以显然不能在中断上下文使用完成量。
struct completion {
unsigned int done;
wait_queue_head_t wait;
};
我们来看一个使用完成量的经典例子:
struct kthread_create_info
{
/* Information passed to kthread() from kthreadd. */
int (*threadfn)(void *data);
void *data;
int node; /* Result passed back to kthread_create() from kthreadd. */
struct task_struct *result;
struct completion done; struct list_head list;
};
在创建内核线程的例子中,我们使用了一个kthread_create_info结构来封装了一个完成量:
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
void *data, int node,
const char namefmt[],
...)
{
struct kthread_create_info create; create.threadfn = threadfn;---------------要创建的线程的主函数
create.data = data;
create.node = node;
init_completion(&create.done);------------动态初始化完成量 spin_lock(&kthread_create_lock);
list_add_tail(&create.list, &kthread_create_list);-------------加入链表,相当于把请求挂在一个双向循环链表中
spin_unlock(&kthread_create_lock); wake_up_process(kthreadd_task);-----------唤醒处理完成量的内核线程,来处理我们发送的请求
wait_for_completion(&create.done);--------等待完成,这个在等待完成量的期间,会导致本进程睡眠
。。。。。。。
如上代码是提交请求的一侧,那么,处理请求的一侧是怎么完成该任务,并通知到请求方呢?
int kthreadd(void *unused)
{
struct task_struct *tsk = current; /* Setup a clean context for our children to inherit. */
set_task_comm(tsk, "kthreadd");
ignore_signals(tsk);
set_cpus_allowed_ptr(tsk, cpu_all_mask);
set_mems_allowed(node_states[N_MEMORY]); current->flags |= PF_NOFREEZE; for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (list_empty(&kthread_create_list))
schedule();
__set_current_state(TASK_RUNNING); spin_lock(&kthread_create_lock);
while (!list_empty(&kthread_create_list)) {
struct kthread_create_info *create; create = list_entry(kthread_create_list.next,
struct kthread_create_info, list);--------------取出请求
list_del_init(&create->list);------------将请求从链表隔离
spin_unlock(&kthread_create_lock);-------解锁,这个锁保证加入请求和解除请求的串行化 create_kthread(create);------------------创建线程 spin_lock(&kthread_create_lock);
}
spin_unlock(&kthread_create_lock);
} return ;
}
简单地看,没看到怎么通知请求方,代码其实是在create_kthread中实现的:
static void create_kthread(struct kthread_create_info *create)
{
int pid; #ifdef CONFIG_NUMA
current->pref_node_fork = create->node;
#endif
/* We want our own signal handler (we take no signals by default). */
pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
if (pid < ) {
create->result = ERR_PTR(pid);
complete(&create->done);-------------------通知请求方,一般就是唤醒了
}
}
以上就是使用完成量的经典例子,两个互不干扰的执行流,一个通过wait_for_completion来等待请求完成,一个通过complete,还有complete_all等来通知请求方,完成交互。
除了动态初始化一个完成量,还有一种静态初始化的方式,
static noinline void __init_refok rest_init(void)
{
int pid; rcu_scheduler_starting();
/*
* We need to spawn init first so that it obtains pid 1, however
* the init task will end up wanting to create kthreads, which, if
* we schedule it before we create kthreadd, will OOPS.
*/
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
numa_default_policy();
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);------------创建2号进程,也就是kthradd内核线程
rcu_read_lock();
kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
rcu_read_unlock();
complete(&kthreadd_done);------------唤醒被阻塞的进程
在kthreadd 创建之前,
static noinline void __init kernel_init_freeable(void)
{
/*
* Wait until kthreadd is all set-up.
*/
wait_for_completion(&kthreadd_done);
也就是说,在2号进程,也就是 kthreadd 被创建好之前,1号进程其实是阻塞的。有一个疑问就是,为什么1号进程要等待2号进程呢?因为假设1号进程不等待,那么用户态进程就可能通过
系统调用来获取资源,而如果这些资源是由2号线程或者2号线程的子线程来维护的话,则必然产生oops。所以这个地方的完成量,起的是一个时序的作用。
我们可以看到,内核线程的创建接口,是由 kthreadd 内核线程来完成fork的,
ps -ef |grep -i kthreadd
root 9月15 ? :: [kthreadd]
这个内核线程的pid是2,其他所有的内核线程都是它fork出来的,因为init进程占据了pid 1,所以它的pid是2。
我们假设一下,如果pid 为1的init进程,最终不去执行
if (!run_init_process("/sbin/init") ||
!run_init_process("/etc/init") ||
!run_init_process("/bin/init") ||
!run_init_process("/bin/sh"))
那么它这个时候纯粹还是内核线程,它全部工作在内核态,没有用户态进程的os有没有用呢?
我觉得是有的,没有交互罢了,全部在内核态。恩,如果你把一些任务放在内核里面完成,完全可以不要用户态进程嘛。
linux 3.10中完成量的使用的更多相关文章
- Linux 4.10中两个新特性与我的一段故事
今早5点半起来没有開始写文章,而是去西湾红树林连跑带走折腾了将近20公里.回来后就8点多了...洗了个澡之后坐稳当.開始写一段关于我的故事. 在2014年到2015年期间,我在负责研发一 ...
- Linux驱动 - 多线程之 完成量
Linux 系统提供了一种比信号量更好的同步机制,即完成量(completion ,它用于一个执行单元等待另一个执行单元执行完某事. Linux 系统中与 completion 相关的操作主要有以下 ...
- Linux设备驱动程序 之 完成量
内核编程中常见的一种模式是,在当前线程之外初始化某个活动,然后等待该活动的结束:这个活动可能是,创建一个新的内核线程或者新的用户空间进程.对一个已有进程的某个请求,或者某种类型的硬件动作等: 内核提供 ...
- Linux内核中锁机制之完成量、互斥量
在上一篇博文中笔者分析了关于信号量.读写信号量的使用及源码实现,接下来本篇博文将讨论有关完成量和互斥量的使用和一些经典问题. 八.完成量 下面讨论完成量的内容,首先需明确完成量表示为一个执行单元需要等 ...
- 大话Linux内核中锁机制之完成量、互斥量
大话Linux内核中锁机制之完成量.互斥量 在上一篇博文中笔者分析了关于信号量.读写信号量的使用及源码实现,接下来本篇博文将讨论有关完成量和互斥量的使用和一些经典问题. 八.完成量 下面讨论完成量的内 ...
- linux信号量与完成量
信号量: 是用于保护临界区的一种常用方法,它的使用和自旋锁类似.与自旋锁相同,只有得到信号量的进程才能执行 临界区的代码.但是与自旋锁不同的是,当获取不到信号量时,进程不会原地打转而是进入休眠等 ...
- 〖Linux〗Ubuntu13.10中打开键盘背光灯
刚刚从淘宝上买回一个带有Led背光的键盘(黑爵战神x5 背光升级版): 然后发现在Linux中背光灯并不亮,在Windows中就可以按下Scroll Lock键点亮: 在网上探索了一番,觉得应该可以使 ...
- linux内核同步之信号量、顺序锁、RCU、完成量、关闭中断【转】
转自:http://blog.csdn.net/goodluckwhh/article/details/9006065 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 一信 ...
- TCP/IP协议栈源码图解分析系列10:linux内核协议栈中对于socket相关API的实现
题记:本系列文章的目的是抛开书本从Linux内核源代码的角度详细分析TCP/IP协议栈内核相关技术 轻松搞定TCP/IP协议栈,原创文章欢迎交流, byhankswang@gmail.com linu ...
随机推荐
- 去中心化存储的QoS是什么?
我的前面一篇文章讲到如何做去中化存储,文其中提到了QoS (Quality of Service),那么QoS是什么?为什么QoS那么重要?下面将详细描述. 什么是QoS? 提到QoS,就要先了解Qo ...
- [UE4]扔枪
1.把枪Detach掉:DetachFromActor 3个都选择“Keep World” 2.模拟物理 3.给一个向前的速度 4.切枪,到上一个武器,或者捡起脚底下的武器 注意Get Compone ...
- [UE4]使用蓝图关闭对象的碰撞SetActorEnableCollision
在一个人的身上创建多把枪的时候,由于枪与枪之间重贴会产生碰撞冲突,到时角色控制出现不正常(上下左右行走总是往一个方向移动),这些可以关闭枪支的碰撞:
- mac gcc develop
1:check version gcc -v / g++ -v 2:compile gcc *.c / g++ *.cpp outfile: a.out 3:excute ./a.out ...
- day24类的继承
类的继承1 什么是继承 继承一种新建类的方式,新建的类称之为子类/派生类,被继承的类称之为父类\基类\超类 python中继承的特点: 1. 子类可以遗传/重用父类的属性 ...
- NodeJs安装以及注意事项
1.测试NodeJs是否安装成功 node --version npm -v 配置node的可执行文件路径到环境变量path 2.安装相关环境 npm install express -g npm i ...
- Redis实现分布式锁原理与实现分析
一.关于分布式锁 关于分布式锁,可能绝大部分人都会或多或少涉及到. 我举二个例子: 场景一:从前端界面发起一笔支付请求,如果前端没有做防重处理,那么可能在某一个时刻会有二笔一样的单子同时到达系统后台. ...
- 【Fiddler学习】Fiddler简介和Web抓包应用(转)
一.Fiddler是什么? Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯,设置断点,查看所有的进出Fiddler的数据. Fiddler 要比其 ...
- 对datetime日期类型进行序列化的处理
datetime类型序列化 在工作中遇到从数据库中取出来一个datetime类型的数据,在对其进行序列化的过程中,报错python datetime.datetime is not JSON ser ...
- 自动化运维工具----ansible
ansible是新出现的运维工具是基于Python研发的糅合了众多老牌运维工具的优点实现了批量操作系统配置.批量程序的部署.批量运行命令等功能. 主要模块以及功能: 1 command 2 user ...