-
Notifications
You must be signed in to change notification settings - Fork 95
/
rwArray.go
75 lines (60 loc) · 1.49 KB
/
rwArray.go
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
package libbpfgo
import (
"sync"
)
type slot struct {
value interface{}
used bool
}
// rwArray allows for multiple concurrent readers but
// only a single writer. The writers lock a mutex while the readers
// are lock free.
// It is implemented as an array of slots where each slot holds a
// value (of type interface{}) and a boolean marker to indicate if it's
// in use or not. The insertion (Put) performs a linear probe
// looking for an available slot as indicated by the in-use marker.
// While probing, it is not touching the value itself, as it's
// being read without a lock by the readers.
type rwArray struct {
slots []slot
mux sync.Mutex
}
func newRWArray(capacity uint) rwArray {
return rwArray{
slots: make([]slot, capacity),
}
}
func (a *rwArray) put(v interface{}) int {
a.mux.Lock()
defer a.mux.Unlock()
limit := len(a.slots)
for i := 0; i < limit; i++ {
if !a.slots[i].used {
a.slots[i].value = v
a.slots[i].used = true
return i
}
}
return -1
}
func (a *rwArray) remove(index uint) {
a.mux.Lock()
defer a.mux.Unlock()
if int(index) >= len(a.slots) {
return
}
a.slots[index].value = nil
a.slots[index].used = false
}
func (a *rwArray) get(index uint) interface{} {
if int(index) >= len(a.slots) {
return nil
}
// N.B. If slot[index].used == false, this is technically
// a race since put() might be putting the value in there
// at the same time.
return a.slots[index].value
}
func (a *rwArray) capacity() uint {
return uint(len(a.slots))
}