這應該是我學習 os 拼圖的最後一塊了, 我已經會實作開機程式, context switch, system call, fork, exec, elf loader, 記憶體管理, mmu 設定, romfs 檔案系統, 剩下應該就是 process 的同步機制。這些主題深入下去都會花上不少時間, 我只取最簡單的實作方式, 主要觀念有完成就可以, 實作並不完美, 但由於我的簡化, 他們都變的很容易理解, 這是簡化後帶來的價值。剩下的工作便是把所有的努力組合起來, 這也是件大工程。os 當然還有其他主題, 不過我認為這樣應該對 os 有達到「略懂」的境界了。
process 同步機制有 spinlock, mutex, semaphore, 我的學習方式是簡化再簡化, 然後用程式碼實作他們, 否則我只會有「名詞」上的理解, 而不會真的理解, 有了 spinlock 就有了基本的 process 同步機制。
由於工作時間就耗掉了我生活的不少時間, 幾乎沒有時間學習一個大主題, 我的 compiler 學習之路只好緩一點 (在 os 上花了很大時間, 想換換口味), 偷空學習這些被我化繁為簡的零星主題。
以下的參考資料幫助我完成這個實作:
由於要分解這些功能並簡化他們, 通常我會設計簡單的測試方式並輔以實作的小程式來理解他們, spinlock 的測試讓我大傷腦筋, 之前的想法是要先實作 process switch, 才能測試 spinlock, 我也的確做了某些成果, 不過在我愈來愈會設計這些小實驗後, 已經變得很擅長這件事情。我想到一個更好的方法, 不用先實作 process switch, 我在 rpi2 寫個 pthread 程式, 然後呼叫我自己寫的 my_spin_lock, my_spin_unlock 取代 pthread_spin_lock, pthread_spin_unlock, 若行為一樣, 就代表我成功了。
spinlock.c L77 ~ 84 是 c 版本的演算法, 為什麼不能用這個版本, 因為需要 atomic 操作, 這大家都知道, 不多說了; 困難的是怎麼實作 atomic, spinlock.c L103 ~ 116 是我參考 linux 3.10.37 arch/arm/include/asm/atomic.h atomic_add 改出來的 (因為我自己寫的都有問題 ... 冏), 這 inline assembly 實在太難, 我沒能完全看懂, ldrex/strex 可以在 armv6, cortex armv7-A 上使用, 我在 rpi2 執行這個測試, 這個版本應該也可以在 cortex m3 上執行, 這才是我真正的目的。
x86 可參考 arch/x86/include/asm/atomic.h, 或是直接參考 arch/x86/include/asm/spinlock.h 的實作。
程式有 3 個 thread 在寫同一個檔案 /tmp/xyz1, 按下 ctrl-c 會收到 SIGINT, 程式會正確的處理這個 SIGINT 然後結束整個程式 (這並不容易, 請參考《
thread 和 signal》)。spinlock test result 為失敗與成功的內容。一開始的實作並不正確, 所以我特別用了 pthread_spin_lock/pthread_spin_unlock 來測試, 而使用pthread_spin_lock/pthread_spin_unlock 的確會得到正確的結果, 所以我一開始的實作是有問題的。
每個 thread 應該以 3 行為輸出單位, 若是被混在一起, 表示雖然有某個 thread 取得了 spinlock, 但其他的 thread 並沒有 busy loop, 而是也取得了同樣的 spinlock 並進入了 critical section, 造成了失敗的結果。
check_result.c 則是用來檢查 /tmp/xyz1 是否是正確。整個測試在 rpi2 上完成。
不知道是不是還需要 memory barrier, dsb, isb, dmb 這些指令 (其實應該要的)。驗證 spinlock function 是否正確非常困難, 我也不確定這個版本一定是對的, 因為只要有一個失敗案例, 這個 spinlock 實作就不正確了, 若用上了有 bug 的 spinlock function, 那程式會很難除錯, 若核4 有這樣的程式碼應該會嚇死不少程式人。
spinlock 做出來了, 那 mutex 呢? 把 spinlock.c L109 改成讓出 cpu 的程式碼就可以了, 這就是俗稱的去「睡覺」。你說要怎麼做? 這在 process switch 的階段就已經會了, 所以你得搞懂那個才行。
實作完 spinlock 後還有使用 spinlock 的議題, 非常的複雜, 感覺起來 mutex 是比較好的, 那為什麼還要設計 spinlock, 又中斷部份的程式碼為什麼要 spinlock 而不用 mutex 呢?
source code:
https://github.com/descent/progs/tree/master/spinlock
ref:
DMB, DSB, ISB:
沒有留言:
張貼留言
使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。
我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。