365bet亚洲版登录-bet官网365入口

365bet亚洲版登录拥有超过百间客房,bet官网365入口的文化历经几十年的传承和积淀形成的核心内容获得业界广泛的认可,365bet亚洲版登录是目前信誉最高的娱乐场所,同国内外几百家网上内容供应商建立了合作关系。

三十天自制操作系统

在那前边的顺序中年老年是新装置二个定时器都要创立三个队列与之相应,这样作用低况且产生操作系统主程序中逻辑复杂。大家先想方法把放大计时器的消息队列合併。怎么统一呢?首先想转手我们为什么事先要把停车计时器的音信队列分开设置,为各个电磁料理计时器分配三个行列呢。首若是因为各样电火花计时器超时所对应的操作不一致样,由此为了不同差别电火花计时器超时操作,所以才把队列分开。那若是大家给各个反应计时器往队列中归入数据的值都比不上,再种种沙漏超时的时候先推断队列中的数据属于哪个沙漏,大家就足以分别进行不一致的操作了,也完成了此前的此时此刻。并且代码显明更简便易行了,起码不用作那么多判定了。

接下去还要做过多停车计时器的优化工作,可是大家以往还不曾思量怎么样测量检验优化的结果。我们能够那样,在机械漏刻3秒中断的时候把count设置为0,平昔努力计数,然后在10秒中断的时候甘休计数,并把结果展现在窗口中。要是数字越大表明系统试行进程越快,质量也就越好。

作者们事先有别沙漏中断时候,是用向消息队列中发送数据的不比来区分的。那能或不可能大家把鼠标和键盘使用的新闻队列也跟反应计时器合在一齐,也用向音讯队列中传递的数量来分别呢?上面我们定义一下抛锚类型。

  • 0~1 光标闪烁计时器
  • 3 3秒电火花计时器
  • 10 10秒沙漏
  • 256~511 键盘输入(从键盘调控器读入的值再增加256)
  • 512~767 鼠标输入(从键盘调节器读入的值再增多 512)

大家在此之前的行列定的运用的数据类型为char独有8位,现在大家将其改为int类型。其他基本未有何样变动。只是在队列中读入键盘和鼠标灵数据的时候要分别减去256和512。

在管理定时器中断的时候根本的小运支付是找下一个过期放大计时器之后的活动操作,大家正是要想办法打消活动操作。

我们在TIMEMurano结构体中新定义二个TIME巴博斯 SLK级指针,指向下八个就要超时的放大计时器。

struct TIMER { struct TIMER *next; unsigned int timeout, flags; struct FIFO32 *fifo; int data;};

骨子里就是把线性表改动成链表操作,中断管理程序这么改写

