大部分基知识看看就行
定义
进程是具有独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的独立单位
- 进程是程序的一次执行过程,一个程序执行多次那是不同的进程
- 是正在运行的程序的抽象,或者说是对CPU的一个抽象
- 将一个CPU变换成多个虚拟的CPU
- 系统资源以进程为单位分配,如内存、文件等,操作系统为每个独立的进程分配了独立的地址空间
- 操作系统将CPU调度给需要的进程,即将CPU的控制权交给某个进程就称为调度
特点
- 结构性:由数据段、程序段、PCB构成
- 动态性:可以被动态地创建、执行、撤销
- 并发性:同一时间内有多个进程在运行
- 独立性:独立运行以及获得OS资源的基本单位
- 异步性:异步执行
状态
- 运行状态
- 进程已经占有CPU,在CPU上运行
- 就绪状态
- 具备运行条件,但是由于无CPU,暂时不能运行
阻塞状态
- 等待信号不能运行
三态转换

五态转换

Linux 下的进程状态
版本不同可能状态不同
可运行态
- 就绪(TASK_RUNNING):在就绪队列中等待调度。
- 运行:已经在运行的进程
- 阻塞状态
- 可中断阻塞态(TASK_INTERRUPTIBLE): 进程处于某个等待队列中,它能够被信号(signal)或中断唤醒。等待资源的请求满足时,也被唤醒。
- 不可中断阻塞态(TASK_UNINTERRUPTIBLE):进程处于某个等待队列中,不能被信号或中断唤醒,只有等待的资源被满足时才被唤醒。例如当进程打开一个设备文件时,使用TASK_UNINTERRUPTIBLE.
- 僵死状态(TASK_ZOMBIE):进程已经停止,但还没有释放进程控制块
- 停止态(TASK_STOPPED):该状态表示进程的执行被暂停。例如正在接受调试的进程处于这种状态。
- 死亡态(TASK_DEAD):处于僵死进程的控制块由其父进程回收后的状态。

进程控制块(PCB)
作用:描述进程状态、资源、和与相关进程关系的数据结构。
创建进程时创建PCB;进程撤销后PCB同时撤销。


