在kernel包中有几个重要的文件夹和文件,他们各司其职,处理着有关内核的一些功能操作。其中文件夹有三个:blk_drv(块设备驱动),chr_drv(字符设备驱动),math(数学协处理器)  文件中asm.s  fork.c   mktime.c   panic.c printk.c  sched.c  signal.c  exit.c   sys.c   traps.c  system_call.c  vsprintf.c   该文件夹下的代码文件从功能上来可以分为三类:

1.硬件中断处理类程序。(asm.s   trap.c)asm.s用于实现大部分硬件异常所引起的中断的汇编语言处理过程。在80X86组成的PC机中,采用了两片8259A可编程中断控制芯片。每片可以管理8个中断源。通过多片的级联方式,能够构成最多可以管理64个中断向量的系统。在PC/AT系列兼容机中,使用了两片8259A芯片,共可管理15级中断向量。如下图:

对于Linux内核来说,中断信号通常分为两类:硬件中断和软件中断(异常)。每个中断时由0-255之间的一个数字来标示。对于中断int0-int31(0x00--0x1f),每个中断的功能有INTEL公司固定设定或者保留用,属于软件中断,单INTEL公司称之为异常。因为这些中断时在CPU执行指令时探测到异常而引起的。中断int32--int255可以由用户自己设定使用,在Linux中int32--int47对应于8259A中断控制芯片发出的硬件中断请求信号IRQ0--IRQ15,并把程序编程发出的系统调用(system_call)中断设置为int128(0x80)。

traps.c程序则实现了asm.s的中断处理过程中调用的C函数。

2.系统调用处理相关程序(system_call.s  fork.c   signal.c  sys.c  exit.c)在Linux中应用程序调用内核的功能是通过中断调用int0x80进行的

3.其他通用类程序(schedule.c   mktime.c  panic.c  printk.c vsprintf.c)   其中,schedule.c最为重要,是内核的核心调度程序,用于对进程的执行进行切换或改变进程的执行状态。

下面是一些具体的文件

1.system_call.s对于软中断,处理过程基本上是首先为调用相应C函数处理程序作准备,将一些参数压入堆栈,然后调用C函数进行相应功能的处理。  对于硬中断请求型号IRQ发来的中断,其处理过程首先是向中断控制芯片8259A发送结束硬件中断控制字指令EOI,然后调用相应的C函数处理程序。   对于系统调用的中断处理过程,可以把它看做是一个“接口”程序,实际每个系统调用功能的处理基本上都是通过调用相应的C函数进行的。即所谓的  下半区  函数。

2.schedule.c是对整个内核进程的调度,这里面把代码贴上,比说什么都要明白。

