首页
社区
课程
招聘
[原创]Linux内核学习笔记
发表于: 2022-5-19 19:33 13770

[原创]Linux内核学习笔记

2022-5-19 19:33
13770

本文长期更新!
由于要换电脑,所以更新要等几天时间!以下是基于linux0.11的代码

1.做CPU工作模式的转化

2.进行寄存器的拷贝与压栈

3.设置中断向量表

4.保存正常运行的函数返回值

5.跳转到对应的中断服务函数上运行

6.进行模式的复原及寄存器的复原

7.跳转回正常工作的函数地址继续运行

1.将所有寄存器值入栈

2.将异常吗入栈(中断号)

3.将当前函数的返回地址入栈

4.调用中断函数

5.返回地址出栈

6.寄存器值出栈

​ 中断前后的处理 中断的执行

硬件中断的处理过程 asm.s trap.c

软件及系统调用的处理过程 system_call.s fork.c/signal.c/exit.c/sys.c

在system_call.s内有存在fork的系统调用,先call _find_empty_process,然后call _copy_process

1、在task链表中找一个进程空位存放

2、创建一个task_struct

3、设置task_struct

这里只是进行一个简单的分析,详细分析请见第五章

do_exit()

sys_waitpid()

​ 1.父进程在运行子进程时一般都会运行wait waitpid这两个函数,用来父进程等待子进程终止

​ 2.当父进程收到SIGCHLD信号时,父进程会终止僵死状态的子进程

​ 3.父进程会把子进程的运行时间累加到自己的运行时间上

​ 4.把对应子进程的进程描述结构体进行释放,置空数组空槽

每创建一个进程就对应着一个task_struct结构体

1、0号和1号进程的创建

Linux在初始化的过程中会进行0号进程的创建

注:分析0.11的main函数

内核要先切换到用户态之后再fork生成0号进程

iret是从中断返回的指令,在iret之前,之前5个push压入的数据会出栈,分别赋给ss,esp,eflags,cs,eip,

fork生成0进程之后,会进行初始化,进一步分析如下

1、0号进程打开标准输入输出错误句柄

2、创建1号进程,首先打开"/dev/rc"文件,执行shell

3、如果1号进程创建失败,会换一种方式再次创建

4、之后就是进行pause()暂停状态,系统等待运行下一步

####

众所周知每创建一个进程都会创建一个相对应的task_struct结构体,task结构体里就有代表该进程唯一的PID;

这是Sched.c函数,

就是exit.c函数的操作

1、进程,线程

创建一个进程之后,就会对应一个task_struct结构体,fork之后,会进行写实复制(Copy-On-Write),也就是说子进程和父进程的内容大部分是一致的。

问:一个进程多个线程的调度方式和一个进程一个线程时的调度方式有什么区别?

答:没有区别,内核中线程和进程都需要do_fork来实现,所以没有区别。

由PC机的BIOS(0xFFFF0是BIOS存储的总线地址)把bootsect从某个固定的地址拿到了内存中的某个固定地址(0x90000),并且进行了一系列的硬件初始化和参数设置

磁盘引导块程序,在磁盘的第一个扇区中的程序(0磁道,0磁头,1扇区)

作用:首先将后续的setup.s代码从磁盘中加载到紧接着bootsect.s的地方,在显示屏上显示loading system ,再将操作系统加载到0x10000,最后转到setup.s运行

解析BIOS/Bootloader传进来的参数,设置系统内核运行的LDT(局部描述符),IDT(中断描述符) GDT(全局描述符),设置中断控制芯片,进入保护模式运行;跳转到head.s运行

GDT(global descriptor table),全局段描述符表,这些64kb数据整齐的排列在内存中某一位置。而该位置的内存地址以及有效的个数就存放在GDTR中,GDTR是特殊的寄存器。GDT在系统内只存在一个。

LDT(local descripotr table),局部段描述符表,LDT在系统内可存在多个,每个任务最多只能拥有一个LDT,另外,每一个LDT自身作为一个段存在,它们的段描述符被放在GDT中。

IDT(interrupt descriptor table),中断描述符表,IDT记录了0~255的中断号码和中断服务函数的关系。当发生中断的时候,通过中断号码去执行中断服务函数。

GDT可以被放在内存的任何位置,那么当程序员通过段寄存器来引用一个段描述符时,CPU必须知道GDT的入口,也就是基地址放在哪里,所以Intel的设计者门提供了一个寄存器GDTR用来存放GDT的入口地址,程序员将GDT设定在内存中某个位置之后,可以通过LGDT指令将GDT的入口地址装入此寄存器,从此以后,CPU就根据此寄存器中的内容作为GDT的入口来访问GDT了。

IA-32为LDT的入口地址也提供了一个寄存器LDTR,因为在任何时刻只能有一个任务在运行,所以LDT寄存器全局也只需要有一个。如果一个任务拥有自身的LDT,那么当它需要引用自身的LDT时,它需要通过LLDT指令将其LDT的段描述符装入此寄存器。LLDT指令与LGDT指令不同的时,LGDT指令的操作数是一个32-bit的内存地址,这个内存地址处存放的是一个32-bit GDT的入口地址,以及16-bit的GDT Limit。而LLDT指令的操作数是一个16-bit的选择子,这个选择子主要内容是:被装入的LDT的段描述符在GDT中的索引值。

加载内核运行时的各数据段寄存器,重新设置中断描述符表,开启内核正常运行时的协处理器等资源;设置内存管理的分页机制,跳转到main.c运行

内核的信号量是很重要的,关于信号的定义在/include/signal.h文件内,比如运行一个elf文件可能会出现段错误(SIGSEGV),玩pwn的同学应该很熟悉。在system_call.s中存在call do_signal,那么do_signal在/kernel/signal.c内定义。

硬件来源:信号由硬件驱动产生

软件来源:系统提供了些API,例如kill命令

当进程收到信号时,会有三种场景;

忽略:忽略信号

执行:执行每个信号所对应的操作

执行自定操作:用户自定义的操作

1.在系统中什么是信号,都有什么信号?

2.在系统接收到信号后,是如何进行处理的?

3.信号作用

顾名思义就是文件所组成的一个系统,linux下所谓“一切皆文件”,所以文件系统在内核中占了很大比重。

Linux启动过程:

1.PCB上电后先由uboot初始化板子,然后将linux内核迁移到内存中运行;

2.由linux内核进行初始化操作,挂载第一个应用程序即根文件系统(linuxrc);

3.根文件系统提供磁盘管理服务(glibc,设备节点,配置文件,应用程序 shell命令)。

文件系统主要包括四个部分:高速缓冲区管理,文件底层操作,文件数据访问,文件高层访问控制。

程序包括对i节点位图和逻辑块位图进行释放和占用处理函数。操作i节点位图的函数是free_inode()new_inode(),操作逻辑块位图的函数是free_block()new_block()

程序包括对数据文件长度截断为0的函数truncate(),他将i节点指定的设备上文件长度截为0,并释放文件数据占用的设备逻辑块。

程序包括分配i节点函数iget()和放回对内存i节点存取函数iput()以及根据i节点信息取文件数据块在设备上对应的逻辑块号函数bmap()

程序主要包括函数namei(),该函数使用iget()iput()bmap()将给定的文件路径名映射到其i节点。

程序专门用于处理文件系统超级块,包括函数get_super()put_super()free_super()free_super()等,还包括几个文件系统加载/卸载处理函数和系统调用,如sys_mount()

程序中的函数block_read()block_write()是用于读写块设备特殊文件的数据,所使用的参数指定要访问的设备号,起始地址和长度

程序中的file_read()file_write()函数是用于访问一般的文件,所使用的参数指定文件对应的i节点和文件结构。

文件中实现了管道读写函数read_pipe()write_pipe(),另外还实现了创建无名管道的系统调用pipe()

系统调用使用read()和write()会调用char_dev.c中的rw_char()函数来操作。字符设备包括控制台终端,串口终端和内存字符设备。

文件用于实现与文件操作相关的系统调用,主要有文件的创建,打开和关闭,文件宿主和属性修改,文件访问权限和操作时间的修改等。

程序实现对二进制可执行文件和shell脚本文件的加载与执行,其中主要是的do_execve(),他是系统中断调用(int 0x80)的功能号__NR_execve()调用的C处理函数,更是exec()函数簇的主要实现函数。

实现了文件控制操作的系统调用fcntl()和两个文件句柄(描述符)复制系统调用dup()和dup2(),dup2()指定了新句柄的数值,dup()则返回当前最小值的未用句柄。句柄复制操作主要用在文件的标准输入/输出重定向和管道操作方面。

文件实现了输入/输出控制系统调用ioctl(),主要调用tty_ioctl()函数,对终端的I/O进行控制。

文件用于实现取得文件状态信息的系统调用,stat()和fstat()。stat()是利用文件名取信息,而fstat()是利用文件句柄取信息。