源码部分解析
源码下载,去Linux官网下载即可,可以下载内核代码,如果嫌下载太慢可以去:http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/
上面没有 0.11的内核,需要去其他地方下载
文件在:$你的内核目录$/include/linux/sched.h
如果找不到 ,可以用find -name sched.h 命令寻找
建议用学习的时候用,Linux低一点的版本,虽然少了很多新东西,但是学习起来更简单。
Linux 1.0 源码
前面介绍的几种状态的定义
1
2
3
4
5
6
到了 linux 2.6.38,代码明显复杂了许多,而且使用二进制的第几位来表示状态。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* in tsk->exit_state */
/* in tsk->state again */
extern char ___assert_task_state[1 - 2*!!(
sizeof(TASK_STATE_TO_CHAR_STR)-1 != ilog2(TASK_STATE_MAX)+1)];
/* Convenience macros for the sake of set_task_state */
/* Convenience macros for the sake of wake_up */
linux1.0 里面的PCB 结构体,写了一部分其他,具体的自己可以去搜索 sched.h 的源码剖析,可以用grep -rn "内柔"查找函数实现1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119// 前面所介绍的 几种 状态
//调度程序初始化函数 实现 在(kernel/sched.c)
extern void sched_init(void);
//显示
extern void show_state(void);
// 异常中断初始化函数 实现在(kernel/traps.c)
extern void trap_init(void);
//进程调度函数。实现在(kernel/sched.c),
asmlinkage void schedule(void);
struct task_struct {
/* these are hardcoded - don't touch */
//运行状态
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
// 时间片
long counter;
// 运行优先数 ,任务开始运行时counter = priority,越大运行越长。
long priority;
//信号。是位图,每个比特位代表一种信号,信号值=位偏移值+1
unsigned long signal;
//进程信号屏蔽码(对应信号位图)
unsigned long blocked; /* bitmap of masked signals */
unsigned long flags; /* per process flags, defined below */
int errno;
int debugreg[8]; /* Hardware debugging registers */
/* various fields */
//下一个 以及上一个 进程
struct task_struct *next_task, *prev_task;
struct sigaction sigaction[32];
unsigned long saved_kernel_stack;
unsigned long kernel_stack_page;
int exit_code, exit_signal;
int elf_executable:1;
int dumpable:1;
int swappable:1;
int did_exec:1;
//代码段信息
unsigned long start_code,end_code,end_data,start_brk,brk,start_stack,start_mmap;
unsigned long arg_start, arg_end, env_start, env_end;
//long pid 进程标识号(进程号)
int pid,pgrp,session,leader;
int groups[NGROUPS];
/*
* pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with
* p->p_pptr->pid)
*/
// p_pptr 父亲进程
struct task_struct *p_opptr,*p_pptr, *p_cptr, *p_ysptr, *p_osptr;
//等待的儿子
struct wait_queue *wait_chldexit; /* for wait4() */
/*
* For ease of programming... Normal sleeps don't need to
* keep track of a wait-queue: every task has an entry of its own
*/
// long pid 进程标识号(进程号)。
// unsigned short euid 有效用户id。
// unsigned short suid 保存的用户id。
// unsigned short gid 组标识号(组id)。
// unsigned short egid 有效组id。
// unsigned short sgid 保存的组id。
unsigned short uid,euid,suid;
unsigned short gid,egid,sgid;
unsigned long timeout;
unsigned long it_real_value, it_prof_value, it_virt_value;
unsigned long it_real_incr, it_prof_incr, it_virt_incr;
// long utime 用户态运行时间(滴答数)。
// long stime 系统态运行时间(滴答数)。
// long cutime 子进程用户态运行时间。
// long cstime 子进程系统态运行时间。
long utime,stime,cutime,cstime,start_time;
unsigned long min_flt, maj_flt;
unsigned long cmin_flt, cmaj_flt;
struct rlimit rlim[RLIM_NLIMITS];
unsigned short used_math;
unsigned short rss; /* number of resident pages */
char comm[16];
struct vm86_struct * vm86_info;
unsigned long screen_bitmap;
/* file system info */
int link_count;
int tty; /* -1 if no tty, so it must be signed */
unsigned short umask;
struct inode * pwd;
struct inode * root;
struct inode * executable;
struct vm_area_struct * mmap;
struct shm_desc *shm;
struct sem_undo *semun;
struct file * filp[NR_OPEN];
fd_set close_on_exec;
/* ldt for this task - used by Wine. If NULL, default_ldt is used */
struct desc_struct *ldt;
/* tss for this task */
struct tss_struct tss;
unsigned long old_maj_flt; /* old value of maj_flt */
unsigned long dec_flt; /* page fault count of the last time */
unsigned long swap_cnt; /* number of pages to swap on next pass */
short swap_table; /* current page table */
short swap_page; /* current page */
struct vm_area_struct *stk_vma;
};
通常PCB 会有
原语:完成某种特定功能的一段程序,具有不可分割性或不可中断性,即原语的执行必须是连续的,在执行过程中不允许被中断。又称原子操作。
进程控制操作完成进程各状态之间的转换,由具有特定功能的原语(其实就是程序,只是这些程序不许与被中断)完成。关于进程控制的原语如下:
- 进程创建原语
- 进程撤销原语
- 阻塞原语
- 唤醒原语
- 激活原语
- 改变进程优先级
是否 看见sched.h里面又一部分 函数的声明。
在sched.c里面有 具体的实现
sched_init
调度初始化,初始化很多都看不懂,知道他是干啥的就行。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29sched_init(void)
{
int i;
struct desc_struct * p;
bh_base[TIMER_BH].routine = timer_bh;
if (sizeof(struct sigaction) != 16)
panic("Struct sigaction MUST be 16 bytes");
set_tss_desc(gdt+FIRST_TSS_ENTRY,&init_task.tss);
set_ldt_desc(gdt+FIRST_LDT_ENTRY,&default_ldt,1);
set_system_gate(0x80,&system_call);
p = gdt+2+FIRST_TSS_ENTRY;
for(i=1 ; i<NR_TASKS ; i++) {
task[i] = NULL;
p->a=p->b=0;
p++;
p->a=p->b=0;
p++;
}
/* Clear NT, so that we won't have troubles with that later on */
__asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
load_TR(0);
load_ldt(0);
outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
outb_p(LATCH & 0xff , 0x40); /* LSB */
outb(LATCH >> 8 , 0x40); /* MSB */
if (request_irq(TIMER_IRQ,(void (*)(int)) do_timer)!=0)
panic("Could not allocate timer IRQ!");
}
show_task和show_state
着两个不用多说吧1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39static void show_task(int nr,struct task_struct * p)
{
static char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" }; // 6 种状态
printk("%-8s %3d ", p->comm, (p == current) ? -nr : nr);
if (((unsigned) p->state) < sizeof(stat_nam)/sizeof(char *))
printk(stat_nam[p->state]);
else
printk(" ");
if (p == current)
printk(" current ");
else
printk(" %08lX ", ((unsigned long *)p->tss.esp)[3]);
printk("%5lu %5d %6d ",
p->tss.esp - p->kernel_stack_page, p->pid, p->p_pptr->pid);
if (p->p_cptr)
printk("%5d ", p->p_cptr->pid);
else
printk(" ");
if (p->p_ysptr)
printk("%7d", p->p_ysptr->pid);
else
printk(" ");
if (p->p_osptr)
printk(" %5d\n", p->p_osptr->pid);
else
printk("\n");
}
void show_state(void) //调用上面那个信息
{
int i;
printk(" free sibling\n");
printk(" task PC stack pid father child younger older\n");
for (i=0 ; i<NR_TASKS ; i++)
if (task[i])
show_task(i,task[i]);
}