Linux内核学习笔记二——进程
Linux内核学习笔记二——进程
一 进程与线程
进程就是处于执行期的程序,包含了独立地址空间,多个执行线程等资源。
线程是进程中活动的对象,每个线程都拥有独立的程序计数器、进程栈和一组进程寄存器。
内核调度的对象是线程而不是进程。对Linux而言,线程是特殊的进程。
二 进程描述符及任务结构
内核使用双向循环链表的任务队列来存放进程,使用结构体task_struct来描述进程所有信息。
1 进程描述符task_struct
struct task_struct {}结构体相当大,大约1.7K字节。大概列出一些看看:
2 分配进程描述符
当进程由于中断或系统调用从用户态转换到内核态时,进程所使用的栈也要从用户栈切换到内核栈。
通过内核栈获取栈尾thread_info,就可以获取当前进程描述符task_struct。
每个进程的thread_info结构在他的内核栈的尾端分配。结构中task域中存放是指向该任务实际的task_struct。
内核处理进程就是通过进程描述符task_struct结构体对象来操作。所以操作进程要获取当前正在运行的进程描述符。
通过thread_info的地址就可以找到task_struct地址;在不同的体系结构上计算thread_info的偏移地址不同。

/* linux-2.6.38.8/arch/arm/include/asm/current.h */
static inline struct task_struct *get_current(void)
{
return current_thread_info()->task;
} #define current (get_current())
/* linux-2.6.38.8/arch/arm/include/asm/thread_info.h */
static inline struct thread_info *current_thread_info(void)
{
//栈指针
register unsigned long sp asm ("sp");
return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
}

3 进程的状态
系统中的每个进程都必然处于五种进程状态中的一种或进行切换。该域的值也必为下列五种状态标志之一:
TASK_RUNNING(运行)—进程是可执行的;它或者正在执行,或者在运行队列中等待执行(运行队列将会在第4章中讨论)。
这是进程在用户空间中执行的唯一可能的状态;这种状态也可以应用到内核空间中正在执行的进程。
TASK_INTERRUPTIBLE(可中断)—进程正在睡眠(也就是说它被阻塞),等待某些条件的达成。一旦这些条件达成,
内核就会把进程状态设置为运行。处于此状态的进程也会因为接收到信号而提前被唤醒并随时准备投入运行。
TASK_UNINTERRUPTIBLE(不可中断)—除了就算是接收到信号也不会被唤醒或准备投入运行外,这个状态与可打断状态相同。
这个状态通常在进程必须在等待时不受干扰或等待事件很快就会发生时出现。由于处于此状态的任务对信号不做响应,
所以较之可中断状态,使用得较少。
__TASK_TRACED—被其他进程跟踪的进程,例如通过ptrace对调试程序进行跟踪。
__TASK_STOPPED(停止)—进程停止执行;进程没有投入运行也不能投入运行。通常这种状态发生在接收到SIGSTOP、
SIGTSTP、SIGTTIN、SIGTTOU等信号的时候。此外,在调试期间接收到任何信号,都会使进程进入这种状态。
三 进程创建
fork:copy当前进程创建一个新的进程;
exec:读取可执行文件并将其载入地址空间开始运行。
1 fork过程
创建进程都是通过调用do_fork函数完成,其中提供了很多参数标志来表明进程创建的方式。

long do_fork(unsigned long clone_flags,
unsigned long stack_start,
struct pt_regs *regs,
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr) {
struct task_struct *p;
…… //创建进程
p = copy_process(clone_flags, stack_start, regs, stack_size,
child_tidptr, NULL, trace);
……
//将进程加入到运行队列中
wake_up_new_task(p);
}

copy_process里面通过父进程创建子进程,并未执行:

task_struct *copy_process(unsigned long clone_flags,
unsigned long stack_start,
struct pt_regs *regs,
unsigned long stack_size,
int __user *child_tidptr,
struct pid *pid,
int trace) {
struct task_struct *p;
//创建进程内核栈和进程描述符
p = dup_task_struct(current); //得到的进程与父进程内容完全一致,初始化新创建进程
……
return p;
}

dup_task_struct根据父进程创建子进程内核栈和进程描述符:

static struct task_struct *dup_task_struct(struct task_struct *orig)
{
struct task_struct *tsk;
struct thread_info *ti;
int node = tsk_fork_get_node(orig); //创建进程描述符对象
tsk = alloc_task_struct_node(node);
//创建进程内核栈 thread_info
ti = alloc_thread_info_node(tsk, node); //使子进程描述符和父进程一致
err = arch_dup_task_struct(tsk, orig); //进程描述符stack指向thread_info
tsk->stack = ti; //使子进程thread_info内容与父进程一致但task指向子进程task_struct
setup_thread_stack(tsk, orig); return tsk; }

创建进程copy_process之后并未执行,返回到do_fork中,将新创建进程加入到运行队列中等待被执行。
四 线程在Linux中的实现与内核线程
线程机制提供了在同一个程序共享内存地址空间,文件等资源的一组线程。在Linux内核中把所有线程都当做进程来实现。
内核并没有提供调度算法,或者数据结构来表征线程,而是作为与其他进程共享资源的进程;与其他系统不同。
内核线程与普通进程间的区别是:
内核线程没有独立的地址空间
只在内核空间运行,不会切换到用户空间
五 进程终结
进程终结时内核释放其所占有的资源,并告诉父进程,更新父子关系。调用exit终结进程,进程被终结时通常最后都要调用do_exit来处理。

