linux 0.11 源码学习(八)

 

shed.c

sched实现内核的调度工作,最主要的是以下几个函数的实现:

  • 初始化 void sched_init(void),完成工作如下:
    • 设置TSS和LDT的描述符:
    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")
复制代码
    • 清任务数据(struct task_struct * task[NR_TASKS] = {&(init_task.task), };)和描述符表项(desc_struct *p);
    • 加载任务0的TSS和LDT到相应寄存器,设置时钟中断、系统调用中断;
  • 内核调度void schedule(void),主要完成工作如下:

备注: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等信号        
    • 首先判断全部TASK_INTERRUPTIBLE状态的进程,是否满足被唤醒条件,有则设置状态为RUNNING;
    • 遍历全部任务数组,查找属于RUNNING状态,且counter最大的任务。counter随任务运行时间递减,counter大则证明运行时间不长;
    • 若无法通过counter获取当前待运行任务,则重新计算counter值,算法为:(*p)->counter = ((*p)->counter >> 1) +(*p)->priority;重新至上一步骤;
    • 当得到当前待运行任务时,调用switch_to(next),进行任务切换;代码如下:
复制代码
#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为新任务变量的起始地址
}
复制代码

 

posted @   Fredric_2013  阅读(503)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示