-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathhaz_ptr.c
76 lines (68 loc) · 1.96 KB
/
haz_ptr.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/*
* a simple hazard pointer implementation
* Kevin Lynx 2015.05.02
*/
#include "haz_ptr.h"
#include "common.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#define HAZ_MAX_COUNT HAZ_MAX_THREAD * HAZ_MAX_COUNT_PER_THREAD
typedef struct free_t {
void *p;
struct free_t *next;
} free_t;
static int _tidSeed = 0;
static hazard_t _haz_array[HAZ_MAX_COUNT];
/* a simple link list to save pending free pointers */
static free_t _free_list[HAZ_MAX_THREAD];
static int get_thread_id() {
static __thread int _tid = -1;
if (_tid >= 0) return _tid;
_tid = ATOMIC_INC(&_tidSeed);
_free_list[_tid].next = NULL;
return _tid;
}
static int haz_confict(int self, void *p) {
int self_p = self * HAZ_MAX_COUNT_PER_THREAD;
for (int i = 0; i < HAZ_MAX_COUNT; ++i) {
if (i >= self_p && i < self_p + HAZ_MAX_COUNT_PER_THREAD)
continue; /* skip self */
if (_haz_array[i] == p)
return TRUE;
}
return FALSE;
}
hazard_t *haz_get(int idx) {
int tid = get_thread_id();
return &_haz_array[tid * HAZ_MAX_COUNT_PER_THREAD + idx];
}
void haz_defer_free(void *p) {
int tid = get_thread_id();
free_t *f = (free_t*) malloc(sizeof(*f));
f->p = p;
f->next = _free_list[tid].next;
_free_list[tid].next = f;
haz_gc();
}
void haz_gc() {
int tid = get_thread_id();
free_t *head = &_free_list[tid];
free_t *pred = head, *next = head->next;
while (next) {
if (!haz_confict(tid, next->p)) { /* safe to free */
free_t *tmp = next->next;
trace("hazard (%d) free ptr %p\n", tid, next->p);
free(next->p);
pred->next = tmp;
free(next);
next = tmp;
} else {
pred = next;
next = next->next;
}
}
if (head->next == NULL) {
trace("thread %d freed all ptrs\n", tid);
}
}