Linux操作系统原理与应用--陈莉君chp3
Linux原理及应用

2.1 Linux进程
系统为每个进程分配一个独立的虚拟地址空间。 进程的虚拟地址空间被分做两个部分:
用户空间。用户进程本身的程序和数据(可执行映 象)映射到用户空间中。 系统空间。内核被映射到所有进程的系统空间中。 它们只允许在具有较高特权的内核态下访问。进程 运行在特权较低的用户态下时,不允许它直接访问 系统空间。进程只能通过系统调用(system call)转换 为内核态后,才能访问系统空间。一个进程在运行 过程中,总是在两种执行状态之间不断地转换。
policy表示进程的进程调度策略,可以通过系统调用 sys_sched_setscheduler()更改(kernel/sched.c)。Linux操作系 统采用的调度策略见下表 。
调度策略 SCHED_OTHER SCHED_FIFO SCHED_RR 值 0 1 2 说明 非实时进程,基于优先权的轮转法 实时进程,先进先出算法 实时进程,基于优先权的轮转法
LINUX原理及应用
武汉大学计算机学院 郑鹏 Email:pzheng51@
第2章 Linux进程管理
程序是为了完成某种任务而设计的软件,是存储在 磁盘上包含可执行的机器指令和数据的静态实体。 进程是一个程序的一次执行的过程,在操作系统中 执行特定的任务,是一个随执行过程不断变化的实 体。进程是Linux系统中基本的调度单位。 进程具有独立的权限与职责,如果系统中某个进程 崩溃,它不会影响到其余的进程。每个进程运行在 其各自的虚拟地址空间中,通过内核控制下的通信 机制,它们之间才能发生联系。 进程在生命期内将使用系统中的资源。它利用系统 中的CPU来执行指令,用物理内存来放置指令和数 据。使用文件系统提供的功能打开并使用文件,同 时直接或者间接地使用物理设备。
Linux操作系统原理与应用--陈莉君chp3

进程P
弟进程
指向父进程
指向子进程
指向兄进程
指向弟进程
进程控制块-部分内容的描述
上面通过对进程状态、标识符及亲属关系的描 述,我们可以把这些域描述如下: task_struct{ long state; /*进程状态*/ int pid,uid,gid; /*一些标识符*/ struct task_struct *parent, *child, *o_sibling, *y_sibling /*一些亲属关系*/ … }
进程调度-衡量值得运行的程度
static inline int goodness(struct task_struct * p, struct task_struct *prev) { int weight; /* 权值,作为衡量进程是否运行的唯一依据 */ if (p->police!=SCHED_OTHER) /*实时进程*/ {weight = 1000 + p->rt_priority; goto out } weight = p->counter; /*普通进程*/ if(!weight) / *p用完了时间片*/ goto out; if(p ==prev) /* 细微调整 */ weight+= 1; weight+=p->priority out: return weight }
调度函数schedule( ) 片段
如果prev进程时间片用完,而且还是实时进程, 就给它分配新的时间片,并让它到可运行队列 末尾:
if (prev->policy == SCHED_RR&&!prev->counter) { prev->counter = prev->priority; move_last_runqueue(prev); }
Linux操作系统(RHEL7/CentOS7)3.3系统和服务管理

3.3 系统和服务管理3.3.1 系统和服务管理器:systemd1.SysV init、Upstart init、systemdRHEL7采用systemd作为默认init程序,所以runlevel的概念基本上也就不存在了。
2.unitsystemd开启和监督整个系统是基于unit的概念。
unit是由一个与配置文件对应的名字和类型组成的(例如:avahi.service unit有一个具有相同名字的配置文件,是守护进程A vahi的一个封装单元)。
unit有以下7种类型:(1)service:(2)socket:(3)device:(4)mount:(5)automount:(6)target:(7)snapshot:3.systemd提供以下主要特性(1)使用socket的前卫的并行性能:(2)D-Bus激活策略启动服务:(3)提供守护进程的按需启动策略。
(4)保留了使用Linux cgroups进程的追踪功能:(5)支持快照和系统状态恢复:(6)维护挂载和自挂载点:(7)实现了各服务间基于依赖关系的一个精细的逻辑控制:4.systemd的主要工具(1)systemctl命令:查询和控制systemd系统和系统服务管理器的状态。
(2)journalctl命令:查询系统的journal(日志)。
(3)systemd-cgls命令:以树形列出正在运行的进程,可以递归显示Linux控制组内容。
3.3.2 监视和控制systemd的命令:systemctl起。
示例如下:3.3.3 改变目标(运行级别)systemd使用比sysvinit的运行级更为自由的target概念作为替代。
第3运行级用multi-user.target替代。
第5运行级用graphical.target替代。
runlevel3.target和runlevel5.target分别是指向multi-user.target和graphical.target的符号链接。
Linux内核入门学习方法

