> [linux2023 summer](https://github.com/RoyWFHuang/linux2023_summer) # HW1 > [ref: 2023 年暑期 Linux 核心課程第 1 次測驗/作業檢討](https://hackmd.io/@sysprog/SkmKiSfh2#RinHizakura) ## 測驗 α ### 測驗 α − 1 ## 測驗 β ### 測驗 β - 1 ```c static inline uintptr_t align_up(uintptr_t sz, size_t alignment) { uintptr_t mask = alignment - 1; if ((alignment & mask) == 0) { /* power of two? */ return ((sz + mask) & ~mask); /* MMMM is here */ } return (((sz + mask) / alignment) * alignment); } ``` 首先取得 mask, 如果 aligment 是 2 的冪, aligment - 1 則可以取得此 aligment 完整的 mask, :::success e.g: $aligment(0b00001000) - 1 = 0b00000111$, 此時取 not 後變成 0b11111000, 就可以把不是 aligment 的倍數給去除. ::: 另外考慮到, 如果 sz 不是剛好 aligment 的倍數, 則需多增加 1個 aligment 來處理 :::success 假設取完畢 aligment 之後剩下的數字為 n $( 0 <= n <= alignment - 1)$, 此時若將此數加上 alignment - 1後取餘數, 則 $(n + (alignment - 1)) \% alignment = n - 1$ 所以加完之後的數字也會落在 0 ~ alignment 之間, 之後再用 mask 將之去除, 就可以得到相對應的 min alignment size. ::: 若非 2 的冪, 則演算法類似, 同樣考慮多增加一個 aligment 處理(+ mask), 之後計算他是 aligment 的幾倍, 在乘上 aligment 來處理, 就可以得出最小值. :::success e.g: aligment 5, input sz = 8 $(8 + (5 -1)) = 12$ $12 / 5 = 2$ $2 * 5 = 10$ $\therefore$ 8 的 aligment 是 10 ::: ### 測驗 β - 2 [__ALIGN_KERNEL(x, a)](https://elixir.bootlin.com/linux/v6.4.8/source/include/uapi/linux/const.h#L31) : Kernel define macro. [fs/ext4](https://elixir.bootlin.com/linux/v6.4.8/source/fs/ext4/file.c), 最近剛好在看 file system的資料, 其中 ext4 在write blk 的時候, 就有使用到對齊這個特性, 如此就可以一次按照 data bus 的寬度, 直接寫入 disk blk 中, 可以避免一筆資料寫入時跨兩個 block 的狀態. [slub](https://elixir.bootlin.com/linux/v6.4.8/source/mm/slub.c#L4456): 在 cache 機制中, 透過 [kmem_cache_create](https://elixir.bootlin.com/linux/v6.4.8/source/mm/slab_common.c#L392)可以用 slub 機制建立 memory cache, 這邊也會計算 alignment. ## 測驗 γ 使用 [thread sanitizer](https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual) ``` ubuntu@maturing-mammal:/home/roy/src-code/github/roy/linux2023_summer$ ./qsort_mt.out -v ================== WARNING: ThreadSanitizer: data race (pid=14800) Write of size 4 at 0x7b4000000080 by thread T1 (mutexes: write M0): #0 allocate_thread /home/roy/src-code/github/roy/linux2023_summer/qsort_mt.c:211 (qsort_mt.out+0x347a) (BuildId: 196c580c3003480e1d098369c8d09e7a6aaa9580) #1 qsort_algo /home/roy/src-code/github/roy/linux2023_summer/qsort_mt.c:315 (qsort_mt.out+0x4199) (BuildId: 196c580c3003480e1d098369c8d09e7a6aaa9580) #2 qsort_thread /home/roy/src-code/github/roy/linux2023_summer/qsort_mt.c:353 (qsort_mt.out+0x45b7) (BuildId: 196c580c3003480e1d098369c8d09e7a6aaa9580) Previous read of size 4 at 0x7b4000000080 by thread T2 (mutexes: write M1): #0 qsort_thread /home/roy/src-code/github/roy/linux2023_summer/qsort_mt.c:344 (qsort_mt.out+0x44cd) (BuildId: 196c580c3003480e1d098369c8d09e7a6aaa9580) Location is heap block of size 256 at 0x7b4000000000 allocated by main thread: #0 calloc ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:701 (libtsan.so.2+0x3c467) (BuildId: 29a32c589768a10ed232cacef24e09c48a66ec41) #1 qsort_mt /home/roy/src-code/github/roy/linux2023_summer/qsort_mt.c:132 (qsort_mt.out+0x28fa) (BuildId: 196c580c3003480e1d098369c8d09e7a6aaa9580) #2 main /home/roy/src-code/github/roy/linux2023_summer/qsort_mt.c:505 (qsort_mt.out+0x5021) (BuildId: 196c580c3003480e1d098369c8d09e7a6aaa9580) Mutex M0 (0x7ffd6ef7b4a8) created at: #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1329 (libtsan.so.2+0x3d7b6) (BuildId: 29a32c589768a10ed232cacef24e09c48a66ec41) #1 qsort_mt /home/roy/src-code/github/roy/linux2023_summer/qsort_mt.c:130 (qsort_mt.out+0x28dd) (BuildId: 196c580c3003480e1d098369c8d09e7a6aaa9580) #2 main /home/roy/src-code/github/roy/linux2023_summer/qsort_mt.c:505 (qsort_mt.out+0x5021) (BuildId: 196c580c3003480e1d098369c8d09e7a6aaa9580) Mutex M1 (0x7b40000000a8) created at: #0 pthread_mutex_init ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1329 (libtsan.so.2+0x3d7b6) (BuildId: 29a32c589768a10ed232cacef24e09c48a66ec41) #1 qsort_mt /home/roy/src-code/github/roy/linux2023_summer/qsort_mt.c:136 (qsort_mt.out+0x2980) (BuildId: 196c580c3003480e1d098369c8d09e7a6aaa9580) #2 main /home/roy/src-code/github/roy/linux2023_summer/qsort_mt.c:505 (qsort_mt.out+0x5021) (BuildId: 196c580c3003480e1d098369c8d09e7a6aaa9580) Thread T1 (tid=14802, running) created by main thread at: #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1036 (libtsan.so.2+0x3d189) (BuildId: 29a32c589768a10ed232cacef24e09c48a66ec41) #1 qsort_mt /home/roy/src-code/github/roy/linux2023_summer/qsort_mt.c:144 (qsort_mt.out+0x2a8f) (BuildId: 196c580c3003480e1d098369c8d09e7a6aaa9580) #2 main /home/roy/src-code/github/roy/linux2023_summer/qsort_mt.c:505 (qsort_mt.out+0x5021) (BuildId: 196c580c3003480e1d098369c8d09e7a6aaa9580) Thread T2 (tid=14803, running) created by main thread at: #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1036 (libtsan.so.2+0x3d189) (BuildId: 29a32c589768a10ed232cacef24e09c48a66ec41) #1 qsort_mt /home/roy/src-code/github/roy/linux2023_summer/qsort_mt.c:144 (qsort_mt.out+0x2a8f) (BuildId: 196c580c3003480e1d098369c8d09e7a6aaa9580) #2 main /home/roy/src-code/github/roy/linux2023_summer/qsort_mt.c:505 (qsort_mt.out+0x5021) (BuildId: 196c580c3003480e1d098369c8d09e7a6aaa9580) SUMMARY: ThreadSanitizer: data race /home/roy/src-code/github/roy/linux2023_summer/qsort_mt.c:211 in allocate_thread ================== ThreadSanitizer: reported 1 warnings ``` 可以發現 ==qsort_mt.c:211== 在 write 的時候, 另一個 thread 在 ==sort_mt.c:344== 時候會 read, 兩個 thread 操作的變數是 struct qsort->st, 而這個變數因為兩個 thread 都會進行操作, 所以必須用 lock 將之保護, 開始看哪個 st 是沒有保護的. ```c static struct qsort *allocate_thread(struct common *c) { verify(pthread_mutex_lock(&c->mtx_al)); for (int i = 0; i < c->nthreads; i++) if (c->pool[i].st == ts_idle) { c->idlethreads--; c->pool[i].st = ts_work; /* here need to protect */ verify(pthread_mutex_lock(&c->pool[i].mtx_st)); verify(pthread_mutex_unlock(&c->mtx_al)); return (&c->pool[i]); } verify(pthread_mutex_unlock(&c->mtx_al)); return (NULL); } ``` c->pool[i].st = ts_work; 這邊變動的時候 沒有進行 lock 保護, 所以將之移入 lock 保護 ```diff --- a/qsort_mt.c +++ b/qsort_mt.c @@ -208,9 +208,8 @@ static struct qsort *allocate_thread(struct common *c) for (int i = 0; i < c->nthreads; i++) if (c->pool[i].st == ts_idle) { c->idlethreads--; - c->pool[i].st = ts_work; verify(pthread_mutex_lock(&c->pool[i].mtx_st)); + c->pool[i].st = ts_work; /* move to here */ verify(pthread_mutex_unlock(&c->mtx_al)); return (&c->pool[i]); } ```