/*
* 'schedule()'是调度函数。这是个很好的代码!没有任何理由对它进行修改,因为它可以在所有的
* 环境下工作(比如能够对IO-边界处理很好的响应等)。只有一件事值得留意,那就是这里的信号
* 处理代码。
* 注意!!任务0 是个闲置('idle')任务,只有当没有其它任务可以运行时才调用它。它不能被杀
* 死,也不能睡眠。任务0 中的状态信息'state'是从来不用的。
*/
void
schedule (void)
{
int i, next, c;
struct task_struct **p; // 任务结构指针的指针。 /* check alarm, wake up any interruptible tasks that have got a signal */
/* 检测alarm(进程的报警定时值),唤醒任何已得到信号的可中断任务 */ // 从任务数组中最后一个任务开始检测alarm。
for (p = &LAST_TASK; p > &FIRST_TASK; --p)
if (*p)
{
// 如果任务的alarm 时间已经过期(alarm<jiffies),则在信号位图中置SIGALRM 信号,然后清alarm。
// jiffies 是系统从开机开始算起的滴答数(10ms/滴答)。定义在sched.h 第139 行。
if ((*p)->alarm && (*p)->alarm < jiffies)
{
(*p)->signal |= (1 << (SIGALRM - 1));
(*p)->alarm = 0;
}
// 如果信号位图中除被阻塞的信号外还有其它信号,并且任务处于可中断状态,则置任务为就绪状态。
// 其中'~(_BLOCKABLE & (*p)->blocked)'用于忽略被阻塞的信号,但SIGKILL 和SIGSTOP 不能被阻塞。
if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
(*p)->state == TASK_INTERRUPTIBLE)
(*p)->state = TASK_RUNNING; //置为就绪(可执行)状态。
} /* this is the scheduler proper: */
/* 这里是调度程序的主要部分 */ while (1)
{
c = -1;
next = 0;
i = NR_TASKS;
p = &task[NR_TASKS];
// 这段代码也是从任务数组的最后一个任务开始循环处理,并跳过不含任务的数组槽。比较每个就绪
// 状态任务的counter(任务运行时间的递减滴答计数)值,哪一个值大,运行时间还不长,next 就
// 指向哪个的任务号。
while (--i)
{
if (!*--p)
continue;
if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
c = (*p)->counter, next = i;
}
// 如果比较得出有counter 值大于0 的结果,则退出124 行开始的循环,执行任务切换(141 行)。
if (c)
break;
// 否则就根据每个任务的优先权值,更新每一个任务的counter 值,然后回到125 行重新比较。
// counter 值的计算方式为counter = counter /2 + priority。[右边counter=0??]
for (p = &LAST_TASK; p > &FIRST_TASK; --p)
if (*p)
(*p)->counter = ((*p)->counter >> 1) + (*p)->priority;
}
switch_to (next); // 切换到任务号为next 的任务,并运行之。
} //// pause()系统调用。转换当前任务的状态为可中断的等待状态,并重新调度。
// 该系统调用将导致进程进入睡眠状态,直到收到一个信号。该信号用于终止进程或者使进程调用
// 一个信号捕获函数。只有当捕获了一个信号,并且信号捕获处理函数返回,pause()才会返回。
// 此时pause()返回值应该是-1,并且errno 被置为EINTR。这里还没有完全实现(直到0.95 版)。
int
sys_pause (void)
{
current->state = TASK_INTERRUPTIBLE;
schedule ();
return 0;
} // 把当前任务置为不可中断的等待状态,并让睡眠队列头的指针指向当前任务。
// 只有明确地唤醒时才会返回。该函数提供了进程与中断处理程序之间的同步机制。
// 函数参数*p 是放置等待任务的队列头指针。(参见列表后的说明)。
void
sleep_on (struct task_struct **p)
{
struct task_struct *tmp; // 若指针无效,则退出。(指针所指的对象可以是NULL,但指针本身不会为0)。
if (!p)
return;
if (current == &(init_task.task)) // 如果当前任务是任务0,则死机(impossible!)。
panic ("task[0] trying to sleep");
tmp = *p; // 让tmp 指向已经在等待队列上的任务(如果有的话)。
*p = current; // 将睡眠队列头的等待指针指向当前任务。
current->state = TASK_UNINTERRUPTIBLE; // 将当前任务置为不可中断的等待状态。
schedule (); // 重新调度。
// 只有当这个等待任务被唤醒时,调度程序才又返回到这里,则表示进程已被明确地唤醒。
// 既然大家都在等待同样的资源,那么在资源可用时,就有必要唤醒所有等待该资源的进程。该函数
// 嵌套调用,也会嵌套唤醒所有等待该资源的进程。然后系统会根据这些进程的优先条件,重新调度
// 应该由哪个进程首先使用资源。也即让这些进程竞争上岗。
if (tmp) // 若还存在等待的任务,则也将其置为就绪状态(唤醒)。
tmp->state = 0;
} // 将当前任务置为可中断的等待状态,并放入*p 指定的等待队列中。参见列表后对sleep_on()的说明。
void
interruptible_sleep_on (struct task_struct **p)
{
struct task_struct *tmp; if (!p)
return;
if (current == &(init_task.task))
panic ("task[0] trying to sleep");
tmp = *p;
*p = current;
repeat:current->state = TASK_INTERRUPTIBLE;
schedule ();
// 如果等待队列中还有等待任务,并且队列头指针所指向的任务不是当前任务时,则将该等待任务置为
// 可运行的就绪状态,并重新执行调度程序。当指针*p 所指向的不是当前任务时,表示在当前任务被放
// 入队列后,又有新的任务被插入等待队列中,因此,既然本任务是可中断的,就应该首先执行所有
// 其它的等待任务。
if (*p && *p != current)
{
(**p).state = 0;
goto repeat;
}
// 下面一句代码有误,应该是*p = tmp,让队列头指针指向其余等待任务,否则在当前任务之前插入
// 等待队列的任务均被抹掉了。参见图4.3。
*p = NULL;
if (tmp)
tmp->state = 0;
} // 唤醒指定任务*p。
void
wake_up (struct task_struct **p)
{
if (p && *p)
{
(**p).state = 0; // 置为就绪(可运行)状态。
*p = NULL;
}
}

 

3.signal.c主要对信号的判断,对于一个进程,当收到一个信号时,可以由三种不同的处理或者操作方式。a。忽略该信号,但是SIGKILL和SIGSTOP不能忽略。b。捕获该信号。c。执行默认操作,内核为每种信号都提供一种默认操作,通常这些默认操作就是终止进程的执行。(对于信号的具体内容还有待研究)

4.fork.c主要是copy_process函数。该函数通过get_free_page ()(为新任务数据结构分配内存)函数得到一个新的task_struct空间。然后将current的信息复制给对方。得到新进程

----

