我是否對核心模組的共享記憶體做出了無效的假設?
我編寫了一個“設備驅動程序”(請參閱此處的原始碼:https ://bitbucket.org/wothke/websid/src/master/raspi/websid_module/ ),大部分時間執行良好(請參閱https://www .youtube.com/watch?v=bE6nSTT_038)但它似乎仍然有可能偶爾隨機崩潰設備。
“設備驅動程序”啟動一個 kthread,該執行緒執行一個簡單但時間關鍵的播放循環,其中它通過多個 GPIO 引腳控制一些連接的音頻晶片。這個 kthread 在一個“隔離的”CPU 核心上執行(使用 kthread_bind),這應該在很大程度上免除正常核心使用(請參閱下面的核心配置的詳細資訊)。kthread 通過 sched_set_fifo 獲得高優先級。kthread 不進行子常式呼叫,也不需要核心中先前未分配的任何記憶體。(該執行緒還使用 get_cpu、local_irq_save 和 local_bh_disable 臨時禁用任何可能干擾其計時的東西。但是,這些似乎不是零星崩潰的根本原因,因為即使不使用該禁用也可能重現崩潰。)
我已經編譯了一個正常的“Raspberry OS”“桌面”核心,但我專門啟動了 NO_HZ_FULL(即“完整動態系統(無滴答聲)”)。此外,我還專門通過 cmdline.txt 隔離核心#3:isolcpus=3 rcu_nocbs=3 rcu_nocb_poll=3 nohz_full=3 (這似乎使大多數 IRQ 遠離 cpu 核心#3 - 正如預期的那樣,所以我上面的 kthread 應該很漂亮獨自在那個核心#3)
可疑的可能是“共享核心記憶體”緩衝區,用於上述“回放”kthread 和位於“使用者空間”中的數據的生產者之間的所有通信。我已經採取了我能想到的所有預防措施來避免潛在的競爭條件,但可能存在某種 CPU 記憶體效應,或者我忽略了其他東西。“共享緩衝區”包含 4 個頁面對齊區域,這些區域已設置/以應確保安全通信/同步的方式使用。
- 第一頁僅包含一個 32 位標誌,作為 u32 或 uint32_t 訪問(這應該是自然的 atomar)。kthread 僅在此標誌為 0 時更新此標誌,並且僅將其設置為非 0。使用者態程式碼僅將此標誌重置為 0,並且僅當它具有一些非 0 值時 - 從而確認它收到了 kthread 設置的非 0 值。
- 第 2 頁包含類似 1) 的標誌,但方向相反,即這裡的 kthread 將從“userland”接收非 0 的內容。
- 然後,第 3(+following)頁包含用於簡單雙緩衝方案的第一個緩衝區。該緩衝區由“使用者空間”生產者專門寫入,並由 kthread 專門讀取。通過 2 個標誌實現的“ping/pong”協議旨在確保緩衝區*從不”同時使用:kthread 通過發出可以填充其中一個緩衝區的信號來啟動一個序列,然後“使用者空間”在之後返回信號它已完成填充相應的緩衝區,即 kthead 僅在看到來自生產者的信號後才開始從緩衝區讀取,現在可以安全地這樣做(在“使用者空間”生產者給出它使用的信號之前 msync(start_page, len, MS_INVALIDATE) 來報告它更新了共享記憶體區域的哪些部分。)。
- 然後第n(+以下)頁包含第二個緩衝區(3中所說的所有內容也適用於此處)
但即使上面出現問題,也可能會阻塞 kthread 或相應的使用者態程序。但我不明白為什麼這會導致整個系統崩潰。
對我來說最合理的解釋是“共享緩衝區”是否被隨機重定位(從而導致隨機記憶體損壞),但我認為這不應該發生在通過以下方式分配的緩衝區上:
_raw_buffer = kmalloc(AREA_SIZE + 2*PAGE_SIZE, GFP_KERNEL & ~__GFP_RECLAIM & ~__GFP_MOVABLE);
或者,如果有一些核心函式專門進入一些阻塞等待來自核心 #3 的某些東西(這可能不會發生,因為我的 kthread 餓死了那個 CPU 上的所有其他東西..).. 但是我會很驚訝為什麼這樣然後問題只會偶爾出現,而不是一直使機器崩潰..
有任何想法嗎?
在我的程式碼中的每個合理點添加“記憶體屏障”未能改善這種情況後,我終於找到了一種可行的解決方法。該問題似乎根本與共享記憶體無關。相反,它似乎是由調度程序觸發的,並且在我長時間執行的 kthread 中添加對“schedule()”的呼叫似乎確實可以避免系統凍結。
不幸的是,這種解決方法對我來說不是一個可行的解決方案,我創建了一個單獨的執行緒來進一步探索它所採取的方向:有沒有辦法在不呼叫 schedule() 的情況下使用長時間執行的 kthread?