1
2
3
4
5 package trace
6
7 import (
8 "fmt"
9 "slices"
10 "strings"
11
12 "internal/trace/tracev2"
13 "internal/trace/version"
14 )
15
16
17
18
19
20
21
22
23 type ordering struct {
24 traceVer version.Version
25 gStates map[GoID]*gState
26 pStates map[ProcID]*pState
27 mStates map[ThreadID]*mState
28 activeTasks map[TaskID]taskState
29 gcSeq uint64
30 gcState gcState
31 initialGen uint64
32 queue queue[Event]
33 }
34
35
36
37
38
39
40
41
42
43
44
45
46
47 func (o *ordering) Advance(ev *baseEvent, evt *evTable, m ThreadID, gen uint64) (bool, error) {
48 if o.initialGen == 0 {
49
50 o.initialGen = gen
51 }
52
53 var curCtx, newCtx schedCtx
54 curCtx.M = m
55 newCtx.M = m
56
57 var ms *mState
58 if m == NoThread {
59 curCtx.P = NoProc
60 curCtx.G = NoGoroutine
61 newCtx = curCtx
62 } else {
63
64 var ok bool
65 ms, ok = o.mStates[m]
66 if !ok {
67 ms = &mState{
68 g: NoGoroutine,
69 p: NoProc,
70 }
71 o.mStates[m] = ms
72 }
73 curCtx.P = ms.p
74 curCtx.G = ms.g
75 newCtx = curCtx
76 }
77
78 f := orderingDispatch[ev.typ]
79 if f == nil {
80 return false, fmt.Errorf("bad event type found while ordering: %v", ev.typ)
81 }
82 newCtx, ok, err := f(o, ev, evt, m, gen, curCtx)
83 if err == nil && ok && ms != nil {
84
85 ms.p = newCtx.P
86 ms.g = newCtx.G
87 }
88 return ok, err
89 }
90
91 func (o *ordering) evName(typ tracev2.EventType) string {
92 return o.traceVer.EventName(typ)
93 }
94
95 type orderingHandleFunc func(o *ordering, ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error)
96
97 var orderingDispatch = [256]orderingHandleFunc{
98
99 tracev2.EvProcsChange: (*ordering).advanceAnnotation,
100 tracev2.EvProcStart: (*ordering).advanceProcStart,
101 tracev2.EvProcStop: (*ordering).advanceProcStop,
102 tracev2.EvProcSteal: (*ordering).advanceProcSteal,
103 tracev2.EvProcStatus: (*ordering).advanceProcStatus,
104
105
106 tracev2.EvGoCreate: (*ordering).advanceGoCreate,
107 tracev2.EvGoCreateSyscall: (*ordering).advanceGoCreateSyscall,
108 tracev2.EvGoStart: (*ordering).advanceGoStart,
109 tracev2.EvGoDestroy: (*ordering).advanceGoStopExec,
110 tracev2.EvGoDestroySyscall: (*ordering).advanceGoDestroySyscall,
111 tracev2.EvGoStop: (*ordering).advanceGoStopExec,
112 tracev2.EvGoBlock: (*ordering).advanceGoStopExec,
113 tracev2.EvGoUnblock: (*ordering).advanceGoUnblock,
114 tracev2.EvGoSyscallBegin: (*ordering).advanceGoSyscallBegin,
115 tracev2.EvGoSyscallEnd: (*ordering).advanceGoSyscallEnd,
116 tracev2.EvGoSyscallEndBlocked: (*ordering).advanceGoSyscallEndBlocked,
117 tracev2.EvGoStatus: (*ordering).advanceGoStatus,
118
119
120 tracev2.EvSTWBegin: (*ordering).advanceGoRangeBegin,
121 tracev2.EvSTWEnd: (*ordering).advanceGoRangeEnd,
122
123
124 tracev2.EvGCActive: (*ordering).advanceGCActive,
125 tracev2.EvGCBegin: (*ordering).advanceGCBegin,
126 tracev2.EvGCEnd: (*ordering).advanceGCEnd,
127 tracev2.EvGCSweepActive: (*ordering).advanceGCSweepActive,
128 tracev2.EvGCSweepBegin: (*ordering).advanceGCSweepBegin,
129 tracev2.EvGCSweepEnd: (*ordering).advanceGCSweepEnd,
130 tracev2.EvGCMarkAssistActive: (*ordering).advanceGoRangeActive,
131 tracev2.EvGCMarkAssistBegin: (*ordering).advanceGoRangeBegin,
132 tracev2.EvGCMarkAssistEnd: (*ordering).advanceGoRangeEnd,
133 tracev2.EvHeapAlloc: (*ordering).advanceHeapMetric,
134 tracev2.EvHeapGoal: (*ordering).advanceHeapMetric,
135
136
137 tracev2.EvGoLabel: (*ordering).advanceAnnotation,
138 tracev2.EvUserTaskBegin: (*ordering).advanceUserTaskBegin,
139 tracev2.EvUserTaskEnd: (*ordering).advanceUserTaskEnd,
140 tracev2.EvUserRegionBegin: (*ordering).advanceUserRegionBegin,
141 tracev2.EvUserRegionEnd: (*ordering).advanceUserRegionEnd,
142 tracev2.EvUserLog: (*ordering).advanceAnnotation,
143
144
145 tracev2.EvGoSwitch: (*ordering).advanceGoSwitch,
146 tracev2.EvGoSwitchDestroy: (*ordering).advanceGoSwitch,
147 tracev2.EvGoCreateBlocked: (*ordering).advanceGoCreate,
148
149
150 tracev2.EvGoStatusStack: (*ordering).advanceGoStatus,
151
152
153
154
155 tracev2.EvSpan: (*ordering).advanceAllocFree,
156 tracev2.EvSpanAlloc: (*ordering).advanceAllocFree,
157 tracev2.EvSpanFree: (*ordering).advanceAllocFree,
158
159
160 tracev2.EvHeapObject: (*ordering).advanceAllocFree,
161 tracev2.EvHeapObjectAlloc: (*ordering).advanceAllocFree,
162 tracev2.EvHeapObjectFree: (*ordering).advanceAllocFree,
163
164
165 tracev2.EvGoroutineStack: (*ordering).advanceAllocFree,
166 tracev2.EvGoroutineStackAlloc: (*ordering).advanceAllocFree,
167 tracev2.EvGoroutineStackFree: (*ordering).advanceAllocFree,
168 }
169
170 func (o *ordering) advanceProcStatus(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
171 pid := ProcID(ev.args[0])
172 status := tracev2.ProcStatus(ev.args[1])
173 if int(status) >= len(tracev2ProcStatus2ProcState) {
174 return curCtx, false, fmt.Errorf("invalid status for proc %d: %d", pid, status)
175 }
176 oldState := tracev2ProcStatus2ProcState[status]
177 if s, ok := o.pStates[pid]; ok {
178 if status == tracev2.ProcSyscallAbandoned && s.status == tracev2.ProcSyscall {
179
180
181
182 oldState = ProcRunning
183 ev.args[1] = uint64(tracev2.ProcSyscall)
184 } else if status == tracev2.ProcSyscallAbandoned && s.status == tracev2.ProcSyscallAbandoned {
185
186
187
188 oldState = ProcIdle
189 ev.args[1] = uint64(tracev2.ProcSyscallAbandoned)
190 } else if s.status != status {
191 return curCtx, false, fmt.Errorf("inconsistent status for proc %d: old %v vs. new %v", pid, s.status, status)
192 }
193 s.seq = makeSeq(gen, 0)
194 } else {
195 o.pStates[pid] = &pState{id: pid, status: status, seq: makeSeq(gen, 0)}
196 if gen == o.initialGen {
197 oldState = ProcUndetermined
198 } else {
199 oldState = ProcNotExist
200 }
201 }
202 ev.extra(version.Go122)[0] = uint64(oldState)
203
204
205 newCtx := curCtx
206 if status == tracev2.ProcRunning || status == tracev2.ProcSyscall {
207 newCtx.P = pid
208 }
209
210
211
212
213
214
215 if status == tracev2.ProcSyscallAbandoned && oldState == ProcRunning {
216
217 found := false
218 for mid, ms := range o.mStates {
219 if ms.p == pid {
220 curCtx.M = mid
221 curCtx.P = pid
222 curCtx.G = ms.g
223 found = true
224 }
225 }
226 if !found {
227 return curCtx, false, fmt.Errorf("failed to find sched context for proc %d that's about to be stolen", pid)
228 }
229 }
230 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
231 return newCtx, true, nil
232 }
233
234 func (o *ordering) advanceProcStart(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
235 pid := ProcID(ev.args[0])
236 seq := makeSeq(gen, ev.args[1])
237
238
239
240
241 state, ok := o.pStates[pid]
242 if !ok || state.status != tracev2.ProcIdle || !seq.succeeds(state.seq) || curCtx.P != NoProc {
243
244
245
246
247
248 return curCtx, false, nil
249 }
250
251
252
253 reqs := schedReqs{M: mustHave, P: mustNotHave, G: mayHave}
254 if err := validateCtx(curCtx, reqs); err != nil {
255 return curCtx, false, err
256 }
257 state.status = tracev2.ProcRunning
258 state.seq = seq
259 newCtx := curCtx
260 newCtx.P = pid
261 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
262 return newCtx, true, nil
263 }
264
265 func (o *ordering) advanceProcStop(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
266
267
268
269
270
271
272
273
274
275 state, ok := o.pStates[curCtx.P]
276 if !ok {
277 return curCtx, false, fmt.Errorf("event %s for proc (%v) that doesn't exist", o.evName(ev.typ), curCtx.P)
278 }
279 if state.status != tracev2.ProcRunning && state.status != tracev2.ProcSyscall {
280 return curCtx, false, fmt.Errorf("%s event for proc that's not %s or %s", o.evName(ev.typ), tracev2.ProcRunning, tracev2.ProcSyscall)
281 }
282 reqs := schedReqs{M: mustHave, P: mustHave, G: mayHave}
283 if err := validateCtx(curCtx, reqs); err != nil {
284 return curCtx, false, err
285 }
286 state.status = tracev2.ProcIdle
287 newCtx := curCtx
288 newCtx.P = NoProc
289 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
290 return newCtx, true, nil
291 }
292
293 func (o *ordering) advanceProcSteal(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
294 pid := ProcID(ev.args[0])
295 seq := makeSeq(gen, ev.args[1])
296 state, ok := o.pStates[pid]
297 if !ok || (state.status != tracev2.ProcSyscall && state.status != tracev2.ProcSyscallAbandoned) || !seq.succeeds(state.seq) {
298
299
300
301 return curCtx, false, nil
302 }
303
304 reqs := schedReqs{M: mustHave, P: mayHave, G: mayHave}
305 if err := validateCtx(curCtx, reqs); err != nil {
306 return curCtx, false, err
307 }
308
309
310
311
312
313
314 oldStatus := state.status
315 ev.extra(version.Go122)[0] = uint64(oldStatus)
316
317
318 state.status = tracev2.ProcIdle
319 state.seq = seq
320
321
322
323 if oldStatus == tracev2.ProcSyscallAbandoned {
324 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
325 return curCtx, true, nil
326 }
327
328
329 mid := ThreadID(ev.args[2])
330
331 newCtx := curCtx
332 if mid == curCtx.M {
333
334 if curCtx.P != pid {
335 return curCtx, false, fmt.Errorf("tried to self-steal proc %d (thread %d), but got proc %d instead", pid, mid, curCtx.P)
336 }
337 newCtx.P = NoProc
338 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
339 return newCtx, true, nil
340 }
341
342
343 mState, ok := o.mStates[mid]
344 if !ok {
345 return curCtx, false, fmt.Errorf("stole proc from non-existent thread %d", mid)
346 }
347
348
349 if mState.p != pid {
350 return curCtx, false, fmt.Errorf("tried to steal proc %d from thread %d, but got proc %d instead", pid, mid, mState.p)
351 }
352
353
354
355
356
357
358
359 mState.p = NoProc
360 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
361 return newCtx, true, nil
362 }
363
364 func (o *ordering) advanceGoStatus(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
365 gid := GoID(ev.args[0])
366 mid := ThreadID(ev.args[1])
367 status := tracev2.GoStatus(ev.args[2])
368
369 if int(status) >= len(tracev2GoStatus2GoState) {
370 return curCtx, false, fmt.Errorf("invalid status for goroutine %d: %d", gid, status)
371 }
372 oldState := tracev2GoStatus2GoState[status]
373 if s, ok := o.gStates[gid]; ok {
374 if s.status != status {
375 return curCtx, false, fmt.Errorf("inconsistent status for goroutine %d: old %v vs. new %v", gid, s.status, status)
376 }
377 s.seq = makeSeq(gen, 0)
378 } else if gen == o.initialGen {
379
380 o.gStates[gid] = &gState{id: gid, status: status, seq: makeSeq(gen, 0)}
381 oldState = GoUndetermined
382 } else {
383 return curCtx, false, fmt.Errorf("found goroutine status for new goroutine after the first generation: id=%v status=%v", gid, status)
384 }
385 ev.args[2] = uint64(oldState)<<32 | uint64(status)
386
387 newCtx := curCtx
388 switch status {
389 case tracev2.GoRunning:
390
391 newCtx.G = gid
392 case tracev2.GoSyscall:
393 if mid == NoThread {
394 return curCtx, false, fmt.Errorf("found goroutine %d in syscall without a thread", gid)
395 }
396
397
398
399 if mid == curCtx.M {
400 if gen != o.initialGen && curCtx.G != gid {
401
402
403
404
405 return curCtx, false, fmt.Errorf("inconsistent thread for syscalling goroutine %d: thread has goroutine %d", gid, curCtx.G)
406 }
407 newCtx.G = gid
408 break
409 }
410
411
412
413
414
415 ms, ok := o.mStates[mid]
416 if ok {
417
418
419 if ms.g != gid {
420
421 return curCtx, false, fmt.Errorf("inconsistent thread for syscalling goroutine %d: thread has goroutine %d", gid, ms.g)
422 }
423
424
425 curCtx.G = ms.g
426 } else if !ok {
427
428
429
430 o.mStates[mid] = &mState{g: gid, p: NoProc}
431
432
433 }
434
435 curCtx.M = mid
436 }
437 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
438 return newCtx, true, nil
439 }
440
441 func (o *ordering) advanceGoCreate(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
442
443
444 reqs := schedReqs{M: mustHave, P: mustHave, G: mayHave}
445 if err := validateCtx(curCtx, reqs); err != nil {
446 return curCtx, false, err
447 }
448
449 if state, ok := o.gStates[curCtx.G]; ok && state.status != tracev2.GoRunning {
450 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", o.evName(ev.typ), GoRunning)
451 }
452
453 newgid := GoID(ev.args[0])
454 if _, ok := o.gStates[newgid]; ok {
455 return curCtx, false, fmt.Errorf("tried to create goroutine (%v) that already exists", newgid)
456 }
457 status := tracev2.GoRunnable
458 if ev.typ == tracev2.EvGoCreateBlocked {
459 status = tracev2.GoWaiting
460 }
461 o.gStates[newgid] = &gState{id: newgid, status: status, seq: makeSeq(gen, 0)}
462 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
463 return curCtx, true, nil
464 }
465
466 func (o *ordering) advanceGoStopExec(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
467
468
469
470 if err := validateCtx(curCtx, userGoReqs); err != nil {
471 return curCtx, false, err
472 }
473 state, ok := o.gStates[curCtx.G]
474 if !ok {
475 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", o.evName(ev.typ), curCtx.G)
476 }
477 if state.status != tracev2.GoRunning {
478 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", o.evName(ev.typ), GoRunning)
479 }
480
481
482 newCtx := curCtx
483 switch ev.typ {
484 case tracev2.EvGoDestroy:
485
486 delete(o.gStates, curCtx.G)
487 newCtx.G = NoGoroutine
488 case tracev2.EvGoStop:
489
490 state.status = tracev2.GoRunnable
491 newCtx.G = NoGoroutine
492 case tracev2.EvGoBlock:
493
494 state.status = tracev2.GoWaiting
495 newCtx.G = NoGoroutine
496 }
497 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
498 return newCtx, true, nil
499 }
500
501 func (o *ordering) advanceGoStart(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
502 gid := GoID(ev.args[0])
503 seq := makeSeq(gen, ev.args[1])
504 state, ok := o.gStates[gid]
505 if !ok || state.status != tracev2.GoRunnable || !seq.succeeds(state.seq) {
506
507
508
509 return curCtx, false, nil
510 }
511
512 reqs := schedReqs{M: mustHave, P: mustHave, G: mustNotHave}
513 if err := validateCtx(curCtx, reqs); err != nil {
514 return curCtx, false, err
515 }
516 state.status = tracev2.GoRunning
517 state.seq = seq
518 newCtx := curCtx
519 newCtx.G = gid
520 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
521 return newCtx, true, nil
522 }
523
524 func (o *ordering) advanceGoUnblock(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
525
526 gid := GoID(ev.args[0])
527 seq := makeSeq(gen, ev.args[1])
528 state, ok := o.gStates[gid]
529 if !ok || state.status != tracev2.GoWaiting || !seq.succeeds(state.seq) {
530
531
532
533 return curCtx, false, nil
534 }
535 state.status = tracev2.GoRunnable
536 state.seq = seq
537
538
539 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
540 return curCtx, true, nil
541 }
542
543 func (o *ordering) advanceGoSwitch(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
544
545
546
547
548
549
550
551
552
553 if err := validateCtx(curCtx, userGoReqs); err != nil {
554 return curCtx, false, err
555 }
556 curGState, ok := o.gStates[curCtx.G]
557 if !ok {
558 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", o.evName(ev.typ), curCtx.G)
559 }
560 if curGState.status != tracev2.GoRunning {
561 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", o.evName(ev.typ), GoRunning)
562 }
563 nextg := GoID(ev.args[0])
564 seq := makeSeq(gen, ev.args[1])
565 nextGState, ok := o.gStates[nextg]
566 if !ok || nextGState.status != tracev2.GoWaiting || !seq.succeeds(nextGState.seq) {
567
568
569
570 return curCtx, false, nil
571 }
572 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
573
574
575
576
577 switch ev.typ {
578 case tracev2.EvGoSwitch:
579
580 curGState.status = tracev2.GoWaiting
581
582
583
584 o.queue.push(makeEvent(evt, curCtx, tracev2.EvGoBlock, ev.time, 0 , 0 ))
585 case tracev2.EvGoSwitchDestroy:
586
587 delete(o.gStates, curCtx.G)
588
589
590 o.queue.push(makeEvent(evt, curCtx, tracev2.EvGoDestroy, ev.time))
591 }
592
593 nextGState.status = tracev2.GoRunning
594 nextGState.seq = seq
595 newCtx := curCtx
596 newCtx.G = nextg
597
598
599 startCtx := curCtx
600 startCtx.G = NoGoroutine
601 o.queue.push(makeEvent(evt, startCtx, tracev2.EvGoStart, ev.time, uint64(nextg), ev.args[1]))
602 return newCtx, true, nil
603 }
604
605 func (o *ordering) advanceGoSyscallBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
606
607
608 if err := validateCtx(curCtx, userGoReqs); err != nil {
609 return curCtx, false, err
610 }
611 state, ok := o.gStates[curCtx.G]
612 if !ok {
613 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", o.evName(ev.typ), curCtx.G)
614 }
615 if state.status != tracev2.GoRunning {
616 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", o.evName(ev.typ), GoRunning)
617 }
618
619 state.status = tracev2.GoSyscall
620 pState, ok := o.pStates[curCtx.P]
621 if !ok {
622 return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, o.evName(ev.typ))
623 }
624 pState.status = tracev2.ProcSyscall
625
626
627
628
629
630
631
632
633
634
635
636 pSeq := makeSeq(gen, ev.args[0])
637 if !pSeq.succeeds(pState.seq) {
638 return curCtx, false, fmt.Errorf("failed to advance %s: can't make sequence: %s -> %s", o.evName(ev.typ), pState.seq, pSeq)
639 }
640 pState.seq = pSeq
641 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
642 return curCtx, true, nil
643 }
644
645 func (o *ordering) advanceGoSyscallEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
646
647
648
649 if err := validateCtx(curCtx, userGoReqs); err != nil {
650 return curCtx, false, err
651 }
652 state, ok := o.gStates[curCtx.G]
653 if !ok {
654 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", o.evName(ev.typ), curCtx.G)
655 }
656 if state.status != tracev2.GoSyscall {
657 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", o.evName(ev.typ), GoRunning)
658 }
659 state.status = tracev2.GoRunning
660
661
662 pState, ok := o.pStates[curCtx.P]
663 if !ok {
664 return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, o.evName(ev.typ))
665 }
666 if pState.status != tracev2.ProcSyscall {
667 return curCtx, false, fmt.Errorf("expected proc %d in state %v, but got %v instead", curCtx.P, tracev2.ProcSyscall, pState.status)
668 }
669 pState.status = tracev2.ProcRunning
670 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
671 return curCtx, true, nil
672 }
673
674 func (o *ordering) advanceGoSyscallEndBlocked(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
675
676
677
678
679
680
681
682
683
684
685 if curCtx.P != NoProc {
686 pState, ok := o.pStates[curCtx.P]
687 if !ok {
688 return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, o.evName(ev.typ))
689 }
690 if pState.status == tracev2.ProcSyscall {
691 return curCtx, false, nil
692 }
693 }
694
695
696 if err := validateCtx(curCtx, schedReqs{M: mustHave, P: mayHave, G: mustHave}); err != nil {
697 return curCtx, false, err
698 }
699 state, ok := o.gStates[curCtx.G]
700 if !ok {
701 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", o.evName(ev.typ), curCtx.G)
702 }
703 if state.status != tracev2.GoSyscall {
704 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", o.evName(ev.typ), GoRunning)
705 }
706 newCtx := curCtx
707 newCtx.G = NoGoroutine
708 state.status = tracev2.GoRunnable
709 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
710 return newCtx, true, nil
711 }
712
713 func (o *ordering) advanceGoCreateSyscall(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
714
715
716
717 if err := validateCtx(curCtx, schedReqs{M: mustHave, P: mayHave, G: mustNotHave}); err != nil {
718 return curCtx, false, err
719 }
720
721 newgid := GoID(ev.args[0])
722 if _, ok := o.gStates[newgid]; ok {
723 return curCtx, false, fmt.Errorf("tried to create goroutine (%v) in syscall that already exists", newgid)
724 }
725 o.gStates[newgid] = &gState{id: newgid, status: tracev2.GoSyscall, seq: makeSeq(gen, 0)}
726
727 newCtx := curCtx
728 newCtx.G = newgid
729 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
730 return newCtx, true, nil
731 }
732
733 func (o *ordering) advanceGoDestroySyscall(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750 if err := validateCtx(curCtx, schedReqs{M: mustHave, P: mayHave, G: mustHave}); err != nil {
751 return curCtx, false, err
752 }
753
754 state, ok := o.gStates[curCtx.G]
755 if !ok {
756 return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", o.evName(ev.typ), curCtx.G)
757 }
758 if state.status != tracev2.GoSyscall {
759 return curCtx, false, fmt.Errorf("%s event for goroutine that's not %v", o.evName(ev.typ), GoSyscall)
760 }
761
762 delete(o.gStates, curCtx.G)
763 newCtx := curCtx
764 newCtx.G = NoGoroutine
765
766
767 if curCtx.P != NoProc {
768 pState, ok := o.pStates[curCtx.P]
769 if !ok {
770 return curCtx, false, fmt.Errorf("found invalid proc %d during %s", curCtx.P, o.evName(ev.typ))
771 }
772 if pState.status != tracev2.ProcSyscall {
773 return curCtx, false, fmt.Errorf("proc %d in unexpected state %s during %s", curCtx.P, pState.status, o.evName(ev.typ))
774 }
775
776 pState.status = tracev2.ProcSyscallAbandoned
777 newCtx.P = NoProc
778
779
780 extra := makeEvent(evt, curCtx, tracev2.EvProcSteal, ev.time, uint64(curCtx.P))
781 extra.base.extra(version.Go122)[0] = uint64(tracev2.ProcSyscall)
782 o.queue.push(extra)
783 }
784 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
785 return newCtx, true, nil
786 }
787
788 func (o *ordering) advanceUserTaskBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
789
790
791
792
793
794
795
796 id := TaskID(ev.args[0])
797 if _, ok := o.activeTasks[id]; ok {
798 return curCtx, false, fmt.Errorf("task ID conflict: %d", id)
799 }
800
801
802 parentID := TaskID(ev.args[1])
803 if parentID == BackgroundTask {
804
805
806
807 parentID = NoTask
808 ev.args[1] = uint64(NoTask)
809 }
810
811
812
813 nameID := stringID(ev.args[2])
814 name, ok := evt.strings.get(nameID)
815 if !ok {
816 return curCtx, false, fmt.Errorf("invalid string ID %v for %v event", nameID, ev.typ)
817 }
818 o.activeTasks[id] = taskState{name: name, parentID: parentID}
819 if err := validateCtx(curCtx, userGoReqs); err != nil {
820 return curCtx, false, err
821 }
822 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
823 return curCtx, true, nil
824 }
825
826 func (o *ordering) advanceUserTaskEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
827 id := TaskID(ev.args[0])
828 if ts, ok := o.activeTasks[id]; ok {
829
830
831
832 ev.extra(version.Go122)[0] = uint64(ts.parentID)
833 ev.extra(version.Go122)[1] = uint64(evt.addExtraString(ts.name))
834 delete(o.activeTasks, id)
835 } else {
836
837 ev.extra(version.Go122)[0] = uint64(NoTask)
838 ev.extra(version.Go122)[1] = uint64(evt.addExtraString(""))
839 }
840 if err := validateCtx(curCtx, userGoReqs); err != nil {
841 return curCtx, false, err
842 }
843 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
844 return curCtx, true, nil
845 }
846
847 func (o *ordering) advanceUserRegionBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
848 if err := validateCtx(curCtx, userGoReqs); err != nil {
849 return curCtx, false, err
850 }
851 tid := TaskID(ev.args[0])
852 nameID := stringID(ev.args[1])
853 name, ok := evt.strings.get(nameID)
854 if !ok {
855 return curCtx, false, fmt.Errorf("invalid string ID %v for %v event", nameID, ev.typ)
856 }
857 gState, ok := o.gStates[curCtx.G]
858 if !ok {
859 return curCtx, false, fmt.Errorf("encountered EvUserRegionBegin without known state for current goroutine %d", curCtx.G)
860 }
861 if err := gState.beginRegion(userRegion{tid, name}); err != nil {
862 return curCtx, false, err
863 }
864 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
865 return curCtx, true, nil
866 }
867
868 func (o *ordering) advanceUserRegionEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
869 if err := validateCtx(curCtx, userGoReqs); err != nil {
870 return curCtx, false, err
871 }
872 tid := TaskID(ev.args[0])
873 nameID := stringID(ev.args[1])
874 name, ok := evt.strings.get(nameID)
875 if !ok {
876 return curCtx, false, fmt.Errorf("invalid string ID %v for %v event", nameID, ev.typ)
877 }
878 gState, ok := o.gStates[curCtx.G]
879 if !ok {
880 return curCtx, false, fmt.Errorf("encountered EvUserRegionEnd without known state for current goroutine %d", curCtx.G)
881 }
882 if err := gState.endRegion(userRegion{tid, name}); err != nil {
883 return curCtx, false, err
884 }
885 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
886 return curCtx, true, nil
887 }
888
889
890
891
892
893
894
895
896 func (o *ordering) advanceGCActive(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
897 seq := ev.args[0]
898 if gen == o.initialGen {
899 if o.gcState != gcUndetermined {
900 return curCtx, false, fmt.Errorf("GCActive in the first generation isn't first GC event")
901 }
902 o.gcSeq = seq
903 o.gcState = gcRunning
904 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
905 return curCtx, true, nil
906 }
907 if seq != o.gcSeq+1 {
908
909 return curCtx, false, nil
910 }
911 if o.gcState != gcRunning {
912 return curCtx, false, fmt.Errorf("encountered GCActive while GC was not in progress")
913 }
914 o.gcSeq = seq
915 if err := validateCtx(curCtx, userGoReqs); err != nil {
916 return curCtx, false, err
917 }
918 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
919 return curCtx, true, nil
920 }
921
922 func (o *ordering) advanceGCBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
923 seq := ev.args[0]
924 if o.gcState == gcUndetermined {
925 o.gcSeq = seq
926 o.gcState = gcRunning
927 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
928 return curCtx, true, nil
929 }
930 if seq != o.gcSeq+1 {
931
932 return curCtx, false, nil
933 }
934 if o.gcState == gcRunning {
935 return curCtx, false, fmt.Errorf("encountered GCBegin while GC was already in progress")
936 }
937 o.gcSeq = seq
938 o.gcState = gcRunning
939 if err := validateCtx(curCtx, userGoReqs); err != nil {
940 return curCtx, false, err
941 }
942 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
943 return curCtx, true, nil
944 }
945
946 func (o *ordering) advanceGCEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
947 seq := ev.args[0]
948 if seq != o.gcSeq+1 {
949
950 return curCtx, false, nil
951 }
952 if o.gcState == gcNotRunning {
953 return curCtx, false, fmt.Errorf("encountered GCEnd when GC was not in progress")
954 }
955 if o.gcState == gcUndetermined {
956 return curCtx, false, fmt.Errorf("encountered GCEnd when GC was in an undetermined state")
957 }
958 o.gcSeq = seq
959 o.gcState = gcNotRunning
960 if err := validateCtx(curCtx, userGoReqs); err != nil {
961 return curCtx, false, err
962 }
963 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
964 return curCtx, true, nil
965 }
966
967 func (o *ordering) advanceAnnotation(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
968
969 if err := validateCtx(curCtx, userGoReqs); err != nil {
970 return curCtx, false, err
971 }
972 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
973 return curCtx, true, nil
974 }
975
976 func (o *ordering) advanceHeapMetric(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
977
978 if err := validateCtx(curCtx, schedReqs{M: mustHave, P: mustHave, G: mayHave}); err != nil {
979 return curCtx, false, err
980 }
981 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
982 return curCtx, true, nil
983 }
984
985 func (o *ordering) advanceGCSweepBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
986
987 if err := validateCtx(curCtx, schedReqs{M: mustHave, P: mustHave, G: mayHave}); err != nil {
988 return curCtx, false, err
989 }
990 if err := o.pStates[curCtx.P].beginRange(makeRangeType(ev.typ, 0)); err != nil {
991 return curCtx, false, err
992 }
993 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
994 return curCtx, true, nil
995 }
996
997 func (o *ordering) advanceGCSweepActive(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
998 pid := ProcID(ev.args[0])
999
1000
1001
1002
1003 pState, ok := o.pStates[pid]
1004 if !ok {
1005 return curCtx, false, fmt.Errorf("encountered GCSweepActive for unknown proc %d", pid)
1006 }
1007 if err := pState.activeRange(makeRangeType(ev.typ, 0), gen == o.initialGen); err != nil {
1008 return curCtx, false, err
1009 }
1010 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
1011 return curCtx, true, nil
1012 }
1013
1014 func (o *ordering) advanceGCSweepEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
1015 if err := validateCtx(curCtx, schedReqs{M: mustHave, P: mustHave, G: mayHave}); err != nil {
1016 return curCtx, false, err
1017 }
1018 _, err := o.pStates[curCtx.P].endRange(ev.typ)
1019 if err != nil {
1020 return curCtx, false, err
1021 }
1022 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
1023 return curCtx, true, nil
1024 }
1025
1026 func (o *ordering) advanceGoRangeBegin(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
1027
1028 if err := validateCtx(curCtx, userGoReqs); err != nil {
1029 return curCtx, false, err
1030 }
1031 desc := stringID(0)
1032 if ev.typ == tracev2.EvSTWBegin {
1033 desc = stringID(ev.args[0])
1034 }
1035 gState, ok := o.gStates[curCtx.G]
1036 if !ok {
1037 return curCtx, false, fmt.Errorf("encountered event of type %d without known state for current goroutine %d", ev.typ, curCtx.G)
1038 }
1039 if err := gState.beginRange(makeRangeType(ev.typ, desc)); err != nil {
1040 return curCtx, false, err
1041 }
1042 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
1043 return curCtx, true, nil
1044 }
1045
1046 func (o *ordering) advanceGoRangeActive(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
1047 gid := GoID(ev.args[0])
1048
1049
1050
1051 gState, ok := o.gStates[gid]
1052 if !ok {
1053 return curCtx, false, fmt.Errorf("uninitialized goroutine %d found during %s", gid, o.evName(ev.typ))
1054 }
1055 if err := gState.activeRange(makeRangeType(ev.typ, 0), gen == o.initialGen); err != nil {
1056 return curCtx, false, err
1057 }
1058 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
1059 return curCtx, true, nil
1060 }
1061
1062 func (o *ordering) advanceGoRangeEnd(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
1063 if err := validateCtx(curCtx, userGoReqs); err != nil {
1064 return curCtx, false, err
1065 }
1066 gState, ok := o.gStates[curCtx.G]
1067 if !ok {
1068 return curCtx, false, fmt.Errorf("encountered event of type %d without known state for current goroutine %d", ev.typ, curCtx.G)
1069 }
1070 desc, err := gState.endRange(ev.typ)
1071 if err != nil {
1072 return curCtx, false, err
1073 }
1074 if ev.typ == tracev2.EvSTWEnd {
1075
1076
1077 ev.args[0] = uint64(desc)
1078 }
1079 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
1080 return curCtx, true, nil
1081 }
1082
1083 func (o *ordering) advanceAllocFree(ev *baseEvent, evt *evTable, m ThreadID, gen uint64, curCtx schedCtx) (schedCtx, bool, error) {
1084
1085 if err := validateCtx(curCtx, schedReqs{M: mustHave, P: mayHave, G: mayHave}); err != nil {
1086 return curCtx, false, err
1087 }
1088 o.queue.push(Event{table: evt, ctx: curCtx, base: *ev})
1089 return curCtx, true, nil
1090 }
1091
1092
1093 func (o *ordering) Next() (Event, bool) {
1094 return o.queue.pop()
1095 }
1096
1097
1098 type schedCtx struct {
1099 G GoID
1100 P ProcID
1101 M ThreadID
1102 }
1103
1104
1105
1106 func validateCtx(ctx schedCtx, reqs schedReqs) error {
1107
1108 if reqs.M == mustHave && ctx.M == NoThread {
1109 return fmt.Errorf("expected a thread but didn't have one")
1110 } else if reqs.M == mustNotHave && ctx.M != NoThread {
1111 return fmt.Errorf("expected no thread but had one")
1112 }
1113
1114
1115 if reqs.P == mustHave && ctx.P == NoProc {
1116 return fmt.Errorf("expected a proc but didn't have one")
1117 } else if reqs.P == mustNotHave && ctx.P != NoProc {
1118 return fmt.Errorf("expected no proc but had one")
1119 }
1120
1121
1122 if reqs.G == mustHave && ctx.G == NoGoroutine {
1123 return fmt.Errorf("expected a goroutine but didn't have one")
1124 } else if reqs.G == mustNotHave && ctx.G != NoGoroutine {
1125 return fmt.Errorf("expected no goroutine but had one")
1126 }
1127 return nil
1128 }
1129
1130
1131
1132
1133 type gcState uint8
1134
1135 const (
1136 gcUndetermined gcState = iota
1137 gcNotRunning
1138 gcRunning
1139 )
1140
1141
1142 func (s gcState) String() string {
1143 switch s {
1144 case gcUndetermined:
1145 return "Undetermined"
1146 case gcNotRunning:
1147 return "NotRunning"
1148 case gcRunning:
1149 return "Running"
1150 }
1151 return "Bad"
1152 }
1153
1154
1155 type userRegion struct {
1156
1157
1158
1159 taskID TaskID
1160 name string
1161 }
1162
1163
1164
1165
1166
1167
1168 type rangeType struct {
1169 typ tracev2.EventType
1170 desc stringID
1171 }
1172
1173
1174 func makeRangeType(typ tracev2.EventType, desc stringID) rangeType {
1175 if styp := tracev2.Specs()[typ].StartEv; styp != tracev2.EvNone {
1176 typ = styp
1177 }
1178 return rangeType{typ, desc}
1179 }
1180
1181
1182 type gState struct {
1183 id GoID
1184 status tracev2.GoStatus
1185 seq seqCounter
1186
1187
1188 regions []userRegion
1189
1190
1191 rangeState
1192 }
1193
1194
1195 func (s *gState) beginRegion(r userRegion) error {
1196 s.regions = append(s.regions, r)
1197 return nil
1198 }
1199
1200
1201 func (s *gState) endRegion(r userRegion) error {
1202 if len(s.regions) == 0 {
1203
1204 return nil
1205 }
1206 if next := s.regions[len(s.regions)-1]; next != r {
1207 return fmt.Errorf("misuse of region in goroutine %v: region end %v when the inner-most active region start event is %v", s.id, r, next)
1208 }
1209 s.regions = s.regions[:len(s.regions)-1]
1210 return nil
1211 }
1212
1213
1214 type pState struct {
1215 id ProcID
1216 status tracev2.ProcStatus
1217 seq seqCounter
1218
1219
1220 rangeState
1221 }
1222
1223
1224 type mState struct {
1225 g GoID
1226 p ProcID
1227 }
1228
1229
1230 type rangeState struct {
1231
1232 inFlight []rangeType
1233 }
1234
1235
1236
1237
1238 func (s *rangeState) beginRange(typ rangeType) error {
1239 if s.hasRange(typ) {
1240 return fmt.Errorf("discovered event already in-flight for when starting event %v", tracev2.Specs()[typ.typ].Name)
1241 }
1242 s.inFlight = append(s.inFlight, typ)
1243 return nil
1244 }
1245
1246
1247
1248 func (s *rangeState) activeRange(typ rangeType, isInitialGen bool) error {
1249 if isInitialGen {
1250 if s.hasRange(typ) {
1251 return fmt.Errorf("found named active range already in first gen: %v", typ)
1252 }
1253 s.inFlight = append(s.inFlight, typ)
1254 } else if !s.hasRange(typ) {
1255 return fmt.Errorf("resource is missing active range: %v %v", tracev2.Specs()[typ.typ].Name, s.inFlight)
1256 }
1257 return nil
1258 }
1259
1260
1261 func (s *rangeState) hasRange(typ rangeType) bool {
1262 return slices.Contains(s.inFlight, typ)
1263 }
1264
1265
1266
1267
1268 func (s *rangeState) endRange(typ tracev2.EventType) (stringID, error) {
1269 st := tracev2.Specs()[typ].StartEv
1270 idx := -1
1271 for i, r := range s.inFlight {
1272 if r.typ == st {
1273 idx = i
1274 break
1275 }
1276 }
1277 if idx < 0 {
1278 return 0, fmt.Errorf("tried to end event %v, but not in-flight", tracev2.Specs()[st].Name)
1279 }
1280
1281 desc := s.inFlight[idx].desc
1282 s.inFlight[idx], s.inFlight[len(s.inFlight)-1] = s.inFlight[len(s.inFlight)-1], s.inFlight[idx]
1283 s.inFlight = s.inFlight[:len(s.inFlight)-1]
1284 return desc, nil
1285 }
1286
1287
1288 type seqCounter struct {
1289 gen uint64
1290 seq uint64
1291 }
1292
1293
1294 func makeSeq(gen, seq uint64) seqCounter {
1295 return seqCounter{gen: gen, seq: seq}
1296 }
1297
1298
1299 func (a seqCounter) succeeds(b seqCounter) bool {
1300 return a.gen == b.gen && a.seq == b.seq+1
1301 }
1302
1303
1304 func (c seqCounter) String() string {
1305 return fmt.Sprintf("%d (gen=%d)", c.seq, c.gen)
1306 }
1307
1308 func dumpOrdering(order *ordering) string {
1309 var sb strings.Builder
1310 for id, state := range order.gStates {
1311 fmt.Fprintf(&sb, "G %d [status=%s seq=%s]\n", id, state.status, state.seq)
1312 }
1313 fmt.Fprintln(&sb)
1314 for id, state := range order.pStates {
1315 fmt.Fprintf(&sb, "P %d [status=%s seq=%s]\n", id, state.status, state.seq)
1316 }
1317 fmt.Fprintln(&sb)
1318 for id, state := range order.mStates {
1319 fmt.Fprintf(&sb, "M %d [g=%d p=%d]\n", id, state.g, state.p)
1320 }
1321 fmt.Fprintln(&sb)
1322 fmt.Fprintf(&sb, "GC %d %s\n", order.gcSeq, order.gcState)
1323 return sb.String()
1324 }
1325
1326
1327 type taskState struct {
1328
1329 name string
1330
1331
1332 parentID TaskID
1333 }
1334
1335
1336 type queue[T any] struct {
1337 start, end int
1338 buf []T
1339 }
1340
1341
1342 func (q *queue[T]) push(value T) {
1343 if q.end-q.start == len(q.buf) {
1344 q.grow()
1345 }
1346 q.buf[q.end%len(q.buf)] = value
1347 q.end++
1348 }
1349
1350
1351 func (q *queue[T]) grow() {
1352 if len(q.buf) == 0 {
1353 q.buf = make([]T, 2)
1354 return
1355 }
1356
1357
1358 newBuf := make([]T, len(q.buf)*2)
1359 pivot := q.start % len(q.buf)
1360 first, last := q.buf[pivot:], q.buf[:pivot]
1361 copy(newBuf[:len(first)], first)
1362 copy(newBuf[len(first):], last)
1363
1364
1365 q.start = 0
1366 q.end = len(q.buf)
1367 q.buf = newBuf
1368 }
1369
1370
1371
1372 func (q *queue[T]) pop() (T, bool) {
1373 if q.end-q.start == 0 {
1374 return *new(T), false
1375 }
1376 elem := &q.buf[q.start%len(q.buf)]
1377 value := *elem
1378 *elem = *new(T)
1379 q.start++
1380 return value, true
1381 }
1382
1383
1384
1385
1386
1387
1388 func makeEvent(table *evTable, ctx schedCtx, typ tracev2.EventType, time Time, args ...uint64) Event {
1389 ev := Event{
1390 table: table,
1391 ctx: ctx,
1392 base: baseEvent{
1393 typ: typ,
1394 time: time,
1395 },
1396 }
1397 copy(ev.base.args[:], args)
1398 return ev
1399 }
1400
1401
1402
1403 type schedReqs struct {
1404 M constraint
1405 P constraint
1406 G constraint
1407 }
1408
1409
1410 type constraint uint8
1411
1412 const (
1413 mustNotHave constraint = iota
1414 mayHave
1415 mustHave
1416 )
1417
1418
1419
1420 var userGoReqs = schedReqs{M: mustHave, P: mustHave, G: mustHave}
1421
View as plain text