github.com/smallnest/goroutine@v1.1.1/gid_go121_test.go (about)

     1  // Copyright ©2023 Dan Kortschak. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build go1.21
     6  // +build go1.21
     7  
     8  package goroutine
     9  
    10  import (
    11  	"fmt"
    12  	"runtime"
    13  	"strconv"
    14  	"strings"
    15  	"sync"
    16  	"testing"
    17  )
    18  
    19  func TestParentID(t *testing.T) {
    20  	var wg sync.WaitGroup
    21  	for i := 0; i < 1000000; i++ {
    22  		i := i
    23  		wg.Add(2)
    24  		go func() {
    25  			defer wg.Done()
    26  			parentID := ID()
    27  			go func() {
    28  				defer wg.Done()
    29  				got := ParentID()
    30  				want := parentGoid()
    31  				if got != want {
    32  					t.Errorf("unexpected parent id for goroutine number %d: mismatch with stack trace: got:%d want:%d", i, got, want)
    33  				}
    34  				if got != parentID {
    35  					t.Errorf("unexpected parent id for goroutine number %d: mismatch with parent: got:%d want:%d", i, got, want)
    36  				}
    37  			}()
    38  		}()
    39  	}
    40  	wg.Wait()
    41  }
    42  
    43  // parentGoid returns the parent goroutine ID extracted from a stack trace.
    44  func parentGoid() int64 {
    45  	var buf [1 << 10]byte
    46  	n := runtime.Stack(buf[:], false)
    47  	_, after, ok := strings.Cut(string(buf[:n]), " in goroutine ")
    48  	if !ok {
    49  		panic("cannot get parent goroutine id: no mark")
    50  	}
    51  	idField := strings.Fields(after)[0]
    52  	id, err := strconv.ParseInt(idField, 10, 64)
    53  	if err != nil {
    54  		panic(fmt.Sprintf("cannot get parent goroutine id: %v", err))
    55  	}
    56  	return id
    57  }