# 2021q3 Homework2 (hp)
contributed by < `ilkclord` >
## Program
The program is a mpmc model . It use Hazzard pointer to assure each element won't be free while some thread is using it .
### Data Structure
#### list_hp
```clike
struct list_hp {
int max_hps;
alignas(128) atomic_uintptr_t *hp[HP_MAX_THREADS];
alignas(128) retirelist_t *rl[HP_MAX_THREADS * CLPAD];
list_hp_deletefunc_t *deletefunc;
};
```
`max_hps` : size of `hp` in each thread
`hp` : a 2D array which store the hazzard pointer . Each threads will check `hp` of each threads when releasing the memory .
`rl` : store the object no longer used
`deletefunc` : delete method
### Hazzard Pointer
The program use these two function to control the `hp` list .
#### list_hp_protect_ptr
```clike
uintptr_t list_hp_protect_ptr(list_hp_t *hp, int ihp, uintptr_t ptr)
{
atomic_store(&hp->hp[tid()][ihp], ptr);
return ptr;
}
```
#### list_hp_protect_release
```clike
uintptr_t list_hp_protect_release(list_hp_t *hp, int ihp, uintptr_t ptr)
{
atomic_store_explicit(&hp->hp[tid()][ihp], ptr, memory_order_release);
return ptr;
}
```
### Find
The find funtion in the program is `list_find` , it keeps tracking if the node it used has been modified . It protected `curr` and `curr->next` in `hp` .
#### list_find
```clike
static bool __list_find(list_t *list,
list_key_t *key,
atomic_uintptr_t **par_prev,
list_node_t **par_curr,
list_node_t **par_next)
{
atomic_uintptr_t *prev = NULL;
list_node_t *curr = NULL, *next = NULL;
try_again:
prev = &list->head;
curr = (list_node_t *) atomic_load(prev);
(void) list_hp_protect_ptr(list->hp, HP_CURR, (uintptr_t) curr);
if (atomic_load(prev) != get_unmarked(curr))
goto try_again;
while (true) {
if (!get_unmarked_node(curr))
return false;
next = (list_node_t *) atomic_load(&get_unmarked_node(curr)->next);
(void) list_hp_protect_ptr(list->hp, HP_NEXT, get_unmarked(next));
if (atomic_load(&get_unmarked_node(curr)->next) != (uintptr_t) next)
break;
if (get_unmarked(next) == atomic_load((atomic_uintptr_t *) &list->tail))
break;
if (atomic_load(prev) != get_unmarked(curr))
goto try_again;
if (get_unmarked_node(next) == next) {
if (!(get_unmarked_node(curr)->key < *key)) {
*par_curr = curr;
*par_prev = prev;
*par_next = next;
return FFF;
}
prev = &get_unmarked_node(curr)->next;
(void) list_hp_protect_release(list->hp, HP_PREV,
get_unmarked(curr));
} else {
uintptr_t tmp = get_unmarked(curr);
if (!atomic_compare_exchange_strong(prev, &tmp, get_unmarked(next)))
goto try_again;
list_hp_retire(list->hp, get_unmarked(curr));
}
curr = next;
(void) list_hp_protect_release(list->hp, HP_CURR, get_unmarked(next));
}
*par_curr = curr;
*par_prev = prev;
*par_next = next;
return false;
}
```
### Insert
The insert funtion `list_insert` will keep try insertion untill it successed . After checking the node isn't exist in the list , it insert the new node at the tail of the list .
#### list_insert
```clike
bool list_insert(list_t *list, list_key_t key)
{
list_node_t *curr = NULL, *next = NULL;
atomic_uintptr_t *prev = NULL;
list_node_t *node = list_node_new(key);
while (true) {
if (__list_find(list, &key, &prev, &curr, &next)) {
list_node_destroy(node);
list_hp_clear(list->hp);
return false;
}
atomic_store_explicit(&node->next, (uintptr_t) curr,
memory_order_relaxed);
uintptr_t tmp = get_unmarked(curr);
if (atomic_compare_exchange_strong(prev, &tmp, (uintptr_t) node)) {
list_hp_clear(list->hp);
return true;
}
}
}
```
### Delete
The delete function `list_delete` will try untill successed , too .It first find the node to delete . Then check the accuracy of the node , true if the node hasn't been deleted . It call `list_retire` to put a object into `rl` and `lsit_retire` will free the object inside `rl` if `rl` is full .
#### list_delete
```clike
bool list_delete(list_t *list, list_key_t key)
{
list_node_t *curr, *next;
atomic_uintptr_t *prev;
while (true) {
if (!__list_find(list, &key, &prev, &curr, &next)) {
list_hp_clear(list->hp);
return false;
}
uintptr_t tmp = get_unmarked(next);
if (!atomic_compare_exchange_strong(&curr->next, &tmp,
get_marked(next)))
continue;
tmp = get_unmarked(curr);
if (atomic_compare_exchange_strong(prev, &tmp, get_unmarked(next))) {
list_hp_clear(list->hp);
DDD;
} else {
list_hp_clear(list->hp);
}
return true;
}
}
```
## Improvement
## Compare with RCU