Source file src/runtime/testdata/testprogcgo/notingo.go
1 // Copyright 2025 The Go Authors. 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 !plan9 && !windows 6 7 package main 8 9 /* 10 #include <stdatomic.h> 11 #include <stddef.h> 12 #include <pthread.h> 13 14 extern void Ready(); 15 16 static _Atomic int spinning; 17 static _Atomic int released; 18 19 static void* enterGoThenSpinTwice(void* arg __attribute__ ((unused))) { 20 Ready(); 21 atomic_fetch_add(&spinning, 1); 22 while(atomic_load(&released) == 0) {}; 23 24 Ready(); 25 atomic_fetch_add(&spinning, 1); 26 while(1) {}; 27 return NULL; 28 } 29 30 static void SpinTwiceInNewCThread() { 31 pthread_t tid; 32 pthread_create(&tid, NULL, enterGoThenSpinTwice, NULL); 33 } 34 35 static int Spinning() { 36 return atomic_load(&spinning); 37 } 38 39 static void Release() { 40 atomic_store(&spinning, 0); 41 atomic_store(&released, 1); 42 } 43 */ 44 import "C" 45 46 import ( 47 "os" 48 "runtime" 49 "runtime/metrics" 50 ) 51 52 func init() { 53 register("NotInGoMetricCallback", NotInGoMetricCallback) 54 } 55 56 func NotInGoMetricCallback() { 57 const N = 10 58 s := []metrics.Sample{{Name: "/sched/goroutines/not-in-go:goroutines"}} 59 60 // Create N new C threads that have called into Go at least once. 61 for range N { 62 C.SpinTwiceInNewCThread() 63 } 64 65 // Synchronize with spinning threads twice. 66 // 67 // This helps catch bad accounting by taking at least a couple other 68 // codepaths which would cause the accounting to change. 69 for i := range 2 { 70 // Make sure they pass through Go. 71 // N.B. Ready is called twice by the new threads. 72 for j := range N { 73 <-readyCh 74 if j == 2 { 75 // Try to trigger an update in the immediate STW handoff case. 76 runtime.ReadMemStats(&m) 77 } 78 } 79 80 // Make sure they're back in C. 81 for C.Spinning() < N { 82 } 83 84 // Do something that stops the world to take all the Ps back. 85 runtime.ReadMemStats(&m) 86 87 if i == 0 { 88 C.Release() 89 } 90 } 91 92 // Read not-in-go. 93 metrics.Read(s) 94 if n := s[0].Value.Uint64(); n != 0 { 95 println("expected 0 not-in-go goroutines, found", n) 96 os.Exit(2) 97 } 98 println("OK") 99 } 100 101 var m runtime.MemStats 102 var readyCh = make(chan bool) 103 104 //export Ready 105 func Ready() { 106 readyCh <- true 107 } 108