---
# System prepended metadata

title: 2023q1 Homework3 (quiz3)
tags: [Linux]

---

###### tags: `Linux`
# 2023q1 Homework3 (quiz3)
contributed by < [`shhung`](https://github.com/shhung) >
[quiz3](https://hackmd.io/@sysprog/linux2023-quiz3)

## 測驗`1`

觀察結構的宣告

```c
typedef struct __node {
    uintptr_t color;
    struct __node *left, *right;
    struct __node *next;
    long value;
} node_t __attribute__((aligned(sizeof(long))));
```
aligned 8 個 byte，代表定址都會是 8 的倍數，也就是最低位的 3 個位元不會被用到，可以利用這三個位元來做顏色的設定。

```c
#define rb_parent(r) ((node_t *) (((r)->color & ~7))) // AAAA
#define rb_color(r) ((color_t) (r)->color & 1)
```
可以看到 `rb_color` 是取最後一個位元當作顏色，所以我們要將顏色設定在最後一個位元

```c
// BBBB
#define rb_set_red(r)               \
    do {                            \
        (r)->color &= ~1;     \
    } while (0)
// CCCC
#define rb_set_black(r)             \
    do {                            \
        (r)->color |= 1;   \
    } while (0)
```

`DDDD` 和 `EEEE` 所在的部份是在做 tree 的尋訪，根據程式碼邏輯分別為向左和向右

```c
    /* Traverse the tree until we hit the end or find a side that is NULL */
    for (node_t *cur = obj->head;;) {
        int res = obj->comparator(&node->value, &cur->value);
        if (!res) /* If the key matches something else, don't insert */
            assert(0 && "not support repetitive value");

        if (res < 0) {
            if (!cur->left) {
                cur->left = node;
                rb_set_parent(node, cur);
                cmap_fix_colors(obj, node);
                break;
            }
            cur = cur->left; // DDDD
        } else {
            if (!cur->right) {
                cur->right = node;
                rb_set_parent(node, cur);
                cmap_fix_colors(obj, node);
                break;
            }
            cur = cur->right; // EEEE
        }
    }
```

`FFFF` ,`GGGG`, `HHHH` 位於 `tree_sort` 之中，程式邏輯是將數列依序存如由紅黑樹實做的 `cmap` 結構中，而在插入的過程中依照大小存放，因此當資料都放進去後，循序走訪將資料都取出後即可獲得排序完的數列。

```c
void tree_sort(node_t **list)
{
    node_t **record = list;
    cmap_t map = cmap_new(sizeof(long), sizeof(NULL), cmap_cmp_int);
    while (*list) {
        cmap_insert(map, *list, NULL);
        // list = FFFF;
        list = &(*list)->next;
    }
    node_t *node = cmap_first(map), *first = node;
    for (; node; node = cmap_next(node)) {
        *list = node;
        // list = GGGG;
        list = &(*list)->next;
    }
    // HHHH;
    *list = NULL;
    *record = first;
    free(map);
}
```


## 測驗 `4`

先思考 `log` 用 bitwise 來看的話要怎麼找， `8` 的二進位是 `b'00001000`，取 `log` 就是 `3`，再觀察其他數值發現最高位往後看第一個 `1` 出現的位置就是 `log` 的答案，類似 `quiz2` 用到的 `__builtin_ffs`，而資料型態為 `32` 位元，所以每次會比較一半的位元， $2^{n-1}, ..., 2^1$ ， `r` 用來累加比較的結果， `shift` 則用來暫存每一次比較的結果，因此在 `return` 的地方也必須再做一次 `r | shift` 將 `(x > 0x3) << 1` 的結果加起來，而最後 `x` 還有 `2` 個位元沒有比到， `x` 可能是 `b'11` `b'10` `b'01` `b'00`，這邊只要將 `x` 右移 `1` 位就能得到結果不需要比較，因此 `return` 要再加上 `x >> 1`，而 `()`外的 `+1` 是因為一開始的 `x--`，使得原本整數解的部份比原先少 `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 (KKKK) + 1;       
    return (r | shift | x >> 1) + 1;       
}

```