File tree Expand file tree Collapse file tree 2 files changed +85
-0
lines changed Expand file tree Collapse file tree 2 files changed +85
-0
lines changed Original file line number Diff line number Diff line change 1+ package sync
2+
3+ import "internal/task"
4+
5+ type Cond struct {
6+ L Locker
7+
8+ unlocking * earlySignal
9+ blocked task.Stack
10+ }
11+
12+ // earlySignal is a type used to implement a stack for signalling waiters while they are unlocking.
13+ type earlySignal struct {
14+ next * earlySignal
15+
16+ signaled bool
17+ }
18+
19+ func (c * Cond ) trySignal () bool {
20+ // Pop a blocked task off of the stack, and schedule it if applicable.
21+ t := c .blocked .Pop ()
22+ if t != nil {
23+ scheduleTask (t )
24+ return true
25+ }
26+
27+ // If there any tasks which are currently unlocking, signal one.
28+ if c .unlocking != nil {
29+ c .unlocking .signaled = true
30+ c .unlocking = c .unlocking .next
31+ return true
32+ }
33+
34+ // There was nothing to signal.
35+ return false
36+ }
37+
38+ func (c * Cond ) Signal () {
39+ c .trySignal ()
40+ }
41+
42+ func (c * Cond ) Broadcast () {
43+ // Signal everything.
44+ for c .trySignal () {
45+ }
46+ }
47+
48+ func (c * Cond ) Wait () {
49+ // Add an earlySignal frame to the stack so we can be signalled while unlocking.
50+ early := earlySignal {
51+ next : c .unlocking ,
52+ }
53+ c .unlocking = & early
54+
55+ // Temporarily unlock L.
56+ c .L .Unlock ()
57+ defer c .L .Lock ()
58+
59+ // If we were signaled while unlocking, immediately complete.
60+ if early .signaled {
61+ return
62+ }
63+
64+ // Remove the earlySignal frame.
65+ if c .unlocking == & early {
66+ c .unlocking = early .next
67+ } else {
68+ // Something else happened after the unlock - the earlySignal is somewhere in the middle.
69+ // This would be faster but less space-efficient if it were a doubly linked list.
70+ prev := c .unlocking
71+ for prev .next != & early {
72+ prev = prev .next
73+ }
74+ prev .next = early .next
75+ }
76+
77+ // Wait for a signal.
78+ c .blocked .Push (task .Current ())
79+ task .Pause ()
80+ }
Original file line number Diff line number Diff line change @@ -69,3 +69,8 @@ func (rw *RWMutex) RUnlock() {
6969 rw .m .Unlock ()
7070 }
7171}
72+
73+ type Locker interface {
74+ Lock ()
75+ Unlock ()
76+ }
You can’t perform that action at this time.
0 commit comments