mirror of
				https://github.com/go-delve/delve.git
				synced 2025-11-04 06:32:16 +08:00 
			
		
		
		
	Adds -chan option to the goroutines command to list only the goroutines running on a specified channel. Also when printing a variable if it is a channel also print the list of goroutines that are waiting on it.
		
			
				
	
	
		
			169 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package api
 | 
						|
 | 
						|
import (
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
type PrintGoroutinesFlags uint8
 | 
						|
 | 
						|
const (
 | 
						|
	PrintGoroutinesStack PrintGoroutinesFlags = 1 << iota
 | 
						|
	PrintGoroutinesLabels
 | 
						|
	PrintGoroutinesExec
 | 
						|
)
 | 
						|
 | 
						|
type FormatGoroutineLoc int
 | 
						|
 | 
						|
const (
 | 
						|
	FglRuntimeCurrent = FormatGoroutineLoc(iota)
 | 
						|
	FglUserCurrent
 | 
						|
	FglGo
 | 
						|
	FglStart
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	maxGroupMembers    = 5
 | 
						|
	maxGoroutineGroups = 50
 | 
						|
)
 | 
						|
 | 
						|
// 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, string, error) {
 | 
						|
	args := strings.Split(argstr, " ")
 | 
						|
	var filters []ListGoroutinesFilter
 | 
						|
	var group GoroutineGroupingOptions
 | 
						|
	var fgl = FglUserCurrent
 | 
						|
	var flags PrintGoroutinesFlags
 | 
						|
	var depth = 10
 | 
						|
	var batchSize = goroutineBatchSize
 | 
						|
	var cmd string
 | 
						|
 | 
						|
	group.MaxGroupMembers = maxGroupMembers
 | 
						|
	group.MaxGroups = maxGoroutineGroups
 | 
						|
 | 
						|
	for i := 0; i < len(args); i++ {
 | 
						|
		arg := args[i]
 | 
						|
		switch arg {
 | 
						|
		case "-u":
 | 
						|
			fgl = FglUserCurrent
 | 
						|
		case "-r":
 | 
						|
			fgl = FglRuntimeCurrent
 | 
						|
		case "-g":
 | 
						|
			fgl = FglGo
 | 
						|
		case "-s":
 | 
						|
			fgl = FglStart
 | 
						|
		case "-l":
 | 
						|
			flags |= PrintGoroutinesLabels
 | 
						|
		case "-t":
 | 
						|
			flags |= PrintGoroutinesStack
 | 
						|
			// optional depth argument
 | 
						|
			if i+1 < len(args) && len(args[i+1]) > 0 {
 | 
						|
				n, err := strconv.Atoi(args[i+1])
 | 
						|
				if err == nil {
 | 
						|
					depth = n
 | 
						|
					i++
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
		case "-w", "-with":
 | 
						|
			filter, err := readGoroutinesFilter(args, &i)
 | 
						|
			if err != nil {
 | 
						|
				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)
 | 
						|
			}
 | 
						|
			filter.Negated = true
 | 
						|
			filters = append(filters, *filter)
 | 
						|
 | 
						|
		case "-group":
 | 
						|
			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)
 | 
						|
			}
 | 
						|
			i++
 | 
						|
			if group.GroupBy == GoroutineLabel {
 | 
						|
				if i+1 >= len(args) {
 | 
						|
					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 "-chan":
 | 
						|
			i++
 | 
						|
			if i >= len(args) {
 | 
						|
				return nil, GoroutineGroupingOptions{}, 0, 0, 0, 0, "", errors.New("not enough arguments after -chan")
 | 
						|
			}
 | 
						|
			filters = append(filters, ListGoroutinesFilter{Kind: GoroutineWaitingOnChannel, Arg: args[i]})
 | 
						|
 | 
						|
		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 filters, group, fgl, flags, depth, batchSize, cmd, nil
 | 
						|
}
 | 
						|
 | 
						|
func readGoroutinesFilterKind(args []string, i int) (GoroutineField, error) {
 | 
						|
	if i >= len(args) {
 | 
						|
		return GoroutineFieldNone, fmt.Errorf("%s must be followed by an argument", args[i-1])
 | 
						|
	}
 | 
						|
 | 
						|
	switch args[i] {
 | 
						|
	case "curloc":
 | 
						|
		return GoroutineCurrentLoc, nil
 | 
						|
	case "userloc":
 | 
						|
		return GoroutineUserLoc, nil
 | 
						|
	case "goloc":
 | 
						|
		return GoroutineGoLoc, nil
 | 
						|
	case "startloc":
 | 
						|
		return GoroutineStartLoc, nil
 | 
						|
	case "label":
 | 
						|
		return GoroutineLabel, nil
 | 
						|
	case "running":
 | 
						|
		return GoroutineRunning, nil
 | 
						|
	case "user":
 | 
						|
		return GoroutineUser, nil
 | 
						|
	default:
 | 
						|
		return GoroutineFieldNone, fmt.Errorf("unrecognized argument to %s %s", args[i-1], args[i])
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func readGoroutinesFilter(args []string, pi *int) (*ListGoroutinesFilter, error) {
 | 
						|
	r := new(ListGoroutinesFilter)
 | 
						|
	var err error
 | 
						|
	r.Kind, err = readGoroutinesFilterKind(args, *pi+1)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	*pi++
 | 
						|
	switch r.Kind {
 | 
						|
	case GoroutineRunning, GoroutineUser:
 | 
						|
		return r, nil
 | 
						|
	}
 | 
						|
	if *pi+1 >= len(args) {
 | 
						|
		return nil, fmt.Errorf("%s %s needs to be followed by an expression", args[*pi-1], args[*pi])
 | 
						|
	}
 | 
						|
	r.Arg = args[*pi+1]
 | 
						|
	*pi++
 | 
						|
 | 
						|
	return r, nil
 | 
						|
}
 |