CosOS任务切换的实现
来源:互联网 发布:手机照片写字软件 编辑:程序博客网 时间:2024/05/14 15:04
CosOS是我为我设计编写的操作系统取的名称,有关CosOS的介绍请阅读:CosOS 0.01 alpha 操作系统预览
CosOS通过时钟中断来中断当前任务的执行,并进行任务切换,当时钟中断触发时,中断处理函数irq_common_stub将得到执行,以下部分将以注释的形式,详细介绍CosOS中任务切换的具体实现。
irq_common_stub:
;pushad将EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI全部压入栈中。
pushad
;由于不能直接把ds段寄存器压入栈,所以先把ds的值传递到ax寄存器中。
mov ax, ds
;这时,eax的低16位中保存有ds的值,压入栈中。
push eax
;以上代码完成当前进程的现场保护。以便下次被调度时还原进程。
;由于段寄存器不能直接使用立即数设置,所以先把值放入ax寄存器中。
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
;以上代码把所有的段寄存器设置0x10,即内核数据段。
push esp
;调用IRQ处理函数,由于触发的是时钟中断,irq_handler内会调用timer_callback函数。
call irq_handler
add esp, 4
jmp switch_stack
每次时钟中断触发时,timer_callback函数都将得到执行。
static void timer_callback(registers_t *regs)
{
tick++;
//tick中保存有自开机以来,时钟中断触发的次数。
if(key_pressed)
{
inform_int(TTY_TASK);
}
//以上代码用于唤醒等待消息中的TTY任务,与任务切换无关。
schedule();
}
//schedule进行任务调度
任务调度的方案是选择剩余时间片最多的进程,并且它处于等待就绪状态,如果所有进程的时间片都已经用完,则按照它们的优先级重新设置时间片。
void schedule()
{
task_t* select_task = NULL;
while(1)
{
// 首先选择时间片最多的进程
select_task = get_greatest_ticks_task();
// 若时间片最多的进程时间片为0,则说明所有进程的时间片都已经用完。需要重新设置它们时间片。
if(select_task->ticks == 0)
{
volatile task_t *p_task = NULL;
for(p_task = ready_queue; p_task != NULL;p_task = p_task->next)
{
// 如果进程处于就绪态,则根据优先级设置时间片
if(p_task->flags == 0)
{
p_task->ticks = MAX_TICKS - p_task->priority;
//时间片时钟为最大时间片减去优先级,因此,priority越小优先级越大
}
}
}
if(select_task->flags != 0)
{
// 若时间片最多的进程不处于就绪态,则将其时间片设置为0,以免下一while轮循环再次被选中。
select_task->ticks = 0;
}
else
{
// 若时间片最多的进程处于就绪态,则跳出while循环。
break;
}
}
// 把当前进程设置为调度算法所选择的进程
current_task = select_task;
// 将其时间片减去一。
current_task->ticks--;
// 将当前所使用的页表切换为当前进程的页表
current_directory = current_task->page_directory;
// 设置TSS结构体中ESP字段,用户下次切换到内核态时,切换到正确的内核栈。
set_kernel_stack(current_task->kernel_stack+KERNEL_STACK_SIZE);
// 以上代码只是设置相应的变量,并没有开始进行真正的任务切换。
// 切换页表,内部通过设置CR3寄存器更新页目录地址来完成。
switch_page_directory(current_directory);
}
从irq_handler返回之后,将执行以下代码:
Switch_stack将堆栈切换到调度之后当前任务的内核栈。
;current_task是C语言代码中的变量,为了在汇编中使用,必须将其申明为外部变量
extern current_task
switch_stack:
; 内核栈的地址保存在task结构体的第一步成员中,首先获取到task结构体的首地址,保存在eax中。
mov eax,dword [current_task]
; 保存有内核栈地址的字段为task结构体的第一个成员,所以其地址和task结构体首地址相等,通过mov指令,将内核栈地址复制到ebx中。
mov ebx,dword [eax]
; 以下三条指令,计算出进程信息所在的位置,并将esp移到改位置。
add ebx,0x2000 ;kernel stack size
sub ebx,0x40
mov esp,ebx
; 跳转到 ret_from_irq,继续执行
jmp ret_from_irq
ret_from_irq:
; 从栈中还原段寄存器
pop ebx
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
; 从栈中还原EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI寄存器
popad
add esp, 8
; 跳过栈中一些无关的数据,如中断号等。
; 执行iret指令之后,将结束时钟中断过程,这时CPU将回到用户态,并且EIP将指向被中断处的下一条指令,继续执行,完成进程的恢复。
iret
实际上,只要触发了中断,中断处理程序都会进行现场保护,只不过时钟中断会调用schedule改变current_task,从而在恢复现场的时候切换到其它进程。其它中断触发时,虽然也进行了现场保护和现场恢复,但current_task未改变所以恢复到的进程还是原先的进程。
更多详情请关注 http://www.ecjtu.org/
- CosOS任务切换的实现
- CosOS中堆管理 malloc free的实现
- 嵌入式os的实现一之任务切换的实现
- 任务,任务的切换,(TCB)
- ucos的任务切换
- UCOS_STM32的任务切换
- 任务切换的方法
- secureCRT+screen实现多任务窗口的快速切换
- 一步一步实现一个简单的OS(试验任务切换)
- 一步一步实现一个简单的OS(任务切换)
- 多任务操作系统的任务切换
- 使用python的yield实现任务调度.给定一个任务列表,每个任务轮流切换执行,类似于切片
- 任务切换的堆栈操作
- uclinux内核的任务切换
- TSS----任务切换的核心
- 任务的调度和切换
- RTOS里的任务切换
- 任务切换的精华思想
- Unix的五个特性
- 我在Archlinux下使用的软件列表
- csdn blog css自定义设置介绍
- jsp乱码问题
- ASP.NET中的Eval和DataBinder.Eval方法
- CosOS任务切换的实现
- 自己写printf函数
- 第三届华为编程大赛【C语言试题】
- 遍历驱动
- System.Data.OracleClient 需要 Oracle 客户端软件 8.1.7 或更高版本
- RS232标准中的RTS与CTS
- 分析setup_arch
- 遍历进程
- 比较失败的项目管理经历总结