MacOS环境-手写操作系统-30-进程之间互相切换

本文涉及的产品
网络型负载均衡 NLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
公网NAT网关,每月750个小时 15CU
简介: MacOS环境-手写操作系统-30-进程之间互相切换

进程之间互相切换

1.简介

上一节 我们初步介绍了进程相关的具体概念


特别是讲解了进程切换相关的数据结构 也就是TSS


也实现了进程的自我切换


本节 我们看看如何从当前的进程切换到新进程 然后再切换回来


进程A -切换->进程B-切换->进程A.


2.代码

先看看进程B的实现 一个进程主要包含一个主函数 我们把进程B的主函数实现如下

void task_b_main(void) {
   showString(shtctl, sht_back, 0, 144, COL8_FFFFFF, "enter task b");

    struct FIFO8 timerinfo_b;
    char timerbuf_b[8];
    struct TIMER *timer_b = 0;

    int i = 0;

    fifo8_init(&timerinfo_b, 8, timerbuf_b);
    timer_b = timer_alloc();
    timer_init(timer_b, &timerinfo_b, 123);

    timer_settime(timer_b, 500);


    for(;;) {

       io_cli();
        if (fifo8_status(&timerinfo_b) == 0) {
            io_sti();
        } else {
           i = fifo8_get(&timerinfo_b);
           io_sti();
           if (i == 123) {
               showString(shtctl, sht_back, 0, 160, COL8_FFFFFF, "switch back");
               taskswitch7();
           }

        }

    }

}

进程B函数的逻辑是这样的


当进入到进程B后 通过它的主函数现在桌面上打印出一个字符串”enter task b”


当这个字符串出现在桌面时 表示进程完成了切换


然后它初始化一个时钟 这个时钟超时是五秒 五秒过后 它调用函数taskswitch7重新切回到进程A


进程A就是主入口函数CMain 既然要切换进程B


那显然 我们需要一个描述进程B的TSS结构并进行相应的初始化


代码如下

int addr_code32 = get_code32_addr();
 tss_b.eip =  (task_b_main - addr_code32);
    tss_b.eflags = 0x00000202; 
    tss_b.eax = 0;
    tss_b.ecx = 0;
    tss_b.edx = 0;
    tss_b.ebx = 0;
    tss_b.esp = 1024;//tss_a.esp;
    tss_b.ebp = 0;
    tss_b.esi = 0;
    tss_b.edi = 0;
    tss_b.es = tss_a.es;
    tss_b.cs = tss_a.cs;//6 * 8;
    tss_b.ss = tss_a.ss;
    tss_b.ds = tss_a.ds;
    tss_b.fs = tss_a.fs;
    tss_b.gs = tss_a.gs;

上面的代码需要详细解释下


首先我们把tss_b.eflags设置成0x202


这个值可以当做一个写死的值


然后 我们把进程B的段寄存器设置成跟A一样


我们看看进程A的各个段寄存器分别指向哪个全局描述符 tss_a.cs 的值是8


对应全局描述符表的下标就是1(数值要除以8,上一节讲解过)


下标为1的描述符是这样的


LABEL_DESC_CODE32:  Descriptor        0,      0fffffh,       DA_CR | DA_32 | DA_LIMIT_4K


这个描述符指向一段内存 这段内存的性质是可执行代码段


这段内存的起始地址在内核的汇编部分进行了初始化 如下


xor   eax, eax
     mov   ax,  cs
     shl   eax, 4
     add   eax, LABEL_SEG_CODE32
     mov   word [LABEL_DESC_CODE32 + 2], ax
     shr   eax, 16
     mov   byte [LABEL_DESC_CODE32 + 4], al
     mov   byte [LABEL_DESC_CODE32 + 7], ah


上面的代码把描述符指向的内存地址的起始位置设置为LABEL_SEG_CODE32


tss_a.ds 的值为24 除以8后为3 也就是对应描述符在全局描述符表中的下标是3 这个描述符内容如下


LABEL_DESC_VRAM:    Descriptor        0,         0fffffh,            DA_DRWA | DA_LIMIT_

4K


这个描述符指向的内存起始地址是0 长度为0fffffh


这段内存的性质是可读写数据段 也就是从0到0fffffh 这段长度的内存是可读写的数据


tss_a.ss 的值是32 除以8后得4 因此对应的是下标为4的描述符 该描述符的内容如下


LABEL_DESC_STACK:   Descriptor        0,             LenOfStackSection,        DA_DRWA | DA_32


它描述的是一段32位可读写的内存 长度为LenOfStackSection


它对应的这段内存是我们在内核的汇编部分分配的内存 具体如下


[SECTION .gs]
ALIGN 32
[BITS 32]
LABEL_STACK:
times 512  db 0
TopOfStack1  equ  $ - LABEL_STACK
times 512 db 0
TopOfStack2 equ $ - LABEL_STACK
LenOfStackSection equ $ - LABEL_STACK


上面分配了两个512字节 总共1024字节的内存


LABEL_STACK将会设置成下标为4的描述符所对应内存的起始地址


第一个512字节 作为进程A的堆栈


第二个512字节 将作为进程B的堆栈 上面tss_b的初始化代码中有这么一句:

tss_b.esp = 1024;


它的作用就是让进程把把堆栈指针指向第二个512字节的末尾处 大家要记得


堆栈是有高地址向低地址生长的 所以设置堆栈指针时 要把它指向内存的末尾


在内核的汇编部分 有代码将下标为4的描述符对应的内容起始地址设置为了LABEL_STACK


代码如下


xor   eax, eax
     mov   ax,  cs
     shl   eax, 4
     add   eax, LABEL_STACK
     mov   word [LABEL_DESC_STACK + 2], ax
     shr   eax, 16
     mov   byte [LABEL_DESC_STACK + 4], al
     mov   byte [LABEL_DESC_STACK + 7], ah


