mirror of
https://github.com/go-delve/delve.git
synced 2025-10-27 20:23:41 +08:00
terminal/command: 'goroutines' command add new flags '-exec command' (#3044)
* terminal/command: 'goroutines' command add new flags '-exec command' Support run command on every goroutine. Fixes #3043 * terminal/command: 'goroutines' command add new flags '-exec command' Support run command on every goroutine. Fixes #3043 * terminal/command: add -per-g-hitcount option to condition command Support use per goroutine hitcount as hintcond operand. Fixes #3050 Co-authored-by: roketyyang <roketyyang@tencent.com>
This commit is contained in:
@ -375,7 +375,7 @@ Aliases: gr
|
||||
## goroutines
|
||||
List program goroutines.
|
||||
|
||||
goroutines [-u|-r|-g|-s] [-t [depth]] [-l] [-with loc expr] [-without loc expr] [-group argument]
|
||||
goroutines [-u|-r|-g|-s] [-t [depth]] [-l] [-with loc expr] [-without loc expr] [-group argument] [-exec command]
|
||||
|
||||
Print out info for every goroutine. The flag controls what information is shown along with each goroutine:
|
||||
|
||||
@ -431,6 +431,12 @@ Groups goroutines by the given location, running status or user classification,
|
||||
|
||||
Groups goroutines by the value of the label with the specified key.
|
||||
|
||||
EXEC
|
||||
|
||||
goroutines -exec <command>
|
||||
|
||||
Runs the command on every goroutine.
|
||||
|
||||
|
||||
Aliases: grs
|
||||
|
||||
|
||||
@ -224,9 +224,9 @@ If called with the locspec argument it will delete all the breakpoints matching
|
||||
{aliases: []string{"toggle"}, group: breakCmds, cmdFn: toggle, helpMsg: `Toggles on or off a breakpoint.
|
||||
|
||||
toggle <breakpoint name or id>`},
|
||||
{aliases: []string{"goroutines", "grs"}, group: goroutineCmds, cmdFn: goroutines, helpMsg: `List program goroutines.
|
||||
{aliases: []string{"goroutines", "grs"}, group: goroutineCmds, cmdFn: c.goroutines, helpMsg: `List program goroutines.
|
||||
|
||||
goroutines [-u|-r|-g|-s] [-t [depth]] [-l] [-with loc expr] [-without loc expr] [-group argument]
|
||||
goroutines [-u|-r|-g|-s] [-t [depth]] [-l] [-with loc expr] [-without loc expr] [-group argument] [-exec command]
|
||||
|
||||
Print out info for every goroutine. The flag controls what information is shown along with each goroutine:
|
||||
|
||||
@ -281,6 +281,12 @@ Groups goroutines by the given location, running status or user classification,
|
||||
goroutines -group label key
|
||||
|
||||
Groups goroutines by the value of the label with the specified key.
|
||||
|
||||
EXEC
|
||||
|
||||
goroutines -exec <command>
|
||||
|
||||
Runs the command on every goroutine.
|
||||
`},
|
||||
{aliases: []string{"goroutine", "gr"}, group: goroutineCmds, allowedPrefixes: onPrefix, cmdFn: c.goroutine, helpMsg: `Shows or changes current goroutine
|
||||
|
||||
@ -796,7 +802,7 @@ func (a byGoroutineID) Len() int { return len(a) }
|
||||
func (a byGoroutineID) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a byGoroutineID) Less(i, j int) bool { return a[i].ID < a[j].ID }
|
||||
|
||||
func printGoroutines(t *Term, indent string, gs []*api.Goroutine, fgl api.FormatGoroutineLoc, flags api.PrintGoroutinesFlags, depth int, state *api.DebuggerState) error {
|
||||
func (c *Commands) printGoroutines(t *Term, ctx callContext, indent string, gs []*api.Goroutine, fgl api.FormatGoroutineLoc, flags api.PrintGoroutinesFlags, depth int, cmd string, state *api.DebuggerState) error {
|
||||
for _, g := range gs {
|
||||
prefix := indent + " "
|
||||
if state.SelectedGoroutine != nil && g.ID == state.SelectedGoroutine.ID {
|
||||
@ -813,12 +819,18 @@ func printGoroutines(t *Term, indent string, gs []*api.Goroutine, fgl api.Format
|
||||
}
|
||||
printStack(t, t.stdout, stack, indent+"\t", false)
|
||||
}
|
||||
if cmd != "" {
|
||||
ctx.Scope.GoroutineID = g.ID
|
||||
if err := c.CallWithContext(cmd, t, ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func goroutines(t *Term, ctx callContext, argstr string) error {
|
||||
filters, group, fgl, flags, depth, batchSize, err := api.ParseGoroutineArgs(argstr)
|
||||
func (c *Commands) goroutines(t *Term, ctx callContext, argstr string) error {
|
||||
filters, group, fgl, flags, depth, batchSize, cmd, err := api.ParseGoroutineArgs(argstr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -847,7 +859,7 @@ func goroutines(t *Term, ctx callContext, argstr string) error {
|
||||
if len(groups) > 0 {
|
||||
for i := range groups {
|
||||
fmt.Fprintf(t.stdout, "%s\n", groups[i].Name)
|
||||
err = printGoroutines(t, "\t", gs[groups[i].Offset:][:groups[i].Count], fgl, flags, depth, state)
|
||||
err = c.printGoroutines(t, ctx, "\t", gs[groups[i].Offset:][:groups[i].Count], fgl, flags, depth, cmd, state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -861,7 +873,7 @@ func goroutines(t *Term, ctx callContext, argstr string) error {
|
||||
}
|
||||
} else {
|
||||
sort.Sort(byGoroutineID(gs))
|
||||
err = printGoroutines(t, "", gs, fgl, flags, depth, state)
|
||||
err = c.printGoroutines(t, ctx, "", gs, fgl, flags, depth, cmd, state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ type PrintGoroutinesFlags uint8
|
||||
const (
|
||||
PrintGoroutinesStack PrintGoroutinesFlags = 1 << iota
|
||||
PrintGoroutinesLabels
|
||||
PrintGoroutinesExec
|
||||
)
|
||||
|
||||
type FormatGoroutineLoc int
|
||||
@ -30,7 +31,7 @@ const (
|
||||
// The number of goroutines we're going to request on each RPC call
|
||||
const goroutineBatchSize = 10000
|
||||
|
||||
func ParseGoroutineArgs(argstr string) ([]ListGoroutinesFilter, GoroutineGroupingOptions, FormatGoroutineLoc, PrintGoroutinesFlags, int, int, error) {
|
||||
func ParseGoroutineArgs(argstr string) ([]ListGoroutinesFilter, GoroutineGroupingOptions, FormatGoroutineLoc, PrintGoroutinesFlags, int, int, string, error) {
|
||||
args := strings.Split(argstr, " ")
|
||||
var filters []ListGoroutinesFilter
|
||||
var group GoroutineGroupingOptions
|
||||
@ -38,6 +39,7 @@ func ParseGoroutineArgs(argstr string) ([]ListGoroutinesFilter, GoroutineGroupin
|
||||
var flags PrintGoroutinesFlags
|
||||
var depth = 10
|
||||
var batchSize = goroutineBatchSize
|
||||
var cmd string
|
||||
|
||||
group.MaxGroupMembers = maxGroupMembers
|
||||
group.MaxGroups = maxGoroutineGroups
|
||||
@ -69,14 +71,14 @@ func ParseGoroutineArgs(argstr string) ([]ListGoroutinesFilter, GoroutineGroupin
|
||||
case "-w", "-with":
|
||||
filter, err := readGoroutinesFilter(args, &i)
|
||||
if err != nil {
|
||||
return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, fmt.Errorf("wrong argument: '%s'", arg)
|
||||
return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, "", fmt.Errorf("wrong argument: '%s'", arg)
|
||||
}
|
||||
filters = append(filters, *filter)
|
||||
|
||||
case "-wo", "-without":
|
||||
filter, err := readGoroutinesFilter(args, &i)
|
||||
if err != nil {
|
||||
return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, fmt.Errorf("wrong argument: '%s'", arg)
|
||||
return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, "", fmt.Errorf("wrong argument: '%s'", arg)
|
||||
}
|
||||
filter.Negated = true
|
||||
filters = append(filters, *filter)
|
||||
@ -85,25 +87,30 @@ func ParseGoroutineArgs(argstr string) ([]ListGoroutinesFilter, GoroutineGroupin
|
||||
var err error
|
||||
group.GroupBy, err = readGoroutinesFilterKind(args, i+1)
|
||||
if err != nil {
|
||||
return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, fmt.Errorf("wrong argument: '%s'", arg)
|
||||
return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, "", fmt.Errorf("wrong argument: '%s'", arg)
|
||||
}
|
||||
i++
|
||||
if group.GroupBy == GoroutineLabel {
|
||||
if i+1 >= len(args) {
|
||||
return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, fmt.Errorf("wrong argument: '%s'", arg)
|
||||
return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, "", fmt.Errorf("wrong argument: '%s'", arg)
|
||||
}
|
||||
group.GroupByKey = args[i+1]
|
||||
i++
|
||||
}
|
||||
batchSize = 0 // grouping only works well if run on all goroutines
|
||||
|
||||
case "-exec":
|
||||
flags |= PrintGoroutinesExec
|
||||
cmd = strings.Join(args[i+1:], " ")
|
||||
i = len(args)
|
||||
|
||||
case "":
|
||||
// nothing to do
|
||||
default:
|
||||
return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, fmt.Errorf("wrong argument: '%s'", arg)
|
||||
return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, "", fmt.Errorf("wrong argument: '%s'", arg)
|
||||
}
|
||||
}
|
||||
return filters, group, fgl, flags, depth, batchSize, nil
|
||||
return filters, group, fgl, flags, depth, batchSize, cmd, nil
|
||||
}
|
||||
|
||||
func readGoroutinesFilterKind(args []string, i int) (GoroutineField, error) {
|
||||
|
||||
@ -1608,7 +1608,7 @@ func (s *Session) onThreadsRequest(request *dap.ThreadsRequest) {
|
||||
gs, next, err = s.debugger.Goroutines(0, maxGoroutines)
|
||||
if err == nil {
|
||||
// Parse the goroutine arguments.
|
||||
filters, _, _, _, _, _, parseErr := api.ParseGoroutineArgs(s.args.GoroutineFilters)
|
||||
filters, _, _, _, _, _, _, parseErr := api.ParseGoroutineArgs(s.args.GoroutineFilters)
|
||||
if parseErr != nil {
|
||||
s.logToConsole(parseErr.Error())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user