作为一名菜鸟学习Linux内核网络模块,打算先看这本《Linux内核设计与实现》再看《深入理解Linux网络技术内幕》。
现把所学历程记录成笔记以激励自己坚持学习。
1、基本概念
同一个进程中的线程共享该进程的虚拟内存(也就是进程的地址空间),但是独享虚拟处理器。进程的创建通过系统调用fork(),该函数返回两次,一次返回到新创建的子进程中,另一次返回到父进程中。因此可能存在主进程调用fork时尚未返回子进程已经开始运行了。子进程退出时被设为僵死状态,直到父进程调用wait()函数。
2、进程描述符及任务结构
进程用struct task_struct 来表示,也叫做进程描述符(对进程的描述,自然要包含进程的所有信息)。2.6版本以前进程描述符存储在自己的内核栈的栈尾,2.6以后Linux使用slab分配器来为进程描述符分配内存空间,通过双向链表来组织进程描述符。这个样每个进程的task_struct 就存储在双向链表里面了。然后在进程内核栈的尾端存储一个 struct thread_info,struct thread_info中有一个指针变量 struct task_struct *task 指向进程描述符 。 内核通过宏current来找到当前正在执行进程的进程描述符。在x86体系结构中current会从thread_info中通过task指针找到正在运行的进程描述符。
进程通过PID来唯一标示一个进程,该字段是struct task_struct的一个域。
3、进程的状态
(1)TASK_RUNING
运行,表示进程可以运行,当前进程可能是正在运行也有可能是在就绪队列中。
(2)TASK_INTERRUPPIBLE
可中断,表示进程正在被阻塞,等待条件的发生。当条件发生时,或者被信号唤醒。进程就进入运行态。
(3)TASK_UNINTERRUPPIBLE
不可中断,该进程也是处于阻塞,但是不能被信号唤醒,只能是被等待的条件发生才能唤醒。
(4)TASK_ZOMBLE
僵死,处于该状态的进程也叫做僵尸进程,进程已经运行结束了,但是其父进程还没有调用wait(),为了使父进程可以 获知其状态信息,该进程的进程描述符并没有释放。
(5)TASK_STOPPED
停止,进程已经停止运行。一般是收到信号SIGSTOP等。
内核对进程状态的设置调用函数set_task_state(task,state)
4、进程家族
进程描述符中有个指针struct task_struct *parent 指向该进程的父进程,指针struct task_struct*children指向该进程的子进程链表。
5、进程的创建
进程创建在用户层调用系统接口fork()-----》调用clone()-----》调用do_fork()------>调用copy_pocess()
在fork中调用clone时传递的参数是clone(CLONE_SIGCHLD,0)
6、线程的实现
在linux内核中其实并没有线程,线程就是进程,线程的数据结构就是struct task_struct,这与windows系统是有区别的,windows内核中有专门的 线程数据结构。我们知道进程间的地址空间是独立的,而线程间的地址空间是共享的,因此linux下,两个进程公用一个进程地址空间就行形成了多线程。
在线程中调用clone(CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGCHLD,0)
7、进程的退出
每个进程最终都会终结的,在用户态进程的退出是通过调用exit或者从main函数return,实际上编译器在编译c的main函数时会在后面加上exit函数
,exit调用do_exit,do_exit的功能实现进程终结前的一些清理工作,比如调用exit_notify()向父进程发送信号然后处于TASK_ZOMBLE状态就不能运行了,在最后阶段会调用schedule切换到其他进程执行。到此时进程的struct_task、thread_info和内核栈资源还是存在的。
父进程调用wait(),获取其退出的子进程的状态,并释放子进程的剩下的那三个资源。也就是说如果父进程不调用wait那么子进程就会一直处于TASK_ZOMBLE状态。
有一种情况是父进程先于子进程退出,那么就得为这个子进程重新找一个父进程,否则这个子进程退出后就会一直出去TASK_ZOMBLE状态,那么它占用的内存资源不会得到释放。同时也说明了,父进程中必须要调用wait函数来处理子进程的退出问题,否则就会浪费内存资源,而调用wait时如果当前进程没有子进程退出就会阻塞当前进程,因此可以采用signal函数,当接收到子进程的退出时发送的信号时signal的处理函数调用wait,这样子进程占用的内存资源就会释放了。
系统会为失去父进程的子进程寻找父进程,如果一个父进程当初创建了多个子进程,那么就会在这些子进程中间寻找一个子进程当做新的父进程,如果只有一个子进程就会让init进程做父进程。
阅读(662) | 评论(0) | 转发(0) |