linux0.11文件分析的更多相关文章

  1. linux-0.11分析:boot文件 head.s 第三篇随笔

    head.s 参考 [github这个博主的][ https://github.com/sunym1993/flash-linux0.11-talk ] 改变栈顶位置 _pg_dir: startup ...

  2. 快速搭建Linux-0.11实验环境

    搭这个实验环境主要是为了学习Linux-0.11的代码,那就需要修改代码再次编译来验证自己的想法.主要的实验环境来自实验楼,但是在那上面毕竟不方便,所以就以实验楼上的为基础在自己的虚拟机上搭建一个环境 ...

  3. linux0.11下的中断机制分析

    http://orbt.blog.163.com/     异常就是控制流中的突变,用来响应处理器状态中的某些变化.当处理器检测到有事件发生时,它就会通过一张叫做异常表的跳转表,进行一个间接过程调用, ...

  4. Linux-0.11内核源代码分析系列:内存管理get_free_page()函数分析

    Linux-0.11内存管理模块是源码中比較难以理解的部分,如今把笔者个人的理解发表 先发Linux-0.11内核内存管理get_free_page()函数分析 有时间再写其它函数或者文件的:) /* ...

  5. 对Linux0.11 中 进程0 和 进程1分析

    1. 背景 进程的创建过程无疑是最重要的操作系统处理过程之一,很多书和教材上说的最多的还是一些原理的部分,忽略了很多细节.比如,子进程复制父进程所拥有的资源,或者子进程和父进程共享相同的物理页面,拥有 ...

  6. rtems 4.11 部分m4文件分析

    本来想把configure.ac和各种m4文件分析明白,发现有点困难,不过好在也能理解一些. 基本教程 首先要明白m4,参见这个教程,写得不错,不论怎么样m4替换来替换去的,还真是不那么容易懂,好在我 ...

  7. 从linux0.11中起动部分代码看汇编调用c语言函数

    上一篇分析了c语言的函数调用栈情况,知道了c语言的函数调用机制后,我们来看一下,linux0.11中起动部分的代码是如何从汇编跳入c语言函数的.在LINUX 0.11中的head.s文件中会看到如下一 ...

  8. linux0.11改进之四 基于内核栈的进程切换

    这是学习哈工大李治军在mooc课操作系统时做的实验记录.原实验报告在实验楼上.现转移到这里.备以后整理之用. 完整的实验代码见:实验楼代码 一.tss方式的进程切换 Linux0.11中默认使用的是硬 ...

  9. Linux0.11小结

    第一部分 基础内容 1.操作系统基础     操作系统是计算机硬件系统与用户程序间重要环节,理解操作系统的原理是编写优秀代码的基础.教课书中阐述的操作系统一般由5部分组成. 一个最简单的操作系统,可以 ...

随机推荐

  1. PHP 魔术方法 __sleep __wakeup(四)

    串行化serialize可以把变量包括对象,转化成连续bytes数据. 你可以将串行化后的变量存在一个文件里或在网络上传输. 然后再反串行化还原为原来的数据. 你在反串行化类的对象之前定义的类,PHP ...

  2. 发送邮件(遵循smtp协议即简单的邮件发送协议)

    HandleSendEmail.aspx逻辑 protected void Page_Load(object sender,EventArgs e) { foreach(var item in Req ...

  3. phpcms v9 打开网站特别慢 增加数据库缓存方法

    SET GLOBAL QUERY_CACHE_SIZE=80000000; 设置好查询缓存的大小就行了.比如设置个20MB.SET GLOBAL QUERY_CACHE_SIZE=20000000; ...

  4. (转载)sql语句解决分页问题

    <来源网址:http://www.delphifans.com/infoview/Article_353.html>sql语句解决分页问题日期:2005年1月17日 作者:treemon2 ...

  5. The connection to adb is down

    有一周时间没有打开ADT了,最近想为我的APP增加下些新的功能,但是在编译的时候出现了一个奇怪问题 [2013-10-18 14:43:50 - zzbus] Android Launch![2013 ...

  6. Oracle中SAVEPOINT和ROLLBACK用法

    savepoint是事务内部允许部分rollback的标志符.因为事务中对记录做了修改,我们可以在事务中创建savepoint来标识不同的点.如果遇到错误,就可以rollback到不同的点或直接回来事 ...

  7. 解决rhel相关系统下yum找不到安装包的解决方法

    最近重新安装了Linux,用的版本是CentOS 5.1.但老是出现很多包找不到的情况. [root@toughhou /]# yum install rlwrap Loaded plugins: f ...

  8. c# DirectoryInfo类 详解

    DirectoryInfo类和Directory类之间的关系与FileInfo类和File类之间的关系十分类似.下面介绍一下DirectoryInfo类的常用属性. DirectoryInfo类的常用 ...

  9. Elasticsearch升级至1.x后API的变化-三

    请支持原创:http://www.cnblogs.com/donlianli/p/3841762.html   1.索引格式 1.x之前的版本,被索引的文档type会同时出现在url和传输的数据格式中 ...

  10. Android中Linux suspend/resume流程

    Android中Linux suspend/resume流程首先我们从linux kernel 的suspend说起,不管你是使用echo mem > /sys/power/state 或者使用 ...