`
colorlife
  • 浏览: 130200 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

spinlock中不允许休眠调度 转

阅读更多

http://blog.csdn.net/unbutun/archive/2010/07/15/5738313.aspx

 

spinlock的使用,由于开始时不太了解,开发内核模块时,出了问题,调试了好多天,后来才发现,原来在lock的代码里,调用的内核api中,执行了schedule!!!!

转发这篇文章以此来警醒我的无知

 

 

Linux系统提供的内核同步机制有很多种。 
spinlock只是一种选择, 并不是所有同步的地方都用spinlock. 
通常它适用于对内核(包括模块)的一些全局数据结构的访问。 
spinlock中所保护的codes最好能迅速完成,同时释放该锁。 
在无法获得该锁的情况下,内核不会切换,而是不断地尝试, 这也是spinlock名字的由来, 
也正因为此,所以spinlock中的代码不能有schedule()之类的放弃CPU的代码,也不会能被抢占,但可以有中断(下面说明)。因为如果正好调度到另一个kernel path也需要这个锁,整个系统将形成死锁。 
如果有中断服务也会申请该spinlock,那么请用spinlock_irqsave()的API,把中断关掉,不然还是会死锁。

 

5.5.2. 自旋锁和原子上下文

想象一会儿你的驱动请求一个自旋锁并且在它的临界区里做它的事情. 在中间某处, 你的驱动失去了处理器. 或许它已调用了一个函数( copy_from_user, 假设) 使进程进入睡眠. 或者, 也许, 内核抢占发威, 一个更高优先级的进程将你的代码推到一边. 你的代码现在持有一个锁, 在可见的将来的如何时间不会释放这个锁. 如果某个别的线程想获得同一个锁, 它会, 在最好的情况下, 等待( 在处理器中自旋 )很长时间. 最坏的情况, 系统可能完全死锁.

大部分读者会同意这个场景最好是避免. 因此, 应用到自旋锁的核心规则是任何代码必须, 在持有自旋锁时, 是原子性的. 它不能睡眠; 事实上, 它不能因为任何原因放弃处理器, 除了服务中断(并且有时即便此时也不行)

内核抢占的情况由自旋锁代码自己处理. 内核代码持有一个自旋锁的任何时间, 抢占在相关处理器上被禁止. 即便单处理器系统必须以这种方式禁止抢占以避免竞争情况. 这就是为什么需要正确的加锁, 即便你从不期望你的代码在多处理器机器上运行.

在持有一个锁时避免睡眠是更加困难; 很多内核函数可能睡眠, 并且这个行为不是都被明确记录了. 拷贝数据到或从用户空间是一个明显的例子: 请求的用户空间页可能需要在拷贝进行前从磁盘上换入, 这个操作显然需要一个睡眠. 必须分配内存的任何操作都可能睡眠. kmalloc 能够决定放弃处理器, 并且等待更多内存可用除非它被明确告知不这样做. 睡眠可能发生在令人惊讶的地方; 编写会在自旋锁下执行的代码需要注意你调用的每个函数.

这有另一个场景: 你的驱动在执行并且已经获取了一个锁来控制对它的设备的存取. 当持有这个锁时, 设备发出一个中断, 使得你的中断处理运行. 中断处理, 在存取设备之前, 必须获得锁. 在一个中断处理中获取一个自旋锁是一个要做的合法的事情; 这是自旋锁操作不能睡眠的其中一个理由. 但是如果中断处理和起初获得锁的代码在同一个处理器上会发生什么? 当中断处理在自旋, 非中断代码不能运行来释放锁. 这个处理器将永远自旋.

避免这个陷阱需要在持有自旋锁时禁止中断( 只在本地 CPU ). 有各种自旋锁函数会为你禁止中断( 我们将在下一节见到它们 ). 但是, 一个完整的中断讨论必须等到第 10 章了.

关于自旋锁使用的最后一个重要规则是自旋锁必须一直是尽可能短时间的持有. 你持有一个锁越长, 另一个进程可能不得不自旋等待你释放它的时间越长, 它不得不完全自旋的机会越大. 长时间持有锁也阻止了当前处理器调度, 意味着高优先级进程 -- 真正应当能获得 CPU 的 -- 可能不得不等待. 内核开发者尽了很大努力来减少内核反应时间( 一个进程可能不得不等待调度的时间 )在 2.5 开发系列. 一个写的很差的驱动会摧毁所有的进程, 仅仅通过持有一个锁太长时间. 为避免产生这类问题, 重视使你的锁持有时间短.

 

 

如果只要和其他CPU 互斥,就要用spin_lock/spin_unlock,如果要和irq及其他CPU互斥,就要用 
spin_lock_irq/spin_unlock_irq,如果既要和irq及其他CPU互斥,又要保存 EFLAG的状态,就要用spin_lock_irqsave/spin_unlock_irqrestore,如果要和bh及其他CPU互斥,就要用spin_lock_bh/spin_unlock_bh,如果不需要和 其他CPU互斥,只要和irq互斥,则用local_irq_disable/local_irq_enable, 如果不需要和其他CPU互斥,只要和bh互斥,则用local_bh_disable/local_bh_enable, 等等。值得指出的是,对同一个数据的互斥,在不同的内核执行路径中, 
所用的形式有可能不同

 

Mutex属于sleep-waiting类型的锁。

而Spin lock则属于busy-waiting类型的锁

分享到:
评论

相关推荐

    linux内核调度与spinlock的相互关系.docx

    linux内核调度与spinlock的相互关系.docx

    嵌入式系统/ARM技术中的spinlock与linux内核调度的关系

     自旋锁在同一时刻只能被最多一个内核任务持有,所以一个时刻只有一个线程允许存在于临界区中。这点可以应用在多处理机器、或运行在单处理器上的抢占式内核中需要的锁定服务。  二、信号量简介  这里也介绍下...

    spinlock_test.c

    在实际使用中,在关抢占的情况下调用schedule,内核允许会报bug 2.3.5.3 自旋锁变种分析 自旋锁变种使用的原则就是谁抢CPU就关谁 ① 何时关中断 如果除了当前的内核任务,还有中断处理程序会访问临界区,则需要关...

    spinlock與linux內核調度的關係

    關於自旋鎖用法介紹的文章,已經有很多,但有些細節的地方點的還不夠透。我這裏就把我個人認為大家容易有疑問的地方拿出來討論一下。 一、自旋鎖(spinlock)簡介

    MCS spinlock的Linux内核模块实现.pdf

    MCS spinlock的Linux内核模块实现.pdf

    嵌入式系统/ARM技术中的分析Linux中Spinlock在ARM及X86平台上的实现

    本文主要以2.6.22.6内核分析Linux中spinlock在ARM及X86平台上的实现(不同版本的内核实现形式会有一些差异,但原理大致相同)。此处默认大家已经熟悉了spinlock的使用,重点解释容易引起迷惑的体系结构相关的实现...

    spinlock:Go和内联汇编器中的Spinlock实现

    Go和内联汇编程序中的Spinlock实现。 概述 程序包自旋锁提供了汇编中低级自旋锁的实现。 此外,它还提供了基于内置原子的实现的后备功能。 在我的私人笔记本电脑上,基准测试结果如下。 所测量的时间是墙上的时间。...

    cas实现spinlock

    cas实现spinlock

    linux系统中基于自旋锁的进程调度的实现

    linux系统中基于自旋锁的进程调度的实现, 有代码和详细的文档说明,自旋锁(spinlock) 是用C和汇编指令实现的,有助于了解linux系统 内核的加锁机制。 很不错的哦。。。

    SpinLock.cpp

    为了效率,不使用C++语言提供的Mutex互斥量,而使用不使用线程被阻塞的方式,即所谓的自旋锁,这是自旋锁的一种实现方式,使用C++11的原子变量,不用锁机制,实现的一种无锁的自旋锁

    LINUX的调度和时钟中断处理代码的分析

    根据操作系统课程设计指导书所提供的基础知识,分析文件kernel/sched.c 和include/asm-i386/spinlock.h 中关于Linux的调度和时钟中断的代码,了解一个LINUX操作系统的进程调度以及时钟中断的处理方式,得到相关的...

    spinlock.rs:Rust 中的自旋锁实现

    Rust 中的自旋锁实现 建造 运行cargo build 用法 该库实现了 Reader/Writer 锁。 锁定共享读取访问的自旋锁时,您将获得对受保护数据的引用,而锁定独占写入访问时,您将获得可变引用。 extern crate spinlock; ...

    Linux操作系统内核抢占补丁的基本原理

    CPU在内核中运行时并不是处处不可抢占的,内核中存在一些空隙,在这时进行抢占是安全的,内核抢占补丁的基本原理就是将SMP可并行的代码段看成是可以进行内核抢占的区域。2.4内核正好细化了多CPU下的内核线程同步机构...

    spinlock:自旋锁的不同实现

    来自Lockless Inc 的这篇文章的各种自旋锁实现。 我做了一些修改以使每个实现自包含并提供一个基准脚本。 代码依赖 GCC 的内置函数进行原子内存访问。 注意:可伸缩性是通过避免共享和争用来实现的,而不是通过可...

    mips 多核 互斥 Spinlock 底层实现

    Linux 在推出了 Multi-Processing 之后,多核处理器的并行处理的能力得到了极大的发挥,但是这同时也带来了一个问题,并行执行势必就存在多个核同时访问共享资源的情况,如何能够保证一个核在访问共享资源时,该共享...

    Linux系统内核抢占补丁的原理

    Linux 2.4内核正好细化了多CPU下的内核线程同步机构,对不可并行的指令块用spinlock和rwlock作了细致的表示,该补丁的实现可谓水到渠成。具 体的方法就是在进程的任务结构上增加一个preempt_count变量作为内核抢占锁...

    cvmx-spinlock.rar_V2

    Spinlocks for Octeon for Linux v2.13.6.

    makefile编写规则

    raw_spinlock_t raw_lock; #if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP) unsigned int break_lock; #endif #ifdef CONFIG_DEBUG_SPINLOCK unsigned int magic, owner_cpu; void *owner;

    操作系统实验的源代码

    实验1 进程与线程 实验2 Linux系统调用 实验3 字符设备 实验4 基于SpinLock的进程调度

    spinlock:Go的自旋锁实现

    自旋锁 Go的实现。 它与共享相同的接口,旨在用于同步异常短暂的操作。安装 go get -u github.com/tidwall/spinlock接触乔希·贝克执照spinlock源代码在MIT下可用。

Global site tag (gtag.js) - Google Analytics