void inthandler20{ int i; struct TIMER *timer; io_out8(PIC0_OCW2, 0x60); timerctl.count++; if (timerctl.next > timerctl.count) { return; } timer = timerctl.t0; //首先把最前面的地址赋给timer for (i = 0; i < timerctl.using; i++) { //因为timers的定时器都处于运行状态,所以不确认flags if (timer->timeout > timerctl.count) { break; } //超时 timer->flags = TIMER_FLAGS_ALLOC; fifo32_put(timer->fifo, timer->data); timer = timer->next; //下一个定时器的地址赋给timer } timerctl.using -= i;/*新移位 */ timerctl.t0 = timer; /* timerctl.next的设定*/ if (timerctl.using > 0) { timerctl.next = timerctl.t0->timeout; } else { timerctl.next = 0xffffffff; } return;}

计时器设置函数

 void timer_settime(struct TIMER *timer, unsigned int timeout){ int e; struct TIMER *t, *s; timer->timeout = timeout + timerctl.count; timer->flags = TIMER_FLAGS_USING; e = io_load_eflags(); io_cli(); timerctl.using++; if (timerctl.using == 1) { timerctl.t0 = timer; timer->next = 0; timerctl.next = timer->timeout; io_store_eflags; return; } t = timerctl.t0; if (timer->timeout <= t->timeout) { timerctl.t0 = timer; timer->next = t; timerctl.next = timer->timeout; io_store_eflags; return; } for  { s = t; t = t->next; if  { break; } if (timer->timeout <= t->timeout) { s->next = timer; timer->next = t; io_store_eflags; return; } } s->next = timer; timer->next = 0; io_store_eflags; return;}

即使前后相继变长了,不过出于引进了链表的概念,不再必要做运动操作,在反应计时器多的景况下,效能绝相比较线性表渐渐移位要快相当多。

解析一下上边程序变长的由来。主倘诺插入链表的时候发出了4种情形:1、运转中的电磁照应计时器唯有二个;2、插入到最前方的气象;3、插入到中间的景观;4、插入到结尾的景色。

为了减小插边链表时候所考虑的情况,大家引进了哨兵的定义。也正是安装贰个永无存在且三番五次在最后到期的电火花计时器。有了那个停车计时器之后,插入链表的时候就唯有2种情景了,插入到最后面包车型客车气象和插入到中游的气象。

修改现在的计时器设置函数

void timer_settime(struct TIMER *timer, unsigned int timeout){ int e; struct TIMER *t, *s; timer->timeout = timeout + timerctl.count; timer->flags = TIMER_FLAGS_USING; e = io_load_eflags(); io_cli(); t = timerctl.t0; if (timer->timeout <= t->timeout) { timerctl.t0 = timer; timer->next = t; timerctl.next = timer->timeout; io_store_eflags; return; } for  { s = t; t = t->next; if (timer->timeout <= t->timeout) { s->next = timer; timer->next = t; io_store_eflags; return; } }}

能够看来简化了数不完。简化后的暂停管理函数

void inthandler20{ struct TIMER *timer; io_out8(PIC0_OCW2, 0x60); timerctl.count++; if (timerctl.next > timerctl.count) { return; } timer = timerctl.t0; for  { if (timer->timeout > timerctl.count) { break; } timer->flags = TIMER_FLAGS_ALLOC; fifo32_put(timer->fifo, timer->data); timer = timer->next; } timerctl.t0 = timer; timerctl.next = timer->timeout; return;}

眼下我们的操作系统使用的分辨率为320*200,大家得以想艺术把分辨率进步上去。从前设置分辨率的时候是用ah = 0; al = 画面方式;设置的。更加大学一年级些的画面模试叫作VBE。在很早时候Computer规格是由IBM公司制定的 ,当然也鲜明了显卡画面情势,各家显卡公司就以IBM的专门的学业制作显卡。但是后来显卡公司的技巧力量超过了IBM,原本的显卡标准已经不适用了,各家显卡集团就制订了上下一心的正规化。为了让操作系统和应用程序能动用各家公司的显卡,各家显卡集团协助实行起来创设了VESA(Video Electronics Standards Association),也等于录制电子标准协会。这么些组织制订了显示通用的设定方法,也创制了专门的BIOS。那么些BIOS被称作VESA BIOS extension,简称为VBE。切换成VBE使用ax = 0x4f02; bx = 画面形式。

  • 0x101 6404808位彩色
  • 0x103 8006008位彩色
  • 0x105 10247688位彩色
  • 0x107 128010248位彩色

想要进步分辨率要先查询一下机器扶助不支持VBE的展现格局。

MOV AX,0x9000MOV ES,AXMOV DI,0MOV AX,0x4f00INT 0x10CMP AX,0x004fJNE scrn320

先把es赋值为0x捌仟,di赋值为0,ax赋值为0x4f00,然后int 0x10。假如ax变为0x004f的话就认证有VBE不是那个值的话就只好使用320*200的分辨率了。

接下去检查VBE的本子是否2.0以上,假如不是2.0之上那也不能够选择高分辨率。

MOV AX,[ES:DI+4]CMP AX,0x0200JB scrn320 

接下来再检查0x105的画面情势能还是不能够选用

MOV CX,VBEMODEMOV AX,0x4f01INT 0x10CMP AX,0x004fJNE scrn320

好,要是证明0x105足以选取了,大家再确认0x105的画面信息,主要的音信有6个。

  • word[es:di+0x00] 方式属性,bit7不是1就不佳办(能加上0x陆仟)
  • word[es:di+0x12] X的分辨 率
  • word[es:di+0x14] Y的分辨率
  • byte[es:di+0x19] 颜色数,必须为8
  • byte[es:di+0x1b] 颜色的钦命方法,必需为4,调色板情势
  • word[es:di+0x28] VRAM的地址

地点的6个根性子质大家假如鲜明3个,都以不利的之后,就足以把这一个音信定入内定的内部存款和储蓄器了,然后跳过scrn320程序段直接进入高级画面方式了。

接下去做键盘输入的拍卖。我们早就得以从键盘中断管理程序中取到键盘调节存放器中的值了。这些值小编实际对应哪个开关被按下也许甩手有贰个应和的报表。在那之中按钮松手时的值为按钮按下时值加上0x80。能够创造三个数组,从0开始遵照那些表格把键盘的扫描码换来字符的ASCII码。之前大家已经用ASCII码创立过字体文件,然后依据获得的ASCII码在显示器上海展览中心示出来。

一旦大家把光标依照键盘输入意况左右平移也很轻便。首先定义二个cursor_x变量,用于存款和储蓄光标的职位。一齐首鼠标邻近窗口的最左边。然后推断键盘输入的开关是还是不是是须求呈现的按钮,假如要求体现,那么在cursor_x地方开写入对应的字符,然后cursor_x+8,然后在新的cursor_x地方再一次画出光标。

那本书还完毕了按住鼠标拖动完结鼠标跟着鼠标指针动。不过跟大家平时windows下移动鼠标的分裂,这里只是简短得落实。管理鼠标循环的一部分中,先判定鼠标左键是还是不是一度按下,假如按下,那把窗口及时移动到鼠标所在的职位。

这一天想方法落实多任务。所谓的多任务就是CPU在快捷得切换各种职务,使Computer使用者认为CPU在同时处理不一样的职分。切换职分的速度不可能太快也不能够太慢。因为切换职务也会有本钱的,要是太快,切换任伤的开支就太大,假使太慢,还不比不要多作务,因为把应太慢。

当CPU管理任务切换时,会先把贮存器中的值全部写入内部存款和储蓄器,然后把运营另四个职分所急需的CPU寄放器的值从内部存款和储蓄器中读收取来,那样就造成了一遍切换。那写入内部存款和储蓄器和读取内存所必要的小运就一职分切换所须求的支付。寄存器写入内部存款和储蓄器的数据结构叫做“职务状态段”(task status segment)。

struct TSS32 { int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3; int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi; int es, cs, ss, ds, fs, gs; int ldtr, iomap;};

TSS32结构体中国共产党有29个int变量,合计104字节第一行保存的不是贮存器数据,而是与任务育设置 相关的别的数据。第二行是三12个人存放器。第二行是14位贮存器,可是大家依旧用三十10个人内部存储器空间存款和储蓄它。第4行也是与职分有关的别的设置。大家一时将ldtr设置为0,将iomap设置为0x伍仟0000。

要进行职分切换要用jmp指令。jmp指令分两种,第一种只改写EIP相当于所谓的near情势;第三种改写cs和eip,就是所谓的far形式。假使一条jmp指令的目的地址段不是可实行的代码,而是tss的话,cpu就不会施行平时的改写cs和eip,而是将那条指令精晓为天职切换。CPU中还会有一个TGL450寄放器,task register,它的效果是让CPU记住当前正值运营哪三个职务,咱们给T奇骏赋值的时候,必得把GDT编号乘以8。给TXC90赋值无法用MOV指令,有八个特意的吩咐:LTKuga。上面我们看一下tss结构体如何赋值:

task_b_esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024;tss_b.eip =  &task_b_main;tss_b.eflags = 0x00000202; /* IF = 1; */tss_b.eax = 0;tss_b.ecx = 0;tss_b.edx = 0;tss_b.ebx = 0;tss_b.esp = task_b_esp;tss_b.ebp = 0;tss_b.esi = 0;tss_b.edi = 0;tss_b.es = 1 * 8;tss_b.cs = 2 * 8;tss_b.ss = 1 * 8;tss_b.ds = 1 * 8;tss_b.fs = 1 * 8;tss_b.gs = 1 * 8;

大家先从后6个段贮存器赋值起首看,大家给cs赋值为GDT2号,别的是GDT1号,和bootpack.c使用了一致的地址段。然后是eip,大家把task_b_main的函数地址赋给它。然后是esp,也等于栈地址,大家新申请了64K内部存款和储蓄器空间,给taskB。假如和原本的主函数使用相同的栈那一个切换任务的时候一定会出难点。

咱俩先那样尝试多职分:在主函数停车计时器10秒超时的时候切换来职分b,然后在职责b的按期候5秒超时的时候切换回职责a。

void task_b_main{ struct FIFO32 fifo; struct TIMER *timer; int i, fifobuf[128]; fifo32_init(&fifo, 128, fifobuf); timer = timer_alloc(); timer_init(timer, &fifo, 1); timer_settime(timer, 500); for  { io_cli(); if (fifo32_status(&fifo) == 0) { io_sti(); io_hlt(); } else { i = fifo32_get(&fifo); io_sti(); if  { taskswitch3(); } } }}

已经达成了八个职分之间的跳转。接下来大家落到实处A,B多个职务每过0.02秒就转变三回。先安装四个电磁料理计时器time_ts变量,超时的时光为0.02秒,就算超时向队列中发送0x2。职责A尚可鼠标和键盘输入的,咱们很轻易确认职分A是或不是在运营,难点就出在职务B大家怎么样规定义务B也能健康运维吧?在职分B中设置多个计数器,每0.01秒在显示屏上写出计数器的数值就足以了。可是碰到二个标题,怎么样技巧让职务B知道sht_back,独有让职责B知道这些地方技巧在桌面上展现数字。大家应用栈来传递数据。首先要知道C语言的函数字传送递参数便是用栈,例如C语言的函数void setA;那些函数被调用后,函数会从esp+4的内部存款和储蓄器中抽取a那几个数值。大家这里就动用C语言的那特脾性。在跳到义务B的时候传递多少个参数,职务B的函数证明为 void task_b_main(struct SHEET *sht_back);那样运营任务B的时候能够一贯使用sht_back那个变量。大家先将任务B的esp减去8,然后把esp+4内存地址的值赋为sht_back,那样即可了,任务B函数在行使sht_back变量值的时候就是esp+4。

前段时间我们都是在职责中一直写切换职责的程序段,即使要实在实现多职分最棒是写一段程序调动职务之间的切换,并不是证任务协调切换。

struct TIMER *mt_timer;int mt_tr;void mt_init{ mt_timer = timer_alloc(); timer_settime(mt_timer, 2); mt_tr = 3 * 8; return;}void mt_taskswitch{ if (mt_tr == 3 * 8) { mt_tr = 4 * 8; } else { mt_tr = 3 * 8; } timer_settime(mt_timer, 2); farjmp; return; }

如上是完结职责切换的函数,这里安装了叁个0.02秒的反应计时器,然后在放大计时器中断里假如现身那当中断时调用mt_taskwitch这一个函数就能够了,三个任务的顺序中就无需和煦写切换职分的前后相继了。

本文由365bet亚洲版登录发布于计算机网络,转载请注明出处:三十天自制操作系统

您可能还会对下面的文章感兴趣: