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

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

三十天自制操作系统

延续多职务之旅。前一天落实了四个职务之间自动切换,先天上马写三个更通用的多职务切换程序。

第一定义存款和储蓄各类职分的数据结构。

struct TASK { int sel, flags; struct TSS32 tss;};

sel表现段先择器,也正是CS的值,flags用于标记该职分是或不是被应用。

再次创下造二个用于存款和储蓄操作系统中颇有职务的数据结构。

struct TASKCTL { int running; int now; struct TASK *tasks[MAX_TASKS]; struct TASK tasks0[MAX_TASKS];};

数据结构有了,然后开展操作,首先大家想创造二个职务,先要获得TASKCTL中的某一个task0。

struct TASK *task_alloc{ int i; struct TASK *task; for (i = 0; i < MAX_TASKS; i++) { if (taskctl->tasks0[i].flags == 0) { task = &taskctl->tasks0[i]; task->flags = 1; task->tss.eflags = 0x00000202; task->tss.eax = 0; task->tss.ecx = 0; task->tss.edx = 0; task->tss.ebx = 0; task->tss.ebp = 0; task->tss.esi = 0; task->tss.edi = 0; task->tss.es = 0; task->tss.ds = 0; task->tss.fs = 0; task->tss.gs = 0; task->tss.ldtr = 0; task->tss.iomap = 0x40000000; return task; } } return 0;}

在TASKCTL中搜索三个还未使用的task用于存款和储蓄,并对task结构举行初使化赋值,然后回到task的地点。

操作系统一先导运维的时候是单职分的,在开展到多职责管理在此之前,要先初使化TASKCTL数据结构,并为TASK数组申请内部存款和储蓄器空间,在多职责效率创立完成之后,还要把自身本人放入多职责管理的限制内。相当于说操作系统一运转,一开机时候,展现了桌面,第贰个任务正是它自身小编。

struct TASK *task_init(struct MEMMAN *memman){ int i; struct TASK *task; struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT; taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL)); for (i = 0; i < MAX_TASKS; i++) { taskctl->tasks0[i].flags = 0; taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8; set_segmdesc(gdt + TASK_GDT0 + i, 103,  &taskctl->tasks0[i].tss, AR_TSS32); } task = task_alloc(); task->flags = 2; taskctl->running = 1; taskctl->now = 0; taskctl->tasks[0] = task; load_tr(task->sel); task_timer = timer_alloc(); timer_settime(task_timer, 2); return task;}

率先定义多个TASKCTL类型的变量,并分配内存空间,然后用循环语句为那些变量赋初步值,flags全体赋为0,因为还未最早运用。然后为各样职责分配gdt序号。再申请三个task,把操作系统当前运作的任务放进去,并安装2ms的电火花计时器。

用task_alloc函数获得task变量之后,再调用task_run函数运转。

void task_run(struct TASK *task){ task->flags = 2; taskctl->tasks[taskctl->running] = task; taskctl->running++; return;}

在init_task函数中曾经安装了2ms的电磁照应计时器,机械漏刻超时的时候,会调用task_switch函数

void task_switch{ timer_settime(task_timer, 2); if (taskctl->running >= 2) { taskctl->now++; if (taskctl->now == taskctl->running) { taskctl->now = 0; } farjmp(0, taskctl->tasks[taskctl->now]->sel); } return;}

先安装2ms停车计时器,然后判定义务数,使命数借使独有七个就无须切换了。要是多于1个,那么切换成下三个职分。要是已然是终极一个职务,那么就运营第三个职责,重新循环叁遍。改动之后的多任务程序看上去就相当多了,不管如何职务,只要alloc三个,放进run里面,操作系统会自动且平均分配2ms的小时运作。平均分配时间也可能有欠缺,假设三个任务创立之后都并未有使用,那么也分配2ms的话就太浪费cpu的图谋工夫了,大家就贯彻让职分休眠的编写制定。

void task_sleep(struct TASK *task){ int i; char ts = 0; if (task->flags == 2) { /* 如果指定任务处于唤醒状态 */ if (task == taskctl->tasks[taskctl->now]) { ts = 1; /* 让自己休眠的话,稍后需要进行任务切换 */ } /* 寻找task所在的位置 */ for (i = 0; i < taskctl->running; i++) { if (taskctl->tasks[i] == task) {/* 在这里 */ break; } } taskctl->running--; if (i < taskctl->now) { taskctl->now--; /* 需要移动成员,要相应地处理 */ } /* 移动成员 */ for (; i < taskctl->running; i++) { taskctl->tasks[i] = taskctl->tasks[i + 1]; } task->flags = 1; /* 不工作的状态 */ if  { /* 任务切换 */ if (taskctl->now >= taskctl->running) { /* 如果now的值出现异常,则进行修正 */ taskctl->now = 0; } farjmp(0, taskctl->tasks[taskctl->now]->sel); } } return;}

