# 2021q3 Homework2 (hp)
contributed by < [`RoyWFHuang`](https://github.com/RoyWFHuang) >
###### tags: `linux_class` `kernel`
> [2021 年暑期 第 2 週隨堂測驗題目](https://hackmd.io/@sysprog/linux2021-summer-quiz2)
> [2021 年暑期 Linux 核心 Homework2](https://hackmd.io/@sysprog/linux2021-summer-homework2)
開發環境為:
OS: ubuntu 20.04
kernel ver: 5.4.0-77-generic
CPU arch: x86_64
使用 multipass 開發
```shell
$ multipass info dev
Name: dev
State: Running
IPv4: 10.195.227.125
Release: Ubuntu 20.04.2 LTS
Image hash: 1d3f69a8984a (Ubuntu 20.04 LTS)
Load: 0.00 0.00 0.00
Disk usage: 1.9G out of 4.7G
Memory usage: 136.6M out of 981.2M
Mounts: /home/roy/src-code => /home/roy/src-code
UID map: 1000:default
GID map: 1000:default
In multipass shell
$ uname -a
Linux dev 5.4.0-80-generic #90-Ubuntu
```
---
## 解釋上述程式碼運作原理
首先先看
```c=
#define is_marked(p) (bool) ((uintptr_t)(p) &0x01)
#define get_marked(p) ((uintptr_t)(p) | (0x01))
#define get_unmarked(p) ((uintptr_t)(p) & (~0x01))
```
這邊最是把 address 最後一個 bit 當作 mark 使用, e.g. 0x40004000 -> 表示此address的資料沒被標注 0x40004001 ->則表示被標注
另外再來看
```c =
list_node_t *node = aligned_alloc(128, sizeof(*node));
```
除了是要作 cache line作用之外, 最主要是因為要拿, 最後一個 bit 當作 mark 使用的關係, 所以要確保每一個 allocate address 最後一個bit 必須為 0,在考慮到對齊特性(Intel 架構下 128 bit 對齊,詳細請參見 [linD026](https://hackmd.io/@linD026/harzard-pointer#Harzard-Pointer-%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B)有詳細說明), 所以只要保持最後一個 byte 當作 mask使用
## 指出改進空間並著手實作
1. 首先修正 delete thread do nothing problem
```c=
static void *delete_thread(void *arg)
{
list_t *list = (list_t *) arg;
// pthread_barrier_wait(&barr);
for (size_t i = 0; i < N_ELEMENTS; i++)
(void) list_delete(list, (uintptr_t) &elements[tid()-1][i]);
return NULL;
}
```
這樣正常來說 tid()在 create 產生的資料, 全部都可以在 tid()-1 的 thread中刪除, 所以可以將後面的
```c=
for (size_t i = 0; i < N_ELEMENTS; i++) {
for (size_t j = 0; j < tid_v_base; j++)
list_delete(list, (uintptr_t) &elements[j][i]);
}
```
將之移除, 但移除後出現了, 程式執行完畢後, 仍有未刪除之節點存在list中
```
curr = 7b4000020400
curr = 7b4000020500
curr = 7b4000020600
curr = 7b4000020700
....
curr = 7b40000b7b00
curr = 7b40000b7c00
curr = 7b40000b7d00
curr = 7b40000b7e00
curr = 7b40000b7f00
curr = 7b4000000000
cnt = 693
```
表示delete的方法因為這樣修改出現問題
2. 修正list_delete
在此 function 中,==if (!__list_find(list, &key, &prev, &curr, &next))== 在未發現 node 的狀態下, 會直接回傳 false, 但在這個程式中, create 產生的 node 只會由某一個 delete 固定去刪除, 所以調整如下:
```c=
if (!__list_find(list, &key, &prev, &curr, &next)) {
list_hp_clear(list->hp);
continue;
// return false;
}
```
將之改為找不到節點則重新找尋
```
output :
curr = 7b4000000000
cnt = 0
inserts = 4098, deletes = 4032
```
3. 修正 所有 create thread 和 delete thread 不是同時開始的問題
使用 barrier 方式解決此問題, 在 create and delete thread 中加入 barrier, 促使所有的 thread 都產生後才開始執行
```c=
pthread_barrier_t barr;
static void *insert_thread(void *arg)
{
list_t *list = (list_t *) arg;
pthread_barrier_wait(&barr); //add barrier
for (size_t i = 0; i < N_ELEMENTS; i++) // 128 * 32(64/2)
(void) list_insert(list, (uintptr_t) &elements[tid()][i]);
return NULL;
}
static void *delete_thread(void *arg)
{
list_t *list = (list_t *) arg;
pthread_barrier_wait(&barr); //add barrier
for (size_t i = 0; i < N_ELEMENTS; i++)
(void) list_delete(list, (uintptr_t) &elements[tid()-1][i]);
return NULL;
}
```
4. create and delete 數量不一致問題
在 list_delete 中
```c=
if (atomic_compare_exchange_strong(prev, &tmp, get_unmarked(next))) {
list_hp_clear(list->hp);
list_hp_retire(list->hp, get_unmarked(curr)); //DDD;
} else {
list_hp_clear(list->hp);
}
```
因為同時刪除的關係, 有可能因為在刪除此 node 時, 其他人剛好在刪除其前面的節點, 造成此節點無法刪除, 因此就無法從 retire list 刪除
因此程式最後結束時, 還必須做回收
//TODO....
6.
## 對比 rcu_list,解釋同為 lock-free 演算法,跟上述 Hazard pointer 手法有何異同?能否指出 rcu_list 實作缺陷並改進?