高速缓冲区位于内核代码与主内存区之间,在块设备与内核其他程序之间起着一个桥梁作用,除了块设备驱动程序以外,内核程序如果需要访问块设备中的数据,就需要通过高速缓冲区来进行操作。

 
 
 
 
 
 
 
 
 
 
 
 
 
.align 2
_sys_fork:
    call _find_empty_process
    testl %eax,%eax
    js 1f
    push %gs
    pushl %esi
    pushl %edi
    pushl %ebp
    pushl %eax
    call _copy_process
    addl $20,%esp
1:    ret
.align 2
_sys_fork:
    call _find_empty_process
    testl %eax,%eax
    js 1f
    push %gs
    pushl %esi
    pushl %edi
    pushl %ebp
    pushl %eax
    call _copy_process
    addl $20,%esp
1:    ret
#include <errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <asm/system.h>
 
extern void write_verify(unsigned long address);
 
long last_pid=0;
 
void verify_area(void * addr,int size)
{
    unsigned long start;
 
    start = (unsigned long) addr;
    size += start & 0xfff;
    start &= 0xfffff000;
    start += get_base(current->ldt[2]);
    while (size>0) {
        size -= 4096;
        write_verify(start);
        start += 4096;
    }
}
 
int copy_mem(int nr,struct task_struct * p)
{
    unsigned long old_data_base,new_data_base,data_limit;
    unsigned long old_code_base,new_code_base,code_limit;
 
    code_limit=get_limit(0x0f);
    data_limit=get_limit(0x17);
    old_code_base = get_base(current->ldt[1]);
    old_data_base = get_base(current->ldt[2]);
    if (old_data_base != old_code_base)
        panic("We don't support separate I&D");
    if (data_limit < code_limit)
        panic("Bad data_limit");
    new_data_base = new_code_base = nr * 0x4000000;
    p->start_code = new_code_base;
    set_base(p->ldt[1],new_code_base);
    set_base(p->ldt[2],new_data_base);
    if (copy_page_tables(old_data_base,new_data_base,data_limit)) {
        free_page_tables(new_data_base,data_limit);
        return -ENOMEM;
    }
    return 0;
}
 
/*
 *  Ok, this is the main fork-routine. It copies the system process
 * information (task[nr]) and sets up the necessary registers. It
 * also copies the data segment in it's entirety.
 */
int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
        long ebx,long ecx,long edx,
        long fs,long es,long ds,
        long eip,long cs,long eflags,long esp,long ss)
{
    struct task_struct *p;   //创建子进程的task_struct结构体
    int i;
    struct file *f;
 
    p = (struct task_struct *) get_free_page();
    if (!p)
        return -EAGAIN;
    task[nr] = p;   //将子进程存到task链表中
    *p = *current;    /* NOTE! this doesn't copy the supervisor stack */
    //下面开始设置结构体内容
    p->state = TASK_UNINTERRUPTIBLE;
    p->pid = last_pid;
    p->father = current->pid;
    p->counter = p->priority;
    p->signal = 0;
    p->alarm = 0;
    p->leader = 0;        /* process leadership doesn't inherit */
    p->utime = p->stime = 0;
    p->cutime = p->cstime = 0;
    p->start_time = jiffies;
    p->tss.back_link = 0;
    p->tss.esp0 = PAGE_SIZE + (long) p;
    p->tss.ss0 = 0x10;
    p->tss.eip = eip;
    p->tss.eflags = eflags;
    p->tss.eax = 0;
    p->tss.ecx = ecx;
    p->tss.edx = edx;
    p->tss.ebx = ebx;
    p->tss.esp = esp;
    p->tss.ebp = ebp;
    p->tss.esi = esi;
    p->tss.edi = edi;
    p->tss.es = es & 0xffff;
    p->tss.cs = cs & 0xffff;
    p->tss.ss = ss & 0xffff;
    p->tss.ds = ds & 0xffff;
    p->tss.fs = fs & 0xffff;
    p->tss.gs = gs & 0xffff;
    p->tss.ldt = _LDT(nr);
    p->tss.trace_bitmap = 0x80000000;
    if (last_task_used_math == current)
        __asm__("clts ; fnsave %0"::"m" (p->tss.i387));  //如果父进程用了协处理器,需要在tss段进行设置
    if (copy_mem(nr,p)) {  //内存拷贝
        task[nr] = NULL;
        free_page((long) p);
        return -EAGAIN;
    }
    for (i=0; i<NR_OPEN;i++)
        if (f=p->filp[i])
            f->f_count++;
    if (current->pwd)
        current->pwd->i_count++;
    if (current->root)
        current->root->i_count++;
    if (current->executable)
        current->executable->i_count++;
    set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
    set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
    p->state = TASK_RUNNING;    /* do this last, just in case */
    return last_pid; 
}
 
int find_empty_process(void)
{
    int i;
 
    repeat:
        if ((++last_pid)<0) last_pid=1;
        for(i=0 ; i<NR_TASKS ; i++)
            if (task[i] && task[i]->pid == last_pid) goto repeat;
    for(i=1 ; i<NR_TASKS ; i++)
        if (!task[i])  
            return i;
    return -EAGAIN;
}
#include <errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <asm/system.h>
 
extern void write_verify(unsigned long address);
 
long last_pid=0;
 
void verify_area(void * addr,int size)
{
    unsigned long start;
 
    start = (unsigned long) addr;
    size += start & 0xfff;
    start &= 0xfffff000;
    start += get_base(current->ldt[2]);
    while (size>0) {
        size -= 4096;
        write_verify(start);
        start += 4096;
    }
}
 
int copy_mem(int nr,struct task_struct * p)
{
    unsigned long old_data_base,new_data_base,data_limit;
    unsigned long old_code_base,new_code_base,code_limit;
 
    code_limit=get_limit(0x0f);
    data_limit=get_limit(0x17);
    old_code_base = get_base(current->ldt[1]);
    old_data_base = get_base(current->ldt[2]);
    if (old_data_base != old_code_base)
        panic("We don't support separate I&D");
    if (data_limit < code_limit)
        panic("Bad data_limit");
    new_data_base = new_code_base = nr * 0x4000000;
    p->start_code = new_code_base;
    set_base(p->ldt[1],new_code_base);
    set_base(p->ldt[2],new_data_base);
    if (copy_page_tables(old_data_base,new_data_base,data_limit)) {
        free_page_tables(new_data_base,data_limit);
        return -ENOMEM;
    }
    return 0;
}
 
/*
 *  Ok, this is the main fork-routine. It copies the system process
 * information (task[nr]) and sets up the necessary registers. It
 * also copies the data segment in it's entirety.
 */
int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
        long ebx,long ecx,long edx,
        long fs,long es,long ds,
        long eip,long cs,long eflags,long esp,long ss)
{
    struct task_struct *p;   //创建子进程的task_struct结构体
    int i;
    struct file *f;
 
    p = (struct task_struct *) get_free_page();
    if (!p)
        return -EAGAIN;
    task[nr] = p;   //将子进程存到task链表中
    *p = *current;    /* NOTE! this doesn't copy the supervisor stack */
    //下面开始设置结构体内容
    p->state = TASK_UNINTERRUPTIBLE;
    p->pid = last_pid;
    p->father = current->pid;
    p->counter = p->priority;
    p->signal = 0;
    p->alarm = 0;
    p->leader = 0;        /* process leadership doesn't inherit */
    p->utime = p->stime = 0;
    p->cutime = p->cstime = 0;
    p->start_time = jiffies;
    p->tss.back_link = 0;
    p->tss.esp0 = PAGE_SIZE + (long) p;
    p->tss.ss0 = 0x10;
    p->tss.eip = eip;
    p->tss.eflags = eflags;
    p->tss.eax = 0;
    p->tss.ecx = ecx;
    p->tss.edx = edx;
    p->tss.ebx = ebx;
    p->tss.esp = esp;
    p->tss.ebp = ebp;
    p->tss.esi = esi;
    p->tss.edi = edi;
    p->tss.es = es & 0xffff;
    p->tss.cs = cs & 0xffff;
    p->tss.ss = ss & 0xffff;
    p->tss.ds = ds & 0xffff;
    p->tss.fs = fs & 0xffff;
    p->tss.gs = gs & 0xffff;
    p->tss.ldt = _LDT(nr);
    p->tss.trace_bitmap = 0x80000000;
    if (last_task_used_math == current)
        __asm__("clts ; fnsave %0"::"m" (p->tss.i387));  //如果父进程用了协处理器,需要在tss段进行设置
    if (copy_mem(nr,p)) {  //内存拷贝
        task[nr] = NULL;
        free_page((long) p);
        return -EAGAIN;
    }
    for (i=0; i<NR_OPEN;i++)
        if (f=p->filp[i])
            f->f_count++;
    if (current->pwd)
        current->pwd->i_count++;
    if (current->root)
        current->root->i_count++;
    if (current->executable)
        current->executable->i_count++;
    set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
    set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
    p->state = TASK_RUNNING;    /* do this last, just in case */
    return last_pid; 
}
 
int find_empty_process(void)
{
    int i;
 
    repeat:
        if ((++last_pid)<0) last_pid=1;
        for(i=0 ; i<NR_TASKS ; i++)
            if (task[i] && task[i]->pid == last_pid) goto repeat;
    for(i=1 ; i<NR_TASKS ; i++)
        if (!task[i])  
            return i;
    return -EAGAIN;
}
 
 
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
 