最重要的三个段寄存器 cs, ds, ss,设置好


其余寄存器 设置成跟进程A一样即可


接下来最重要的设置是eip指针 这个指针将指向要执行代码的首地址


我们要执行的函数是task_b_main


因此eip应该指向这个函数 但注意 我们不能直接把这个函数的地址直接赋值给eip


eip指向的是相对于代码段起始地址的偏移 当前代码段的其实地址是LABEL_SEG_CODE32


因此我们需要把task_b_main的地址减去LABEL_SEG_CODE32


所得的结果就是相对偏移了


这也是eip初始化的逻辑


tss_b.eip = (task_b_main - addr_code32);


get_code32_addr是内核的汇编部分实现的行数


目的就是返回LABEL_SEG_CODE32对应的地址


实现如下


get_code32_addr:
        mov  eax, LABEL_SEG_CODE32
        ret


上一节 我们已经看到


我们通过代码 将一个描述符指向结构tss_b了


代码如下


set_segmdesc(gdt + 9, 103, (int) &tss_b, AR_TSS32);


指向tss_b结构的描述符下标是9 初始化好tss_b后


只要通过一个jmp语句 跳转到下标为9的描述符


那么就能将当前指向进程切换成运行task_b_main的进程了 这个跳转语句实现如下


taskswitch9:
        jmp 9*8:0
        ret


进程A运行的是CMain函数 它会创建一个5秒的计时器 一旦超时 则调用上面的函数实现任务切换


for(;;) {
.....
else if (fifo8_status(&timerinfo) != 0) {
           io_sti();
           int i = fifo8_get(&timerinfo);
           if (i == 10) {
               showString(shtctl, sht_back, 0, 176, COL8_FFFFFF, "switch to task b");
                //switch task 
               taskswitch9();
           }
.....
}


在跳转前 我们会在桌面上打印出一句switch to task b表示即将进行任务切换


task_b_main的实现我们已经看过了 进入task_b_main后


它会在桌面打印一条语句 表示跳转成功


然后启动一个5秒的计时器 五秒过后 通过taskswitch7重新跳转回进程A


一旦跳转到task_b_main 桌面会打印出相关字符串


然后光标会停止住 等5秒后


进程从task_b_main 切换回进程A,进程A恢复执行


于是在卡死5秒后 在跳转会进程A前


task_b_main会打印出一条语句”switch back”


当这条语句出现在桌面上时 控制器转回到进程A 于是光标会重新开始闪烁


这样的话 我们就实现了进程从A切换到B再从B切换回A的整个流程


3.编译运行

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
高可用应用架构
欢迎来到“高可用应用架构”课程,本课程是“弹性计算Clouder系列认证“中的阶段四课程。本课程重点向您阐述了云服务器ECS的高可用部署方案,包含了弹性公网IP和负载均衡的概念及操作,通过本课程的学习您将了解在平时工作中,如何利用负载均衡和多台云服务器组建高可用应用架构,并通过弹性公网IP的方式对外提供稳定的互联网接入,使得您的网站更加稳定的同时可以接受更多人访问,掌握在阿里云上构建企业级大流量网站场景的方法。 学习完本课程后,您将能够: 理解高可用架构的含义并掌握基本实现方法 理解弹性公网IP的概念、功能以及应用场景 理解负载均衡的概念、功能以及应用场景 掌握网站高并发时如何处理的基本思路 完成多台Web服务器的负载均衡,从而实现高可用、高并发流量架构
相关文章
|
11小时前
|
iOS开发 MacOS
MacOS环境-手写操作系统-40-进程消息通讯 和 回车键处理
MacOS环境-手写操作系统-40-进程消息通讯 和 回车键处理
9 2
|
12小时前
|
缓存 Java iOS开发
MacOS环境-手写操作系统-13-鼠标中断
MacOS环境-手写操作系统-13-鼠标中断
8 1
|
13小时前
|
存储 Java C语言
MacOS环境-手写操作系统-04-实模式进入保护模式
MacOS环境-手写操作系统-04-实模式进入保护模式
6 1
|
11小时前
|
存储 算法 调度
MacOS环境-手写操作系统-29-进程切换
MacOS环境-手写操作系统-29-进程切换
5 0
|
11小时前
|
算法 调度 iOS开发
MacOS环境-手写操作系统-31-进程自动切换
MacOS环境-手写操作系统-31-进程自动切换
6 0
|
12小时前
|
Java C语言 iOS开发
MacOS环境-手写操作系统-11-建立中断机制
本文详细介绍了如何为内核建立中断机制,涉及8259A中断控制器的初始化、中断信号的传递过程以及中断描述符表的设置。通过汇编和C语言代码展示了如何处理中断,特别是键盘和鼠标中断,最后给出了编译和运行的步骤。 摘要由CSDN通过智能技术生成
7 0
|
11小时前
|
存储 调度 iOS开发
MacOS环境-手写操作系统-32-进程挂起和恢复
MacOS环境-手写操作系统-32-进程挂起和恢复
6 0
|
13小时前
|
Java C语言 iOS开发
MacOS环境-手写操作系统-01-最小操作系统
MacOS环境-手写操作系统-01-最小操作系统
5 0
|
12小时前
|
存储 算法 C语言
MacOS环境-手写操作系统-15-内核管理 检测可用内存
MacOS环境-手写操作系统-15-内核管理 检测可用内存
8 0
|
11小时前
|
存储 算法 调度
MacOS环境-手写操作系统-34-进程优先级
MacOS环境-手写操作系统-34-进程优先级
6 0