首先僵尸进程产生的原因是子进程退出了,但是父进程没有回收他的资源(pcb),所以我们从源头开始分析这个过程。那就是子进程退出的时候。进程是通过exit系统调用退出的。 我们看一下exit函数的代码。...1 修改当前进程的子进程的新父进程为init进程。如果子进程已经退出了,则通知init进程。否则init无法回收该子进程的资源。 2 释放一系列资源。 3 修改进程状态和退出码。...// 子进程的新父进程是进程id为1的进程 task[i]->father = 1; /* 父进程没有调wait,子进程退出了,然后父进程也退出了...1的进程(init进程)。...如果这时候当前进程的某些进程已经退出了(当前进程没有调waitpid处理子进程的退出),则给init进程发送SIGCHLD信号。这时候init会回收这个子进程的pcb。下面是init进程的逻辑。
下面是进程调度函数及其相关函数的代码。...task_struct ** p; /* check alarm, wake up any interruptible tasks that have got a signal */ // 处理进程的信号和状态...,相与 得到进程当前阻塞的集合,即排除进程阻塞了不能阻塞的信号,然后取反得到可以接收的 信号集合,再和signal相与,得到当前进程当前收到的信号...switch_to(next); } #define switch_to(n) {\ struct {long a,b;} __tmp; \ // ecx是第n个进程对应的pcb首地址,判断切换的下一个进程是不是就是当前执行的进程...如果时间用完则直接重新调度,否则进程可以继续执行。进程调度的时候,系统会选择时间最长的进程,防止有的进程得不到执行,当所有进程的时间片都消耗完毕,则重新计算时间。
进程的睡眠是通过调用sleep_on函数,该函数修改了进程的状态并且通过schedule函数切换到其他进程执行,从而实现进程的挂起,TASK_UNINTERRUPTIBLE状态的进程只能被wake_up...TASK_INTERRUPTIBLE状态的进程可以被wake_up和信号唤醒。唤醒的时候也是通过修改进程的状态为可运行,然后等待下一次进程调度,被唤醒的进程不一定马上得到执行。...} // 当前进程挂载到睡眠队列p中,p指向队列头指针的地址 void sleep_on(struct task_struct **p) { struct task_struct *tmp;...,这个版本的实现没有采用真正链表的形式, 他通过每个进程在栈中的临时变量形成一个链表,每个睡眠的进程, 在栈里有一个变量指向后面一个睡眠节点,然后把链表的头指针指向当前进程...自己被信号唤醒了, 去唤醒别的进程,自己却还睡眠 */ if (*p && *p !
该表保存了系统和所有进程的tss和ldt描述符信息。tss就是我们平时说的进程上下文。每个进程有一个ldt数组,里面保存了代码段和数据段的描述符信息。 首先,从一个进程的诞生说起。...我们知道,通过fork可以创建一个进程。下面我们来看一下fork的过程都做了什么事情。先通过find_empty_process获取一个可用的进程id和pcb。pid是进程id。...,p)) { task[nr] = NULL; free_page((long) p); return -EAGAIN; } // 父子进程都有同样的文件描述符...tss描述符地址的偏移, 单位是8个字节,即选择描述符大小,_LDT是偏移的大小,单位是1,这里是8 */ set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY...挂载tss和ldt地址到gdt,nr << 1即乘以2,这里算出的是第nr个进程距离第一个tss描述符地址的偏移, 单位是8个字节,即选择描述符大小,_LDT是偏移的大小,单位是1,这里是
2 流程分析 2.1 引导内核阶段 2.2 内核启动阶段 2.3 init 进程启动 2.4 shell 命令执行 Linux0.11 考古笔记 最近读完《Linux 内核完全注释》和《品读 Linux0.11...核心代码》,大致理解下 Linux0.11 内核的全貌。...1.4 如何理解进程控制? 程序是一个可执行的文件,而进程是一个执行中的程序实例。关于 Linux0.11 操作系统的进程设计,这里仅侧重理解几个比较重要的概念。...2 流程分析 根据《品读 Linux0.11 核心代码》这个专栏,它是按照系统启动到运行的时间顺序结合 Linux0.11 源码来展开的,我根据专栏的内容进行二次整理。...4)head.s 程序 head.s 程序执行时,重新设置中断描述符表和全局描述符表,然后设置几个相关的段寄存器,然后启动内存管理的分页机制,最后跳转到 main 函数。
fd.pdf 众所周知,子进程会继承父进程已经打开的文件描述符fd,但是fork之后的是不会被继承的,这个时候是否无能无力了?答应是NO。...Linux提供了一个系统调用sendmsg,借助它,可以实现进程间传递文件描述符fd,而且不仅限于父进程到子进程。...通过sendmsg发送的fd,并不是将fd值传递给目标进程,而是活生生地在目标进程空间里复制指向同一个file结构体的fd,所以不要期望在两个进程中,fd值相同。
1.介绍 ---- ulimit 命令提供了针对 shell和或由该 shell 启动的进程占用资源的控制。 持久化修改生效是在/etc/security/limits.conf中进行数据写入....maxsyslogins/priority/locks/sigpending/msgqueue/nice/rtprio/ value: -1/unlimited/infinity/ 具体值 要修改最大文件描述符重点在于...item和value 2.修改 ---- 2.1 先查看当前用户最大文件描述符数量: 1 ulimit -Hn 2 ulimit -Sn 2.2 修改当前用户进程的最大文件描述符数量: 1 vim
Linux 中的进程其实就是一个数据结构,顺带可以理解文件描述符、重定向、管道命令的底层工作原理,最后我们从操作系统的角度看看为什么说线程和进程基本没有区别。...内核对于一个进程的描述,也可以称为「进程描述符」。...mm指向的是进程的虚拟内存,也就是载入资源和可执行文件的地方;files指针指向一个数组,这个数组里装着所有该进程打开的文件的指针。 二、文件描述符是什么 先说files,它是一个文件指针数组。...我们常说的「文件描述符」就是指这个文件指针数组的索引,所以程序的文件描述符默认情况下 0 是输入,1 是输出,2 是错误。...、另一个进程、socket 套接字还是真正的文件,全部都可以读写,统一装进一个简单的files数组,进程通过简单的文件描述符访问相应资源,具体细节交于操作系统,有效解耦,优美高效。
Linux 中的进程其实就是一个数据结构,顺带可以理解文件描述符、重定向、管道命令的底层工作原理,最后我们从操作系统的角度看看为什么说线程和进程基本没有区别。...内核对于一个进程的描述,也可以称为「进程描述符」。...mm指向的是进程的虚拟内存,也就是载入资源和可执行文件的地方;files指针指向一个数组,这个数组里装着所有该进程打开的文件的指针。 二、文件描述符是什么 先说files,它是一个文件指针数组。...我们常说的「文件描述符」就是指这个文件指针数组的索引,所以程序的文件描述符默认情况下 0 是输入,1 是输出,2 是错误。 我们可以重新画一幅图: ?...到这里,你可能也看出「Linux 中一切皆文件」设计思路的高明了,不管是设备、另一个进程、socket 套接字还是真正的文件,全部都可以读写,统一装进一个简单的files数组,进程通过简单的文件描述符访问相应资源
sendmsg 会搭乘一个特殊的「管道」将 Master 进程的套接字描述符传递到 Slave 进程,Slave 进程通过 recvmsg 系统调用从这个「管道」中将描述符取出来。...注意这里的传递描述符,本质上不是传递,而是复制。父进程的描述符并不会在 sendmsg 自动关闭自动消失,子进程收到的描述符和父进程的描述符也不是同一个整数值。...但是父子进程的描述符都会指向同一个内核套接字对象。 有了描述符的传递能力,父进程就可以将 accept 到的客户端套接字轮流传递给多个 Slave 进程,负载均衡的目标就可以顺利实现了。...fork 调用创建了多个子进程,然后又使用 socketpair 调用为每一个子进程都创建一个无名套接字用来传递描述符。...父进程使用 roundrobin 策略平均分配接收到的客户端套接字。子进程接收到的是一个描述符整数,需要将描述符包装成套接字对象后方可读写。
本文以linux0.11版本为基础,分析进程的内存布局,现代版本已经发生比较大的变化,都是很多原理都是类似的。...每个进程可以定义一个LDT,用于存储代码段和数据段信息。GDT布局如下。 ? GDT每个项(GDT描述符)对应的结构体是 ?...// nr是进程id,计算进程的ldt结构在gdt中的索引,执行该进程的时候,从GDT的第tss->ldt项中取得进程的信息。...= new_code_base = nr * 0x4000000; p->start_code = new_code_base; // 设置线性地址到ldt的描述符中 set_base(p->ldt[...和ldt地址到gdt,nr << 1即乘以2,这里算出的是第nr个进程距离第一个tss描述符地址的偏移, 单位是8个字节,即选择描述符大小,_LDT是偏移的大小,单位是1,这里是8 */ set_tss_desc
Linux内核通过一个被称为进程描述符的task_struct结构体来管理进程,这个结构体包含了一个进程所需的所有信息。它定义在include/linux/sched.h文件中。...进程内核栈 void *stack; 内核栈与线程描述符 对每个进程,Linux内核都把两个不同的数据结构紧凑的存放在一个单独为进程分配的内存区域中; 一个是内核态的进程堆栈 另一个是紧挨着进程描述符的小数据结构...thread_info,叫做线程描述符。...线程描述符驻留与这个内存区的开始,而栈顶末端向下增长。 下图摘自ULK3,进程内核栈与进程描述符的关系如下图: ?...进程最常用的是进程描述符结构task_struct而不是thread_info结构的地址。
进程的数据被存放在一个叫做进程控制块的数据结构当中,进程控制块又可以称之为PCB(process control block),进程控制块中包含进程标识符、上下文数据、进程调度信息、进程控制信息、IO状态信息以及进程对应的磁盘代码等...下面的7088进程的父进程就是1492,1492实际上就是bash,7088的子进程是7089,这个进程就是fork函数创建出来的子进程,这个子进程的父进程是7088,也就是bash的子进程,所以7088...子进程先退出,父进程不退出继续运行且不回收子进程,那么这个子进程就是僵尸进程,但如果父进程先退出,那么子进程就变成孤儿进程,它会被1号进程回收,1号进程另一个叫法是init进程,init进程会回收孤儿进程剩余资源...通过进程状态的查看,发现子进程的父进程变为1号进程,我们称被1号进程领养的子进程为孤儿进程,1号进程其实就是操作系统,所以实际上子进程是被操作系统领养。 4....前台进程创建的子进程如果变为孤儿进程,那么这个进程会自动被切换为后台进程 五、进程优先级(受nice值调控的priority值 ) 1.什么是优先级?
,p)) { task[nr] = NULL; free_page((long) p); return -EAGAIN; } // 父子进程都有同样的文件描述符...tss描述符地址的偏移, 单位是8个字节,即选择描述符大小 */ set_tss_desc(gdt+(nrtss));...接着计算一个在全局描述符GDT中的一个索引,这个索引是ldt选择子。后面会讲到。然后计算进程的代码和数据的线性地址首地址和限长,写到ldt的描述符中。接着复制页表,但是不分配物理地址。...下面看看选择子和描述符的格式。 ? ?...最后根据tss中的cs和ip执行进程。这就是文章开头的过程。这就是linux0.11版本中进程地址管理的实现。下面是fork后的结构图。 ?
, hog_image=hog(im, orientations=8,pixels_per_cell=(16,16),cells_per_block=(1,1),visualize=True)#HoG描述符...hog_image_rescaled,cmap=pylab.cm.gray) axes2.set_title('Histogram of Oriented Gradients') pylab.show() 算法:HOG描述符是利用该算法最终得到的归一化区间描述符...首先计算水平和垂直梯度图像 然后计算梯度直方图 接着块(区间)集归一化处理 最后,扁平组合成特征描述符向量
算法:SIFT描述符是将图像内容转换为不受平移、旋转、缩放和其他成像参数影响的局部特征坐标。...对多个尺度和图像位置进行搜索,利用DoG检测器给出位置和特征尺度 关键点定位:根据稳定性指标选择关键点,剔除低对比度和边缘关键点,只保留强感兴趣点 方向分配:计算每个关键点区域的最佳方向,以提高匹配的稳定性 关键点描述符计算
通常,设备会通过一个描述符表格(其固件的一部分)来提供这些信息。描述符表格是数据的结构化序列,描述了设备信息;这些值由开发人员定义。所有描述符表格都具有一个标准信息,用于介绍设备属性和电源要求。...如果某个设计满足指定 USB 设备类别的要求,则该 USB 设备必须具备的其他描述符信息都将包含在设备描述符结构中。附录 A 包含一个 PSoC USB 的全功能设备描述符的示例。...如果您正在阅读或创建您自己的描述符,那么请注意,传输数据字段时,优先传输最低有效位。许多参数的长度均为 2个字节。请确保先发送低字节,然后再发送高字节。
例如Thread的类名叫java.lang.Thread,但是在class文件格式的描述符中使用的内部格式,对Thread类名称utf8的引用却是:java/lang/Thread 不信我们随便打开一个...class文件 可以看到类似的描述符 那如何获取类的描述符呢?...首先,基本类型描述符,都是以ASCII字符表示,例如L 正斜杠类名;表示对象类型,[表示数组类型 我们可以在sun.invoke.util.Wrapper下看到对应枚举常量 例如: int的描述符为...I Integer的描述符为Ljava/lang/Integer; void的描述符为V java.lang.Void的描述符为Ljava/lang/Void; Object的描述符为...Ljava/lang/Object; double d[][][]的描述符为[[[D 然后方法描述符的规则是: (参数描述符们)返回值描述符 例如: 这样一个方法: Object m(int
%esp) // 压栈寄存器 pushl %ecx pushl %edx push %ds push %es push %fs // 内核数据段描述符...12) & 0x3ff] = page | 7; /* no need for invalidate */ // 返回线性地址 return page; } 2 否则先判断是否有另一个进程和当前进程使用了同一个执行文件...= current->executable) continue; // 找到一个不是当前进程,但都执行了同一个可执行文件的进程 if (try_to_share...= current, and that they * share the same executable. */ // 使得另一个进程的页目录和页表项指向另一个进程的正在使用的物理地址 static...(线性地址),取得p进程的页目录项地址,再加上address算出的偏移 from_page += ((p->start_code>>20) & 0xffc); // 取得当前进程的页目录项地址
具体的分析可以看linux0.11系统调用过程和fork源码解析这篇文章。下面贴一下代码。...pcb地址赋值给eax movl _current,%eax // 判断当前进程状态,0是可执行,即判断当前进程是否可以继续执行 cmpl $0,state(%eax) # state...用于清除栈上的参数和正确返回用户进程要执行的下一条执行。...信号处理的时机是在进程进行系统调用的时候。假设通过kill系统调用给进程发送一个信号。...,大于0则给某个进程发信号,-1则给全部进程发,小于-1则给某个组发信号 if (!
领取专属 10元无门槛券
手把手带您无忧上云