mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 02:36:18 +08:00 
			
		
		
		
	 ec1d1efb7f
			
		
	
	ec1d1efb7f
	
	
	
		
			
			* 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>
		
			
				
	
	
		
			161 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package api
 | |
| 
 | |
| import (
 | |
| 	"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 "-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
 | |
| }
 |