第一判别准务休眠的职责是还是不是近日正值周转的天职。然后寻觅就要休眠的职务所处于TASKCTL变量中的地方,然后将以此地点覆盖,如若决断是正在运作的天职立即切换职务。将下来的难题是收纳鼠标、键盘可能其余中断后,怎么着唤醒体眠的职分。

老是中断发生后都会往音讯队列中发送数据,假使唤醒某三个职责也理应从队列出手。更动队列的数据结构,扩大存款和储蓄TASK指针的字段。

struct FIFO32 { int *buf; int p, q, size, free, flags; struct TASK *task;};

下一场在脚刹踏板管理程序往消息队列写入数据的时候将职分唤醒,大家修改一下入队函数。

int fifo32_put(struct FIFO32 *fifo, int data){ if (fifo->free == 0) { fifo->flags |= FLAGS_OVERRUN; return -1; } fifo->buf[fifo->p] = data; fifo->p++; if (fifo->p == fifo->size) { fifo->p = 0; } fifo->free--; if (fifo->task != 0) { if (fifo->task->flags != 2) { task_run(fifo->task); } } return 0;}

追加了return 0以前的5行,正是说中断管理程序往队列中写入音讯的时候,决断当前队列所表示的任务是或不是处在活动状态,假设休眠的话那就提醒。

接下去大家别的更创立3个职分,各种职责都展现一下窗口,在窗口中只做一件业务,那正是不停得计数并把计数结果展现到窗口上。

要落到实处也相比较简单,先创制3个TASK类型的指针,再调用task_alloc函数分配职务存款和储蓄空间。创设SHEET指针,再调用sheet_alloc函数分配存款和储蓄空间。再调用task_run函数运维。

自己在看源代码时候看见3个窗口职分的输入地址都以task_b_main函数,蓦然有一个问号,入口地址都以同样的的,那么这么些函数中定义的变量和音讯队列会不会搅乱。前前后后看了好三次,task_b[i]->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024 - 8;那句程序为各类任务申请了分化的栈空间。程序入口函数中定义的int i; int fifobuf[128],固然是在入口函数中央政府机关接定义,不过C语言分配内部存款和储蓄器空间的时候是把栈中的内部存款和储蓄器空间拿过来使用。所以就算的职责入口函数是一律的,程序的进口也在内部存款和储蓄器中的同一职责,但是每一个职分所使用的多寡都以区别样的。通过近半个钟头的考虑,笔者觉着对C语言的内部存款和储蓄器分配办公室法有了越来越深远的打听。

笔者们现在为各样职务平均分配了2ms的周转时刻,然而倘使要把操作系统做得更加好,料定要分出任务的高低,也正是要设置每种职分的先行级。大家得以安装13个品级,分配运转的小运从0.01秒~0.1秒。在TASK结构体中增添int priority字段,用于表示优先级。我们把职责a设置成10,约等于说任务a运维的光阴有0.1秒,可是由于a不运维的时候会自动休眠,所以也不会潜移默化其余职分的运维。

行使为任务分配计时器的时刻情势是最简便易行的法子。要是任务A是最注重的,只是给A设置高级中学一年级点的优先级,那么其余职责照旧会运作。有的时候候我们会遇见一种状态,希望假使职务A供给周转,那么在职分A运营完从前任何职务都不可能运转。

咱俩如若给职务分3个阶段,分别是level0~2。在那之中level0优先级最高,假诺level0里的任务须要周转,那么,level1和2都不能够运作。

以前大家管理多职分的数据结构有2层,首先是意味着具体任务的TASK结构,然后是把TASK结构统一管理的TASKCTL结构。未来大家在那三头以前扩展TASKLEVEL结构,用于表示职责的等级关系。

struct TASK { int sel, flags; int level, priority; struct TSS32 tss;};

level变量表示义务所处的品级。

struct TASKLEVEL { int running; /* 正在运行的任务数量 */ int now; /* 这个变量表示正在运行的是哪个任务 */ struct TASK *tasks[MAX_TASKS_LV];};struct TASKCTL { int now_lv; /* 现在活动中的LEVEL */ char lv_change; /* 在下次任务切换时是否需要改变LEVEL */ struct TASKLEVEL level[MAX_TASKLEVELS]; struct TASK tasks0[MAX_TASKS];};

现行反革命TASKCTL不再直接是管制职务,而是管理TASKLEVEL,再由TASKLEVEL管理各类职务。书中拍卖那有的代码不是很复杂,小编也就不贴出来了。首要注意的地方是task_switch函数里假使TASKCTL中lv_change字段为1将在重复查看LEVEL是或不是有新的更尖端的层系任务急需实行。

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

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