#include <signal.h>
 
volatile void do_exit(int error_code);
 
int sys_sgetmask()
{
    return current->blocked;
}
 
int sys_ssetmask(int newmask)
{
    int old=current->blocked;
 
    current->blocked = newmask & ~(1<<(SIGKILL-1));
    return old;
}
 
static inline void save_old(char * from,char * to)
{
    int i;
 
    verify_area(to, sizeof(struct sigaction));
    for (i=0 ; i< sizeof(struct sigaction) ; i++) {
        put_fs_byte(*from,to);
        from++;
        to++;
    }
}
 
static inline void get_new(char * from,char * to)
{
    int i;
 
    for (i=0 ; i< sizeof(struct sigaction) ; i++)
        *(to++) = get_fs_byte(from++);
}
 
int sys_signal(int signum, long handler, long restorer)
{
    struct sigaction tmp;
 
    if (signum<1 || signum>32 || signum==SIGKILL) //判断信号值是否合法
        return -1;
    tmp.sa_handler = (void (*)(int)) handler;
    tmp.sa_mask = 0;
    tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
    tmp.sa_restorer = (void (*)(void)) restorer;   //设置sigaction结构体
    handler = (long) current->sigaction[signum-1].sa_handler;
    current->sigaction[signum-1] = tmp; //将当前进程对应的信号结构体改为新分配的结构体
    return handler; //返回处理函数
}
 
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 = current->sigaction[signum-1];
    get_new((char *) action,
        (char *) (signum-1+current->sigaction));
    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;
}
 
void do_signal(long signr,long eax, long ebx, long ecx, long edx,
    long fs, long es, long ds,
    long eip, long cs, long eflags,
    unsigned long * esp, long ss)
{
    unsigned long sa_handler;
    long old_eip=eip;
    struct sigaction * sa = current->sigaction + signr - 1;
    int longs;
    unsigned long * tmp_esp;
 
    sa_handler = (unsigned long) sa->sa_handler;
    if (sa_handler==1)
        return;
    if (!sa_handler) {
        if (signr==SIGCHLD)
            return;
        else
            do_exit(1<<(signr-1));
    }
    if (sa->sa_flags & SA_ONESHOT)
        sa->sa_handler = NULL;
    *(&eip) = sa_handler;
    longs = (sa->sa_flags & SA_NOMASK)?7:8;
    *(&esp) -= longs;
    verify_area(esp,longs*4);
    tmp_esp=esp;
    put_fs_long((long) sa->sa_restorer,tmp_esp++);
    put_fs_long(signr,tmp_esp++);
    if (!(sa->sa_flags & SA_NOMASK))
        put_fs_long(current->blocked,tmp_esp++);
    put_fs_long(eax,tmp_esp++);
    put_fs_long(ecx,tmp_esp++);
    put_fs_long(edx,tmp_esp++);
    put_fs_long(eflags,tmp_esp++);
    put_fs_long(old_eip,tmp_esp++);
    current->blocked |= sa->sa_mask;
}
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
 
#include <signal.h>
 
volatile void do_exit(int error_code);
 
int sys_sgetmask()
{
    return current->blocked;
}
 
int sys_ssetmask(int newmask)
{
    int old=current->blocked;
 
    current->blocked = newmask & ~(1<<(SIGKILL-1));
    return old;
}
 
static inline void save_old(char * from,char * to)
{
    int i;
 
    verify_area(to, sizeof(struct sigaction));
    for (i=0 ; i< sizeof(struct sigaction) ; i++) {
        put_fs_byte(*from,to);
        from++;
        to++;
    }
}
 
static inline void get_new(char * from,char * to)
{
    int i;
 
    for (i=0 ; i< sizeof(struct sigaction) ; i++)
        *(to++) = get_fs_byte(from++);
}
 
int sys_signal(int signum, long handler, long restorer)
{
    struct sigaction tmp;
 
    if (signum<1 || signum>32 || signum==SIGKILL) //判断信号值是否合法
        return -1;
    tmp.sa_handler = (void (*)(int)) handler;
    tmp.sa_mask = 0;
    tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
    tmp.sa_restorer = (void (*)(void)) restorer;   //设置sigaction结构体
    handler = (long) current->sigaction[signum-1].sa_handler;
    current->sigaction[signum-1] = tmp; //将当前进程对应的信号结构体改为新分配的结构体
    return handler; //返回处理函数
}
 
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 = current->sigaction[signum-1];
    get_new((char *) action,
        (char *) (signum-1+current->sigaction));
    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;
}
 
void do_signal(long signr,long eax, long ebx, long ecx, long edx,
    long fs, long es, long ds,
    long eip, long cs, long eflags,
    unsigned long * esp, long ss)
{
    unsigned long sa_handler;
    long old_eip=eip;
    struct sigaction * sa = current->sigaction + signr - 1;
    int longs;
    unsigned long * tmp_esp;
 
    sa_handler = (unsigned long) sa->sa_handler;
    if (sa_handler==1)
        return;
    if (!sa_handler) {
        if (signr==SIGCHLD)
            return;
        else
            do_exit(1<<(signr-1));
    }
    if (sa->sa_flags & SA_ONESHOT)
        sa->sa_handler = NULL;
    *(&eip) = sa_handler;
    longs = (sa->sa_flags & SA_NOMASK)?7:8;
    *(&esp) -= longs;
    verify_area(esp,longs*4);
    tmp_esp=esp;
    put_fs_long((long) sa->sa_restorer,tmp_esp++);
    put_fs_long(signr,tmp_esp++);
    if (!(sa->sa_flags & SA_NOMASK))
        put_fs_long(current->blocked,tmp_esp++);
    put_fs_long(eax,tmp_esp++);
    put_fs_long(ecx,tmp_esp++);
    put_fs_long(edx,tmp_esp++);
    put_fs_long(eflags,tmp_esp++);
    put_fs_long(old_eip,tmp_esp++);
    current->blocked |= sa->sa_mask;
}
// Line 12
#define SIGHUP         1        // 挂断控制终端或进程
#define SIGINT         2        // 键盘中断
#define SIGQUIT         3        // 键盘退出
#define SIGILL         4        // 非法指令
#define SIGTRAP         5        // 跟踪断点
#define SIGABRT         6        // 异常结束
#define SIGIOT         6        // 异常结束
#define SIGUNUSED     7        // 未使用
#define SIGFPE         8        // 协处理器错误
#define SIGKILL         9        // 终止进程
#define SIGUSR1        10        // 用户信号 1
#define SIGSEGV        11        // 无效的内存引用
#define SIGUSR2        12        // 用户信号 2
#define SIGPIPE        13        // 管道写出错,读端全关闭
#define SIGALRM        14        // 定时器警报
#define SIGTERM        15        // 进程终止
#define SIGSTKFLT    16        // 栈出错
#define SIGCHLD        17        // 子进程状态改变
#define SIGCONT        18        // 恢复进程继续执行
#define SIGSTOP        19        // 暂停进程执行
#define SIGTSTP        20        // tty 发出的停止进程信号
#define SIGTTIN        21        // 后台进程请求输入
#define SIGTTOU        22        // 后台进程请求输出
 
// Line 37
#define SA_NOCLDSTOP    1            // 当子进程处于停止状态,就不对 SIGCHLD 信号做处理
#define SA_NOMASK    0x40000000        // 允许在指定信号处理程序中再次收到该信号
#define SA_ONESHOT    0x80000000        // 信号句柄一旦被调用过就恢复默认处理函数
 
// Line 45
#define SIG_DFL        ((void (*)(int))0)    // 默认处理程序
#define SIG_IGN        ((void (*)(int))1)    // 忽略信号对应的处理程序
typedef unsigned int sigset_t;
 
struct sigaction {
    void (*sa_handler)(int);    // 信号处理程序指针
    sigset_t sa_mask;        // 指出当前信号处理程序执行期间需要被屏蔽的信号
    int sa_flags;            // 37 行的三个定义中选出
    void (*sa_restorer)(void);    // 恢复函数指针,由 libc 提供
};
// Line 12
#define SIGHUP         1        // 挂断控制终端或进程
#define SIGINT         2        // 键盘中断
#define SIGQUIT         3        // 键盘退出
#define SIGILL         4        // 非法指令
#define SIGTRAP         5        // 跟踪断点
#define SIGABRT         6        // 异常结束
#define SIGIOT         6        // 异常结束
#define SIGUNUSED     7        // 未使用
#define SIGFPE         8        // 协处理器错误
#define SIGKILL         9        // 终止进程
#define SIGUSR1        10        // 用户信号 1
#define SIGSEGV        11        // 无效的内存引用
#define SIGUSR2        12        // 用户信号 2
#define SIGPIPE        13        // 管道写出错,读端全关闭
#define SIGALRM        14        // 定时器警报
#define SIGTERM        15        // 进程终止
#define SIGSTKFLT    16        // 栈出错
#define SIGCHLD        17        // 子进程状态改变
#define SIGCONT        18        // 恢复进程继续执行
#define SIGSTOP        19        // 暂停进程执行
#define SIGTSTP        20        // tty 发出的停止进程信号
#define SIGTTIN        21        // 后台进程请求输入
#define SIGTTOU        22        // 后台进程请求输出
 
