Source File
subscribe.go
Belonging Package
runtime/trace
// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package trace
import (
_
)
var tracing traceMultiplexer
type traceMultiplexer struct {
sync.Mutex
enabled atomic.Bool
subscribers int
subscribersMu sync.Mutex
traceStartWriter io.Writer
flightRecorder *recorder
}
func ( *traceMultiplexer) ( *recorder) error {
.Lock()
defer .Unlock()
.subscribersMu.Lock()
if .flightRecorder != nil {
.subscribersMu.Unlock()
return fmt.Errorf("flight recorder already enabled")
}
.flightRecorder =
.subscribersMu.Unlock()
if := .addedSubscriber(); != nil {
.subscribersMu.Lock()
.flightRecorder = nil
.subscribersMu.Unlock()
return
}
return nil
}
func ( *traceMultiplexer) () error {
.Lock()
defer .Unlock()
.removingSubscriber()
.subscribersMu.Lock()
if .flightRecorder == nil {
.subscribersMu.Unlock()
return fmt.Errorf("attempt to unsubscribe missing flight recorder")
}
.flightRecorder = nil
.subscribersMu.Unlock()
.removedSubscriber()
return nil
}
func ( *traceMultiplexer) ( io.Writer) error {
.Lock()
defer .Unlock()
.subscribersMu.Lock()
if .traceStartWriter != nil {
.subscribersMu.Unlock()
return fmt.Errorf("execution tracer already enabled")
}
.traceStartWriter =
.subscribersMu.Unlock()
if := .addedSubscriber(); != nil {
.subscribersMu.Lock()
.traceStartWriter = nil
.subscribersMu.Unlock()
return
}
return nil
}
func ( *traceMultiplexer) () {
.Lock()
defer .Unlock()
.removingSubscriber()
.subscribersMu.Lock()
if .traceStartWriter == nil {
.subscribersMu.Unlock()
return
}
.traceStartWriter = nil
.subscribersMu.Unlock()
.removedSubscriber()
return
}
func ( *traceMultiplexer) () error {
if .enabled.Load() {
// This is necessary for the trace reader goroutine to pick up on the new subscriber.
runtime_traceAdvance(false)
} else {
if := .startLocked(); != nil {
return
}
}
.subscribers++
return nil
}
func ( *traceMultiplexer) () {
if .subscribers == 0 {
return
}
.subscribers--
if .subscribers == 0 {
runtime.StopTrace()
.enabled.Store(false)
} else {
// This is necessary to avoid missing trace data when the system is under high load.
runtime_traceAdvance(false)
}
}
func ( *traceMultiplexer) () {
if .subscribers > 0 {
// This is necessary for the trace reader goroutine to pick up on the new subscriber.
runtime_traceAdvance(false)
}
}
func ( *traceMultiplexer) () error {
if := runtime.StartTrace(); != nil {
return
}
// Grab the trace reader goroutine's subscribers.
//
// We only update our subscribers if we see an end-of-generation
// signal from the runtime after this, so any new subscriptions
// or unsubscriptions must call traceAdvance to ensure the reader
// goroutine sees an end-of-generation signal.
.subscribersMu.Lock()
:= .flightRecorder
:= .traceStartWriter
.subscribersMu.Unlock()
go func() {
:= runtime_readTrace()
if != nil {
.Write()
}
if != nil {
.Write()
}
for {
:= runtime_readTrace()
if == nil {
break
}
if len() == 1 && tracev2.EventType([0]) == tracev2.EvEndOfGeneration {
if != nil {
.endGeneration()
}
// Pick up any changes.
.subscribersMu.Lock()
:= != .flightRecorder && .flightRecorder != nil
:= != .traceStartWriter && .traceStartWriter != nil
= .flightRecorder
= .traceStartWriter
.subscribersMu.Unlock()
if {
.Write()
}
if {
.Write()
}
} else {
if != nil {
.Write()
}
if != nil {
.Write()
}
}
}
}()
.enabled.Store(true)
return nil
}
//go:linkname runtime_readTrace
func runtime_readTrace() ( []byte)
![]() |
The pages are generated with Golds v0.7.7-preview. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |