---
tags: linux2022
---
# 2022q1 Homework (quiz4)
contributed by < `hankluo6` >
> [第 4 週測驗題](https://hackmd.io/@sysprog/linux2022-quiz4)
## 測驗 `1`
### 運作原理
```c=
int ceil_log2(uint32_t x)
{
uint32_t r, shift;
x--;
r = (x > 0xFFFF) << 4;
x >>= r;
shift = (x > 0xFF) << 3;
x >>= shift;
r |= shift;
shift = (x > 0xF) << 2;
x >>= shift;
r |= shift;
shift = (x > 0x3) << 1;
x >>= shift;
return (EXP1) + 1;
}
```
要得到 $\lceil \log_2{x} \rceil$ 相當於取得最高位元 0 的位置與 LSB 間的數字數量,所以可以用 binary search 的方法從 16, 8, 4, 2 位元間隔尋找。
15 行後 `x` 只剩兩個位元,所以需要 `(x >> 1)` 進行最後一次搜尋,並加上缺少的一次 `r |= shift`,可得出 `EXP1 = r | shift | (x >> 1)`
---
## 測驗 `2`
### 運作原理
```c=
#define BITS_PER_BYTE 8
#define BITS_PER_LONG (sizeof(unsigned long) * BITS_PER_BYTE)
#include <stddef.h>
static inline size_t ffs(unsigned long x)
{
if (x == 0)
return 0;
size_t o = 1;
unsigned long t = ~0UL;
size_t shift = BITS_PER_LONG;
shift >>= 1;
t >>= shift;
while (shift) {
if ((EXP2) == 0) {
x >>= shift;
EXP3;
}
shift >>= 1;
t >>= shift;
}
return o;
}
```
與前一題一樣,從 32, 16, 8, 4, 2 位元去尋找,所以當在搜尋範圍內有位元為 1 時,需要右移 `x` 並將結果加到回傳值 `o` 上。所以 `EXP2 = s & t`;而回傳值 `o` 則需加上對應的位元數,故 `EXP3 = o += shift`。
---
## 測驗 `3`
### 運作原理
```c
struct foo_consumer {
int (*handler)(struct foo_consumer *self, void *);
struct foo_consumer *next;
};
struct foo {
struct foo_consumer *consumers;
unsigned long flags;
};
#include <stdbool.h>
/*
* For foo @foo, delete the consumer @fc.
* Return true if the @fc is deleted sfccessfully
* or return false.
*/
static bool consumer_del(struct foo *foo, struct foo_consumer *fc)
{
struct foo_consumer **con;
bool ret = false;
for (con = &foo->consumers; *con; EXP4) {
if (*con == fc) {
*con = EXP5;
ret = true;
break;
}
}
return ret;
}
```
從結構可以看出 `foo_consumer` 透過 `next` 相連,所以 `for` 迴圈應該為遍歷所有的 `foo_consumer`,而這邊使用 pointer to pointer 當作 iterator,所以 `EXP4 = con = &(*con)->next`。`EXP5` 需要將刪除的 `foo_consumer` 後方的 element 接上,可得出 `EXP5 = fc->next`。
---