]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/internal/trace/v2/order.go
internal/trace/v2: resolve syscall parsing ambiguity
[gostls13.git] / src / internal / trace / v2 / order.go
index 728879257f9d517eb6abe726896497ed3880c826..8b503d4dc406e1b2c67e03e1f815f8071952af1f 100644 (file)
@@ -306,7 +306,7 @@ func (o *ordering) advance(ev *baseEvent, evt *evTable, m ThreadID, gen uint64)
                }
                o.gStates[newgid] = &gState{id: newgid, status: go122.GoRunnable, seq: makeSeq(gen, 0)}
                return curCtx, true, nil
-       case go122.EvGoDestroy, go122.EvGoStop, go122.EvGoBlock, go122.EvGoSyscallBegin:
+       case go122.EvGoDestroy, go122.EvGoStop, go122.EvGoBlock:
                // These are goroutine events that all require an active running
                // goroutine on some thread. They must *always* be advance-able,
                // since running goroutines are bound to their M.
@@ -335,14 +335,6 @@ func (o *ordering) advance(ev *baseEvent, evt *evTable, m ThreadID, gen uint64)
                        // Goroutine blocked. It's waiting now and not running on this M.
                        state.status = go122.GoWaiting
                        newCtx.G = NoGoroutine
-               case go122.EvGoSyscallBegin:
-                       // Goroutine entered a syscall. It's still running on this P and M.
-                       state.status = go122.GoSyscall
-                       pState, ok := o.pStates[curCtx.P]
-                       if !ok {
-                               return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, go122.EventString(typ))
-                       }
-                       pState.status = go122.ProcSyscall
                }
                return curCtx, true, nil
        case go122.EvGoStart:
@@ -380,6 +372,43 @@ func (o *ordering) advance(ev *baseEvent, evt *evTable, m ThreadID, gen uint64)
                // N.B. No context to validate. Basically anything can unblock
                // a goroutine (e.g. sysmon).
                return curCtx, true, nil
+       case go122.EvGoSyscallBegin:
+               // Entering a syscall requires an active running goroutine with a
+               // proc on some thread. It is always advancable.
+               if err := validateCtx(curCtx, event.UserGoReqs); err != nil {
+                       return curCtx, false, err
+               }
+               state, ok := o.gStates[curCtx.G]
+               if !ok {
+                       return curCtx, false, fmt.Errorf("event %s for goroutine (%v) that doesn't exist", go122.EventString(typ), curCtx.G)
+               }
+               if state.status != go122.GoRunning {
+                       return curCtx, false, fmt.Errorf("%s event for goroutine that's not %s", go122.EventString(typ), GoRunning)
+               }
+               // Goroutine entered a syscall. It's still running on this P and M.
+               state.status = go122.GoSyscall
+               pState, ok := o.pStates[curCtx.P]
+               if !ok {
+                       return curCtx, false, fmt.Errorf("uninitialized proc %d found during %s", curCtx.P, go122.EventString(typ))
+               }
+               pState.status = go122.ProcSyscall
+               // Validate the P sequence number on the event and advance it.
+               //
+               // We have a P sequence number for what is supposed to be a goroutine event
+               // so that we can correctly model P stealing. Without this sequence number here,
+               // the syscall from which a ProcSteal event is stealing can be ambiguous in the
+               // face of broken timestamps. See the go122-syscall-steal-proc-ambiguous test for
+               // more details.
+               //
+               // Note that because this sequence number only exists as a tool for disambiguation,
+               // we can enforce that we have the right sequence number at this point; we don't need
+               // to back off and see if any other events will advance. This is a running P.
+               pSeq := makeSeq(gen, ev.args[0])
+               if !pSeq.succeeds(pState.seq) {
+                       return curCtx, false, fmt.Errorf("failed to advance %s: can't make sequence: %s -> %s", go122.EventString(typ), pState.seq, pSeq)
+               }
+               pState.seq = pSeq
+               return curCtx, true, nil
        case go122.EvGoSyscallEnd:
                // This event is always advance-able because it happens on the same
                // thread that EvGoSyscallStart happened, and the goroutine can't leave