shed.c
sched实现内核的调度工作,最主要的是以下几个函数的实现:
set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); //初始化一个TSS set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt)); //初始化一个LDT,linux中每个任务定义了三个LDT,分别是0,代码段和数据段
#define _set_tssldt_desc(n,addr,type) \ __asm__ ("movw $104,%1\n\t" \ //段界限为104?? "movw %%ax,%2\n\t" \ //addr的低16字节赋值至描述符的BYTE2/3 "rorl $16,%%eax\n\t" \//addr右移16个bit "movb %%al,%3\n\t" \//将al,相当于把原始addr的第三个BYTE赋值到描述符的BYTE4 "movb $" type ",%4\n\t" \ //将0x89(可用的TSS)和0x82(LDT)赋值给描述符的第五个字节 "movb $0x00,%5\n\t" \//描述符属性定义的高字节为0 "movb %%ah,%6\n\t" \ //eax高8位,相当于把原始addr的第四个BYTE赋值到描述符的BYTE7 "rorl $16,%%eax" \ //ead清零 ::"a" (addr), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \ //addr是描述符定义的起始地址,赋值给eax "m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \ ) #define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),"0x89") #define set_ldt_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),"0x82")
备注:linux中的进程或者说任务,定义的状态有五种:
#define TASK_RUNNING 0 //运行状态,随时被调度 #define TASK_INTERRUPTIBLE 1 //可中断睡眠状态,当收到相应信号时可已被唤醒,进入TASK_RUNNING状态 #define TASK_UNINTERRUPTIBLE 2 //不可中断睡眠状态,只能被wake_up函数唤醒 #define TASK_ZOMBIE 3 //进程已停止运行 #define TASK_STOPPED 4 //暂停状态,收到SIGSTOP等信号
#define switch_to(n) {\ struct {long a,b;} __tmp; \ __asm__("cmpl %%ecx,current\n\t" \ //待切换任务,不是当前任务 "je 1f\n\t" \ //是当前任务跳转至1:,即不做任何工作 "movw %%dx,%1\n\t" \ //描述符复制给_tmp.b "xchgl %%ecx,current\n\t" \ //将新任务的地址复制给current "ljmp *%0\n\t" \ //长跳转到TSS选择描述符,CPU根据给出的TSS完成切换及上下文保存 "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])); \ //edx为TSS的选择描述符,ecx为新任务变量的起始地址 }