一、什么叫抢占

所谓抢占,说白了就是进程切换。

linux的用户空间,进程A在执行中,来(硬?)中断打断A,从中断处理程序返回时,如果有更高优先级进程B在排队的话,那么执行进程B。 用户空间下进程总是可抢占的

在linux的内核空间就不一定了,linux 2.4是不可抢占的,实时性就会降低,如下面这个样子:

二、抢占的API

preempt_enable()  开启抢占

preempt_disable() 禁止抢占

内核中每个进程数据结构里有一个计数器preempt_count

抢占的开启与禁止,操作当前进程的preempt_count

内核在进行进程调度的时候,只要prempt_count为0,内核就可以进行抢占。

struct thread_info {

struct task_struct *task; /* main task structure */

............//省略

int     cpu;              /* cpu we're on */

int     preempt_count;    /* 0 => preemptable,  <0 => BUG */

};

#define preempt_enable() \

do { \

preempt_enable_no_resched(); \

barrier(); \

preempt_check_resched(); \

} while (0)

#define preempt_disable() \

do { \

inc_preempt_count(); \

barrier(); \

} while (0)

#define preempt_enable_no_resched() \

do { \

barrier(); \

dec_preempt_count(); \

} while (0)

#define inc_preempt_count() add_preempt_count(1)

#define dec_preempt_count() sub_preempt_count(1)

#define add_preempt_count(val) do { preempt_count() += (val); } while (0)

#define sub_preempt_count(val) do { preempt_count() -= (val); } while (0)

#define preempt_count() (current_thread_info()->preempt_count)

三、发生抢占的时机

linux进程调度的核心函数是 schedule(),进程调度就是在这里做的。

schedule的调用分为主动调用和被动调用。

主动调用是指内核显示的直接去调用shedule(),如当前进程调用了可休眠函数,里面会调用schedule

被动调用是指在系统调用、中断处理或异常处理结束之后,由相应的回调函数调用schedule

判断完当前进程是否可抢占,才会接着去调用schedule()

只看了看中断返回时schedule被动调用的情况

至于主动调用的地方就太多了,什么进程结束,pause等等,没耐心看了。。。

3.1 从中断返回时

首先是从中断处理程序do_IRQ()返回后,会调用ret_from_except() (看《PowerPC中断相关知识》)

ret_from_except()里要先check一下,判定前面被中断的执行体是运行在用户空间还是内核空间,

在决定返回到用户空间或内核空间

用户空间的话:(现在知道为什么用户空间程序总是可抢占了吧)

ret_from_except

--> user_exc_return

--> do_work

--> 调用 do_signal 和 schedule

内核空间的话:(编译内核时要打开可抢占选项才行)

ret_form_except

--> resume_kernel

--> preempt_schedule_irq

--> schedule

.globl ret_from_except

ret_from_except:

LOAD_MSR_KERNEL(r10,MSR_KERNEL)  //将MSR_KERNEL常量设置到MSR,以禁止外部中断

SYNC                             //Some chip revs have problems here...

MTMSRD(r10)                      //disable interrupts

lwz r3,_MSR(r1)                  //读栈中的MSR[PR],Returning to user mode?

andi. r0,r3,MSR_PR

beq resume_kernel

user_exc_return:                   //r10 contains MSR_KERNEL here

rlwinm r9,r1,0,0,(31-THREAD_SHIFT) //Check current_thread_info()->flags

lwz r9,TI_FLAGS(r9)

andi. r0,r9,(_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NEED_RESCHED)

bne do_work

restore_user:

#ifdef CONFIG_PREEMPT

b restore

resume_kernel:

rlwinm r9,r1,0,0,(31-THREAD_SHIFT) /* check current_thread_info->preempt_count */

lwz r0,TI_PREEMPT(r9)

cmpwi 0,r0,0                       /* if non-zero, just restore regs and return */

bne restore

lwz r0,TI_FLAGS(r9)

andi. r0,r0,_TIF_NEED_RESCHED

beq+ restore

andi. r0,r3,MSR_EE                /* interrupts off? */

beq restore                       /* don't schedule if so */

1: bl preempt_schedule_irq

