# Real-time operating system, RTOS初探
## 定義
即時作業系統(Real-time operating system,RTOS),是指作業系統要在一個固定時間內,做出正確反應,以及對時序及穩定度的要求十分嚴格,它會按照排序執行、管理系統資源,並為開發應用程式提供一致的基礎。
即時作業系統相較一般的作業系統,最大的特色就在於「即時性」,也就是說,如有一個 process 需執行,即時作業系統會在最短時間內執行該 process ,不會有較長的延遲。這種特性保證了各個 process 的即時執行。通常都具備有最基礎的 kernel,以及外加上去的模組,像是檔案系統、網路協定堆疊和應用、裝置驅動程式……等模組。RTOS 的核心通常包括,排程器、物件、服務程式。
衡量一個即時作業系統堅固性的重要指標,是他從接收一個 process,到完成該 process 所需的時間,其時間的變化稱為 jitter。硬即時作業系統比軟即時作業系統有更少的 jitter。設計即時作業系統的首要標的不是高的 throughput,而是保證 process 在特定時間內完成。
即時作業系統可分類為「軟式(Soft)」與「硬式(Hard)」。硬即時作業系統,是指系統從命令起始到執行動作之間的中斷延遲回應特性。一般像是 Win CE 這種的軟即時作業系統,其反應時間約為 1~2ms,要達到硬即時性能的要求,其反應時間必須要在 150μs 以內;軟即時系統通常指超過期限後,系統的公用程式可容忍某段誤差時間。舉例來說,當行動電話來電時,則必須在按下按鈕時即建立連結。然而,此限制時間並非絕對,亦可有些許的延遲。
硬即時作業系統必須使 process 在確定的時間內完成,而軟即時作業系統能讓絕大多數 process 在確定時間內完成。
(參考資料: [連結](https://sls.weco.net/node/21340) )
## 硬即時和軟即時的比較
| | 硬性即時作業系統<br>(Hard Real-Time System) | 軟性即時系統<br>(Soft Real-Time System) |
|-|-|-|
| 簡介 | 也可稱為安全臨界系統,有最迫切的需求,<br>必須在特定期限之前回應事件,保證在它們<br>的期限內完成臨界即時任務。 | 跟硬性即時系統比較起來,限制的範圍比<br>較少,簡單提供一件臨界的即時系統,將<br>在其它的任務上接受優先權並保有優先權<br>直到它完成。|
| 應用 | 通常指不能有任何差錯的工作,一般而言,<br>與安全相關的系統均屬於硬即時系統。<br><br>例如:軍事系統、核能安控、車用電子煞車<br>系統…等。 |比較容許差錯的工作,即時工作的執行擁<br>有最高的優先權即可,直到執行完畢為止<br><br>例如:多媒體播放器…等。 |
| 延遲 | 所有工作都不能夠延遲 | 允許少量的工作延遲,若沒有在回應時間<br>內完成,只是造成系統的效能變差,不會<br>影響系統的執行 |
| 要求 | 非常嚴苛 | 比較寬鬆 |
(參考資料: [連結](https://sls.weco.net/node/21340))
## 使用軟體方法設定執行緒優先順序層級是否可以逼近RTOS?(效果不顯著)
windows系統中,所以程式都會依其優先序搶奪CPU資源,若能將重要程式執行優先序提升為最高,是否可以讓其執行順序永遠優先於其他程式?
以下程式碼使用c++搭配win 32 API,嘗試將"javaw.exe"執行優先順序調整為最高。執行後發現雖然讓程序優先度被提升為最高,但優先執行的效果並不顯著。
```c++=
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <tchar.h>
using namespace std;
BOOL SetPriority();
BOOL SetPriority()
{
HANDLE hsnapprocess;
HANDLE hprocess;
PROCESSENTRY32 entry32;
DWORD Size;
// 1. 取得系統 process 之 snapshot
hsnapprocess = CreateToolhelp32Snapshot(
TH32CS_SNAPPROCESS, // flag
0); // th32ProcessID
if(hsnapprocess==INVALID_HANDLE_VALUE){
printf("CreateToolhelp32Snapshot fail: %d\n",GetLastError());
return FALSE;
}
// 2. 設定 struct 大小
entry32.dwSize = sizeof(PROCESSENTRY32);
// 3. 確認正確取得第一個 process
if(!Process32First(hsnapprocess, &entry32)){
printf("Process32First fail.\n");
CloseHandle(hsnapprocess);
return FALSE;
}
// 4. 顯示 process 相關訊息
int i = 0;
do{
/* list all process
printf("\n\n(%d)===============================\n", ++i);
printf("Name :%s\n", entry32.szExeFile);
printf("PID :%08x\n", entry32.th32ProcessID);
printf("parent ID:%08x\n", entry32.th32ParentProcessID);
printf("thread cnt:%u\n", entry32.cntThreads);
printf("base pri:%ld\n", entry32.pcPriClassBase);
printf("$$$:%s\n", entry32.szExeFile);
*/
if(strcmp (entry32.szExeFile, "javaw.exe") ==0){
printf("javaw.exe is found, do set priority...\n");
printf("Name :%s\n", entry32.szExeFile);
printf("PID :%08x\n", entry32.th32ProcessID);
printf("parent ID:%08x\n", entry32.th32ParentProcessID);
printf("thread cnt:%u\n", entry32.cntThreads);
printf("base pri:%ld\n", entry32.pcPriClassBase);
DWORD dwPriClass = GetPriorityClass(GetCurrentProcess());
_tprintf(TEXT("Current priority is 0x%x\n"), dwPriClass);
if(!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)){
DWORD dwError = GetLastError();
printf("set priority error: %s", dwError);
}else{
printf("set priority success!\n");
}
Sleep(1000);
}
}while(Process32Next(hsnapprocess, &entry32));
return TRUE;
}
// ==================================
int main(){
SetPriority();
printf("-------------\n");
SetPriority();
return 0;
}
```
參考資料:
* [windows應用程式開發](https://docs.microsoft.com/zh-tw/windows/win32/procthread/scheduling-priorities)
* [win32 API](https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setpriorityclass)
## RTOS的運作原理
RTOS其實是一款為**有效管理中央處理器(CPU)時間所設計的軟體**,多任務運行的實現實際上是靠CPU在許多任務之間轉換、調度。
為了降低複雜度,通常會採用 threads 導向的設計,把一個專案切分成比較易於管理的小塊(也就是 threads),而後每一個 thread 負責該應用程式的一部分。這樣的系統有助於識別 threads 之間的重要順序。也就是說,某些 threads 具有即時性的需求,必須盡量快速並且正確地回應它們。如果你的系統採用了專業的 RTOS,一定會有劃分 threads 優先權 (prioritization) 的設計。除了優先權之外,也會提供一套乾淨而且被仔細測試過的 API,有助於簡化 threads 之間的通訊。
* ### 核心
RTOS 的核心被稱為 kernel,並提供有一個可以透過 kernel 去創建 threads 的 API。一個 thread 就像是一個擁有自己的堆疊、並帶有 Thread 控制區塊(TCB – Thread Control Block)的函式。除了 thread 本身私有的堆疊之外,每個 TCB 也保有一部分該 thread 的狀態訊息。
kernel 還包含有一個 scheuler,scheuler 會按照一套排程機制來執行 threads。各種 scheulers 之間主要的差異,就是如何分配執行他們所管理之各種 threads 的時間。基於優先權的 preemptive scheuler 是嵌入式 RTOS 之間最流行和普遍的 threads 調度演算法。通常情況下,相同優先權的 threads 會以 round-robin 循環的方式加以執行。
多數內核還會利用系統時脈 (system tick) 中斷,其典型的頻率為 10ms。如果在 RTOS 中缺乏系統時鐘,仍然能夠有某種基本形式的調度,但時間相關的服務則否。這種與時間有關的服務內容包括:軟體定時器、thread 睡眠 API 呼叫、thread 時間片段、以及逾時的 API 呼叫。
RTOS的內核提供了一個抽象層,它向應用軟件隱藏了應用軟件將在其上運行的處理器(或一組處理器)的硬件細節。在此過程中,它為應用軟件提供了五種主要類別的基本服務:

內核服務最基本的類別是任務管理。這組服務允許應用程序軟件開發人員將他們的軟件設計為多個獨立的軟件“塊”——每個塊處理一個不同的主題、一個不同的目標,也許還有它自己的實時截止日期。每個單獨的軟件塊稱為一個_[任務](http://en.wikipedia.org/wiki/Task_(computers))_。此類別中的服務包括啟動任務並為其分配優先級的能力。此類別中的主要 RTOS 服務是嵌入式系統運行時的任務調度。任務調度器控制應用軟件任務的執行,並且可以使它們以非常及時和響應的方式運行。
第二類內核服務是任務間通信和同步。這些服務使任務可以將信息從一個傳遞到另一個,而不會有信息被損壞的危險。它們還使任務的協調成為可能,以便它們可以有效地相互合作。如果沒有這些 RTOS 服務的幫助,任務可能會很好地傳達損壞的信息或以其他方式相互干擾。由於很多嵌入式系統都有嚴格的時序要求,因此大多數 RTOS 內核還提供了一些基本的定時器服務,例如任務延遲和超時。
除了內核服務之外,許多 RTOS 還為高級服務提供了許多可選的附加操作系統組件,例如文件系統組織、網絡通信、網絡管理、數據庫管理和用戶界面圖形。儘管其中許多附加組件比 RTOS 內核大得多且複雜得多,但它們依賴於 RTOS 內核的存在並利用其基本服務。為了將內存消耗降至最低,這些附加組件中的每一個僅在需要其服務時才包含在嵌入式系統中。
* ### 任務調度
大多數 RTOS 使用稱為「基於優先級的搶占式調度的方案來進行任務調度」。必須為軟件應用程序中的每個任務分配一個優先級,更高的優先級值表示需要更快的響應。_任務調度的搶先_ 性質使得非常快速的響應成為可能。_搶先_ 意味著如果調度程序確定另一個任務需要立即運行,則允許調度程序在其執行的任何時間點停止任何任務。管理基於優先級的搶占式調度的基本規則是,在每個時刻,“準備好運行的最高優先級任務將是必須運行的任務。” 換句話說,如果低優先級任務和高優先級任務都準備好運行,調度程序將允許高優先級任務先運行。低優先級任務只有在高優先級任務完成當前工作後才能運行。
如果一個低優先級的任務已經開始運行,然後一個高優先級的任務準備好了怎麼辦?這可能是由於外部世界觸發(例如開關閉合)而發生的。基於優先級的搶占式調度器的行為如下:它將允許低優先級任務完成它正在執行的當前彙編語言指令。(但它不允許它完成一整行高級語言代碼;也不允許它繼續運行直到下一個時鐘滴答。)然後它將立即停止低優先級任務的執行,並且允許更高優先級的任務運行。在高優先級任務完成當前工作後,將允許低優先級任務繼續運行。

當然,當更高優先級的任務正在運行時,甚至更高優先級的任務可能已經就緒。在這種情況下,正在運行的任務將被搶占(暫時停止)以允許更高優先級的任務運行。當該任務完成其當前工作時,將允許被搶占的任務繼續。因此在這種情況下,兩個較高優先級的任務都會在允許低優先級的任務繼續運行之前完成它們的工作。這種情況可能被稱為「嵌套搶占」。
基於優先級的搶占式調度器每次收到外部世界觸發(如開關閉合)或軟件觸發(如消息到達)的警報時,必須經過以下 5 個步驟:
- 確定當前運行的任務是否應該繼續運行。如果不…
- 確定接下來應該運行哪個任務。
- 保存已停止任務的環境(以便稍後繼續)。
- 設置接下來要運行的任務的運行環境。
- 允許此任務運行。
這 5 個步驟合起來稱為「任務切換」。
* ### 什麼RTOS最適合 ?
市場上的RTOS非常多,依不同使用情境各有適合,其授權亦有商業、免費及開源多種選擇。在此列出幾項介紹:
* **FreeRTOS:**
- 依EETimes從2011年起的「嵌入式系統市場OS/RTOS」使用調查,FreeRTOS使用者始終名列前芧,使用者眾多的優勢在於可以確保系統的穩定性,且在開發遭遇困難時較易找到資料或供發問的社群。
- FreeRTOS內核僅有3個.c檔案,易於理解學習,同時它雖然是一套開源的免費軟體,但其[官網]([https://](https://www.freertos.org/Documentation/RTOS_book.html))文檔齊全。
- 附圖為2017RTOS使用率排行(EETimes)

* **QNX:**
- QNX是黑莓公司(BlackBerry)開發的一套商業RTOS,它也是首批在商業上取得成功的微內核操作系統(microkernel operating systems)之一。其原生API為POSIX及JAVA。
- QNX是一個微核心即時作業系統,其核心僅提供4種服務:進程調度、進程間通信、底層網路通信和中斷處理,其進程在獨立的地址空間運行。所有其它OS服務,都實現為協作的使用者進程,因此QNX核心非常小巧(QNX4.x大約為12Kb)而且運行速度極快。
-
* **RTX/RTX64:**
- 可將 Microsoft Windows 從通用型作業系統 (GPOS) 轉變為即時作業系統 (RTOS)。
- 單一整合開發環境,使用Visual Studio和所有Windows等較為習慣的工具進行開發。
- 有[台灣代理](https://www.intervalzero.com/tw/)。
* **uCOS家族(I/II/III):**
- 具有高的可移植性及擴展性。
- 高效能且穩定。
*
參考資料:
[iT邦幫忙](https://ithelp.ithome.com.tw/articles/10204700)
[EETimes](https://www.eetimes.com/intro-to-real-time-operating-systems/)
## RTX/RTX64 example

### WindowsRTX64UsingSTL
* Sharing data between a real-time process and a Windows process.
* Using IPC methods to send signals between processes.
* Using C++ STL classes.
### RtkIPC
* Windows kernel driver can access RTX shared memory and IPC mechanisms.
* Windows sees the kernel driver as a normal driver.
## 補充: Windows IOT Real-time程序
Windows 10軟體即時是[具有 Windows 10 IoT 企業版 21H2 版](https://docs.microsoft.com/zh-TW/windows/iot/product-family/what%27s-new-in-windows-10-iot-enterprise-21h2)的新功能,可讓裝置製作者在其裝置上引進軟即時功能。
此即時行為是透過 4 個主要設定引進:
1. **CPU 隔離**:從隔離的 CPU 移轉系統層級的干擾,減少使用者即時應用程式的潛在抖動
2. **隔離 CPU 上的自訂 ISR/DPC 釘選**:所有硬體中斷都會路由傳送至系統和非即時核心,但藉由撰寫自訂 ISR/DPC 驅動程式,您可以將裝置特定的中斷路由傳送至即時核心。
3. **Mutex 的優先順序繼承**:此設定可確保執行最高優先順序的執行緒,即使在複雜的多執行緒案例中也一定。
4. **最多 16 個 RT 執行緒優先順序層級**:這可讓程式設計人員在即時工作之間分割資源,以確保先執行最重要的資源。
(參考資料: [連結](https://docs.microsoft.com/zh-tw/windows/iot/iot-enterprise/soft-real-time/soft-real-time))