Asahi Lina講述了使用Rust編寫Linux驅動程式的經驗
關於核心中的Rust是否有用,有很多奇怪的爭論......根據我的經驗,它比我想象的要有用得多!"。
在我的驅動程式上只除錯了大約兩天,我就從第一次渲染變成了一個可以執行遊戲、瀏覽器等的穩定桌面。
所有的併發性錯誤都在Rust中消失了!記憶體在需要釋放的時候就會被釋放!
一旦你學會讓Rust和你一起工作,我覺得它就會引導你寫出正確的程式碼,甚至超越語言的安全承諾。它真的很有魔力!
如果我用C語言寫這篇文章,我絕對不可能不遇到鎖競爭競態條件、UAF、記憶體洩漏和各種各樣的壞問題。
在Rust中只是一些邏輯錯誤和一些核心記憶體管理問題。
一旦這些被修復,驅動程式其餘部分就會工作!!
我試了一下kmscube,它順利地渲染幀。然後我試著啟動一個KDE會話,過了一會兒它就崩潰了,而你知道什麼原因沒有導致它?3個程式試圖同時使用GPU,並行分配和提交命令,是並行!!
在這樣一個複雜的驅動中,當事情在單執行緒中執行後,所有的鎖定和執行緒都神奇地按計劃執行,沒有奇怪的鎖競爭或事情互相踩踏,就我而言,對於一個如此複雜的驅動來說,這是完全聞所未聞的。
然後所有的記憶體管理……就像魔術一樣發生。使用 GPU 的程式退出,它使用的所有記憶體和結構都被釋放。我的日誌中有幾十行都被正確釋放了。我沒有寫任何膠水,Rust 為我做了這一切!
(我寫了將 DRM 子系統連線到 Rust 的部分,包括在檔案關閉時刪除一個File結構,這就是觸發所有記憶體管理的原因......剩下的部分由Rust完成!)
我實際上花了更多的時間來追蹤一個被遺忘*的 DCP 驅動程式(由Alyssa和Janne用C語言編寫,已經過測試),它導致堆溢位,在上面花費的時間比我花在Rust中追蹤我的全新驅動的CPU端安全問題(unsafe 程式碼)的時間還要多。
甚至像正確處理ERESTARTSYS這樣的事情。Linux Rust鼓勵你在任何地方使用Result<T>(Err 是 errno 的核心變體),然後你只需在你睡眠/等待sleeping/waiting條件的地方後面加一個?(就像編譯器告訴你的那樣),它就能正常工作了。
說真的,C和Rust在這裡有很大的區別。
Rust的炒作是真實的!無畏的併發性是真實的!
雖然有一些unsafe {} 塊並不能掩蓋否定Rust的優勢!
Asahi Lina補充:
從真正的驅動程式的第一次渲染到穩定的驅動程式,需要兩天時間。當我拿到第一張渲染圖的時候,幾乎所有的驅動程式都已經寫好了!"。
我真正想說的是,我花了兩天時間來修復錯誤,使事情能夠正常和穩定地進行,而如果驅動是用C語言編寫的,我還必須處理併發和記憶體安全問題,那就會花更多的時間。
請記住,這是核心方面的驅動程式,它的工作只是管理記憶體和向GPU提交請求。
要達到這個目的有很多複雜的因素,但是一旦你達到了這個目的,從核心的角度來看,不同的應用在使用GPU的方式上幾乎沒有任何差異。所有OpenGL的東西都是在使用者空間處理的,Alyssa在這方面已經工作了很長時間(在macOS下測試)。因此,最終,對於這種驅動,在你獲得了渲染和(相對較少的)功能/用例支援之後,剩下的大部分工作就是使其穩定並修復安全和併發錯誤。而......在Rust中並沒有多少這樣的東西!"。
以下是這兩天的大致情況:
- 移除mesa中的一些舊的駭客,這些駭客會破壞事情。
- 修復mesa中的kmsro/buffer匯入問題
- 實現PRIME緩衝區共享工作所缺少的東西
- 重寫我的DRM抽象,因為我誤解了C語言的API,導致它不能和PRIME一起工作。
- 重構了一些驅動程式碼,因為它也破壞了驅動內部的PRIME緩衝區共享,這也是因為我誤解了它應該如何工作。
- 弄清楚如何修復韌體端的TLB無效性。
- 為GPU端TLB不能正常失效而導致的記憶體損壞問題傷透腦筋,然後想出了一個愚蠢的解決方法,即每次渲染後等待GPU關閉。
因此,實際上,大部分工作是使緩衝區共享工作,這對於讓多個圖形應用程式相互傳送幀是必要的,然後與TLB失效問題作鬥爭(這在硬體層面上導致記憶體安全問題,所以這不是Rust可以幫助解決的問題--這場戰鬥仍在進行,我現在有的只是一個解決它的駭客)。
在最後一個解決方法之後,一切都開始穩定地工作,所以事實證明,所有明顯的剩餘記憶體安全問題的根源實際上是GPU TLB,而驅動本身實際上是非常可靠的。這就是令人驚奇的部分!
Reddit網友:
1、我是一名長期的 C 開發人員,C++ 開發人員已經有幾年了,現在已經使用 Rust 作為我的主要語言 3 年了。
我發現 Rust 是最容易閱讀的語言。跳入 Rust 核心或其他專案的某些部分並快速開始理解程式碼流是多麼容易,這讓我感到非常驚訝。
2、閱讀 Rust 程式碼時,這種語言使得隱藏棘手的錯誤變得非常困難(顯然並非不可能,但慣用程式碼通常非常簡單)。
閱讀 C 語言時,您需要時刻注意一切,因為該語言不允許抽象。您需要了解指標可能變為無效的每個位置,您需要手動跟蹤資源所有權,以確保它們在正確的時間釋放,您需要了解給定函式可能呼叫未定義行為的每種情況,以及有時,規則可能會根據您所針對的平臺或正在使用的編譯器版本而改變。核心程式碼也不是嚴格的標準 C,而是使用 GCC 擴充套件,這是您需要注意的更多內容。
C++ 允許抽象,但也伴隨著糟糕的設計決策、不能很好地協同工作的特性以及許多未定義行為的例項。
Rust 只是一種較新的語言,其高階功能從一開始就被設計為難以濫用,並且安全性是一等公民。
3、Rust 是迄今為止最容易審查的程式碼,甚至比 Python 更容易。您可以非常準確地瞭解某些程式碼的執行時行為,而無需調查可能採用的路徑的實現。在哪裡存在潛在問題,您總是知道它們可能源自哪裡,因為它們需要顯式的函式呼叫或 unsafe塊。
相關文章
- Linux驅動實踐:如何編寫【 GPIO 】裝置的驅動程式?Linux
- Linux網路驅動程式編寫(四)(轉)Linux
- Linux網路驅動程式編寫(三)(轉)Linux
- Linux網路驅動程式編寫(二)(轉)Linux
- Linux網路驅動程式編寫(一)(轉)Linux
- usb驅動程式初步編寫
- Linux驅動開發筆記(一):helloworld驅動原始碼編寫、makefile編寫以及驅動編譯Linux筆記原始碼編譯
- ekzhang/rustpad:使用Rust編寫的高效程式碼編輯器Rust
- Linux RN6752 驅動編寫Linux
- linux裝置驅動編寫入門Linux
- 如何編寫linux下nandflash驅動-4LinuxNaN
- linux裝置驅動編寫基礎Linux
- 如何編寫一個簡單的Linux驅動(三)——完善裝置驅動Linux
- linux 觸控式螢幕驅動編寫Linux
- Linux系統核心模組和驅動的編寫(轉)Linux
- 使用rust編寫dwm status-bar應用程式Rust
- Windows95的裝置驅動程式的編寫 (轉)Windows
- Linux驅動開發筆記(三):基於ubuntu的驅動、makefile編寫以及編譯載入流程Linux筆記Ubuntu編譯
- 使用 Rust + WebAssembly 編寫 crc32RustWeb
- 用 Delphi 編寫 VxD 裝置驅動程式(轉) (轉)
- 編寫安全的驅動程式之輸入輸出檢查
- Rust是如何用Rust編寫的? - RedditRust
- 三個Rust程式碼庫的經驗分享:何時開始使用Rust? - convexRust
- 需求編寫的幾點經驗之談
- 使用Rust編寫的各種遊戲 - GameDev#28Rust遊戲GAMdev
- Linux驅動實踐:你知道【字元裝置驅動程式】的兩種寫法嗎?Linux字元
- linux網路卡驅動程式的編譯與安裝(轉)Linux編譯
- 用Rust編寫的快如閃電的程式碼編輯器:lapceRust
- 入門文章:教你學會編寫Linux裝置驅動(轉)Linux
- 使用 Rust 語言編寫 Java JNI 實現RustJava
- 使用 macro_rules 編寫生產 Rust 宏!MacRust
- Linux驅動實踐:帶你一步一步編譯核心驅動程式Linux編譯
- SoftwareMill實現領域驅動設計的經驗REM
- 給程式設計師的幾點程式設計經驗----《編寫高質量程式碼》程式設計師
- 編寫軟體動態載入NT式驅動
- [譯]使用 Rust 編寫快速安全的原生 Node.js 模組RustNode.js
- 編寫靜態頁面經驗總結
- 實驗一 命令解釋程式的編寫