linux lock函数,Linux lock_kernel()函数的分析。
这只是暂时的记录,以后会把它归类到start_kernel()函数的分析。在分析之前,我先要说说几个概念。
内核抢占:在2.6内核加入了抢占的能力,就是说调度程序有办法在一个内核级的任务正在执行的时候从新调度。但是必须要保证重新调度要安全,这样就要靠一把锁来保证了。
计数器(thread_info.[reempt_count):其实也可以把他叫成锁的,它的初值定义为0,每当使用锁的时候加1.
好了,我们现在来看看lock_kernel()的具体代码啦(2.6.10版本的)
#ifndef __LINUX_SMPLOCK_H
#define __LINUX_SMPLOCK_H
#include
#include
#include
#ifdef CONFIG_LOCK_KERNEL
#define kernel_locked() (current->lock_depth >= 0)
extern int __lockfunc get_kernel_lock(void);
extern void __lockfunc put_kernel_lock(void);
/*
* Release/re-acquire global kernel lock for the scheduler
*/
#define release_kernel_lock(tsk) do { /
if (unlikely((tsk)->lock_depth >= 0)) /
put_kernel_lock(); /
} while (0)
/*
* Non-SMP kernels will never block on the kernel lock,
* so we are better off returning a constant zero from
* reacquire_kernel_lock() so that the compiler can see
* it at compile-time.
*/
#ifdef CONFIG_SMP
#define return_value_on_smp return
#else
#define return_value_on_smp
#endif
static inline int reacquire_kernel_lock(struct task_struct *task)
{
if (unlikely(task->lock_depth >= 0))
return_value_on_smp get_kernel_lock();
return 0;
}
extern void __lockfunc lock_kernel(void) __acquires(kernel_lock);
extern void __lockfunc unlock_kernel(void) __releases(kernel_lock);
#else
#define lock_kernel() do { } while(0)
#define unlock_kernel() do { } while(0)
#define release_kernel_lock(task) do { } while(0)
#define reacquire_kernel_lock(task) 0
#define kernel_locked() 1
#endif /* CONFIG_LOCK_KERNEL */
#endif /* __LINUX_SMPLOCK_H */
这个是对lock_kernel()函数的宏定义,#ifdef CONFIG_LOCK_KERNEL这里判断是否支持内核锁,如果不支持的话,lock_kernel就不做任何事情,我们来具体分析一下当配置了CONFIG_LOCK_KERNEL时lock_kernel()做些什么!我们直接看看这行代码extern void __lockfunc lock_kernel(void) __acquires(kernel_lock);
void __lockfunc lock_kernel(void)
{
int depth = current->lock_depth+1;
if (likely(!depth))
__lock_kernel();
current->lock_depth = depth;
}
这里可以看到有个标志lock_depth存在,对于这个标志,它的初始值为-1,如果自加后发现其实为0时,说明kernel_flag这个内核全局锁成功被这个进程所占有(current->lock_depth+1这个意味着0号进程的init_task.lock_depth加1)。接着就来到了__lock_kernel();这里的调用。我们来展开看看它的代码吧!
#ifdef CONFIG_PREEMPT
static inline void __lock_kernel(void)
{
preempt_disable();
if (unlikely(!_raw_spin_trylock(&kernel_flag))) {
/*
* If preemption was disabled even before this
* was called, there's nothing we can be polite
* about - just spin.
*/
if (preempt_count() > 1) {
_raw_spin_lock(&kernel_flag);
return;
}
/*
* Otherwise, let's wait for the kernel lock
* with preemption enabled..
*/
do {
preempt_enable();
while (spin_is_locked(&kernel_flag))
cpu_relax();
preempt_disable();
} while (!_raw_spin_trylock(&kernel_flag));
}
}
#else
/*
* Non-preemption case - just get the spinlock
*/
static inline void __lock_kernel(void)
{
_raw_spin_lock(&kernel_flag);
}
#endif
看到一上来就对CONFIG_PREEMPT进行判断,这个是判断内核是否支持抢占。如果是抢占大的话,就执行上面的__lock_kernel(),我们来看看第一行语句, preempt_disable();
#define preempt_disable() /
do { /
inc_preempt_count(); /
barrier(); /
} while (0)
我们来看看inc_preempt_count();这个函数是什么内容。
#define inc_preempt_count() /
do { /
preempt_count()++; /
} while (0)
我再进一步再往里看看。
#define preempt_count() (current_thread_info()->preempt_count)
终于看到了是对current_thread_info()->preempt_count自增。(在start_kernel来说就是init_thread_info.preempt_count加1)这样我们又回到了__lock_kernel函数了,对于下面代码的分析不太清楚,这里就不进行讲解了。接着我们来到了没有进行宏定义的else部分。
#else
/* * Non-preemption case - just get the spinlock */static inline void __lock_kernel(void){ _raw_spin_lock(&kernel_flag);}#endif这里就是简单的对kernel_flag这个全局变量加锁。好了,到这里我们算是把lock_kernel()分析了一遍了。其实总的来说,对于有抢占的,我们就不用用kernel_flag这个全局变量。这个全局变量其实是在2.4内核没有抢占功能内核的代码使用的。对于lock_kernel的分析就只是理解这么多,以后了解了跟多再来完善!
linux lock函数,Linux lock_kernel()函数的分析。相关推荐
- linux C函数之strdup函数分析【转】
本文转载自:http://blog.csdn.net/tigerjibo/article/details/12784823 linux C函数之strdup函数分析 一.函数分析 1.函数原型: [c ...
- linux EHCI DRIVER之中断处理函数ehci_irq()分析(一)
EHCI 的 interrupt 在 HCD 中被分为了 6 种类型,如下宏定义: /* these STS_* flags are also intr_enable bits (USBINTR) * ...
- linux C函数之strdup函数分析
本文转载自:http://blog.csdn.net/tigerjibo/article/details/12784823 linux C函数之strdup函数分析 一.函数分析 1.函数原型: #i ...
- linux timerfd_settime函数,Linux的timerfd分析
timerfd是Linux为用户程序提供的一个定时器接口.这个接口基于文件描述符,所以能够被用于select/poll的应用场景. 1.使用方法 timerfd提供了如下接口供用户使用 timerfd ...
- linux waitpid实例,【Linux】僵尸进程,孤儿进程以及wait函数,waitpid函数(有样例,分析很详细)...
本文内容: 1.僵尸进程,孤儿进程的定义,区别,产生原因,处理方法 2.wait函数,waitpid函数的分析,以及比较 背景:由于子进程的结束和父进程的运行是一个异步的过程,即父进程永远无法预测子进 ...
- brk函数 linux,brk和sbrk及内存分配函数相关-linux+内存
brk和sbrk主要的工作是实现虚拟内存到内存的映射.在GNUC中,内存分配是这样的: 每个进程可访问的虚拟内存空间为3G,但在程序编译时,不可能也没必要为程序分配这么大的空间,只分配并不大的数据段空 ...
- Linux动态库加载函数dlopen源码梳理(一)
下载了libc的源码,现在就开始libc源码的学习,最近了解到了linux动态库的相关知识,那么就从linux动态库加载函数dlopen进行梳理学习吧. 如果还没下载libc源码,可通过 https: ...
- Linux 下调用UEFI的函数
Linux 下调用UEFI的函数 摘要 Linux 调用UEFI function 时候调用约定的转换 64bits calling convention Microsoft calling conv ...
- Linux系统函数之IO函数
技术交流 QQ 群:1027579432,欢迎你的加入! 欢迎关注我的微信公众号:CurryCoder的程序人生 1.标准C库IO函数工作流程 IO缓冲区的作用? 大部分硬盘都是机械硬盘,读取寻道时间 ...
最新文章
- Torque2D MIT 实战记录: 塔防进度(3)
- 进程互斥的要求与实现方法
- mysql修改虚拟列属性失败_mysql虚拟列(Generated Columns)及JSON字段类型的使用
- linux io读写次数 oid,Oidiomycosis in Porto Rico.
- 2017/Province_Java_B/4/魔方状态
- 技术人员究竟应该如何保持快速学习的能力?
- 【在路上4】在派件时效分析中剥离有效因素
- python(1) - 数据类型和变量
- 第十节:基于MVC5+Unity+EF+Log4Net的基础结构搭建
- 隐式类型转换中显式申明的非必要性
- object转换成Integer
- mybatis分页插件 pagehelper点击末页跳到第8页
- 完整计算器java代码_计算器java代码
- Excel VBA打开IE浏览器的网页
- 为何我工作十年,内心仍无比恐慌(腾讯产品总监曹菲)
- Linux 系统管理 : last 命令详解
- MyBatis-Plus分页查询
- 制作kali live usb启动盘-win10下
- 企业申请AAA企业信用等级认证的4大好处
- android手机应用字体颜色代码,安卓手机字体颜色修改教程
热门文章
- SQL SERVER数据页checksum校验算法
- 一道简单的面试题:竟然有90%的程序员不能把这个算法完全写正确。。。
- 【leetcode】394. Decode String
- linux 脚本判断一个目录不存在
- 老男孩教育每日一题-2017年4月28日- MySQL主从复制常见故障及解决方法?
- 原码,反码,补码,移码的概念以及各自的用途和优点
- js学习笔记1---使用方法
- “.中国”域名总量跌至25.9万个:9月份净减2,249个
- 表格排序——tablesorter.js使用(支持中文排序)
- postgresql-9.3.0级联复制搭建及简单配置