// Line 37
#define SA_NOCLDSTOP    1            // 当子进程处于停止状态,就不对 SIGCHLD 信号做处理
#define SA_NOMASK    0x40000000        // 允许在指定信号处理程序中再次收到该信号
#define SA_ONESHOT    0x80000000        // 信号句柄一旦被调用过就恢复默认处理函数
 
// Line 45
#define SIG_DFL        ((void (*)(int))0)    // 默认处理程序
#define SIG_IGN        ((void (*)(int))1)    // 忽略信号对应的处理程序
typedef unsigned int sigset_t;
 
struct sigaction {
    void (*sa_handler)(int);    // 信号处理程序指针
    sigset_t sa_mask;        // 指出当前信号处理程序执行期间需要被屏蔽的信号
    int sa_flags;            // 37 行的三个定义中选出
    void (*sa_restorer)(void);    // 恢复函数指针,由 libc 提供
};
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
 
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <asm/segment.h>
 
int sys_pause(void);
int sys_close(int fd);
 
void release(struct task_struct * p)  //释放进程p
{
    int i;
 
    if (!p)
        return;
    for (i=1 ; i<NR_TASKS ; i++)
        if (task[i]==p) {
            task[i]=NULL;
            free_page((long)p);  //释放内存页
            schedule();   //之后重新进行进程调度
            return;
        }
    panic("trying to release non-existent task");
}
 
static inline int send_sig(long sig,struct task_struct * p,int priv)
{
    if (!p || sig<1 || sig>32)
        return -EINVAL;
    if (priv || (current->euid==p->euid) || suser())
        p->signal |= (1<<(sig-1));   //给p进程发送信号
    else
        return -EPERM;
    return 0;
}
 
static void kill_session(void)  //关闭对话函数
{
    struct task_struct **p = NR_TASKS + task; //获得task数组最后一个任务
 
    while (--p > &FIRST_TASK) {  //从最后一个向前遍历
        if (*p && (*p)->session == current->session) //如果遍历到当前的任务
            (*p)->signal |= 1<<(SIGHUP-1);     //则将SIGHUP挂断信号发送给当前任务
    }
}
 
/*
 * XXX need to check permissions needed to send signals to process
 * groups, etc. etc.  kill() permissions semantics are tricky!
 */
int sys_kill(int pid,int sig)  //linux命令kill不是杀死的意思,是向某进程发送任何信号
{
    struct task_struct **p = NR_TASKS + task;  //指向最后
    int err, retval = 0;
 
// 注: 每个进程组都有一个组长进程,组长进程的进程号等于进程组ID
 
    if (!pid) while (--p > &FIRST_TASK) {  //如果pid为0,进入循环
        if (*p && (*p)->pgrp == current->pid) //向进程组的所有成员发送信号
            if (err=send_sig(sig,*p,1))
                retval = err;
    }
    else if (pid>0) while (--p > &FIRST_TASK) { //如果pid大于0
        if (*p && (*p)->pid == pid)  //仅向pid进程发送信号
            if (err=send_sig(sig,*p,0))
                retval = err;
    }
    else if (pid == -1) while (--p > &FIRST_TASK) //如果pid=-1
        if (err = send_sig(sig,*p,0)) //向除0号进程外的进程发送信号
            retval = err;
    else while (--p > &FIRST_TASK) //如果pid<-1
        if (*p && (*p)->pgrp == -pid) //向进程组号为-pid的进程组发送信号
            if (err = send_sig(sig,*p,0))
                retval = err;
    return retval;
}
 
static void tell_father(int pid)  //传入参数为父进程的pid
{
    int i;
 
    if (pid)
        for (i=0;i<NR_TASKS;i++) {
            if (!task[i])
                continue;
            if (task[i]->pid != pid)
                continue;
            task[i]->signal |= (1<<(SIGCHLD-1)); //SIGCHLD=17
            return;
        }
/* if we don't find any fathers, we just release ourselves */
/* This is not really OK. Must change it to make father 1 */
    printk("BAD BAD - no father found\n\r");
    release(current);  //释放子进程
}
 
int do_exit(long code)
{
    int i;
                                                                //#define LDT_NUL 0
                                                                //#define LDT_CODE 1
                                                                //#define LDT_DATA 2
    free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); //释放当前进程的CODE段所占用的内存页
    free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
    for (i=0 ; i<NR_TASKS ; i++//从前向后遍历
        if (task[i] && task[i]->father == current->pid) { //若当前进程就是某个进程的父进程时;
            task[i]->father = 1; //就让1号进程作为某个进程的父进程(因为current这个进程将会exit)
            if (task[i]->state == TASK_ZOMBIE) //若某进程是僵死状态
                /* assumption task[1] is always init */
                (void) send_sig(SIGCHLD, task[1], 1); //1号进程发送信号
        }
    for (i=0 ; i<NR_OPEN ; i++)
        if (current->filp[i]) //关闭当前进程打开的所有文件
            sys_close(i);
    iput(current->pwd);  //把当前进程的路径放回i节点并置空
    current->pwd=NULL;
    iput(current->root);
    current->root=NULL;
    iput(current->executable);
    current->executable=NULL;
    if (current->leader && current->tty >= 0) //若当前进程是进程组的头头,并且拥有tty终端
        tty_table[current->tty].pgrp = 0; //释放该终端
    if (last_task_used_math == current)
        last_task_used_math = NULL;
    if (current->leader)
        kill_session(); //关闭session
    current->state = TASK_ZOMBIE; //设置成僵死状态
    current->exit_code = code;
    tell_father(current->father); //向当前进程的父进程发送 SIGCHLD 信号
    schedule();
    return (-1);    /* just to suppress warnings */
}
 
int sys_exit(int error_code)
{
    return do_exit((error_code&0xff)<<8);
}
 
int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
{
    int flag, code;
    struct task_struct ** p;
 
    verify_area(stat_addr,4);
repeat:
    flag=0;
    for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
        if (!*p || *p == current) //若该项为空或者该项是当前进程,则跳过
            continue;
        if ((*p)->father != current->pid) //若该项的父进程不是当前进程,则跳过
            continue;
        if (pid>0) {  //若pid>0
            if ((*p)->pid != pid) //若该项的pid不是waitpid传进来的pid参数,则跳过
                continue;
        } else if (!pid) {    //若pid=0,
            if ((*p)->pgrp != current->pgrp) //若当前项不在当前进程组,则跳过
                continue;
        } else if (pid != -1) { //若pid<-1
            if ((*p)->pgrp != -pid) //若当前项不在-pid的进程组,则跳过
                continue;
        }
        switch ((*p)->state) {  //若pid=-1,则直接来到switch;判断所选进程p的状态
            case TASK_STOPPED: //若是停止状态
                if (!(options & WUNTRACED))   //
                    continue;
                put_fs_long(0x7f,stat_addr);
                return (*p)->pid;
            case TASK_ZOMBIE:
                current->cutime += (*p)->utime;
                current->cstime += (*p)->stime;
                flag = (*p)->pid;
                code = (*p)->exit_code;
                release(*p);
                put_fs_long(code,stat_addr);
                return flag;
            default:   //p是睡眠或运行状态,设置flag为1
                flag=1;
                continue;
        }
    }
    if (flag) {
        if (options & WNOHANG)  //WNOHANG 表示若没有子进程处于退出或终止态就返回
            return 0;
        current->state=TASK_INTERRUPTIBLE; //否则将当前进程的状态置为可中断睡眠态
        schedule();
        if (!(current->signal &= ~(1<<(SIGCHLD-1))))
            goto repeat;
        else
            return -EINTR;
    }
    return -ECHILD;
}
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
 
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <asm/segment.h>
 
int sys_pause(void);
int sys_close(int fd);
 
void release(struct task_struct * p)  //释放进程p
{
    int i;
 
    if (!p)
        return;
    for (i=1 ; i<NR_TASKS ; i++)
        if (task[i]==p) {
            task[i]=NULL;
            free_page((long)p);  //释放内存页
            schedule();   //之后重新进行进程调度
            return;
        }
    panic("trying to release non-existent task");
}
 
static inline int send_sig(long sig,struct task_struct * p,int priv)
{
    if (!p || sig<1 || sig>32)
        return -EINVAL;
    if (priv || (current->euid==p->euid) || suser())
        p->signal |= (1<<(sig-1));   //给p进程发送信号
    else
        return -EPERM;
    return 0;
}
 
static void kill_session(void)  //关闭对话函数
{
    struct task_struct **p = NR_TASKS + task; //获得task数组最后一个任务
 
    while (--p > &FIRST_TASK) {  //从最后一个向前遍历
        if (*p && (*p)->session == current->session) //如果遍历到当前的任务
            (*p)->signal |= 1<<(SIGHUP-1);     //则将SIGHUP挂断信号发送给当前任务
    }
}
 