rlwinm r9,r1,0,0,(31-THREAD_SHIFT)

lwz r3,TI_FLAGS(r9)

andi. r0,r3,_TIF_NEED_RESCHED

bne- 1b

#else

resume_kernel:

#endif /* CONFIG_PREEMPT */

do_work:            /* r10 contains MSR_KERNEL here */

andi.   r0,r9,_TIF_NEED_RESCHED

beq do_user_signal

do_resched:         /* r10 contains MSR_KERNEL here */

ori r10,r10,MSR_EE

SYNC

MTMSRD(r10)     /* hard-enable interrupts */

bl  schedule

recheck:

LOAD_MSR_KERNEL(r10,MSR_KERNEL)

SYNC

MTMSRD(r10)     /* disable interrupts */

rlwinm  r9,r1,0,0,(31-THREAD_SHIFT)

lwz r9,TI_FLAGS(r9)

andi.   r0,r9,_TIF_NEED_RESCHED

bne-    do_reschedandi.   r0,r9,_TIF_SIGPENDING

beq restore_user

do_user_signal:         /* r10 contains MSR_KERNEL here */

asmlinkage void __sched preempt_schedule_irq(void){

struct thread_info *ti = current_thread_info();

BUG_ON(ti->preempt_count || !irqs_disabled());

do {

add_preempt_count(PREEMPT_ACTIVE);

local_irq_enable();

schedule();

local_irq_disable();

sub_preempt_count(PREEMPT_ACTIVE);

barrier();

} while (unlikely(test_thread_flag(TIF_NEED_RESCHED)));

}

asmlinkage void __sched preempt_schedule(void){

struct thread_info *ti = current_thread_info();

//preempt_cout非0的话,就不调用schedule

if (likely(ti->preempt_count || irqs_disabled()))

return;

do {

add_preempt_count(PREEMPT_ACTIVE);

schedule();

sub_preempt_count(PREEMPT_ACTIVE);

barrier();

} while (unlikely(test_thread_flag(TIF_NEED_RESCHED)));

}

#########################################################################################;

内核中的执行路径主要有:

1  用户进程的内核态,此时有进程context,主要是代表进程在执行系统调用等。

还包括,内核中自己的进程,如 ksoftirqd 等等

2  中断或者异常或者自陷等,从概念上说,此时没有进程context,不能进行context switch。

3  bottom_half,从概念上说,此时也没有进程context。

4  同时,相同的执行路径还可能在其他的CPU上运行。

Linux2.6中网络代码中的preempt_enable/disable移到softirqd调用的地方原因是这样的.

一、部分softirq是isr处理之后调用的,

对于这部分代码,由于是在底半处理中运行,必须是是在运行进程系统调用之前返回的.

所以实际上preempt_disable(); preempt_enable();代码对于他们来说是没有意义的.

二、部分softirq是在ksoftirqd的内核线程运行的,

因为这个相当于运行在进程的内核空间,由于软中断都是对中断上半部的继续,

所以这些工作都需要尽快的完成.所以在softirqd运行的时候,禁止了preempt,

这样就可以保证softirq运行完之后才会调度下一个进程,因为softirq里面的所有函数都不会睡眠.

