1
2
3
4
5
6
7
8
9 package oldtrace
10
11 import "errors"
12
13 type orderEvent struct {
14 ev Event
15 proc *proc
16 }
17
18 type gStatus int
19
20 type gState struct {
21 seq uint64
22 status gStatus
23 }
24
25 const (
26 gDead gStatus = iota
27 gRunnable
28 gRunning
29 gWaiting
30
31 unordered = ^uint64(0)
32 garbage = ^uint64(0) - 1
33 noseq = ^uint64(0)
34 seqinc = ^uint64(0) - 1
35 )
36
37
38
39 func stateTransition(ev *Event) (g uint64, init, next gState) {
40
41
42 switch ev.Type {
43 case EvGoCreate:
44 g = ev.Args[0]
45 init = gState{0, gDead}
46 next = gState{1, gRunnable}
47 return
48 case EvGoWaiting, EvGoInSyscall:
49 g = ev.G
50 init = gState{1, gRunnable}
51 next = gState{2, gWaiting}
52 return
53 case EvGoStart, EvGoStartLabel:
54 g = ev.G
55 init = gState{ev.Args[1], gRunnable}
56 next = gState{ev.Args[1] + 1, gRunning}
57 return
58 case EvGoStartLocal:
59
60
61
62
63
64
65 g = ev.G
66 init = gState{noseq, gRunnable}
67 next = gState{seqinc, gRunning}
68 return
69 case EvGoBlock, EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect,
70 EvGoBlockSync, EvGoBlockCond, EvGoBlockNet, EvGoSleep,
71 EvGoSysBlock, EvGoBlockGC:
72 g = ev.G
73 init = gState{noseq, gRunning}
74 next = gState{noseq, gWaiting}
75 return
76 case EvGoSched, EvGoPreempt:
77 g = ev.G
78 init = gState{noseq, gRunning}
79 next = gState{noseq, gRunnable}
80 return
81 case EvGoUnblock, EvGoSysExit:
82 g = ev.Args[0]
83 init = gState{ev.Args[1], gWaiting}
84 next = gState{ev.Args[1] + 1, gRunnable}
85 return
86 case EvGoUnblockLocal, EvGoSysExitLocal:
87 g = ev.Args[0]
88 init = gState{noseq, gWaiting}
89 next = gState{seqinc, gRunnable}
90 return
91 case EvGCStart:
92 g = garbage
93 init = gState{ev.Args[0], gDead}
94 next = gState{ev.Args[0] + 1, gDead}
95 return
96 default:
97
98 g = unordered
99 return
100 }
101 }
102
103 func transitionReady(g uint64, curr, init gState) bool {
104 return g == unordered || (init.seq == noseq || init.seq == curr.seq) && init.status == curr.status
105 }
106
107 func transition(gs map[uint64]gState, g uint64, init, next gState) error {
108 if g == unordered {
109 return nil
110 }
111 curr := gs[g]
112 if !transitionReady(g, curr, init) {
113
114
115 return errors.New("encountered impossible goroutine state transition")
116 }
117 switch next.seq {
118 case noseq:
119 next.seq = curr.seq
120 case seqinc:
121 next.seq = curr.seq + 1
122 }
123 gs[g] = next
124 return nil
125 }
126
127 type orderEventList []orderEvent
128
129 func (l *orderEventList) Less(i, j int) bool {
130 return (*l)[i].ev.Ts < (*l)[j].ev.Ts
131 }
132
133 type eventList []Event
134
135 func (l *eventList) Len() int {
136 return len(*l)
137 }
138
139 func (l *eventList) Less(i, j int) bool {
140 return (*l)[i].Ts < (*l)[j].Ts
141 }
142
143 func (l *eventList) Swap(i, j int) {
144 (*l)[i], (*l)[j] = (*l)[j], (*l)[i]
145 }
146
147 func (h *orderEventList) Push(x orderEvent) {
148 *h = append(*h, x)
149 heapUp(h, len(*h)-1)
150 }
151
152 func (h *orderEventList) Pop() orderEvent {
153 n := len(*h) - 1
154 (*h)[0], (*h)[n] = (*h)[n], (*h)[0]
155 heapDown(h, 0, n)
156 x := (*h)[len(*h)-1]
157 *h = (*h)[:len(*h)-1]
158 return x
159 }
160
161 func heapUp(h *orderEventList, j int) {
162 for {
163 i := (j - 1) / 2
164 if i == j || !h.Less(j, i) {
165 break
166 }
167 (*h)[i], (*h)[j] = (*h)[j], (*h)[i]
168 j = i
169 }
170 }
171
172 func heapDown(h *orderEventList, i0, n int) bool {
173 i := i0
174 for {
175 j1 := 2*i + 1
176 if j1 >= n || j1 < 0 {
177 break
178 }
179 j := j1
180 if j2 := j1 + 1; j2 < n && h.Less(j2, j1) {
181 j = j2
182 }
183 if !h.Less(j, i) {
184 break
185 }
186 (*h)[i], (*h)[j] = (*h)[j], (*h)[i]
187 i = j
188 }
189 return i > i0
190 }
191
View as plain text