(7)從1開始寫乙個作業系統

2021-09-27 08:18:27 字數 4010 閱讀 2829

時間片輪轉排程是一種最古老,最簡單,最公平且使用最廣的演算法。每個任務被分配乙個時間段,稱作它的時間片,即該任務允許執行的時間。如果在時間片結束時程序還在執行,則cpu將被剝奪並分配給另乙個任務。如果任務在時間片結束前阻塞或結束,則cpu當即進行切換。排程程式所要做的就是維護一張任務先後執行的列表,當任務用完它的時間片後,它被插入到列表的前邊,後面的任務順序移動到佇列的末尾。

當任務5的時間片用完時,中斷中進行任務排程,開始遍歷任務就緒表,假設上面任務都是就緒狀態,並且任務2,4,5的優先順序相同,由於4的任務比較靠後說明任務4更久沒有被執行,所以此時切換到任務4。將任務4放入已執行列表前面。

如果下次時間片用完的時候再切換就會切換到任務2。如果任務4由於掛起釋放cpu也會優先切換到任務2。

我們在中斷中需要對就緒的任務進行判斷,遍歷就緒任務找到:任務優先順序最高,並且不在已執行列表中的或者在已執行列表中較靠後的任務。

這裡有乙個需要注意的地方就是有時候可能會由於某些情況導致無效的任務切換,也就是當前執行的任務的時間片沒有到,也沒有更高優先順序的任務就緒導致的任務排程,這個時候需要增加當前執行的任務的時間片是否用完的邏輯判斷,如果時間片還有則只查詢優先順序比當前任務高的任務。

首先在任務控制塊中新增時間片設定和剩餘時間片記錄變數。

typedef struct os_tcb ;
然後我們修改任務建立函式,要求使用者設定任務的時間片。

if ( time_quanta == 0 )

os_tcb[taskid].ostcbtimequanta = os_default_time_quanta;

else

os_tcb[taskid].ostcbtimequanta = time_quanta;

在設定任務為就緒態的時候需要檢查時間片剩餘是否為0,如果為0則重新計時。並把當前執行的任務新增到已執行任務佇列的頭部。

任務切換部分**

//切換任務棧

for (; ios_tcb[highest_prio_id].ostcbprio) }}

}os_task_running_id = highest_prio_id;

//把當前任務插入已執行任務佇列中

os_task_run[0] = os_task_running_id;}}

if (os_tcb[os_task_running_id].ostcbtimequantactr == 0)//給當前執行的時間片賦值

os_tcb[os_task_running_id].ostcbtimequantactr = os_tcb[os_task_running_id].ostcbtimequanta;

os_tcb[os_task_running_id].ostcbstatus = os_stat_running;

sp = os_tcb[os_task_running_id].ostcbstkptr;

現在我們需要完成最重要的部分,在中斷中判斷任務時間片,並且需要切換任務時,在中斷中切換任務。

我們需要把任務切換中的邏輯在中斷中在實現一次,並且判斷時間片是否為0,如果為0則進行任務切換的邏輯,如果不為0僅僅是時間片自減操作。

首先我們來看一下中斷函式。

void timer0_int (void) interrupt timer0_vector }}

}os_task_running_id = highest_prio_id;

//把當前任務插入已執行任務佇列中

task_sequence = os_task_run[0];}}

if (os_tcb[os_task_running_id].ostcbtimequantactr == 0) //給當前執行的時間片賦值

os_tcb[os_task_running_id].ostcbtimequantactr = os_tcb[os_task_running_id].ostcbtimequanta;

os_tcb[os_task_running_id].ostcbstatus = os_stat_running;

sp = os_tcb[os_task_running_id].ostcbstkptr;

}else

}

我們來看一下中斷函式的彙編。

; function timer0_int (begin)

0000 c0e0              push    acc

0002 c0f0              push    b

0004 c083              push    dph

0006 c082              push    dpl

0008 c0d0              push    psw

000a 75d000            mov     psw,#00h

000d c000              push    ar0

000f c004              push    ar4

0011 c005              push    ar5

0013 c006              push    ar6

0015 c007              push    ar7

; source line # 40

我們看到在中斷函式開始的時候只是把acc,b,dph,dpl,psw,r0,r4,r5,r6,r7入棧了,如果我們沒有在中斷中切換任務是沒有關係的,因為在中斷退出的時候還會出棧,但是一旦我們要在中斷中切換任務,任務的棧就會切換,而且還會涉及到在中斷外切換任務os_task_sw(),在中斷外切換任務時可是將所有暫存器都進行了入棧,這樣就會導致中斷與非中斷時的入棧出棧暫存器對不上,會發生非常不好的事情。所以我們需要讓中斷也將全部暫存器入棧。我們需要做的事情只有乙個,就是在中斷函式開頭處呼叫組合語言進行一次暫存器的使用,keil就會將所有的暫存器在函式進入時入棧。

新增

#pragma asm

mov ar1,ar1

#pragma endasm

彙編結果如下:

; void timer0_int (void) interrupt timer0_vector } 

執行的時候差不多每隔3s會出現一次,這裡有個思考,為什麼**中寫的delay1s,執行時3s乙個週期呢?

執行結果如下,時間並不是非常準確地3s,因為delay函式本身不準確導致的:

[2019-09-09 00:33:45.496]# recv ascii>

stc15f2k60s2 rt-os test prgramme!

[2019-09-09 00:33:45.713]# recv ascii>

[2019-09-09 00:33:45.823]# recv ascii>

[2019-09-09 00:33:48.148]# recv ascii>

[2019-09-09 00:33:48.588]# recv ascii>

[2019-09-09 00:33:48.920]# recv ascii>

[2019-09-09 00:33:50.912]# recv ascii>

[2019-09-09 00:33:51.352]# recv ascii>

[2019-09-09 00:33:51.682]# recv ascii>

[2019-09-09 00:33:54.447]# recv ascii>

[2019-09-09 00:33:54.557]# recv ascii>

[2019-09-09 00:33:54.997]# recv ascii>

(8)從1開始寫乙個作業系統

搶占式核心 即當任務正在執行,有乙個更高優先順序的任務出現時,如果當前核心允許搶占,則可以將當前任務掛起,執行優先順序更高的任務。在我們上一章的基礎上我們已經做了這個工作。說白了就是在任務建立的時候進行了任務排程,已保證更高優先順序的任務能夠被及時執行。還有就是在更高優先順序從非就緒態到就緒態的時候...

寫乙個國產的作業系統?

如果我要寫乙個國產的作業系統,以下幾點也許可以考慮一下 中文程式設計。我們能不能做乙個用中文 寫成的作業系統呢?是的,中文 不僅僅要能顯示中文,處理中文,還要求作業系統的源 也是盡可能的用中文來寫。為了做成這件事,看來下面的事情是逃不掉的 寫乙個支援中文的編譯器 彙編,高階語言 乙個支援中文的控制台...

從零實現乙個作業系統 day7

我的部落格startcraft 因為在核心中,大部分的c標準庫函式無法使用,字串操作的函式又比較常用,所有自己實現一些 ifndef include string h define include string h include types.h void memcpy uint8 t dest,c...