void do_exit(long code)
{
//获取当前运行进程
struct task_struct *tsk = current;
…… //sets PF_EXITING
exit_signals(tsk); //释放task_struct的mm_struct内存
exit_mm(tsk); //退出接收IPC信号队列
exit_sem(tsk); //进程名字空间
exit_shm(tsk); //文件描述符
exit_files(tsk); //文件系统
exit_fs(tsk); //资源释放
exit_thread(); //向父进程发送信号
exit_notify(tsk, group_dead);
…… //切换到其他进程
tsk->state = TASK_DEAD;
tsk->flags |= PF_NOFREEZE;
schedule();
……
}

Linux内核学习笔记二——进程的更多相关文章
- Linux内核学习笔记-2.进程管理
原创文章,转载请注明:Linux内核学习笔记-2.进程管理) By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...
- Linux内核学习笔记-1.简介和入门
原创文章,转载请注明:Linux内核学习笔记-1.简介和入门 By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...
- 20135316王剑桥Linux内核学习笔记
王剑桥Linux内核学习笔记 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 计算机是如何工作的 个人理 ...
- linux内核学习之二:编译内核
在linux内核学习系列的第一课中讲述了搭建学习环境的过程(http://www.cnblogs.com/xiongyuanxiong/p/3523306.html),环境搭好后,马上就进入到下一环节 ...
- 马哥Linux SysAdmin学习笔记(二)
Linux网络属性管理: 局域网:以太网,令牌环网 Ethernet:CSMA/CD 冲突域 广播域 MAC:media access control地址 48bit: 24bits 24bits ...
- Linux内核学习笔记(1)-- 进程管理概述
一.进程与线程 进程是处于执行期的程序,但是并不仅仅局限于一段可执行程序代码.通常,进程还要包含其他资源,像打开的文件,挂起的信号,内核内部数据,处理器状态,一个或多个具有内存映射的内存地址空间及一个 ...
- linux内核学习之二 一个精简内核的分析(基于时间片轮转)
一 实验过程及效果 1.准备好相关的代码,分别是mymain.c,mypcb.h,myinterrupt.c ,如下图,make make成功: 在qemu创建的虚拟环境下的运行效果:(使用的命令 ...
- Linux内核学习笔记——内核内存管理方式
一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页 ...
- linux内核学习之四:进程切换简述
在讲述专业知识前,先讲讲我学习linux内核使用的入门书籍:<深入理解linux内核>第三版(英文原版叫<Understanding the Linux Kernel>),不过 ...
随机推荐
- HIDL学习笔记
一.HIDL简单介绍 HIDL是Android8.0新出的一个技能,以service和client的方式实现hal接口,目的是想使Android系统和BSP解绑,使系统升级更加方便.HIDL的使用方法 ...
- sqler sql 转rest api 的工具试用
sqler 从开源很快就获取了1k的star,使用起来很方便,而且也很灵活,支持的数据库也比较多. 支持的功能 无需依赖,可独立使用: 支持多种数据可类型,包括:SQL Server, MYSQL, ...
- Singer 学习十二 指南
版本0.3.0 tap是一个应用程序,需要一个配置文件和可选的状态文件作为输入,并产生有序的流记录, 状态和模式信息作为输出. 一个记录是任何类型的JSON编码的数据.tap 状态消息用于保留一个调用 ...
- 改变codeblocks里面各种注释的颜色。
->Setting->Editor->Syntax highlighting->“Comment(normal)” /* 改变块注释颜色 */"Comment lin ...
- leetcode第一刷_Insert Interval
这道题的难度跟微软的那道面试题相当. 要在集合中插入一段新的集合,相当于求两个集合的并了.对于新增加一段集合的情况,分为以下几种: 1. 增加段跟原来的全然相交,也即他的起点和终点都在被包括在原来的段 ...
- Winform里面的缓存,MemoryCache使用
缓存在很多情况下需要用到,合理利用缓存可以一方面可以提高程序的响应速度,同时可以减少对特定资源访问的压力.本文主要针对自己在Winform方面的缓存使用做一个引导性的介绍,希望大家能够从中了解一些缓存 ...
- 如何对 PHP 代码加密?
这几天有同事问如何对 PHP 代码进行加密? 在我印象中 PHP 加密还是比较麻烦的,之前只知道 Zend Guard . 刚刚找了一圈发现现在还是有很多可行的方案,先记录一下,以后使用. 使用混淆 ...
- java-plupload上传大文件
参考链接: https://blog.csdn.net/hjf_1291030386/article/details/74784172 https://www.cnblogs.com/tengyunh ...
- SDRAM初识
SDRAM初识 1. 2. 3. 4. SDRAM分为bank地址和行列地址,看bank地址的位宽就可以推断出bank的数量,行列地址信号是集成在了一个信号中,是并行的. 5. 6. SDRAM与主机 ...
- 关键两招就解决Wampserver 打开localhost显示IIS7图片问题
我们在安装集成环境Wampserver之后,有时会遇到一个问题, 打开localhost显示一张IIS7图片,这个问题该如何解决呢,我在网上找了一些说的都很乱,我在这里简单整理了一下解决方法 1 ...