linux 内核 禁止抢占,内核抢占实现(preempt)相关推荐

  1. 【Linux 内核 内存管理】优化内存屏障 ③ ( 编译器屏障 | 禁止 / 开启内核抢占 与 方法保护临界区 | preempt_disable 禁止内核抢占源码 | 开启内核抢占源码 )

    文章目录 一.禁止 / 开启内核抢占 与 方法保护临界区 二.编译器优化屏障 三.preempt_disable 禁止内核抢占 源码 四.preempt_enable 开启内核抢占 源码 一.禁止 / ...

  2. linux实时进程优先级rt,Linux实时性- PREEMPT_RT实时抢占实现

    作者:Paul E. McKenney 翻译整理:土豆丝624 原文链接: 概述: 本篇文章主要讲Linux的实时包PREEMPT_RT 是如何实现的. PREEMPT_RT 的原理 PREEMPT_ ...

  3. 嵌入式之linux用户空间与内核空间,进程上下文与中断上下文

    文章目录 前言 用户空间与内核空间 内核态与用户态 进程上下文和中断上下文 上下文 原子 进程上下文 中断上下文 进程上下文VS中断上下文 原子上下文 前言 之前在学习嵌入式linux系统的时候,一直 ...

  4. Linux 2.6 menuconfig内核编译配置选项详解

    Code maturity level options 代码成熟度选项 Prompt for development and/or incomplete code/drivers 显示尚在开发中或尚未 ...

  5. Linux进程管理:内核中的优先级继承互斥(rtmutex.h):防止优先级反转

    目录 Priority inheritance in the kernel 译文 Priority inheritance in the kernel https://lwn.net/Articles ...

  6. Linux内核信号杀死内核线程,linux内核线程对信号的处理过程.

    linux中的线程分为用户线程和内核线程,用户线程是规范的线程,全面的自主性,全面的抢占性:然而内核线程就不那么好了,某种含义上未曾用户线程那么安逸,这个怎么会意呢?用户线程的编写者只必需告终利用逻辑 ...

  7. Linux用户态与内核态通信的几种方式(待完善)

    文章目录 1. 内核启动参数 2.模块参数与sysfs 3.sysctl 4.系统调用 5.netlink 6. procfs(/proc) 7.seq_file 8.debugfs 9.relayf ...

  8. Solaris, Linux 和 FreeBSD 的内核比较(转)

    Solaris, Linux 和 FreeBSD 的内核比较(转) 1.我个人认为作者MAX对Linux的了解不像他对Solaris那样深入,我不知道也没法知道他的下列关于Linux的内容来自自己的代 ...

  9. linux内核编程_内核线程kthread_run

    linux内核编程_内核线程kthread_run 1. 简述: 2. 使用示例: 3. 详述: 1. 简述: 头文件: include/linux/kthread.h 数据类型: struct ta ...

  10. Linux内核可自己增加吗6,一篇最完善可行的Linux 2.6.10内核升级文档Linux -电脑资料...

    一篇最完善可行的Linux 2.6.10内核升级文档 huangki | 05 三月, 2005 23:22 Linux 2.6.10 kernel installation 做一件事情,首先要知道自 ...

最新文章

  1. AHOI2009 中国象棋
  2. 科大星云诗社动态20201223
  3. mysql笔记 doc_Mysql DOC阅读笔记
  4. CodeForces - 1551F Equidistant Vertices(暴力+dp)
  5. hadoop 环境搭建
  6. 20155202《网络对抗》Exp9 web安全基础实践
  7. 实现多国语言的几个小知识
  8. mysql pdo支持_使php支持pdo_mysql
  9. 实时计算在天猫双十一大屏中的应用
  10. inDesign教程,如何在文档中添加交互性预览?
  11. 苹果11蓝牙配对不成功怎么办_【苹果手机蓝牙不能配对】苹果手机蓝牙无法配对_苹果手机蓝牙怎么配对...
  12. 【路径生成--绘制的方法】矢量地图巡线式路径探索
  13. 炒鞋风潮下的“真鞋”鉴定生意
  14. jquery弹出层插件jquery.ColorBox.js学习
  15. PHP实现身份证认证和银行卡认证
  16. Bomb数据的存储与查询
  17. 写一篇文章记录我的论文之路
  18. 射影几何----综合射影几何基础英文在线阅读网页
  19. Adobe国际认证证书介绍
  20. 如何避开精准算法推送的新闻或文章呢?

热门文章

  1. BF2地图下载 战地系列非官方单机地图集
  2. 使用HBuilder打包App教程
  3. python安装后桌面没有显示图标_Win10安装软件后找不到软件图标如何解决
  4. stm32采集脉冲信号_STM32单片机怎么产生脉冲信号控制步进电动机?
  5. 网站优化策略有哪几种方法
  6. ctfshow F5杯 部分WP(writeup) 超详细
  7. 战网在线更改服务器,暴雪的“战网”是如何从无到有 并改变了在线游戏的?...
  8. zotero+PDF expert+坚果云+iPad
  9. java-commons-pool2--(1)--连接池详解
  10. Windows10快捷键合集