/*
 * XXX need to check permissions needed to send signals to process
 * groups, etc. etc.  kill() permissions semantics are tricky!
 */
int sys_kill(int pid,int sig)  //linux命令kill不是杀死的意思,是向某进程发送任何信号
{
    struct task_struct **p = NR_TASKS + task;  //指向最后
    int err, retval = 0;
 
// 注: 每个进程组都有一个组长进程,组长进程的进程号等于进程组ID
 
    if (!pid) while (--p > &FIRST_TASK) {  //如果pid为0,进入循环
        if (*p && (*p)->pgrp == current->pid) //向进程组的所有成员发送信号
            if (err=send_sig(sig,*p,1))
                retval = err;
    }
    else if (pid>0) while (--p > &FIRST_TASK) { //如果pid大于0
        if (*p && (*p)->pid == pid)  //仅向pid进程发送信号
            if (err=send_sig(sig,*p,0))
                retval = err;
    }
    else if (pid == -1) while (--p > &FIRST_TASK) //如果pid=-1
        if (err = send_sig(sig,*p,0)) //向除0号进程外的进程发送信号
            retval = err;
    else while (--p > &FIRST_TASK) //如果pid<-1
        if (*p && (*p)->pgrp == -pid) //向进程组号为-pid的进程组发送信号
            if (err = send_sig(sig,*p,0))
                retval = err;
    return retval;
}
 
static void tell_father(int pid)  //传入参数为父进程的pid
{
    int i;
 
    if (pid)
        for (i=0;i<NR_TASKS;i++) {
            if (!task[i])
                continue;
            if (task[i]->pid != pid)
                continue;
            task[i]->signal |= (1<<(SIGCHLD-1)); //SIGCHLD=17
            return;
        }
/* if we don't find any fathers, we just release ourselves */
/* This is not really OK. Must change it to make father 1 */
    printk("BAD BAD - no father found\n\r");
    release(current);  //释放子进程
}
 
int do_exit(long code)
{
    int i;
                                                                //#define LDT_NUL 0
                                                                //#define LDT_CODE 1
                                                                //#define LDT_DATA 2
    free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); //释放当前进程的CODE段所占用的内存页
    free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
    for (i=0 ; i<NR_TASKS ; i++//从前向后遍历
        if (task[i] && task[i]->father == current->pid) { //若当前进程就是某个进程的父进程时;
            task[i]->father = 1; //就让1号进程作为某个进程的父进程(因为current这个进程将会exit)
            if (task[i]->state == TASK_ZOMBIE) //若某进程是僵死状态
                /* assumption task[1] is always init */
                (void) send_sig(SIGCHLD, task[1], 1); //1号进程发送信号
        }
    for (i=0 ; i<NR_OPEN ; i++)
        if (current->filp[i]) //关闭当前进程打开的所有文件
            sys_close(i);
    iput(current->pwd);  //把当前进程的路径放回i节点并置空
    current->pwd=NULL;
    iput(current->root);
    current->root=NULL;
    iput(current->executable);
    current->executable=NULL;
    if (current->leader && current->tty >= 0) //若当前进程是进程组的头头,并且拥有tty终端
        tty_table[current->tty].pgrp = 0; //释放该终端
    if (last_task_used_math == current)
        last_task_used_math = NULL;
    if (current->leader)
        kill_session(); //关闭session
    current->state = TASK_ZOMBIE; //设置成僵死状态
    current->exit_code = code;
    tell_father(current->father); //向当前进程的父进程发送 SIGCHLD 信号
    schedule();
    return (-1);    /* just to suppress warnings */
}
 
int sys_exit(int error_code)
{
    return do_exit((error_code&0xff)<<8);
}
 
int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
{
    int flag, code;
    struct task_struct ** p;
 
    verify_area(stat_addr,4);
repeat:
    flag=0;
    for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
        if (!*p || *p == current) //若该项为空或者该项是当前进程,则跳过
            continue;
        if ((*p)->father != current->pid) //若该项的父进程不是当前进程,则跳过
            continue;
        if (pid>0) {  //若pid>0
            if ((*p)->pid != pid) //若该项的pid不是waitpid传进来的pid参数,则跳过
                continue;
        } else if (!pid) {    //若pid=0,
            if ((*p)->pgrp != current->pgrp) //若当前项不在当前进程组,则跳过
                continue;
        } else if (pid != -1) { //若pid<-1
            if ((*p)->pgrp != -pid) //若当前项不在-pid的进程组,则跳过
                continue;
        }
        switch ((*p)->state) {  //若pid=-1,则直接来到switch;判断所选进程p的状态
            case TASK_STOPPED: //若是停止状态
                if (!(options & WUNTRACED))   //
                    continue;
                put_fs_long(0x7f,stat_addr);
                return (*p)->pid;
            case TASK_ZOMBIE:
                current->cutime += (*p)->utime;
                current->cstime += (*p)->stime;
                flag = (*p)->pid;
                code = (*p)->exit_code;
                release(*p);
                put_fs_long(code,stat_addr);
                return flag;
            default:   //p是睡眠或运行状态,设置flag为1
                flag=1;
                continue;
        }
    }
    if (flag) {
        if (options & WNOHANG)  //WNOHANG 表示若没有子进程处于退出或终止态就返回
            return 0;
        current->state=TASK_INTERRUPTIBLE; //否则将当前进程的状态置为可中断睡眠态
        schedule();
        if (!(current->signal &= ~(1<<(SIGCHLD-1))))
            goto repeat;
        else
            return -EINTR;
    }
    return -ECHILD;
}
 
 
 
 
struct task_struct {
/* these are hardcoded - don't touch */
    long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
    long counter; 
    long priority;
    long signal;
    struct sigaction sigaction[32];
    long blocked;    /* bitmap of masked signals */
/* various fields */
    int exit_code;
    unsigned long start_code,end_code,end_data,brk,start_stack;
    long pid,father,pgrp,session,leader;
    unsigned short uid,euid,suid;
    unsigned short gid,egid,sgid;
    long alarm;
    long utime,stime,cutime,cstime,start_time;
    unsigned short used_math;
/* file system info */
    int tty;        /* -1 if no tty, so it must be signed */
    unsigned short umask;
    struct m_inode * pwd;
    struct m_inode * root;
    struct m_inode * executable;
    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];
/* tss for this task */
    struct tss_struct tss;  //cpu运行一个进程后各个寄存器都保存在tss内
};
struct task_struct {
/* these are hardcoded - don't touch */
    long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
    long counter; 
    long priority;
    long signal;
    struct sigaction sigaction[32];
    long blocked;    /* bitmap of masked signals */
/* various fields */
    int exit_code;
    unsigned long start_code,end_code,end_data,brk,start_stack;
    long pid,father,pgrp,session,leader;
    unsigned short uid,euid,suid;
    unsigned short gid,egid,sgid;
    long alarm;
    long utime,stime,cutime,cstime,start_time;
    unsigned short used_math;
/* file system info */
    int tty;        /* -1 if no tty, so it must be signed */
    unsigned short umask;
    struct m_inode * pwd;
    struct m_inode * root;
    struct m_inode * executable;
    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];
/* tss for this task */
    struct tss_struct tss;  //cpu运行一个进程后各个寄存器都保存在tss内
};
 
 
void main(void)        /* This really IS void, no error here. */
{            /* The startup routine assumes (well, ...) this */
/*
 * Interrupts are still disabled. Do necessary setups, then
 * enable them
 */
     ROOT_DEV = ORIG_ROOT_DEV;
     drive_info = DRIVE_INFO;
    memory_end = (1<<20) + (EXT_MEM_K<<10);
    memory_end &= 0xfffff000;
    if (memory_end > 16*1024*1024)
        memory_end = 16*1024*1024;
    if (memory_end > 12*1024*1024)
        buffer_memory_end = 4*1024*1024;
    else if (memory_end > 6*1024*1024)
        buffer_memory_end = 2*1024*1024;
    else
        buffer_memory_end = 1*1024*1024;
    main_memory_start = buffer_memory_end;
#ifdef RAMDISK
    main_memory_start += rd_init(main_memory_start, RAMDISK*1024);
#endif
    mem_init(main_memory_start,memory_end);
    trap_init();
    blk_dev_init();
    chr_dev_init();
    tty_init();
    time_init();
    sched_init();
    buffer_init(buffer_memory_end);
    hd_init();
    floppy_init();
    sti();
    move_to_user_mode(); //切换到用户态
    if (!fork()) {        /* 创建0号进程 */  
        init();
    }
    for(;;) pause();
}
void main(void)        /* This really IS void, no error here. */
{            /* The startup routine assumes (well, ...) this */
/*
 * Interrupts are still disabled. Do necessary setups, then
 * enable them
 */
     ROOT_DEV = ORIG_ROOT_DEV;
     drive_info = DRIVE_INFO;
    memory_end = (1<<20) + (EXT_MEM_K<<10);
    memory_end &= 0xfffff000;
    if (memory_end > 16*1024*1024)
        memory_end = 16*1024*1024;
    if (memory_end > 12*1024*1024)
        buffer_memory_end = 4*1024*1024;
    else if (memory_end > 6*1024*1024)
        buffer_memory_end = 2*1024*1024;
    else
        buffer_memory_end = 1*1024*1024;
    main_memory_start = buffer_memory_end;
#ifdef RAMDISK
    main_memory_start += rd_init(main_memory_start, RAMDISK*1024);
#endif
    mem_init(main_memory_start,memory_end);
    trap_init();
    blk_dev_init();
    chr_dev_init();
    tty_init();
    time_init();
    sched_init();
    buffer_init(buffer_memory_end);
    hd_init();
    floppy_init();
    sti();
    move_to_user_mode(); //切换到用户态
    if (!fork()) {        /* 创建0号进程 */  
        init();
    }
    for(;;) pause();
}
#define move_to_user_mode() \
__asm__ ("movl %%esp,%%eax\n\t" \
    "pushl $0x17\n\t" \
    "pushl %%eax\n\t" \
    "pushfl\n\t" \
    "pushl $0x0f\n\t" \
    "pushl $1f\n\t" \
    "iret\n" \
    "1:\tmovl $0x17,%%eax\n\t" \
    "movw %%ax,%%ds\n\t" \
    "movw %%ax,%%es\n\t" \
    "movw %%ax,%%fs\n\t" \
    "movw %%ax,%%gs" \
    :::"ax")
