--- tags: linux2022 --- # 2022q1 Homework8 (quiz8) 2022-04-04 contributed by < `bebo1010` > [Github repository link](https://github.com/bebo1010/linux2022-quiz8) ## 測驗一 實際行為應該和 [lib/string.c](https://github.com/torvalds/linux/blob/master/lib/string.c) 中的 [memchr](https://man7.org/linux/man-pages/man3/memchr.3.html) 相同,要能做到找出第一個相符的字元位置。 我大致上讀了一下程式碼後,看到了 mask 的做法,就意識到應該是一次比對多個 byte 是否與 mask (目標字元) 相同。 實際上再去了解後,發現做法是一次比對 8 個字元是否和目標字元相同。 以下內容是我的實作,使用 DETECT_CHAR macro 幫我找出是否這 8 個字元中含有目標字元 * 如果有找到的話,在這八個字元中用 linear scan 的方式從頭開始找起字元的實際位置 * 如果沒有找到的話,把指標頭往後移動八個字元,並把剩餘要找的字元數減八 ```c while (length >= LBLOCKSIZE) { /* XXXXX: Your implementation should appear here */ if (DETECT_CHAR(*asrc, mask) != 0) { // char in mask detected for (int i = 0; i < 8; i++) { // linear scan in this 8 characters if (*(src + i) == d) return (void *)(src + i); } } else { // char in mask not detected src = src + 8; asrc = (unsigned long *)src; length = length - 8; } } ``` ## 測驗二 看了許久後,還是看不出個所以然來,我也不確定這份程式碼是要做出什麼東西。 我目前猜測這個 `struct lfring` 應該是一個暫存的區塊,存放從 producer 跑出的東西給 consumer 用掉。 但是這個 struct 並不是一個 linked list,那這個 struct 是如何去記錄目前的每一個東西? 裡面有個 function 是 `before()`,可是我很困惑這個 `before()` 放入的 index 值有沒有意義,如果 `struct lfring` 有被宣告為陣列那這個 index 才可能有意義做比較 後來很像看到了 `struct lfring` 中有個 `struct element`,而 `struct element` 有 `void *ptr`,這部分就是 linked list 嗎? 那為何存取 `ptr` 時都會用到 `& mask` 的部分? ```c static inline ringidx_t cond_reload(ringidx_t idx, const ringidx_t *loc) { ringidx_t fresh = __atomic_load_n(loc, __ATOMIC_RELAXED); if (before(idx, fresh)) { /* fresh is after idx, use this instead */ idx = fresh; } else { /* Continue with next slot */ /* XXXXX */ return cond_reload(fresh, &idx); } return idx; } ``` ```c static inline ringidx_t find_tail(lfring_t *lfr, ringidx_t head, ringidx_t tail) { if (lfr->flags & LFRING_FLAG_SP) /* single-producer enqueue */ return __atomic_load_n(&lfr->tail, __ATOMIC_ACQUIRE); /* Multi-producer enqueue. * Scan ring for new elements that have been written but not released. */ ringidx_t mask = lfr->mask; ringidx_t size = /* XXXXX */ lfr->tail; while (before(tail, head + size) && __atomic_load_n(/* XXXXX */ &lfr->tail, __ATOMIC_ACQUIRE) == tail) tail++; tail = cond_update(&lfr->tail, tail); return tail; } ``` ```c uint32_t lfring_dequeue(lfring_t *lfr, void **restrict elems, uint32_t n_elems, uint32_t *index) { ringidx_t mask = lfr->mask; intptr_t actual; ringidx_t head = __atomic_load_n(&lfr->head, __ATOMIC_RELAXED); ringidx_t tail = __atomic_load_n(&lfr->tail, __ATOMIC_ACQUIRE); do { actual = MIN((intptr_t)(tail - head), (intptr_t)n_elems); if (UNLIKELY(actual <= 0)) { /* Ring buffer is empty, scan for new but unreleased elements */ tail = find_tail(lfr, head, tail); actual = MIN((intptr_t)(tail - head), (intptr_t)n_elems); if (actual <= 0) return 0; } for (uint32_t i = 0; i < (uint32_t)actual; i++) elems[i] = lfr->ring[(head + i) & mask].ptr; smp_fence(LoadStore); // Order loads only if (UNLIKELY(lfr->flags & LFRING_FLAG_SC)) { /* Single-consumer */ __atomic_store_n(&lfr->head, head + actual, __ATOMIC_RELAXED); break; } /* else: lock-free multi-consumer */ } while (!__atomic_compare_exchange_n( &lfr->head, &head, /* Updated on failure */ /* XXXXX */ &mask, // desired position, write here if equal /* weak */ false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)); *index = (uint32_t)head; return (uint32_t)actual; } ``` ## 測驗三 我嘗試著去看懂這個程式碼,但我看不懂 `periodic_routine` 的目的到底是什麼 `periodic_routine` 中的 `if(likely(X))` 是假設 `X` 是很容易發生的事情,但是這個 `X` 我找不到一個可能填入的東西,要找到這個 process 是不是 tracer 只能從 `task_struct` 內找,而不是 `work_struct`。 在前面的條件成立後就會呼叫 `check()`,而 `check()` 的目的似乎是找出每個 `process` 是否是 tracer,如果是 tracer 的話就把底下的 tracee 全部 kill 掉後再把自己 kill 掉。 剩下的部分我已經找不出線索可以繼續找答案了,也很有可能是我錯過了什麼線索。