1. 进程的内核描述
struct task_struct {
/*----------------------- these are hardcoded - don't touch -----------------------*/
long state; // 进程运行状态(-1不可运行,0可运行,>0以停止)
long counter; // 任务运行时间片,递减到0是说明时间片用完
long priority; // 任务运行优先数,刚开始是counter=priority
long signal; // 任务的信号位图,信号值=偏移+1
struct sigaction sigaction[32]; //信号执行属性结构,对应信号将要执行的操作和标志信息
long blocked; // 信号屏蔽码
/*----------------------------------- various fields--------------------------------- */
int exit_code; // 任务退出码,当任务结束时其父进程会读取
unsigned long start_code,end_code,end_data,brk,start_stack;
// start_code 代码段起始的线性地址
// end_code 代码段长度
// end_data 代码段长度+数据段长度
// brk 代码段长度+数据段长度+bss段长度
// start_stack 堆栈段起始线性地址
long pid,father,pgrp,session,leader;
// pid 进程号
// father 父进程号
// pgrp 父进程组号
// session 会话号
// leader 会话首领
unsigned short uid,euid,suid;
// uid 用户标id
// euid 有效用户id
// suid 保存的用户id
unsigned short gid,egid,sgid;
// gid 组id
// egid 有效组id
// sgid 保存组id
long alarm; // 报警定时值
long utime,stime,cutime,cstime,start_time;
// utime 用户态运行时间
// stime 内核态运行时间
// cutime 子进程用户态运行时间
// cstime 子进程内核态运行时间
// start_time 进程开始运行时刻
unsigned short used_math; // 标志,是否使用了387协处理器
/* ----------------------------------file system info-------------------------------- */
int tty; // 进程使用tty的子设备号,-1表示没有使用
unsigned short umask; //文件创建属性屏蔽码
struct m_inode * pwd; // 当前工作目录的i节点
struct m_inode * root; // 根目录的i节点
struct m_inode * executable; // 可执行文件的i节点
unsigned long close_on_exec; // 执行时关闭文件句柄位图标志
struct file * filp[NR_OPEN]; // 进程使用的文件
/*------------------ ldt for this task 0 - zero 1 - cs 2 - ds&ss -------------------*/
struct desc_struct ldt[3]; // 本任务的ldt表,0-空,1-代码段,2-数据和堆栈段
/* ---------------------------------tss for this task ---------------------------------*/
struct tss_struct tss; // TSS
};
2. 进程0的描述符信息
/* state etc */ { 0,15,15, /
/* signals */ 0,{{},},0, /
/* ec,brk... */ 0,0,0,0,0,0, /
/* pid etc.. */ 0,-1,0,0,0, /
/* uid etc */ 0,0,0,0,0,0, /
/* alarm */ 0,0,0,0,0,0, /
/* math */ 0, /
/* fs info */ -1,0022,NULL,NULL,NULL,0, /
/* filp */ {NULL,}, /
{ /
{0,0}, / // ldt第0项是空
/* ldt */ {0x9f,0xc0fa00}, / //代码段长640K,基地0,G=1,D=1,DPL=3,P=1,TYPE=0x0a
{0x9f,0xc0f200}, / //数据段长640K,基地0,G=1, D=1, DPL=3,P=1, TYPE=0x02
}, /
/*tss*/ {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,/
// esp0 = PAGE_SIZE+(long)&init_task 内核态堆栈指针初始化为页面最后
// ss0 = 0x10 内核态堆栈的段选择符,指向系统数据段描述符,进程0的进程控制
// 块和内核态堆栈都在system模块中
// cr3 = (long)&pg_dir 页目录表,其实linux0.11所有进程共享一个页目录表
0,0,0,0,0,0,0,0, /
0,0,0x17,0x17,0x17,0x17,0x17,0x17, /
_LDT(0),0x80000000, / // ldt表选择符指向gdt中的LDT0处
{} /
}
3. 进程的内存布局
4. 进程控制相关函数
1). sys_fork(), 克隆一个进程;
2). sys_execve(), 加载一个可执行程序(换上新的代码);
3). sys_exit(),进程退出。释放内存, 将所有孩子过继给进程1, 释放当前使用的文件资源, 释放TTY,如果是会话首领则结束会话。
4). sys_waitpid(), 等待某进程退出;
5. 信号处理
信号相当于软中断, 用于进程间通讯. CPU在执行每条指令的末端检测是否有硬件中断,而内核在进程从内核态返回时检测是否响应信号。
struct sigaction { // 信号响应结构体
void (*sa_handler)(int); // 信号响应函数地址,相当与中断服务程序入口
sigset_t sa_mask; // 进程正在处理当前信号时,可能需要屏蔽新的信号
// 将要屏蔽的信息存在这里。
// 通常是把当前正在处理的信号屏蔽调。进程对正在处理
// 的信号肯定是允许的,通过设置这个变量来决定是否允许
// 当前信号嵌套。
int sa_flags; // 改变信号处理过程的信号集
void (*sa_restorer)(void); // 恢复函数入口地址,用于清除用户堆栈
// 这个函数由libc提供,用户无法自行设置
};
/*****************************************************************************/
/* 功能:为信号注册新的响应函数 */
/* 该响应函数是临时的,调用过一次后就恢复成SIG_DFL */
/* 参数:signum 指定的信号 */
/* handler 待注册的响应函数 */
/* restorer 恢复函数,libc提供 */
/* 返回:signum信号原先的响应函数 */
/*****************************************************************************/
int sys_signal(int signum, long handler, long restorer)
{
struct sigaction tmp;
// 信号值不在范围内,或者企图修改SIGKILL的响应函数,则出错
// SIGKILL是不能被屏蔽的,收到SIGKILL的进程必须退出,所以SIGKILL的
// 响应函数必须是SIG_DFL且不允许被修改
if (signum<1 || signum>32 || signum==SIGKILL)
return -1;
//下面4句创建新的响应结构体
tmp.sa_handler = (void (*)(int)) handler; // 填入新的响应函数句柄
tmp.sa_mask = 0; // 响应信号时不屏蔽任何信号
tmp.sa_flags = SA_ONESHOT | SA_NOMASK; // 新的响应函数使用一次后就恢复成
// SIG_DFL
tmp.sa_restorer = (void (*)(void)) restorer; // 转入恢复函数
handler = (long) current->sigaction[signum-1].sa_handler; // 保持旧的响应函数
current->sigaction[signum-1] = tmp; // 装入新的响应结构
return handler; // 返回旧函数的句柄
}
/*****************************************************************************/
/* 功能:为信号转载响应机构体 */
/* 该响应结构体永远存在,知道该信号被再次装载 */
/* 参数:signum 指定的信号 */
/* action 待转入的响应结构体指针,这是用户空间中的逻辑地址 */
/* oldaction 用于返回旧的响应结构体,这是用户空间中的逻辑地址 */
/* 返回:0 成功 –1 出错 */
/*****************************************************************************/
int sys_sigaction(int signum, const struct sigaction * action,
struct sigaction * oldaction)
{
struct sigaction tmp;
if (signum<1 || signum>32 || signum==SIGKILL)
return -1;
// 取出旧的响应结构体,放入tmp中。
// 这里用的是“=”,因为tmp和current都在内核空间
tmp = current->sigaction[signum-1];
// 装入新的响应结构体action
// 这里不能用“=”,因为新结构体是用户定义,在用户空间。action指向的是
// 用户空间中的逻辑地址
get_new((char *) action,
(char *) (signum-1+current->sigaction));
// 如果oldaction不是空,则把旧的响应结构体保存在它指向的地址
// 同眼,oldaction也是用户空间中的逻辑地址,不能用“=”直接赋值
if (oldaction)
save_old((char *) &tmp,(char *) oldaction);
// 如果允许信号在自己的信号处理函数中收到,则清空屏蔽码
if (current->sigaction[signum-1].sa_flags & SA_NOMASK)
current->sigaction[signum-1].sa_mask = 0;
else // 否则屏蔽自己
current->sigaction[signum-1].sa_mask |= (1<<(signum-1));
return 0;
}