一.内核进程
程序与进程的区别:
1.程序是磁盘上的一系列代码和数据的可执行映像,是一个静止的实体.
2.进程是一个执行中的程序,它是动态的实体.
进程与线程的区别:
1.进程是分配资源的最小单位.
2.线程是最小的调度单位.
进程的四要素:
1.有一段程序供其执行.
2.专用的内核空间.
3.有一个task_struct数据结构.
4.有独立的用户空间堆栈. (主要区别)
Linux中,线程,进程都是使用struct task_struct来表示包含大量描述线程/进程的信息.
进程描述:
1.pid_t pid :进程号.
2.struct mm_struct *mm:用户空间描述指针.内核线程为空.
3.unsigned int policy:进程调度策略.
4.int prio:优先级.
5.intstatic_prio:静态优先级.
6.struct sched_rt_entity rt.
rt->time_slice:时间片.
进程状态:
1.TASK_RUNNING:进程可执行,准备就绪. (重要)
2.TASK_INTERRUPTIBLE:可中断唤醒. (重要)
3.TASK_UNINTERRUPTIBLE:不可中断欢喜那个. (重要)
4.TASK_KILLABLE:Linux2.6.25新引入的,可以SIGKILL唤醒.
5.TASK_STOPPED:接收SIGSTOP或SIGTSTP等进入阻塞态,当接收SIGCONT
重新进入TASK_RUNNING.
6.TASK_TRACED:处于调试状态.
7.TASK_DEAD:进程退出.
intexit_state:进程退出时的状态.
EXIT_ZOMBIE:僵死进程,父进程还没发布waitpid()系统调用收集有关死亡的进程的信息.
EXIT_DEAD:僵死撤销状态.进程将由系统删除.
二. Linux进程调度
调度:从就需的进程中选出最合适的一个来执行.
1.调度策略.
2.调度时机.
3.调度步骤.
调度策略:
1.SCHED_NORMAL:普通分时进程. (默认)
2.SCHED_FIFO:先入先出的实时进程.
3.SCHED_RR:时间片轮转的实时进程.
4.SCHED_BATCH:批处理进程.
5.SCHED_IDLE:只在系统空闲时才能够被调度执行的进程.
调度类:
CFS调度类:(kernel/sched_fair.c) 1 , 4 ,5
实时调度类:(kernel/sched_rt.c) 2 ,3
调度时机:
1. 主动式:调用schedule();
例子:主动放弃CPU:current->state =TASK_INTERRUPTIBLE;
schedule();
2. 被动式:用户抢占. (2.4内核 2.6内核)
内核抢占.(2.6内核)
内核抢占:
不允许:
1.内核正进行中断处理.
2.处于中断上下文.
3.进程正持有spinlock自旋锁,writelock/readlock读写锁等.
4.正在执行调度程序scheduler().
可能发生在:
1.中断处理程序完成,返回内核空间之前.
2.当内核代码再一次具有可抢占性的时候
例子:解锁and 使能软中断 等.
调度步骤:
1.清理当前运行中的进程.
2.选择下一个要运行的进程. (pick_next_task分析)
3.设置新进程的运行环境.
4.进程上下文切换.
三. Linux系统调用(2.6.29内核:arch/arm/include/asm/unistd.h)
实现新的系统调用步骤:
1.添加新的内核函数.
2.更新头文件unistd.h
3.针对新函数更改新系统调用表 (call.S)
例子:
1.在kernel/sys.c中添加函数.
asmlinkage int sys_add(int a , intb)
{
int sum;
sum = a + b;
return sum;
}
//asmlinkage:使用栈传递参数.(汇编程序调用)
2.在arch/arm/include/asm/unistd.h中添加如下代码:
#define _ _NR_sys_add (_ _NR_ SYSCALL_BASE + 361)
361:是内核调用函数的次序,可按实际情况改变.
sys_add:函数名字.
3.在arch/arm/kernel/calls.S中添加代码,指向新实现的系统调用函数:
CALL(sys_add)
4.重新编译内核.
5.使用新实现的系统调用.
#include<stdio.h>
#include<linux/unistd.h>
main()
{
int sum;
sum = syscall(361 , 1 , 2);
printf("sum = %d\n" , sum);
}