#define move_to_user_mode() \
__asm__ ("movl %%esp,%%eax\n\t" \
    "pushl $0x17\n\t" \
    "pushl %%eax\n\t" \
    "pushfl\n\t" \
    "pushl $0x0f\n\t" \
    "pushl $1f\n\t" \
    "iret\n" \
    "1:\tmovl $0x17,%%eax\n\t" \
    "movw %%ax,%%ds\n\t" \
    "movw %%ax,%%es\n\t" \
    "movw %%ax,%%fs\n\t" \
    "movw %%ax,%%gs" \
    :::"ax")
 
static char * argv_rc[] = { "/bin/sh", NULL };
static char * envp_rc[] = { "HOME=/", NULL };
 
static char * argv[] = { "-/bin/sh",NULL };
static char * envp[] = { "HOME=/usr/root", NULL };
 
void init(void)
{
    int pid,i;
 
    setup((void *) &drive_info);
    (void) open("/dev/tty0",O_RDWR,0); //tty0设备是标准输入控制台,句柄为0
    (void) dup(0);
    (void) dup(0);
    printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,
        NR_BUFFERS*BLOCK_SIZE);
    printf("Free mem: %d bytes\n\r",memory_end-main_memory_start);
    if (!(pid=fork())) {  //对于被创建的子进程,返回值为0,所以if里面的语句是在子进程中执行,并打开rc文件并用获得的shell在/执行rc里的命令
        close(0);  //关闭标准输入,所有进程共用文件描述符
        if (open("/etc/rc",O_RDONLY,0))
            _exit(1);
        execve("/bin/sh",argv_rc,envp_rc);
        _exit(2);
    }
    if (pid>0//fork后对于父进程来说,返回的是子进程的进程号,即if语句内是父进程要执行的代码
        while (pid != wait(&i))  //等待子进程退出   
            /* nothing */;
    while (1) {   //如果执行到了这里,就说明子进程已经创建完成退出或者终止,下面是再创建一个子进程,
        if ((pid=fork())<0) {
            printf("Fork failed in init\r\n");
            continue;
        }
        if (!pid) {  //创建成功
            close(0);close(1);close(2);
            setsid();
            (void) open("/dev/tty0",O_RDWR,0);
            (void) dup(0);
            (void) dup(0);
            _exit(execve("/bin/sh",argv,envp));
        }
        while (1)
            if (pid == wait(&i))
                break;
        printf("\n\rchild %d died with code %04x\n\r",pid,i);
        sync();
    }
    _exit(0);    /* NOTE! _exit, not exit() */
}
static char * argv_rc[] = { "/bin/sh", NULL };
static char * envp_rc[] = { "HOME=/", NULL };
 
static char * argv[] = { "-/bin/sh",NULL };
static char * envp[] = { "HOME=/usr/root", NULL };
 
void init(void)
{
    int pid,i;
 
    setup((void *) &drive_info);
    (void) open("/dev/tty0",O_RDWR,0); //tty0设备是标准输入控制台,句柄为0
    (void) dup(0);
    (void) dup(0);
    printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,
        NR_BUFFERS*BLOCK_SIZE);
    printf("Free mem: %d bytes\n\r",memory_end-main_memory_start);
    if (!(pid=fork())) {  //对于被创建的子进程,返回值为0,所以if里面的语句是在子进程中执行,并打开rc文件并用获得的shell在/执行rc里的命令
        close(0);  //关闭标准输入,所有进程共用文件描述符
        if (open("/etc/rc",O_RDONLY,0))
            _exit(1);
        execve("/bin/sh",argv_rc,envp_rc);
        _exit(2);
    }
    if (pid>0//fork后对于父进程来说,返回的是子进程的进程号,即if语句内是父进程要执行的代码
        while (pid != wait(&i))  //等待子进程退出   
            /* nothing */;
    while (1) {   //如果执行到了这里,就说明子进程已经创建完成退出或者终止,下面是再创建一个子进程,
        if ((pid=fork())<0) {
            printf("Fork failed in init\r\n");
            continue;
        }
        if (!pid) {  //创建成功
            close(0);close(1);close(2);
            setsid();
            (void) open("/dev/tty0",O_RDWR,0);
            (void) dup(0);
            (void) dup(0);
            _exit(execve("/bin/sh",argv,envp));
        }
        while (1)
            if (pid == wait(&i))
                break;
        printf("\n\rchild %d died with code %04x\n\r",pid,i);
        sync();
    }
    _exit(0);    /* NOTE! _exit, not exit() */
}
 
 
 
 
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/sys.h>
#include <linux/fdreg.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
 
#include <signal.h>
 
#define _S(nr) (1<<((nr)-1))
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
 
void show_task(int nr,struct task_struct * p)  //nr就是pid
{
    int i,j = 4096-sizeof(struct task_struct);
 
    printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state); //打印pid与state
    i=0;
    while (i<j && !((char *)(p+1))[i])
        i++;
    printk("%d (of %d) chars free in kernel stack\n\r",i,j); //打印栈
}
 
void show_stat(void)
{
    int i;
 
    for (i=0;i<NR_TASKS;i++)
        if (task[i])
            show_task(i,task[i]);
}
 
#define LATCH (1193180/HZ)
 
extern void mem_use(void);
 
extern int timer_interrupt(void);
extern int system_call(void);
 
union task_union {
    struct task_struct task;
    char stack[PAGE_SIZE];
};
 
static union task_union init_task = {INIT_TASK,};
 
long volatile jiffies=0;
long startup_time=0;
struct task_struct *current = &(init_task.task);
struct task_struct *last_task_used_math = NULL;
 
struct task_struct * task[NR_TASKS] = {&(init_task.task), };
 
long user_stack [ PAGE_SIZE>>2 ] ;
 
struct {
    long * a;
    short b;
    } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };
/*
 *  'math_state_restore()' saves the current math information in the
 * old math state array, and gets the new ones from the current task
 */
void math_state_restore()  //进程切换时完成协处理器中寄存器的切换
{
    if (last_task_used_math == current)
        return;
    __asm__("fwait");
    if (last_task_used_math) {
        __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
    }
    last_task_used_math=current;
    if (current->used_math) {
        __asm__("frstor %0"::"m" (current->tss.i387));
    } else {
        __asm__("fninit"::);
        current->used_math=1;
    }
}
 
/*
 *  'schedule()' is the scheduler function. This is GOOD CODE! There
 * probably won't be any reason to change this, as it should work well
 * in all circumstances (ie gives IO-bound processes good response etc).
 * The one thing you might take a look at is the signal-handler code here.
 *
 *   NOTE!!  Task 0 is the 'idle' task, which gets called when no other
 * tasks can run. It can not be killed, and it cannot sleep. The 'state'
 * information in task[0] is never used.
 */
void schedule(void) 
{
    int i,next,c;
    struct task_struct ** p;
 
/* check alarm, wake up any interruptible tasks that have got a signal */
 
/*
#define TASK_RUNNING        0     只有state是0时,该进程才会被运行,或进入就绪队列
#define TASK_INTERRUPTIBLE    1     可中断睡眠状态   可以被信号中断,变成running状态
#define TASK_UNINTERRUPTIBLE    2 不可中断睡眠状态 只能被wakeup函数唤醒,变成running状态
#define TASK_ZOMBIE        3         僵死状态        进程停止运行,但是其task_struct未被清空
#define TASK_STOPPED        4     暂停状态  
*/
    for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) //从后往前遍历
        if (*p) { //若进程存在
            if ((*p)->alarm && (*p)->alarm < jiffies) { //若alarm不为空且小于jiffies(此处是0)
                    (*p)->signal |= (1<<(SIGALRM-1));
                    (*p)->alarm = 0;
                }
            if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&  //进程不理会某些信号;并且进程是可中断睡眠状态
            (*p)->state==TASK_INTERRUPTIBLE)
                (*p)->state=TASK_RUNNING;
        }
 
