-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathslots.go
More file actions
56 lines (49 loc) · 1.22 KB
/
slots.go
File metadata and controls
56 lines (49 loc) · 1.22 KB
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
package radix
import (
"runtime"
"sync/atomic"
)
type item struct {
// cacheline padding
_ [8]uint64
v uint64
}
// slots is a cache friendly Get/Put pool with a small fixed number of items [0 - n).
// It's used internally for keeping track of available allocators.
type slots struct {
slots []item
}
// newSlots returns a new Slots with n items.
// From start, all items are all in the pool (available)
func newSlots(n int) *slots {
return &slots{
slots: make([]item, n),
}
}
// free counts the number of currently available items
func (s *slots) available() (c int) {
for i := 0; i < len(s.slots); i++ {
if atomic.LoadUint64(&s.slots[i].v) == 0 {
c++
}
}
return
}
// get returns an item from the pool.
// A call will block if no items are available.
func (s *slots) get() int {
for {
for i := 0; i < len(s.slots); i++ {
// this looks silly, but by simple benchmarks it looks like this if still faster since CompareAndSwap is a relatively slow operation
a := atomic.LoadUint64(&s.slots[i].v)
if a == 0 && atomic.CompareAndSwapUint64(&s.slots[i].v, 0, 1) {
return i
}
}
runtime.Gosched()
}
}
// put marks item i as available again.
func (s *slots) put(i int) {
atomic.StoreUint64(&s.slots[i].v, 0)
}