iT邦幫忙

2025 iThome 鐵人賽

DAY 11
0
自我挑戰組

30 天 hypervisor 入門系列 第 11

Day 11 實作 I/O thread

  • 分享至 

  • xImage
  •  

I/O Thread

到目前為止,我們的 Guest 雖然能跑起來,但它沒有辦法真實地「感受到」外部事件。
沒有 IRQ、沒有鍵盤輸入,等於只是一個單純的 while(1) loop。
I/O thread 的目的:讓 Host 能在背景持續監聽外部事件(timer、鍵盤),並把這些事件透過 fd 或共享記憶體注入給 Guest。這是 Guest 能「和外界互動」的第一步。

昨天我完成了 I/O 模組的實作,讓 Host 可以定期送出 timer 中斷,也能把鍵盤事件注入給 Guest。但目前這些事件只能靠 vm-exit 被動處理,對 Guest 來說還不是真正的「中斷」。為了達到和硬體行為一致的效果,我需要額外建立一個獨立的 I/O thread,把所有事件集中監聽、轉換成 IRQ,並即時注入 Guest。

今天的任務,就是要在 Guest 端補齊這個缺口:建立 IDT、初始化 PIC,讓這些來自 I/O thread 的事件,能夠以「中斷」的形式被正確接收並交給 ISR。這樣 Hypervisor 的基礎互動路徑才算真正完成。

架構與流程

static void start_io_thread(struct vm_runtime *vm)
{
    if (vm->io_thread_running)
        return; // 確保只建立一次,避免重複啟動

    vm->io_thread_stop = 0;
    if (pthread_create(&vm->io_thread, NULL, io_thread_main, vm) != 0)
        die("pthread_create io_thread");

    vm->io_thread_running = 1; // 標記執行緒已經成功啟動
}

這個函式只負責一件事:啟動 I/O thread,而且只啟一次。旗標 io_thread_stop 必須在 pthread_create 之前清為 0,這樣新 thread 才能在正確狀態下進入主迴圈。

static void *io_thread_main(void *opaque)
{
    struct vm_runtime *vm = opaque;
    if (!vm)
        return NULL;

    while (!vm->io_thread_stop) {
        int ready = host_io_poll(&vm->host_io, 100); // 對接 epoll
        if (ready < 0) {
            if (errno == EINTR)
                continue;
            perror("host_io_poll");
            break;
        }
    }
    return NULL;
}

這個迴圈是 epoll 的唯一擁有者,所有註冊的事件(timerfd、eventfd、鍵盤輸入)都由這條 thread 處理。
由於僅有 I/O thread 處理外部事件,因此不必加鎖。
host_io_poll 內部呼叫 epoll_wait,timeout 設為 100ms。這個 timeout 有兩個目的:
讓關閉流程最久 100ms 就能生效,不需要另建喚醒機制。
保證執行緒即使沒有事件,也能週期性醒來檢查停止旗標。
如果 epoll_wait 被訊號打斷(errno = EINTR),則直接重試;其它錯誤則輸出訊息後跳出,避免卡住。


上一篇
Day 10 實作 Host I/O
系列文
30 天 hypervisor 入門11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言