/* this is the scheduler proper: */
 
    while (1) {  //进行counter的比较,来决定进程的调用
        c = -1;
        next = 0;
        i = NR_TASKS;
        p = &task[NR_TASKS];
        while (--i) {
            if (!*--p)
                continue;
            if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
                c = (*p)->counter, next = i;  //遍历之后,会将counter的最大值赋给c,并且next存着最大counter的pid
        }
        if (c) break;
        for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
            if (*p)
                (*p)->counter = ((*p)->counter >> 1) +    //counter = counter/2 + priority
                        (*p)->priority;
    }
    switch_to(next); //进程切换
}
/*
这部分代码的目的是在所有就绪状态的任务进程中筛选出counter值最大的进程ID。之后如果counter值不为0则进入调度这个进程执行,如果counter值为0,则说明所有就绪状态的进程的时间片都已用完,需要重新调整所有进程的时间片。
*/
 
 
/*#define switch_to(n) {\
struct {long a,b;} __tmp; \
__asm__("cmpl %%ecx,_current\n\t" \
    "je 1f\n\t" \
    "movw %%dx,%1\n\t" \
    "xchgl %%ecx,_current\n\t" \
    "ljmp %0\n\t" \
    "cmpl %%ecx,_last_task_used_math\n\t" \
    "jne 1f\n\t" \
    "clts\n" \
    "1:" \
    ::"m" (*&__tmp.a),"m" (*&__tmp.b), \
    "d" (_TSS(n)),"c" ((long) task[n])); \
}
*/
 
 
 
 
 
int sys_pause(void)
{
    current->state = TASK_INTERRUPTIBLE;
    schedule();
    return 0;
}
 
void sleep_on(struct task_struct **p) //当p进程想访问cpu的某个资源,但是该资源被占用;
{
    struct task_struct *tmp;
 
    if (!p)
        return;
    if (current == &(init_task.task)) //如果当前进程为0号进程时,就返回,不能sleep
        panic("task[0] trying to sleep");
    tmp = *p;
    *p = current; //将p赋为当前进程
    current->state = TASK_UNINTERRUPTIBLE;
    schedule();
    if (tmp)
        tmp->state=0;
}
 
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();
    if (*p && *p != current) {
        (**p).state=0;
        goto repeat;
    }
    *p=NULL;
    if (tmp)
        tmp->state=0;
}
 
void wake_up(struct task_struct **p)
{
    if (p && *p) {
        (**p).state=0;
        *p=NULL;
    }
}
 
/*
 * OK, here are some floppy things that shouldn't be in the kernel
 * proper. They are here because the floppy needs a timer, and this
 * was the easiest way of doing it.
 */
static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL};
static int  mon_timer[4]={0,0,0,0};
static int moff_timer[4]={0,0,0,0};
unsigned char current_DOR = 0x0C;
 
int ticks_to_floppy_on(unsigned int nr)
{
    extern unsigned char selected;
    unsigned char mask = 0x10 << nr;
 
    if (nr>3)
        panic("floppy_on: nr>3");
    moff_timer[nr]=10000;        /* 100 s = very big :-) */
    cli();                /* use floppy_off to turn it off */
    mask |= current_DOR;
    if (!selected) {
        mask &= 0xFC;
        mask |= nr;
    }
    if (mask != current_DOR) {
        outb(mask,FD_DOR);
        if ((mask ^ current_DOR) & 0xf0)
            mon_timer[nr] = HZ/2;
        else if (mon_timer[nr] < 2)
            mon_timer[nr] = 2;
        current_DOR = mask;
    }
    sti();
    return mon_timer[nr];
}
 
void floppy_on(unsigned int nr)
{
    cli();
    while (ticks_to_floppy_on(nr))
        sleep_on(nr+wait_motor);
    sti();
}
 
void floppy_off(unsigned int nr)
{
    moff_timer[nr]=3*HZ;
}
 
void do_floppy_timer(void)
{
    int i;
    unsigned char mask = 0x10;
 
    for (i=0 ; i<4 ; i++,mask <<= 1) {
        if (!(mask & current_DOR))
            continue;
        if (mon_timer[i]) {
            if (!--mon_timer[i])
                wake_up(i+wait_motor);
        } else if (!moff_timer[i]) {
            current_DOR &= ~mask;
            outb(current_DOR,FD_DOR);
        } else
            moff_timer[i]--;
    }
}
 
#define TIME_REQUESTS 64
 
static struct timer_list {
    long jiffies;
    void (*fn)();
    struct timer_list * next;
} timer_list[TIME_REQUESTS], * next_timer = NULL;
 
void add_timer(long jiffies, void (*fn)(void))
{
    struct timer_list * p;
 
    if (!fn)
        return;
    cli();
    if (jiffies <= 0)
        (fn)();
    else {
        for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++)
            if (!p->fn)
                break;
        if (p >= timer_list + TIME_REQUESTS)
            panic("No more time requests free");
        p->fn = fn;
        p->jiffies = jiffies;
        p->next = next_timer;
        next_timer = p;
        while (p->next && p->next->jiffies < p->jiffies) {
            p->jiffies -= p->next->jiffies;
            fn = p->fn;
            p->fn = p->next->fn;
            p->next->fn = fn;
            jiffies = p->jiffies;
            p->jiffies = p->next->jiffies;
            p->next->jiffies = jiffies;
            p = p->next;
        }
    }
    sti();
}
 
void do_timer(long cpl)
{
    extern int beepcount;
    extern void sysbeepstop(void);
 
    if (beepcount)
        if (!--beepcount)
            sysbeepstop();
 
    if (cpl)
        current->utime++;
    else
        current->stime++;
 
    if (next_timer) {
        next_timer->jiffies--;
        while (next_timer && next_timer->jiffies <= 0) {
            void (*fn)(void);
 
            fn = next_timer->fn;
            next_timer->fn = NULL;
            next_timer = next_timer->next;
            (fn)();
        }
    }
    if (current_DOR & 0xf0)
        do_floppy_timer();
    if ((--current->counter)>0) return;
    current->counter=0;
    if (!cpl) return;
    schedule();
}
 
int sys_alarm(long seconds)
{
    int old = current->alarm;
 
    if (old)
        old = (old - jiffies) / HZ;
    current->alarm = (seconds>0)?(jiffies+HZ*seconds):0;
    return (old);
}
 
int sys_getpid(void)
{
    return current->pid;
}
 
int sys_getppid(void)
{
    return current->father;
}
 
int sys_getuid(void)
{
    return current->uid;
}
 
int sys_geteuid(void)
{
    return current->euid;
}
 
int sys_getgid(void)
{
    return current->gid;
}
 
int sys_getegid(void)
{
    return current->egid;
}
 
int sys_nice(long increment)
{
    if (current->priority-increment>0)
        current->priority -= increment;
    return 0;
}
 
void sched_init(void)
{
    int i;
    struct desc_struct * p;
 
    if (sizeof(struct sigaction) != 16)
        panic("Struct sigaction MUST be 16 bytes");
    set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
    set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
    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");
    ltr(0);
    lldt(0);
    outb_p(0x36,0x43);        /* binary, mode 3, LSB/MSB, ch 0 */
    outb_p(LATCH & 0xff , 0x40);    /* LSB */
    outb(LATCH >> 8 , 0x40);    /* MSB */
    set_intr_gate(0x20,&timer_interrupt);
    outb(inb_p(0x21)&~0x01,0x21);
    set_system_gate(0x80,&system_call);
}
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/sys.h>
#include <linux/fdreg.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
 
#include <signal.h>
 
#define _S(nr) (1<<((nr)-1))
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
 
void show_task(int nr,struct task_struct * p)  //nr就是pid
{
    int i,j = 4096-sizeof(struct task_struct);
 
    printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state); //打印pid与state
    i=0;
    while (i<j && !((char *)(p+1))[i])
        i++;
    printk("%d (of %d) chars free in kernel stack\n\r",i,j); //打印栈
}
 
void show_stat(void)
{
    int i;
 
    for (i=0;i<NR_TASKS;i++)
        if (task[i])
            show_task(i,task[i]);
}
 
#define LATCH (1193180/HZ)
 
extern void mem_use(void);
 
extern int timer_interrupt(void);
extern int system_call(void);
 
union task_union {
    struct task_struct task;
    char stack[PAGE_SIZE];
};
 
static union task_union init_task = {INIT_TASK,};
 
long volatile jiffies=0;
long startup_time=0;
struct task_struct *current = &(init_task.task);
struct task_struct *last_task_used_math = NULL;
 
struct task_struct * task[NR_TASKS] = {&(init_task.task), };
 
long user_stack [ PAGE_SIZE>>2 ] ;
 
struct {
    long * a;
    short b;
    } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };
/*
 *  'math_state_restore()' saves the current math information in the
 * old math state array, and gets the new ones from the current task
 */
