// Read everything out of the last gen's CPU profile buffer.
traceReadCPU(gen)
- systemstack(func() {
- // Flush CPU samples, stacks, and strings for the last generation. This is safe,
- // because we're now certain no M is writing to the last generation.
- //
- // Ordering is important here. traceCPUFlush may generate new stacks and dumping
- // stacks may generate new strings.
- traceCPUFlush(gen)
- trace.stackTab[gen%2].dump(gen)
- trace.stringTab[gen%2].reset(gen)
+ // Flush CPU samples, stacks, and strings for the last generation. This is safe,
+ // because we're now certain no M is writing to the last generation.
+ //
+ // Ordering is important here. traceCPUFlush may generate new stacks and dumping
+ // stacks may generate new strings.
+ traceCPUFlush(gen)
+ trace.stackTab[gen%2].dump(gen)
+ trace.stringTab[gen%2].reset(gen)
- // That's it. This generation is done producing buffers.
+ // That's it. This generation is done producing buffers.
+ systemstack(func() {
lock(&trace.lock)
trace.flushedGen.Store(gen)
unlock(&trace.lock)
// traceCPUFlush flushes trace.cpuBuf[gen%2]. The caller must be certain that gen
// has completed and that there are no more writers to it.
-//
-// Must run on the systemstack because it flushes buffers and acquires trace.lock
-// to do so.
-//
-//go:systemstack
func traceCPUFlush(gen uintptr) {
// Flush any remaining trace buffers containing CPU samples.
if buf := trace.cpuBuf[gen%2]; buf != nil {
- lock(&trace.lock)
- traceBufFlush(buf, gen)
- unlock(&trace.lock)
- trace.cpuBuf[gen%2] = nil
+ systemstack(func() {
+ lock(&trace.lock)
+ traceBufFlush(buf, gen)
+ unlock(&trace.lock)
+ trace.cpuBuf[gen%2] = nil
+ })
}
}
// dump writes all previously cached stacks to trace buffers,
// releases all memory and resets state. It must only be called once the caller
// can guarantee that there are no more writers to the table.
-//
-// This must run on the system stack because it flushes buffers and thus
-// may acquire trace.lock.
-//
-//go:systemstack
func (t *traceStackTable) dump(gen uintptr) {
w := unsafeTraceWriter(gen, nil)
}
// Still, hold the lock over reset. The callee expects it, even though it's
// not strictly necessary.
- lock(&t.tab.lock)
- t.tab.reset()
- unlock(&t.tab.lock)
+ systemstack(func() {
+ lock(&t.tab.lock)
+ t.tab.reset()
+ unlock(&t.tab.lock)
+ })
w.flush().end()
}
// writeString writes the string to t.buf.
//
-// Must run on the systemstack because it may flush buffers and thus could acquire trace.lock.
+// Must run on the systemstack because it acquires t.lock.
//
//go:systemstack
func (t *traceStringTable) writeString(gen uintptr, id uint64, s string) {
w.varint(uint64(len(s)))
w.stringData(s)
- // Store back buf if it was updated during ensure.
+ // Store back buf in case it was updated during ensure.
t.buf = w.traceBuf
unlock(&t.lock)
}
//
// Must be called only once the caller is certain nothing else will be
// added to this table.
-//
-// Because it flushes buffers, this may acquire trace.lock and thus
-// must run on the systemstack.
-//
-//go:systemstack
func (t *traceStringTable) reset(gen uintptr) {
if t.buf != nil {
- lock(&trace.lock)
- traceBufFlush(t.buf, gen)
- unlock(&trace.lock)
+ systemstack(func() {
+ lock(&trace.lock)
+ traceBufFlush(t.buf, gen)
+ unlock(&trace.lock)
+ })
t.buf = nil
}
// Reset the table.
- lock(&t.tab.lock)
- t.tab.reset()
- unlock(&t.tab.lock)
+ systemstack(func() {
+ lock(&t.tab.lock)
+ t.tab.reset()
+ unlock(&t.tab.lock)
+ })
}