Linux内核入门学习方法作者介绍:刘冰,西安邮电大学研一在读,跟随陈莉君导师求学,刚刚踏入Linux内核的高山密林之中。
在学习Linux内核的过程中,由于Linux还在蓬勃的生长发展,内核还是会经常变化,我们会在实践学习,比如修改编译内核、调试系统时遇到许许多多的问题,想要快速的掌握一些相关的知识,并不是一件容易的事情。
我在学习内核的过程中摸索了一些方法出来。
找资料途径上,在信息量爆炸的今天,要学习一个经常变化的东西,比如新版Linux 内核的特性,主要是通过官方文档,或搜索引擎查找,找到的平台大部分都是博客等,可以根据它的排版、热度等来对其进行一个可信度的初判,可以自己通过实验进行验证,要敢于质疑;有了初步了解以后,要学习一个开源程序的实现、运行原理,可以找到它的源代码进行深入的学习,linux 内核的源代码可读性很好,里面有适量的代码注释和完善的接口注释,可以利用vscode软件对代码进行一个深入的追踪学习,我整理了一些vscode阅读代码的技巧:/XdoSy。
如果要学习的是一些沉淀了已久的知识,最好是根据一些相关评价,找一本经典教程来深入学习,比如学习数据结构,网上推荐最多的便清华大学严蔚敏老师写的《数据结构(C 语言版)》,上面宝贵的不仅是条理清晰的知识点,从中还能体会到作者更科学的思维方式。
书上代码对抽象性原则的躬身力行让我对C 语言有了全新的认识,将书里的算法尽可能的用代码实现一下使我受益良多。
理论方面,理解每个术语、英文缩写的含义和由来,有助于我们为总体目标的出现梳理出一个符合逻辑的产生发展过程,便于我们对总目标知识的掌握和记忆;实验方面,要与自己学的理论知识相结合,敢于创新,加深对理论的理解和对技术的掌握。
笔记找一个可以构建知识网络的笔记软件,可以将知识点连接起来,在出现以前学过的知识点时可以关联起来,温故知新,在获取新知识的同时也在不断巩固旧的知识。
推荐软件比如印象笔记、思源笔记等。
Linux操作系统原理与应用第3章

下一行合并为一行。
第3章 vi文本编辑器
d+定位符 删除从光标位置到指定位置范围内的字符。常用的有:
d0、d^ d$ dG db de dw 删除光标左面的文本。0或^代表行首。 删除光标右面的文本。$代表行尾。 删除光标所在行之后的所有行。G代表最后一行。 删除光标处前的字符直到词首。b代表词首。 删除光标处的字符直到词尾。e代表词尾。 删除光标处的字符直到下一个词的词首。w代表下一 词词首。
2. 文本的删除
删除(delete)文本的最简单方法是将光标移到要删除的 字符上,然后,每按一下x键或Delete键就会删掉一个字符。 若要删除的文本较多时,可以使用下面更加灵活的删除命 令。 删除命令: x、X 与Delete键相同。 dd D J 删除光标所在的行。 删除光标右面的文本。 删除当前行尾的换行符,使当前行与 删除光标处、光标前的字符。x的作用
始输入。
第3章 vi文本编辑器
插入命令:
a、A 在光标位置后、行尾后开始插入。
i、 I
在光标位置前、行首前开始插入。i的
作用与Insert键相同。
o、O 的新行开始插入。
在光标所在行之后、光标所在行之前
图3-4所示为插入命令的用法。
第3章 vi文本编辑器
图3-4 插入命令用法示意
第3章 vi文本编辑器
和系统管理员的编辑利器。初学者经过一段时间的使用,
也会逐渐习惯vi的操作方式,并形成自己特有的操作风格。
第3章 vi文本编辑器
3.1.2 vi的工作模式
vi是一个多模式的软件,它有三种工作模式。在不同的 工作模式下,它对输入的内容有不同的解释。 1. 命令模式(Command mode) 在命令模式下,输入的任何字符都作为命令来解释执
Linux操作系统应用kj3-3

