# 2025q1 Homework3 (kxo) contributed by <`leowu0411`> {%hackmd NrmQUGbRQWemgwPfhzXj6g %} ## 畫面呈現 ### 移動至使用者層級 (初步改動) > commit : [f14c99d](https://github.com/leowu0411/kxo/commit/f14c99d9ec887cd97a424e54b5c895ca82f99348) 在原先的程式碼中,棋盤於核心模式繪製完畢後方傳送至使用者層級,通訊成本較高,故在最初的版本中改動為,傳送原始資料 `table` 而非繪製完畢的版本 `draw_buffer` ```diff - unsigned int len = kfifo_in(&rx_fifo, draw_buffer, sizeof(draw_buffer)); + unsigned int len = kfifo_in(&rx_fifo, table, sizeof(table)); ``` #### 傳輸大小 `draw_buffer` 除了棋盤本身的資料,需額外儲存空白以及 ' | ' 字元,故需要自核心模式傳送大小為 (以棋盤大小 4 * 4 舉例) 64 byte 的資料。 ```c #define DRAWBUFFER_SIZE \ ((BOARD_SIZE * (BOARD_SIZE + 1) << 1) + (BOARD_SIZE * BOARD_SIZE) + \ ((BOARD_SIZE << 1) + 1) + 1) ``` 而反觀傳送 `table` 只需 `BOARD_SIZE * BOARD_SIZE` byte,亦即 16 byte。 :::danger 提供數學分析 ::: #### 邏輯改動 將原先繪製棋盤之函式 `draw_board()` 移至 `xo-user.c`,並在此用者拿到自核心模式傳來之 `table` 時,呼叫該函式完成棋盤繪製。 ```diff -read(device_fd, display_buf, DRAWBUFFER_SIZE); +read(device_fd, table, N_GRIDS); +draw_board(table, display_buf); ``` kernel 端則將原先繪製之邏輯去除: ```diff -mutex_lock(&producer_lock); -draw_board(table); -mutex_unlock(&producer_lock); ``` 但須注意的是原先的加之於函式 `produce_board()` 之互斥鎖需替換為 `producer_lock`,這是因為在改動後,`ai_XX_work_func()` 會與 `produce_board()` 存取同一資源 `table`,因此應統一使用 `producer_lock` 來保護所有對 `table` 的存取,確保在並發操作情境下操作正確。 ```diff -mutex_lock(&consumer_lock); +mutex_lock(&producer_lock); produce_board(); -mutex_unlock(&consumer_lock); +mutex_unlock(&producer_lock); ``` 原先的版本中: * producer_lock : 確保 `ai_XX_work_func()` 與 `draw_board()` 對共享資源 `table` 的正確同步 * consumer_lock : 確保 `kfifio` 在多個函式 `produce_board()` 並發操作下能夠正確同步 :::info 疑惑: 假設系統正在執行 `drawboard_work_func()`,並在其中呼叫 `produce_board()`,此時已持有某把互斥鎖用以保護共享資源。 此時,計時器(timer)剛好觸發,進而進入 softirq context,並在該 context 中檢查發現勝負已分(`win != ' '`),因此試圖執行某些需要相同互斥鎖保護的操作。 根據 Linux 核心設計: * Softirq 不允許睡眠(不可阻塞), * 但若此時互斥鎖已被 `drawboard_work_func()` 持有,理論上需等待釋放, * 然而 softirq context 又無法睡眠等鎖,否則將造成系統不穩甚至 hang。 (可以排除 `ai_XX_work_func()` 與 `softirq` 之間衝突的狀況,因條件 `win != ' '` 與 `ai_XX_work_func()` 不可能同時發生) 那麼此時是否會: * 放棄這次鎖的取得? * 延遲處理直到稍後 retry? * 犧牲已經拿到該互斥鎖的 context 優先服務此 softirq ? * 或者需要避免讓 softirq 使用會 sleep 的鎖? ::: ### 將傳送資料傳換為棋步 `move` 而非當前棋盤狀態 `table` > commit : [e50e724](https://github.com/leowu0411/kxo/commit/e50e724928a31ac39cdbce8dada40b4e6a229da4) #### 利用閒置位元儲存資料 > commit : [b9286a0](https://github.com/leowu0411/kxo/commit/b9286a001a4c34b3aff6a7e5ac1e35497adeeba7) ### 輸出棋步紀錄以及各局贏家 > commit : [b74af57](https://github.com/leowu0411/kxo/commit/b74af57a55fde04049aee8b6e02c2879de7a741f) ### 避免每次重跑皆須重新載入模組 > commit : [652aadb](https://github.com/leowu0411/kxo/commit/652aadbe5d96319faec12e9475ebe7ee7eb982f0)