void math_state_restore()  //进程切换时完成协处理器中寄存器的切换
{
    if (last_task_used_math == current)
        return;
    __asm__("fwait");
    if (last_task_used_math) {
        __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
    }
    last_task_used_math=current;
    if (current->used_math) {
        __asm__("frstor %0"::"m" (current->tss.i387));
    } else {
        __asm__("fninit"::);
        current->used_math=1;
    }
}
 
/*
 *  'schedule()' is the scheduler function. This is GOOD CODE! There
 * probably won't be any reason to change this, as it should work well
 * in all circumstances (ie gives IO-bound processes good response etc).
 * The one thing you might take a look at is the signal-handler code here.
 *
 *   NOTE!!  Task 0 is the 'idle' task, which gets called when no other
 * tasks can run. It can not be killed, and it cannot sleep. The 'state'
 * information in task[0] is never used.
 */
void schedule(void) 
{
    int i,next,c;
    struct task_struct ** p;
 
/* check alarm, wake up any interruptible tasks that have got a signal */
 
/*
#define TASK_RUNNING        0     只有state是0时,该进程才会被运行,或进入就绪队列
#define TASK_INTERRUPTIBLE    1     可中断睡眠状态   可以被信号中断,变成running状态
#define TASK_UNINTERRUPTIBLE    2 不可中断睡眠状态 只能被wakeup函数唤醒,变成running状态
#define TASK_ZOMBIE        3         僵死状态        进程停止运行,但是其task_struct未被清空
#define TASK_STOPPED        4     暂停状态  
*/
    for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) //从后往前遍历
        if (*p) { //若进程存在
            if ((*p)->alarm && (*p)->alarm < jiffies) { //若alarm不为空且小于jiffies(此处是0)
                    (*p)->signal |= (1<<(SIGALRM-1));
                    (*p)->alarm = 0;
                }
            if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&  //进程不理会某些信号;并且进程是可中断睡眠状态
            (*p)->state==TASK_INTERRUPTIBLE)
                (*p)->state=TASK_RUNNING;
        }
 
/* this is the scheduler proper: */
 
    while (1) {  //进行counter的比较,来决定进程的调用
        c = -1;
        next = 0;
        i = NR_TASKS;
        p = &task[NR_TASKS];
        while (--i) {
            if (!*--p)
                continue;
            if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
                c = (*p)->counter, next = i;  //遍历之后,会将counter的最大值赋给c,并且next存着最大counter的pid
        }
        if (c) break;
        for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
            if (*p)
                (*p)->counter = ((*p)->counter >> 1) +    //counter = counter/2 + priority
                        (*p)->priority;
    }
    switch_to(next); //进程切换
}
/*
这部分代码的目的是在所有就绪状态的任务进程中筛选出counter值最大的进程ID。之后如果counter值不为0则进入调度这个进程执行,如果counter值为0,则说明所有就绪状态的进程的时间片都已用完,需要重新调整所有进程的时间片。
*/
 
 
/*#define switch_to(n) {\
struct {long a,b;} __tmp; \
__asm__("cmpl %%ecx,_current\n\t" \
    "je 1f\n\t" \
    "movw %%dx,%1\n\t" \
    "xchgl %%ecx,_current\n\t" \
    "ljmp %0\n\t" \
    "cmpl %%ecx,_last_task_used_math\n\t" \
    "jne 1f\n\t" \
    "clts\n" \
    "1:" \
    ::"m" (*&__tmp.a),"m" (*&__tmp.b), \
    "d" (_TSS(n)),"c" ((long) task[n])); \
}
*/
 
 
 
 
 
int sys_pause(void)
{
    current->state = TASK_INTERRUPTIBLE;
    schedule();
    return 0;
}
 
void sleep_on(struct task_struct **p) //当p进程想访问cpu的某个资源,但是该资源被占用;
{
    struct task_struct *tmp;
 
    if (!p)
        return;
    if (current == &(init_task.task)) //如果当前进程为0号进程时,就返回,不能sleep
        panic("task[0] trying to sleep");
    tmp = *p;
    *p = current; //将p赋为当前进程
    current->state = TASK_UNINTERRUPTIBLE;
    schedule();
    if (tmp)
        tmp->state=0;
}
 
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();
    if (*p && *p != current) {
        (**p).state=0;
        goto repeat;
    }
    *p=NULL;
    if (tmp)
        tmp->state=0;
}
 
void wake_up(struct task_struct **p)
{
    if (p && *p) {
        (**p).state=0;
        *p=NULL;
    }
}
 
/*
 * OK, here are some floppy things that shouldn't be in the kernel
 * proper. They are here because the floppy needs a timer, and this
 * was the easiest way of doing it.
 */
static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL};
static int  mon_timer[4]={0,0,0,0};
static int moff_timer[4]={0,0,0,0};
unsigned char current_DOR = 0x0C;
 
int ticks_to_floppy_on(unsigned int nr)
{
    extern unsigned char selected;
    unsigned char mask = 0x10 << nr;
 
    if (nr>3)
        panic("floppy_on: nr>3");
    moff_timer[nr]=10000;        /* 100 s = very big :-) */
    cli();                /* use floppy_off to turn it off */
    mask |= current_DOR;
    if (!selected) {
        mask &= 0xFC;
        mask |= nr;
    }
    if (mask != current_DOR) {
        outb(mask,FD_DOR);
        if ((mask ^ current_DOR) & 0xf0)
            mon_timer[nr] = HZ/2;
        else if (mon_timer[nr] < 2)
            mon_timer[nr] = 2;
        current_DOR = mask;
    }
    sti();
    return mon_timer[nr];
}
 
void floppy_on(unsigned int nr)
{
    cli();
    while (ticks_to_floppy_on(nr))
        sleep_on(nr+wait_motor);
    sti();
}
 
void floppy_off(unsigned int nr)
{
    moff_timer[nr]=3*HZ;
}
 
void do_floppy_timer(void)
{
    int i;
    unsigned char mask = 0x10;
 
    for (i=0 ; i<4 ; i++,mask <<= 1) {
        if (!(mask & current_DOR))
            continue;
        if (mon_timer[i]) {
            if (!--mon_timer[i])
                wake_up(i+wait_motor);
        } else if (!moff_timer[i]) {
            current_DOR &= ~mask;
            outb(current_DOR,FD_DOR);
        } else
            moff_timer[i]--;
    }
}
 
#define TIME_REQUESTS 64
 
static struct timer_list {
    long jiffies;
    void (*fn)();
    struct timer_list * next;
} timer_list[TIME_REQUESTS], * next_timer = NULL;
 
void add_timer(long jiffies, void (*fn)(void))
{
    struct timer_list * p;
 
    if (!fn)
        return;
    cli();
    if (jiffies <= 0)
        (fn)();
    else {
        for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++)
            if (!p->fn)
                break;
        if (p >= timer_list + TIME_REQUESTS)
            panic("No more time requests free");
        p->fn = fn;
        p->jiffies = jiffies;
        p->next = next_timer;
        next_timer = p;
        while (p->next && p->next->jiffies < p->jiffies) {
            p->jiffies -= p->next->jiffies;
            fn = p->fn;
            p->fn = p->next->fn;
            p->next->fn = fn;
            jiffies = p->jiffies;
            p->jiffies = p->next->jiffies;
            p->next->jiffies = jiffies;
            p = p->next;
        }
    }
    sti();
}
 
void do_timer(long cpl)
{
    extern int beepcount;
    extern void sysbeepstop(void);
 
    if (beepcount)
        if (!--beepcount)
            sysbeepstop();
 
    if (cpl)
        current->utime++;
    else
        current->stime++;
 
    if (next_timer) {
        next_timer->jiffies--;
        while (next_timer && next_timer->jiffies <= 0) {
            void (*fn)(void);
 
            fn = next_timer->fn;
            next_timer->fn = NULL;
            next_timer = next_timer->next;
            (fn)();
        }
    }

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 12
支持
分享
最新回复 (9)
雪    币: 676
活跃值: (322)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
不错,很详细
2022-5-19 20:47
0
雪    币: 319
活跃值: (347)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
不错,收藏了在看
2022-5-19 21:14
0
雪    币: 221
活跃值: (1110)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
牛逼!!!
2022-5-20 16:56
0
雪    币: 893
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
好文
2022-5-20 17:40
0
雪    币: 22411
活跃值: (25361)
能力值: ( LV15,RANK:910 )
在线值:
发帖
回帖
粉丝
6
这是要读LINUX源码了嘛
2022-5-20 19:56
0
雪    币: 3441
活跃值: (6242)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
7
1900 这是要读LINUX源码了嘛
是啊,读好基础的;高版本才不至于云里雾里!
2022-5-20 22:05
0
雪    币: 271
活跃值: (290)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
感觉有点像是chandler那套Linux内核教程笔记
2023-1-19 18:44
0
雪    币: 199
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
学习惹
2023-1-21 11:20
0
雪    币: 1392
活跃值: (3075)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
10
我家猫看完都会了
2023-2-19 14:45
0
游客
登录 | 注册 方可回帖
返回
//