技能拓展
任务总结
操作练习
3
准备批量创建的9个 用户分别为hbzy、hbvtc、 pan、shen、li、sun、 wei、wang、tang,这 些用户都属于mygroup 组群,组群GID为600。 (有关用户及组群具体 创建详见学习情境四)。
Linux 操作系统应用
上一页
下一页
退出
3.3 子情境:vi编辑器的使用
步骤7 替换字符串
按【:】键进入最后行模式,输入“1,9 s/hbzyvtc/hbvtc/g” 将1-9行中的字符串“hbzyvtc”替换成“hbvtc”。
技能拓展
任务总结 操作练习
步骤8 保存文件
按【:】键进入最后行模式,输入“wq”, 保存编辑内容并 退出vi。
Linux 操作系统应用
上一页
下一页
(2) 文本编辑模
式
文本编辑模式用于字符编辑,在命令模式下输入i (插入命令)、a(附加命令)等命令后进入文本 编辑模式。
(3) 最后行模式
在命令模式下,按【:】键进入最后行模式,命 令执行完毕后,vi自动回到命令模式。
vi的三种工作模式之间的相互转换的关系如图315所示。
命令模式
:
自动返回
Esc
i或a
Linux 操作系统应用
上一页
下一页
退出
3.3 子情境:vi编辑器的使用
• 任务实施
任务描述
实施流程
相关资讯 任务准备 任务实施 任务检测 技能拓展
步骤5 修改用户 名和用户
识别码
UID
按【i】键切换到文本编辑模式,第2行的用户名hbzy改 为hbzyvtc;用户识别码601改为602;
按相同的方法,依次将第3-9行的用户名hbzy分别改为 pan、shen、li、sun、wei、wang、tang,用户识别码601 分别改为603、604、…、609。如图3-21所示。
Linux26内核调度机制剖析与改进-计算机系统应用

Practical Experience 实践经验 191
计 算机 系统 应用
2009 年 第 11 期
rq->active = rq->expired; rq->expired = array; array = rq->active; rq->expired_timestamp = 0; rq->best_expired_prio = MAX_PRIO; } 这段代码的作用 是执行两 个数组(活 动数组 active 和过期数组 expired)的切换。首先,如果活 动数组中没有进程了,则通过指针操作来 切换两个数 组。之前我们看到在过期数组中的进程时 间片已经被 计算好了。所以在两个数组切换后,过期 数组中的进 程都变为活动进程,交换数组的时间就是 交换指针的 时间。这种交换就是 O(1)调度算法的核心。整个 O(1) 算法的工作机制可以用图 1 形象地描述:
图 3 schedul e()函数的运行流程
2009 年 第 11 期
计 算机 系统 应用
3.2 内核抢占 2.4 版之前的 Linux 和大部分 Unix-Lik e 操作系
统一样,只支持用户 抢占,不支持内 核抢占[2]。为了 提高对交互式进程的支持并更好地实现软 实时工作方 式,2.6 内核引入了内核抢占。现在,只要重新调度 是安全的,那么内核就可以在任何时间抢 占正在执行 的进程[2]。
4 一种改进的实时调度算法
为了使 Linux 2.6 内核支持硬实时应用环境,笔 者给出了一种改进的实时调度算法——改 进的最小裕 度优先(LSF)调度算法。 4.1 改进的最小裕度优先调度算法
最小裕度优先(Least Slack First)调度算法是实 时系统中较为常见的动态优先级调度算法 ,它是对最 早截止期优先(EDF)算法的改进[3]。这种算法依据富裕 时间来确定任务的优先级,该富裕时间即为“裕度”。 裕度小的,优先级高,反之则低。在该算 法中,通过 结合任务执行的缓急程度来给任务分配优 先级。它克 服了 EDF 算法中因仅仅考虑截止期限而带来的缺陷。 在 LSF 算法中,裕度 S 定义如下:
Linux内核定时器--原版PPT优秀课件

