This repository has been archived by the owner on May 29, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathstack.go
108 lines (95 loc) · 2.07 KB
/
stack.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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// +build !race
package synapse
import (
"github.com/tinylib/spin"
)
// this file is just defines a thread-safe
// stack to use as a free-list for *connWrapper
// and *waiter structures, since they are allocated
// and de-allocated frequently and predictably.
//
// we statically allocate 'arenaSize' waiters
// and connWrappers in contiguous blocks, and
// then create a LIFO out of them during
// initialization. if we run out of elements
// in the stack, we fall back to using the
// heap. wrappers are heap-allocated if
// c.next == c, and waiters are heap allocated
// if (*waiter).static == false.
const arenaSize = 512
var (
waiters waitStack
wrappers connStack
waiterSlab [arenaSize]waiter
wrapperSlab [arenaSize]connWrapper
)
func init() {
// set up the pointers and lock
// the waiter semaphores
waiterSlab[0].static = true
for i := 0; i < (arenaSize - 1); i++ {
waiterSlab[i].next = &waiterSlab[i+1]
waiterSlab[i+1].static = true
wrapperSlab[i].next = &wrapperSlab[i+1]
}
waiters.top = &waiterSlab[0]
wrappers.top = &wrapperSlab[0]
}
type connStack struct {
top *connWrapper
lock uint32
}
type waitStack struct {
top *waiter
lock uint32
}
func (s *connStack) pop() (ptr *connWrapper) {
spin.Lock(&s.lock)
if s.top != nil {
ptr, s.top = s.top, s.top.next
spin.Unlock(&s.lock)
return
}
spin.Unlock(&s.lock)
ptr = &connWrapper{}
ptr.next = ptr
return
}
func (s *connStack) push(ptr *connWrapper) {
if ptr.next == ptr {
return
}
spin.Lock(&s.lock)
s.top, ptr.next = ptr, s.top
spin.Unlock(&s.lock)
return
}
// the following should always hold:
// - ptr.next = nil
// - ptr.parent = c
// - ptr.done is Lock()ed
func (s *waitStack) pop(c *Client) (ptr *waiter) {
spin.Lock(&s.lock)
if s.top != nil {
ptr, s.top = s.top, s.top.next
spin.Unlock(&s.lock)
ptr.parent = c
ptr.next = nil
return
}
spin.Unlock(&s.lock)
ptr = &waiter{}
ptr.parent = c
return
}
func (s *waitStack) push(ptr *waiter) {
ptr.parent = nil
ptr.err = nil
if !ptr.static {
return
}
spin.Lock(&s.lock)
s.top, ptr.next = ptr, s.top
spin.Unlock(&s.lock)
return
}