7
2.1.1 理想的HZ值
自Linux问世以来,i386体系结构中时 钟中断频率就设定为100HZ,但是在2.5开发 版本内核中,中断频率被提高到1000HZ。
提高节拍率意味着时钟中断产生得更 加频繁,所以中断处理程序也会更频繁的 执行,带来以下几点好处: • 更高的时钟中断解析度可提高时间驱动事 件的解析度。 • 提高了时间驱动事件的准确度。
13
2.2.1 jiffies的回绕
• Jiffies变量总是无符号长整数,因此,在32 位体系结构上时32位,在64位体系结构上 时64位。32位的jiffies变量,如果HZ = 100, 497天后会溢出,如果HZ = 1000,49.7天后 会溢出。而64位则别指望能看到溢出。
• 访问jiffies的代码仅会读取jiffies_64的低32位, 通过get_jiffies_64()函数,可以读取整个64 位,多数代码只需要访问低32位就够了。
/*还没有超时,继续执行任务*/ }
/*超时了,发生错误*/
15
• 正常的情况下,上面的代码没有问题。但是当 jiffies接近最大值的时候,就会出现回绕问题, 如下图所示:
• 1. 循环中第一次比较时,jiffies = J1,没有超时 • 2. 循环中第二次比较时,jiffies = J2,实际已经
执行中断处理程序,占用CPU时间过多。 • 减少了处理器对其他工作的时间,更频繁
的打乱处理器高速缓存并增加耗电。
11
2.2 jiffies
• 全局变量jiffies用来记录自系统启动以来产 生得节拍的总数。例如:系统启动了N秒, 那么jiffies就为N x HZ。
• Jiffies的类型为无符号长整型(unsigned long),用其它任何类型存放都不正确。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
调度函数schedule( ) 片段
如果prev进程处于浅度睡眠状态,而且它有未 处理的信号,就应当唤醒它,给它一个被选择 执行的机会。
if (prev->state == TASK_INTERRUPTIBLE && signal_pending(prev)) prev->state = TASK_RUNNING;
如果prev进程不是可运行状态,说明它必须等 待某一外部资源,那就让它去睡觉,因此,必 须从运行队列链表中删除prev:
第三章 进程
进程介绍
进程控制块
进程的组织方式
进程调度 进程的创建
与进程相关的系统调用及其应用 与调度相关的系统调用及应用
进程介绍-程序和进程
进程介绍-进程层次结构
ini t
A C D
B E
进程介绍-进程状态
运行态
阻塞态
就绪态
进程介绍-进程示例
#include <sys/types.h> /* 提供类型pid_t的定义,在PC机上与int型 相同 */ #include <unistd.h> /* 提供系统调用的定义 */ main() { pid_t pid; /*此时仅有一个进程*/ printf(“PID before fork():%d\n”,(int)getpid()); pid=fork(); /*此时已经有两个进程在同时运行*/ if(pid<0) printf("error in fork!"); else if(pid==0) printf("I am the child process, my process ID is %d\n",getpid()); else printf("I am the parent process, my process ID is %d\n",getpid()); }
每个进程都属于某个用户组。
task_struct结构中定义有用户标识符UID(User Identifier)和组标识符GID(Group Identifier) 这两种标识符用于系统的安全控制 系统通过这两种标识符控制进程对系统中文件和 设备的访问。
进程控制块-进程之间的亲属关系
父进程
兄进程
为什么在这些时机返 回?
进程调度-与调度相关的域
need_resched:调度标志,以决定是否调用 schedule( )函数。 counter: 进程处于可运行状态时所剩余的时钟节 拍(即时钟中断的间隔时间,为10ms或1ms)数。 这个域也叫动态优先级。 priority: 进程的基本优先级或叫“静态优先级” rt_priority: 实时进程的优先级 policy: 调度的类型,允许的取值是: SCHED_FIFO:先入先出的实时进程 SCHED_RR:时间片轮转的实时进程 SCHED_OTHER:普通的分时进程。
进程介绍-进程示例
编译并运行这个程序: $gcc fork_test.c -o fork_test $./fork_test PID before fork():1991 I am the parent process, my process ID is 1991 I am the child process, my process ID is 1992
进程的组织方式-可运行队列
把可运行状态的进程组成一个双向循环链表,也叫可 运行队列(runqueue) 在task_struct结构中定义了两个指针。 struct task_struct *next_run, *prev_run;
init_task起链表头的作用
在调度程序运行过程中,允许队列中加入新出现的可 运行态进程,新出现的可运行态进程插入到队尾
进程的组织方式-进程链表
在task_struct中定义如下: task_struct *prev_task, *next_task
宏for_each_task()遍历整个进程链表 #define for_each_task(p) \ for (p = &init_task ; (p = p->next_task) != &init_task ; )
进程的组织方式-哈希表
哈希函数 #define pid_hashfn(x) \ ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
图为地址法处理冲突时的哈希表 假定哈希表义为: struct task_struct *pidhash[PIDHASH_SZ] 对给定的PID,如何快速找到对应进程?
时间片过长会导致系统对交互的响应表现欠佳 时间片太短会明显增大进程切换带来的处理器 时间。 Linux调度程序提高交互式程序的优先级,让它们 运行得更频繁,于是,调度程序提供较长的默认时 间片给交互式程序 Linux调度程序还根据进程的优先级动态调整分配 给它的时间片
进程调度-调度时机
进程状态转换的时刻:进程终止、进程睡眠 当前进程的时间片用完时; 设备驱动程序运行时; 从内核态返回到用户态时;
TASK_STOPPED 暂停
schedule() ptrace()
do_exit()
TASK_ZOMBIE 僵死
进程控制块-进程标识符
每个进程都有一个唯一的标识符,内核通过 这个标识符来识别不同的进程 。
进程标识符PID也是内核提供给用户程序的接口, 用户程序通过PID对进程发号施令 。 PID是32位的无符号整数,它被顺序编号
调度函数schedule( ) 片段
如果prev进程时间片用完,而且还是实时进程, 就给它分配新的时间片,并让它到可运行队列 末尾:
if (prev->policy == SCHED_RR&&!prev->counter) { prev->counter = prev->priority; move_last_runqueue(prev); }
进程控制块-如何存放
把PCB与内核栈放在一起具有以下好处: (1) 内核可以方便而快速地找到PCB,用伪代码描述如 下: p = (struct task_struct *) STACK_POINTER & 0xffffe000 (2) 避免在创建进程时动态分配额外的内存 在Linux中,为了表示当前正在运行的进程,定义了一 个current宏,可以把它看作全局变量来用,例如 current->pid返回正在执行的进程的标识符
进程调度-调度算法考虑的因素
公平:保证每个进程得到合理的CPU时间。 高效:使CPU保持忙碌状态,即总是有进程 在CPU上运行。 响应时间:使交互用户的响应时间尽可能短。 周转时间:使批处理用户等待输出的时间尽 可能短。 吞吐量:使单位时间内处理的进程数量尽可 能多。
进程调度-调度算法
进程控制块-如何存放
C语言使用下列的联合结构表示这样一个混合结构: union task_union { struct task_struct task; unsigned long stack[2408]; }; Linux调用alloc_task_struct()函数分配8KB的 task_union 内存区,调用free_task_struct()函数释 放它
再运行一遍,输出结果可能不同。 读者考虑一下描述的数据结构
Linux中把对进程的描述结构叫做task_struct: struct task_struct { … … }
传统上,这样的数据结构被叫做进程控制块 PCB(process control blaock)
时间片轮转调度算法
系统使每个进程依次地按时间片轮流地执行 优先权调度算法 非抢占式优先权算法 抢占式优先权调度算法 多级反馈队列调度 优先权高的进程先运行给定的时间片,相同优先 权的进程轮流运行给定的时间片 实时调度 一般采用抢占式调度方式
进程调度-时间片
时间片表明进程在被抢占前所能持续运行的 时间。
进程的组织方式-等待队列
等待队列表示一组睡眠的进程 可以把等待队列定义为如下结构: struct wait_queue { struct task_struct * task; struct wait_queue * next; }; 如何让正在运行的进程等待某一特定事件? Linux内 核中实现了sleep_on()函数,请给出该函数的实现。 如果要让等待的进程唤醒,就调用唤醒函数wake_up (),它让待唤醒的进程进入TASK_RUNNING状态。
进程调度-衡量值得运行的程度
static inline int goodness(struct task_struct * p, struct task_struct *prev) { int weight; /* 权值,作为衡量进程是否运行的唯一依据 */ if (p->police!=SCHED_OTHER) /*实时进程*/ {weight = 1000 + p->rt_priority; goto out } weight = p->counter; /*普通进程*/ if(!weight) / *p用完了时间片*/ goto out; if(p ==prev) /* 细微调整 */ weight+= 1; weight+=p->priority out: return weight }
进程控制块-Linux进程状态及转换
fork() SIGCONT 收到信号 wake_up() TASK_RUNNING 就绪 资源到位 wake_up() schedule() TASK_UNINTERRUPTIBLE 深度睡眠 等待资源到位 sleep_on() schedule() 占有CPU 执行 等待资源到位 interruptible_sleep_on() schedule() 时间片耗尽 TASK_INTERRUPTIBLE 浅度睡眠 资源到位 wake_up_interruptible() 或收到信号 wake_up()