X7ROOT File Manager
Current Path:
/opt/golang/1.22.0/src/runtime
opt
/
golang
/
1.22.0
/
src
/
runtime
/
📁
..
📄
HACKING.md
(13.85 KB)
📄
Makefile
(178 B)
📄
abi_test.go
(2.83 KB)
📄
alg.go
(10.99 KB)
📄
align_runtime_test.go
(1.82 KB)
📄
align_test.go
(5.37 KB)
📄
arena.go
(31.66 KB)
📄
arena_test.go
(13.39 KB)
📁
asan
📄
asan.go
(1.55 KB)
📄
asan0.go
(760 B)
📄
asan_amd64.s
(2.45 KB)
📄
asan_arm64.s
(2.14 KB)
📄
asan_loong64.s
(2.12 KB)
📄
asan_ppc64le.s
(2.75 KB)
📄
asan_riscv64.s
(1.92 KB)
📄
asm.s
(719 B)
📄
asm_386.s
(42.54 KB)
📄
asm_amd64.h
(631 B)
📄
asm_amd64.s
(60.09 KB)
📄
asm_arm.s
(31.58 KB)
📄
asm_arm64.s
(43.33 KB)
📄
asm_loong64.s
(27.58 KB)
📄
asm_mips64x.s
(24.34 KB)
📄
asm_mipsx.s
(25.82 KB)
📄
asm_ppc64x.h
(1.93 KB)
📄
asm_ppc64x.s
(45.19 KB)
📄
asm_riscv64.s
(26.97 KB)
📄
asm_s390x.s
(27.55 KB)
📄
asm_wasm.s
(11.82 KB)
📄
atomic_arm64.s
(259 B)
📄
atomic_loong64.s
(245 B)
📄
atomic_mips64x.s
(300 B)
📄
atomic_mipsx.s
(262 B)
📄
atomic_pointer.go
(3.66 KB)
📄
atomic_ppc64x.s
(437 B)
📄
atomic_riscv64.s
(275 B)
📄
auxv_none.go
(298 B)
📄
callers_test.go
(12.13 KB)
📁
cgo
📄
cgo.go
(2.5 KB)
📄
cgo_mmap.go
(2.42 KB)
📄
cgo_ppc64x.go
(418 B)
📄
cgo_sigaction.go
(3.28 KB)
📄
cgocall.go
(23.23 KB)
📄
cgocallback.go
(317 B)
📄
cgocheck.go
(7.97 KB)
📄
chan.go
(23.74 KB)
📄
chan_test.go
(23.44 KB)
📄
chanbarrier_test.go
(1.4 KB)
📄
checkptr.go
(3.29 KB)
📄
checkptr_test.go
(2.86 KB)
📄
closure_test.go
(937 B)
📄
compiler.go
(410 B)
📄
complex.go
(1.59 KB)
📄
complex_test.go
(1.05 KB)
📄
conv_wasm_test.go
(2.96 KB)
📄
coro.go
(4.92 KB)
📁
coverage
📄
covercounter.go
(749 B)
📄
covermeta.go
(2.4 KB)
📄
cpuflags.go
(810 B)
📄
cpuflags_amd64.go
(533 B)
📄
cpuflags_arm64.go
(312 B)
📄
cpuprof.go
(7.94 KB)
📄
cputicks.go
(437 B)
📄
crash_cgo_test.go
(23.35 KB)
📄
crash_test.go
(23.12 KB)
📄
crash_unix_test.go
(9.19 KB)
📄
create_file_nounix.go
(305 B)
📄
create_file_unix.go
(368 B)
📁
debug
📄
debug.go
(3.53 KB)
📄
debug_test.go
(7.99 KB)
📄
debugcall.go
(6.75 KB)
📄
debuglog.go
(18.24 KB)
📄
debuglog_off.go
(357 B)
📄
debuglog_on.go
(1.09 KB)
📄
debuglog_test.go
(4.9 KB)
📄
defer_test.go
(11.4 KB)
📄
defs1_linux.go
(845 B)
📄
defs1_netbsd_386.go
(2.91 KB)
📄
defs1_netbsd_amd64.go
(3.14 KB)
📄
defs1_netbsd_arm.go
(3.03 KB)
📄
defs1_netbsd_arm64.go
(3.25 KB)
📄
defs1_solaris_amd64.go
(4.01 KB)
📄
defs2_linux.go
(3.22 KB)
📄
defs3_linux.go
(1.09 KB)
📄
defs_aix.go
(4.17 KB)
📄
defs_aix_ppc64.go
(3.63 KB)
📄
defs_arm_linux.go
(2.67 KB)
📄
defs_darwin.go
(4.18 KB)
📄
defs_darwin_amd64.go
(6.34 KB)
📄
defs_darwin_arm64.go
(4.17 KB)
📄
defs_dragonfly.go
(2.73 KB)
📄
defs_dragonfly_amd64.go
(3.41 KB)
📄
defs_freebsd.go
(3.96 KB)
📄
defs_freebsd_386.go
(4.52 KB)
📄
defs_freebsd_amd64.go
(4.79 KB)
📄
defs_freebsd_arm.go
(3.92 KB)
📄
defs_freebsd_arm64.go
(4.18 KB)
📄
defs_freebsd_riscv64.go
(4.19 KB)
📄
defs_illumos_amd64.go
(285 B)
📄
defs_linux.go
(2.92 KB)
📄
defs_linux_386.go
(4.2 KB)
📄
defs_linux_amd64.go
(4.7 KB)
📄
defs_linux_arm.go
(3.89 KB)
📄
defs_linux_arm64.go
(3.62 KB)
📄
defs_linux_loong64.go
(3.43 KB)
📄
defs_linux_mips64x.go
(3.6 KB)
📄
defs_linux_mipsx.go
(3.6 KB)
📄
defs_linux_ppc64.go
(3.69 KB)
📄
defs_linux_ppc64le.go
(3.69 KB)
📄
defs_linux_riscv64.go
(3.81 KB)
📄
defs_linux_s390x.go
(3.16 KB)
📄
defs_netbsd.go
(2.83 KB)
📄
defs_netbsd_386.go
(855 B)
📄
defs_netbsd_amd64.go
(1.01 KB)
📄
defs_netbsd_arm.go
(764 B)
📄
defs_openbsd.go
(3.06 KB)
📄
defs_openbsd_386.go
(2.91 KB)
📄
defs_openbsd_amd64.go
(3.11 KB)
📄
defs_openbsd_arm.go
(3.03 KB)
📄
defs_openbsd_arm64.go
(2.78 KB)
📄
defs_openbsd_mips64.go
(2.75 KB)
📄
defs_openbsd_ppc64.go
(3 KB)
📄
defs_openbsd_riscv64.go
(2.89 KB)
📄
defs_plan9_386.go
(1.63 KB)
📄
defs_plan9_amd64.go
(1.82 KB)
📄
defs_plan9_arm.go
(1.73 KB)
📄
defs_solaris.go
(3.32 KB)
📄
defs_solaris_amd64.go
(1004 B)
📄
defs_windows.go
(2.25 KB)
📄
defs_windows_386.go
(2.28 KB)
📄
defs_windows_amd64.go
(3.19 KB)
📄
defs_windows_arm.go
(2.57 KB)
📄
defs_windows_arm64.go
(3.07 KB)
📄
duff_386.s
(8.24 KB)
📄
duff_amd64.s
(5.64 KB)
📄
duff_arm.s
(7.11 KB)
📄
duff_arm64.s
(5.27 KB)
📄
duff_loong64.s
(11.9 KB)
📄
duff_mips64x.s
(11.28 KB)
📄
duff_ppc64x.s
(7.06 KB)
📄
duff_riscv64.s
(11.4 KB)
📄
duff_s390x.s
(507 B)
📄
ehooks_test.go
(2.04 KB)
📄
env_plan9.go
(3 KB)
📄
env_posix.go
(1.56 KB)
📄
env_test.go
(1.16 KB)
📄
error.go
(9.29 KB)
📄
example_test.go
(1.55 KB)
📄
exithook.go
(2.32 KB)
📄
export_aix_test.go
(207 B)
📄
export_arm_test.go
(226 B)
📄
export_darwin_test.go
(207 B)
📄
export_debug_amd64_test.go
(3.6 KB)
📄
export_debug_arm64_test.go
(3.49 KB)
📄
export_debug_ppc64le_test.go
(3.5 KB)
📄
export_debug_test.go
(5.07 KB)
📄
export_debuglog_test.go
(1.27 KB)
📄
export_linux_test.go
(378 B)
📄
export_mmap_test.go
(429 B)
📄
export_pipe2_test.go
(310 B)
📄
export_pipe_test.go
(219 B)
📄
export_test.go
(50.52 KB)
📄
export_unix_test.go
(2.27 KB)
📄
export_windows_test.go
(903 B)
📄
extern.go
(18.58 KB)
📄
fastlog2.go
(1.22 KB)
📄
fastlog2_test.go
(784 B)
📄
fastlog2table.go
(904 B)
📄
fds_nonunix.go
(256 B)
📄
fds_test.go
(1.43 KB)
📄
fds_unix.go
(1.27 KB)
📄
float.go
(1.35 KB)
📄
float_test.go
(699 B)
📄
funcdata.h
(2.53 KB)
📄
gc_test.go
(20.32 KB)
📄
gcinfo_test.go
(5.95 KB)
📄
go_tls.h
(366 B)
📄
hash32.go
(1.58 KB)
📄
hash64.go
(1.95 KB)
📄
hash_test.go
(17.24 KB)
📄
heap_test.go
(529 B)
📄
heapdump.go
(17.88 KB)
📄
histogram.go
(7.3 KB)
📄
histogram_test.go
(3.51 KB)
📄
iface.go
(20.92 KB)
📄
iface_test.go
(7.45 KB)
📄
import_test.go
(1.42 KB)
📄
importx_test.go
(763 B)
📁
internal
📄
lfstack.go
(2.03 KB)
📄
lfstack_test.go
(2.74 KB)
📄
libfuzzer.go
(6.34 KB)
📄
libfuzzer_amd64.s
(5.03 KB)
📄
libfuzzer_arm64.s
(3.15 KB)
📄
lock_futex.go
(5.4 KB)
📄
lock_js.go
(7.28 KB)
📄
lock_sema.go
(6.75 KB)
📄
lock_wasip1.go
(2.01 KB)
📄
lockrank.go
(18.19 KB)
📄
lockrank_off.go
(1.17 KB)
📄
lockrank_on.go
(10.27 KB)
📄
lockrank_test.go
(856 B)
📄
malloc.go
(58.5 KB)
📄
malloc_test.go
(10.64 KB)
📄
map.go
(52.17 KB)
📄
map_benchmark_test.go
(10.59 KB)
📄
map_fast32.go
(12.74 KB)
📄
map_fast64.go
(12.92 KB)
📄
map_faststr.go
(14.32 KB)
📄
map_test.go
(31.75 KB)
📄
mbarrier.go
(13.78 KB)
📄
mbitmap.go
(22.54 KB)
📄
mbitmap_allocheaders.go
(44.67 KB)
📄
mbitmap_noallocheaders.go
(28.95 KB)
📄
mcache.go
(10 KB)
📄
mcentral.go
(8.05 KB)
📄
mcheckmark.go
(2.85 KB)
📄
mem.go
(6.72 KB)
📄
mem_aix.go
(2.01 KB)
📄
mem_bsd.go
(2.21 KB)
📄
mem_darwin.go
(1.96 KB)
📄
mem_js.go
(457 B)
📄
mem_linux.go
(4.98 KB)
📄
mem_plan9.go
(447 B)
📄
mem_sbrk.go
(4.19 KB)
📄
mem_wasip1.go
(392 B)
📄
mem_wasm.go
(488 B)
📄
mem_windows.go
(3.88 KB)
📄
memclr_386.s
(2.38 KB)
📄
memclr_amd64.s
(4.91 KB)
📄
memclr_arm.s
(2.6 KB)
📄
memclr_arm64.s
(3.62 KB)
📄
memclr_loong64.s
(843 B)
📄
memclr_mips64x.s
(1.72 KB)
📄
memclr_mipsx.s
(1.32 KB)
📄
memclr_plan9_386.s
(983 B)
📄
memclr_plan9_amd64.s
(511 B)
📄
memclr_ppc64x.s
(4.44 KB)
📄
memclr_riscv64.s
(1.71 KB)
📄
memclr_s390x.s
(1.96 KB)
📄
memclr_wasm.s
(485 B)
📄
memmove_386.s
(4.42 KB)
📄
memmove_amd64.s
(12.48 KB)
📄
memmove_arm.s
(5.9 KB)
📄
memmove_arm64.s
(5.96 KB)
📄
memmove_linux_amd64_test.go
(1.53 KB)
📄
memmove_loong64.s
(1.87 KB)
📄
memmove_mips64x.s
(1.83 KB)
📄
memmove_mipsx.s
(4.4 KB)
📄
memmove_plan9_386.s
(3.06 KB)
📄
memmove_plan9_amd64.s
(3.04 KB)
📄
memmove_ppc64x.s
(4.91 KB)
📄
memmove_riscv64.s
(5.46 KB)
📄
memmove_s390x.s
(2.92 KB)
📄
memmove_test.go
(21.23 KB)
📄
memmove_wasm.s
(479 B)
📁
metrics
📄
metrics.go
(26.01 KB)
📄
metrics_test.go
(42.46 KB)
📄
mfinal.go
(18.91 KB)
📄
mfinal_test.go
(5.57 KB)
📄
mfixalloc.go
(3.13 KB)
📄
mgc.go
(59.29 KB)
📄
mgclimit.go
(17.28 KB)
📄
mgclimit_test.go
(9.02 KB)
📄
mgcmark.go
(53.07 KB)
📄
mgcpacer.go
(55.36 KB)
📄
mgcpacer_test.go
(39.26 KB)
📄
mgcscavenge.go
(52.32 KB)
📄
mgcscavenge_test.go
(25.2 KB)
📄
mgcstack.go
(10.58 KB)
📄
mgcsweep.go
(32.26 KB)
📄
mgcwork.go
(12.89 KB)
📄
mheap.go
(72.64 KB)
📄
minmax.go
(1.46 KB)
📄
minmax_test.go
(3.31 KB)
📄
mkduff.go
(8.04 KB)
📄
mkfastlog2table.go
(3.08 KB)
📄
mklockrank.go
(9 KB)
📄
mkpreempt.go
(15.33 KB)
📄
mksizeclasses.go
(9.52 KB)
📄
mmap.go
(844 B)
📄
mpagealloc.go
(39.23 KB)
📄
mpagealloc_32bit.go
(4.56 KB)
📄
mpagealloc_64bit.go
(9.34 KB)
📄
mpagealloc_test.go
(32.59 KB)
📄
mpagecache.go
(5.59 KB)
📄
mpagecache_test.go
(10.79 KB)
📄
mpallocbits.go
(12.58 KB)
📄
mpallocbits_test.go
(13.69 KB)
📄
mprof.go
(47.4 KB)
📄
mranges.go
(14.46 KB)
📄
mranges_test.go
(5.68 KB)
📁
msan
📄
msan.go
(1.5 KB)
📄
msan0.go
(725 B)
📄
msan_amd64.s
(2.3 KB)
📄
msan_arm64.s
(1.98 KB)
📄
msan_loong64.s
(1.96 KB)
📄
msize_allocheaders.go
(1.32 KB)
📄
msize_noallocheaders.go
(915 B)
📄
mspanset.go
(13.12 KB)
📄
mstats.go
(33.81 KB)
📄
mwbbuf.go
(8.13 KB)
📄
nbpipe_pipe.go
(405 B)
📄
nbpipe_pipe2.go
(344 B)
📄
nbpipe_pipe_test.go
(706 B)
📄
nbpipe_test.go
(1.99 KB)
📄
net_plan9.go
(645 B)
📄
netpoll.go
(20.55 KB)
📄
netpoll_aix.go
(5.06 KB)
📄
netpoll_epoll.go
(4.4 KB)
📄
netpoll_fake.go
(664 B)
📄
netpoll_kqueue.go
(5.62 KB)
📄
netpoll_os_test.go
(520 B)
📄
netpoll_solaris.go
(11.2 KB)
📄
netpoll_stub.go
(1.48 KB)
📄
netpoll_wasip1.go
(6.08 KB)
📄
netpoll_windows.go
(4.01 KB)
📄
nonwindows_stub.go
(729 B)
📄
norace_linux_test.go
(915 B)
📄
norace_test.go
(983 B)
📄
numcpu_freebsd_test.go
(381 B)
📄
os2_aix.go
(20.88 KB)
📄
os2_freebsd.go
(302 B)
📄
os2_openbsd.go
(296 B)
📄
os2_plan9.go
(1.48 KB)
📄
os2_solaris.go
(320 B)
📄
os3_plan9.go
(3.94 KB)
📄
os3_solaris.go
(17.59 KB)
📄
os_aix.go
(8.89 KB)
📄
os_android.go
(463 B)
📄
os_darwin.go
(11.92 KB)
📄
os_darwin_arm64.go
(329 B)
📄
os_dragonfly.go
(7.14 KB)
📄
os_freebsd.go
(11.64 KB)
📄
os_freebsd2.go
(603 B)
📄
os_freebsd_amd64.go
(658 B)
📄
os_freebsd_arm.go
(1.45 KB)
📄
os_freebsd_arm64.go
(320 B)
📄
os_freebsd_noauxv.go
(241 B)
📄
os_freebsd_riscv64.go
(198 B)
📄
os_illumos.go
(3.93 KB)
📄
os_js.go
(767 B)
📄
os_linux.go
(25.71 KB)
📄
os_linux_arm.go
(1.51 KB)
📄
os_linux_arm64.go
(478 B)
📄
os_linux_be64.go
(806 B)
📄
os_linux_generic.go
(870 B)
📄
os_linux_loong64.go
(263 B)
📄
os_linux_mips64x.go
(996 B)
📄
os_linux_mipsx.go
(987 B)
📄
os_linux_noauxv.go
(337 B)
📄
os_linux_novdso.go
(347 B)
📄
os_linux_ppc64x.go
(526 B)
📄
os_linux_riscv64.go
(198 B)
📄
os_linux_s390x.go
(825 B)
📄
os_linux_x86.go
(234 B)
📄
os_netbsd.go
(10.12 KB)
📄
os_netbsd_386.go
(617 B)
📄
os_netbsd_amd64.go
(614 B)
📄
os_netbsd_arm.go
(1.07 KB)
📄
os_netbsd_arm64.go
(769 B)
📄
os_nonopenbsd.go
(437 B)
📄
os_only_solaris.go
(357 B)
📄
os_openbsd.go
(6.23 KB)
📄
os_openbsd_arm.go
(662 B)
📄
os_openbsd_arm64.go
(329 B)
📄
os_openbsd_libc.go
(1.49 KB)
📄
os_openbsd_mips64.go
(329 B)
📄
os_openbsd_syscall.go
(1.36 KB)
📄
os_openbsd_syscall1.go
(441 B)
📄
os_openbsd_syscall2.go
(2.51 KB)
📄
os_plan9.go
(10.18 KB)
📄
os_plan9_arm.go
(375 B)
📄
os_solaris.go
(6.62 KB)
📄
os_unix.go
(436 B)
📄
os_unix_nonlinux.go
(374 B)
📄
os_wasip1.go
(7 KB)
📄
os_wasm.go
(3.15 KB)
📄
os_windows.go
(41.39 KB)
📄
os_windows_arm.go
(511 B)
📄
os_windows_arm64.go
(339 B)
📄
pagetrace_off.go
(550 B)
📄
pagetrace_on.go
(10.36 KB)
📄
panic.go
(41.85 KB)
📄
panic32.go
(4.8 KB)
📄
panic_test.go
(1.71 KB)
📄
panicnil_test.go
(1.25 KB)
📄
pinner.go
(10.98 KB)
📄
pinner_test.go
(11.04 KB)
📄
plugin.go
(4.37 KB)
📁
pprof
📄
preempt.go
(15.03 KB)
📄
preempt_386.s
(824 B)
📄
preempt_amd64.s
(1.67 KB)
📄
preempt_arm.s
(1.49 KB)
📄
preempt_arm64.s
(1.97 KB)
📄
preempt_loong64.s
(2.41 KB)
📄
preempt_mips64x.s
(2.72 KB)
📄
preempt_mipsx.s
(2.68 KB)
📄
preempt_nonwindows.go
(290 B)
📄
preempt_ppc64x.s
(2.72 KB)
📄
preempt_riscv64.s
(2.26 KB)
📄
preempt_s390x.s
(1.01 KB)
📄
preempt_wasm.s
(176 B)
📄
print.go
(5.92 KB)
📄
proc.go
(204.28 KB)
📄
proc_runtime_test.go
(1.38 KB)
📄
proc_test.go
(25.85 KB)
📄
profbuf.go
(18.26 KB)
📄
profbuf_test.go
(8.54 KB)
📄
proflabel.go
(1.52 KB)
📁
race
📄
race.go
(18.81 KB)
📄
race0.go
(2.79 KB)
📄
race_amd64.s
(13.94 KB)
📄
race_arm64.s
(14.21 KB)
📄
race_ppc64le.s
(15.93 KB)
📄
race_s390x.s
(11.99 KB)
📄
rand.go
(7.11 KB)
📄
rand_test.go
(1.95 KB)
📄
rdebug.go
(550 B)
📄
retry.go
(760 B)
📄
rt0_aix_ppc64.s
(4.09 KB)
📄
rt0_android_386.s
(822 B)
📄
rt0_android_amd64.s
(754 B)
📄
rt0_android_arm.s
(843 B)
📄
rt0_android_arm64.s
(941 B)
📄
rt0_darwin_amd64.s
(399 B)
📄
rt0_darwin_arm64.s
(1.69 KB)
📄
rt0_dragonfly_amd64.s
(448 B)
📄
rt0_freebsd_386.s
(454 B)
📄
rt0_freebsd_amd64.s
(442 B)
📄
rt0_freebsd_arm.s
(298 B)
📄
rt0_freebsd_arm64.s
(1.88 KB)
📄
rt0_freebsd_riscv64.s
(2.72 KB)
📄
rt0_illumos_amd64.s
(311 B)
📄
rt0_ios_amd64.s
(425 B)
📄
rt0_ios_arm64.s
(425 B)
📄
rt0_js_wasm.s
(1.53 KB)
📄
rt0_linux_386.s
(450 B)
📄
rt0_linux_amd64.s
(307 B)
📄
rt0_linux_arm.s
(1007 B)
📄
rt0_linux_arm64.s
(1.81 KB)
📄
rt0_linux_loong64.s
(2.01 KB)
📄
rt0_linux_mips64x.s
(1014 B)
📄
rt0_linux_mipsx.s
(797 B)
📄
rt0_linux_ppc64.s
(847 B)
📄
rt0_linux_ppc64le.s
(2.89 KB)
📄
rt0_linux_riscv64.s
(2.65 KB)
📄
rt0_linux_s390x.s
(676 B)
📄
rt0_netbsd_386.s
(452 B)
📄
rt0_netbsd_amd64.s
(309 B)
📄
rt0_netbsd_arm.s
(296 B)
📄
rt0_netbsd_arm64.s
(1.8 KB)
📄
rt0_openbsd_386.s
(454 B)
📄
rt0_openbsd_amd64.s
(311 B)
📄
rt0_openbsd_arm.s
(298 B)
📄
rt0_openbsd_arm64.s
(1.96 KB)
📄
rt0_openbsd_mips64.s
(976 B)
📄
rt0_openbsd_ppc64.s
(370 B)
📄
rt0_openbsd_riscv64.s
(372 B)
📄
rt0_plan9_386.s
(523 B)
📄
rt0_plan9_amd64.s
(481 B)
📄
rt0_plan9_arm.s
(397 B)
📄
rt0_solaris_amd64.s
(311 B)
📄
rt0_wasip1_wasm.s
(387 B)
📄
rt0_windows_386.s
(1.28 KB)
📄
rt0_windows_amd64.s
(1.14 KB)
📄
rt0_windows_arm.s
(386 B)
📄
rt0_windows_arm64.s
(733 B)
📄
runtime-gdb.py
(15.44 KB)
📄
runtime-gdb_test.go
(24.04 KB)
📄
runtime-gdb_unix_test.go
(9.4 KB)
📄
runtime-lldb_test.go
(4.95 KB)
📄
runtime-seh_windows_test.go
(4.7 KB)
📄
runtime.go
(7.1 KB)
📄
runtime1.go
(16.66 KB)
📄
runtime2.go
(46.16 KB)
📄
runtime_boring.go
(606 B)
📄
runtime_linux_test.go
(1.77 KB)
📄
runtime_mmap_test.go
(1.77 KB)
📄
runtime_test.go
(11.81 KB)
📄
runtime_unix_test.go
(1.22 KB)
📄
rwmutex.go
(5 KB)
📄
rwmutex_test.go
(4.21 KB)
📄
security_aix.go
(449 B)
📄
security_issetugid.go
(502 B)
📄
security_linux.go
(335 B)
📄
security_nonunix.go
(256 B)
📄
security_test.go
(4.09 KB)
📄
security_unix.go
(818 B)
📄
select.go
(14.82 KB)
📄
sema.go
(18.43 KB)
📄
sema_test.go
(4.21 KB)
📄
semasleep_test.go
(3.46 KB)
📄
sigaction.go
(489 B)
📄
signal_386.go
(1.72 KB)
📄
signal_aix_ppc64.go
(3.54 KB)
📄
signal_amd64.go
(2.73 KB)
📄
signal_arm.go
(2.54 KB)
📄
signal_arm64.go
(3.83 KB)
📄
signal_darwin.go
(2.13 KB)
📄
signal_darwin_amd64.go
(4 KB)
📄
signal_darwin_arm64.go
(3.6 KB)
📄
signal_dragonfly.go
(2.17 KB)
📄
signal_dragonfly_amd64.go
(2.01 KB)
📄
signal_freebsd.go
(2.2 KB)
📄
signal_freebsd_386.go
(1.55 KB)
📄
signal_freebsd_amd64.go
(2.03 KB)
📄
signal_freebsd_arm.go
(2.18 KB)
📄
signal_freebsd_arm64.go
(3.24 KB)
📄
signal_freebsd_riscv64.go
(3.08 KB)
📄
signal_linux_386.go
(1.59 KB)
📄
signal_linux_amd64.go
(2.05 KB)
📄
signal_linux_arm.go
(2.12 KB)
📄
signal_linux_arm64.go
(2.95 KB)
📄
signal_linux_loong64.go
(3.22 KB)
📄
signal_linux_mips64x.go
(3.35 KB)
📄
signal_linux_mipsx.go
(3.67 KB)
📄
signal_linux_ppc64x.go
(3.5 KB)
📄
signal_linux_riscv64.go
(2.92 KB)
📄
signal_linux_s390x.go
(4.49 KB)
📄
signal_loong64.go
(3.01 KB)
📄
signal_mips64x.go
(3.18 KB)
📄
signal_mipsx.go
(3.06 KB)
📄
signal_netbsd.go
(2.18 KB)
📄
signal_netbsd_386.go
(1.76 KB)
📄
signal_netbsd_amd64.go
(2.33 KB)
📄
signal_netbsd_arm.go
(2.3 KB)
📄
signal_netbsd_arm64.go
(3.4 KB)
📄
signal_openbsd.go
(2.18 KB)
📄
signal_openbsd_386.go
(1.58 KB)
📄
signal_openbsd_amd64.go
(2.04 KB)
📄
signal_openbsd_arm.go
(2.12 KB)
📄
signal_openbsd_arm64.go
(3.39 KB)
📄
signal_openbsd_mips64.go
(3.28 KB)
📄
signal_openbsd_ppc64.go
(3.53 KB)
📄
signal_openbsd_riscv64.go
(3.12 KB)
📄
signal_plan9.go
(1.93 KB)
📄
signal_ppc64x.go
(3.71 KB)
📄
signal_riscv64.go
(2.91 KB)
📄
signal_solaris.go
(4.5 KB)
📄
signal_solaris_amd64.go
(2.47 KB)
📄
signal_unix.go
(44.11 KB)
📄
signal_windows.go
(14.48 KB)
📄
signal_windows_test.go
(8.98 KB)
📄
sigqueue.go
(7.62 KB)
📄
sigqueue_note.go
(648 B)
📄
sigqueue_plan9.go
(3.25 KB)
📄
sigtab_aix.go
(11.3 KB)
📄
sigtab_linux_generic.go
(3.52 KB)
📄
sigtab_linux_mipsx.go
(5.95 KB)
📄
sizeclasses.go
(9.17 KB)
📄
sizeof_test.go
(1003 B)
📄
slice.go
(11.23 KB)
📄
slice_test.go
(10.32 KB)
📄
softfloat64.go
(11.54 KB)
📄
softfloat64_test.go
(4.04 KB)
📄
stack.go
(40.02 KB)
📄
stack_test.go
(23.14 KB)
📄
start_line_amd64_test.go
(647 B)
📄
start_line_test.go
(2.58 KB)
📄
stkframe.go
(9.88 KB)
📄
string.go
(13.35 KB)
📄
string_test.go
(13.33 KB)
📄
stubs.go
(17.39 KB)
📄
stubs2.go
(1.15 KB)
📄
stubs3.go
(324 B)
📄
stubs_386.go
(708 B)
📄
stubs_amd64.go
(1.38 KB)
📄
stubs_arm.go
(689 B)
📄
stubs_arm64.go
(700 B)
📄
stubs_linux.go
(650 B)
📄
stubs_loong64.go
(638 B)
📄
stubs_mips64x.go
(522 B)
📄
stubs_mipsx.go
(441 B)
📄
stubs_nonlinux.go
(298 B)
📄
stubs_ppc64.go
(302 B)
📄
stubs_ppc64x.go
(688 B)
📄
stubs_riscv64.go
(695 B)
📄
stubs_s390x.go
(414 B)
📄
symtab.go
(34.76 KB)
📄
symtab_test.go
(7.48 KB)
📄
symtabinl.go
(3.81 KB)
📄
symtabinl_test.go
(2.97 KB)
📄
sys_aix_ppc64.s
(7.42 KB)
📄
sys_arm.go
(521 B)
📄
sys_arm64.go
(469 B)
📄
sys_darwin.go
(22.56 KB)
📄
sys_darwin_amd64.s
(19.65 KB)
📄
sys_darwin_arm64.go
(1.74 KB)
📄
sys_darwin_arm64.s
(18.28 KB)
📄
sys_dragonfly_amd64.s
(8.31 KB)
📄
sys_freebsd_386.s
(9.41 KB)
📄
sys_freebsd_amd64.s
(12.67 KB)
📄
sys_freebsd_arm.s
(10.38 KB)
📄
sys_freebsd_arm64.s
(9.49 KB)
📄
sys_freebsd_riscv64.s
(8.92 KB)
📄
sys_libc.go
(1.84 KB)
📄
sys_linux_386.s
(17.89 KB)
📄
sys_linux_amd64.s
(15.74 KB)
📄
sys_linux_arm.s
(13.5 KB)
📄
sys_linux_arm64.s
(16.71 KB)
📄
sys_linux_loong64.s
(14.16 KB)
📄
sys_linux_mips64x.s
(11.96 KB)
📄
sys_linux_mipsx.s
(9.69 KB)
📄
sys_linux_ppc64x.s
(18.09 KB)
📄
sys_linux_riscv64.s
(11.48 KB)
📄
sys_linux_s390x.s
(12.49 KB)
📄
sys_loong64.go
(489 B)
📄
sys_mips64x.go
(500 B)
📄
sys_mipsx.go
(496 B)
📄
sys_netbsd_386.s
(9.61 KB)
📄
sys_netbsd_amd64.s
(9.78 KB)
📄
sys_netbsd_arm.s
(10.58 KB)
📄
sys_netbsd_arm64.s
(9.47 KB)
📄
sys_nonppc64x.go
(245 B)
📄
sys_openbsd.go
(2.59 KB)
📄
sys_openbsd1.go
(1.23 KB)
📄
sys_openbsd2.go
(8.67 KB)
📄
sys_openbsd3.go
(3.37 KB)
📄
sys_openbsd_386.s
(20.4 KB)
📄
sys_openbsd_amd64.s
(15.54 KB)
📄
sys_openbsd_arm.s
(18.46 KB)
📄
sys_openbsd_arm64.s
(15.05 KB)
📄
sys_openbsd_mips64.s
(8.81 KB)
📄
sys_openbsd_ppc64.s
(15.3 KB)
📄
sys_openbsd_riscv64.s
(16.8 KB)
📄
sys_plan9_386.s
(4.48 KB)
📄
sys_plan9_amd64.s
(4.56 KB)
📄
sys_plan9_arm.s
(7.03 KB)
📄
sys_ppc64x.go
(532 B)
📄
sys_riscv64.go
(469 B)
📄
sys_s390x.go
(469 B)
📄
sys_solaris_amd64.s
(6.42 KB)
📄
sys_wasm.go
(758 B)
📄
sys_wasm.s
(1.43 KB)
📄
sys_windows_386.s
(6.46 KB)
📄
sys_windows_amd64.s
(8.41 KB)
📄
sys_windows_arm.s
(7.72 KB)
📄
sys_windows_arm64.s
(6.8 KB)
📄
sys_x86.go
(552 B)
📄
syscall2_solaris.go
(1.85 KB)
📄
syscall_aix.go
(6.33 KB)
📄
syscall_solaris.go
(8.38 KB)
📄
syscall_unix_test.go
(635 B)
📄
syscall_windows.go
(16.57 KB)
📄
syscall_windows_test.go
(32.45 KB)
📄
tagptr.go
(496 B)
📄
tagptr_32bit.go
(927 B)
📄
tagptr_64bit.go
(3.23 KB)
📄
test_amd64.go
(196 B)
📄
test_amd64.s
(316 B)
📄
test_stubs.go
(218 B)
📁
testdata
📄
textflag.h
(1.47 KB)
📄
time.go
(30.57 KB)
📄
time_fake.go
(2.5 KB)
📄
time_linux_amd64.s
(2.02 KB)
📄
time_nofake.go
(709 B)
📄
time_test.go
(2.04 KB)
📄
time_windows.h
(753 B)
📄
time_windows_386.s
(1.71 KB)
📄
time_windows_amd64.s
(786 B)
📄
time_windows_arm.s
(1.97 KB)
📄
time_windows_arm64.s
(906 B)
📄
timeasm.go
(418 B)
📄
timestub.go
(532 B)
📄
timestub2.go
(363 B)
📄
tls_arm.s
(3.45 KB)
📄
tls_arm64.h
(1.1 KB)
📄
tls_arm64.s
(1.2 KB)
📄
tls_loong64.s
(589 B)
📄
tls_mips64x.s
(733 B)
📄
tls_mipsx.s
(710 B)
📄
tls_ppc64x.s
(1.52 KB)
📄
tls_riscv64.s
(615 B)
📄
tls_s390x.s
(1.55 KB)
📄
tls_stub.go
(260 B)
📄
tls_windows_amd64.go
(294 B)
📁
trace
📄
trace.go
(62.76 KB)
📄
trace2.go
(33.81 KB)
📄
trace2buf.go
(6.58 KB)
📄
trace2cpu.go
(8.87 KB)
📄
trace2event.go
(8.39 KB)
📄
trace2map.go
(4.36 KB)
📄
trace2region.go
(1.68 KB)
📄
trace2runtime.go
(24.2 KB)
📄
trace2stack.go
(9.45 KB)
📄
trace2status.go
(7.24 KB)
📄
trace2string.go
(2.59 KB)
📄
trace2time.go
(3.21 KB)
📄
trace_cgo_test.go
(4.47 KB)
📄
traceback.go
(54.61 KB)
📄
traceback_test.go
(22.95 KB)
📄
tracebackx_test.go
(509 B)
📄
type.go
(12.1 KB)
📄
typekind.go
(743 B)
📄
unsafe.go
(2.97 KB)
📄
unsafepoint_test.go
(3.27 KB)
📄
utf8.go
(3.39 KB)
📄
vdso_elf32.go
(2.76 KB)
📄
vdso_elf64.go
(2.84 KB)
📄
vdso_freebsd.go
(2.44 KB)
📄
vdso_freebsd_arm.go
(454 B)
📄
vdso_freebsd_arm64.go
(454 B)
📄
vdso_freebsd_riscv64.go
(429 B)
📄
vdso_freebsd_x86.go
(1.86 KB)
📄
vdso_in_none.go
(443 B)
📄
vdso_linux.go
(7.77 KB)
📄
vdso_linux_386.go
(669 B)
📄
vdso_linux_amd64.go
(685 B)
📄
vdso_linux_arm.go
(669 B)
📄
vdso_linux_arm64.go
(670 B)
📄
vdso_linux_loong64.go
(793 B)
📄
vdso_linux_mips64x.go
(850 B)
📄
vdso_linux_ppc64x.go
(672 B)
📄
vdso_linux_riscv64.go
(666 B)
📄
vdso_linux_s390x.go
(659 B)
📄
vdso_test.go
(3.71 KB)
📄
vlop_386.s
(2.02 KB)
📄
vlop_arm.s
(7.06 KB)
📄
vlop_arm_test.go
(3.75 KB)
📄
vlrt.go
(6.71 KB)
📄
wincallback.go
(3.45 KB)
📄
write_err.go
(291 B)
📄
write_err_android.go
(4.65 KB)
📄
zcallback_windows.go
(155 B)
📄
zcallback_windows.s
(63.06 KB)
📄
zcallback_windows_arm.s
(89.32 KB)
📄
zcallback_windows_arm64.s
(89.32 KB)
Editing: trace2.go
// Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build goexperiment.exectracer2 // Go execution tracer. // The tracer captures a wide range of execution events like goroutine // creation/blocking/unblocking, syscall enter/exit/block, GC-related events, // changes of heap size, processor start/stop, etc and writes them to a buffer // in a compact form. A precise nanosecond-precision timestamp and a stack // trace is captured for most events. // // Tracer invariants (to keep the synchronization making sense): // - An m that has a trace buffer must be on either the allm or sched.freem lists. // - Any trace buffer mutation must either be happening in traceAdvance or between // a traceAcquire and a subsequent traceRelease. // - traceAdvance cannot return until the previous generation's buffers are all flushed. // // See https://go.dev/issue/60773 for a link to the full design. package runtime import ( "runtime/internal/atomic" "unsafe" ) // Trace state. // trace is global tracing context. var trace struct { // trace.lock must only be acquired on the system stack where // stack splits cannot happen while it is held. lock mutex // Trace buffer management. // // First we check the empty list for any free buffers. If not, buffers // are allocated directly from the OS. Once they're filled up and/or // flushed, they end up on the full queue for trace.gen%2. // // The trace reader takes buffers off the full list one-by-one and // places them into reading until they're finished being read from. // Then they're placed onto the empty list. // // Protected by trace.lock. reading *traceBuf // buffer currently handed off to user empty *traceBuf // stack of empty buffers full [2]traceBufQueue workAvailable atomic.Bool // State for the trace reader goroutine. // // Protected by trace.lock. readerGen atomic.Uintptr // the generation the reader is currently reading for flushedGen atomic.Uintptr // the last completed generation headerWritten bool // whether ReadTrace has emitted trace header // doneSema is used to synchronize the reader and traceAdvance. Specifically, // it notifies traceAdvance that the reader is done with a generation. // Both semaphores are 0 by default (so, acquires block). traceAdvance // attempts to acquire for gen%2 after flushing the last buffers for gen. // Meanwhile the reader releases the sema for gen%2 when it has finished // processing gen. doneSema [2]uint32 // Trace data tables for deduplicating data going into the trace. // There are 2 of each: one for gen%2, one for 1-gen%2. stackTab [2]traceStackTable // maps stack traces to unique ids stringTab [2]traceStringTable // maps strings to unique ids // cpuLogRead accepts CPU profile samples from the signal handler where // they're generated. There are two profBufs here: one for gen%2, one for // 1-gen%2. These profBufs use a three-word header to hold the IDs of the P, G, // and M (respectively) that were active at the time of the sample. Because // profBuf uses a record with all zeros in its header to indicate overflow, // we make sure to make the P field always non-zero: The ID of a real P will // start at bit 1, and bit 0 will be set. Samples that arrive while no P is // running (such as near syscalls) will set the first header field to 0b10. // This careful handling of the first header field allows us to store ID of // the active G directly in the second field, even though that will be 0 // when sampling g0. // // Initialization and teardown of these fields is protected by traceAdvanceSema. cpuLogRead [2]*profBuf signalLock atomic.Uint32 // protects use of the following member, only usable in signal handlers cpuLogWrite [2]atomic.Pointer[profBuf] // copy of cpuLogRead for use in signal handlers, set without signalLock cpuSleep *wakeableSleep cpuLogDone <-chan struct{} cpuBuf [2]*traceBuf reader atomic.Pointer[g] // goroutine that called ReadTrace, or nil // Fast mappings from enumerations to string IDs that are prepopulated // in the trace. markWorkerLabels [2][len(gcMarkWorkerModeStrings)]traceArg goStopReasons [2][len(traceGoStopReasonStrings)]traceArg goBlockReasons [2][len(traceBlockReasonStrings)]traceArg // Trace generation counter. gen atomic.Uintptr lastNonZeroGen uintptr // last non-zero value of gen // shutdown is set when we are waiting for trace reader to finish after setting gen to 0 // // Writes protected by trace.lock. shutdown atomic.Bool // Number of goroutines in syscall exiting slow path. exitingSyscall atomic.Int32 // seqGC is the sequence counter for GC begin/end. // // Mutated only during stop-the-world. seqGC uint64 } // Trace public API. var ( traceAdvanceSema uint32 = 1 traceShutdownSema uint32 = 1 ) // StartTrace enables tracing for the current process. // While tracing, the data will be buffered and available via [ReadTrace]. // StartTrace returns an error if tracing is already enabled. // Most clients should use the [runtime/trace] package or the [testing] package's // -test.trace flag instead of calling StartTrace directly. func StartTrace() error { if traceEnabled() || traceShuttingDown() { return errorString("tracing is already enabled") } // Block until cleanup of the last trace is done. semacquire(&traceShutdownSema) semrelease(&traceShutdownSema) // Hold traceAdvanceSema across trace start, since we'll want it on // the other side of tracing being enabled globally. semacquire(&traceAdvanceSema) // Initialize CPU profile -> trace ingestion. traceInitReadCPU() // Compute the first generation for this StartTrace. // // Note: we start from the last non-zero generation rather than 1 so we // can avoid resetting all the arrays indexed by gen%2 or gen%3. There's // more than one of each per m, p, and goroutine. firstGen := traceNextGen(trace.lastNonZeroGen) // Reset GC sequencer. trace.seqGC = 1 // Reset trace reader state. trace.headerWritten = false trace.readerGen.Store(firstGen) trace.flushedGen.Store(0) // Register some basic strings in the string tables. traceRegisterLabelsAndReasons(firstGen) // Stop the world. // // The purpose of stopping the world is to make sure that no goroutine is in a // context where it could emit an event by bringing all goroutines to a safe point // with no opportunity to transition. // // The exception to this rule are goroutines that are concurrently exiting a syscall. // Those will all be forced into the syscalling slow path, and we'll just make sure // that we don't observe any goroutines in that critical section before starting // the world again. // // A good follow-up question to this is why stopping the world is necessary at all // given that we have traceAcquire and traceRelease. Unfortunately, those only help // us when tracing is already active (for performance, so when tracing is off the // tracing seqlock is left untouched). The main issue here is subtle: we're going to // want to obtain a correct starting status for each goroutine, but there are windows // of time in which we could read and emit an incorrect status. Specifically: // // trace := traceAcquire() // // <----> problem window // casgstatus(gp, _Gwaiting, _Grunnable) // if trace.ok() { // trace.GoUnpark(gp, 2) // traceRelease(trace) // } // // More precisely, if we readgstatus for a gp while another goroutine is in the problem // window and that goroutine didn't observe that tracing had begun, then we might write // a GoStatus(GoWaiting) event for that goroutine, but it won't trace an event marking // the transition from GoWaiting to GoRunnable. The trace will then be broken, because // future events will be emitted assuming the tracer sees GoRunnable. // // In short, what we really need here is to make sure that the next time *any goroutine* // hits a traceAcquire, it sees that the trace is enabled. // // Note also that stopping the world is necessary to make sure sweep-related events are // coherent. Since the world is stopped and sweeps are non-preemptible, we can never start // the world and see an unpaired sweep 'end' event. Other parts of the tracer rely on this. stw := stopTheWorld(stwStartTrace) // Prevent sysmon from running any code that could generate events. lock(&sched.sysmonlock) // Reset mSyscallID on all Ps while we have them stationary and the trace is disabled. for _, pp := range allp { pp.trace.mSyscallID = -1 } // Start tracing. // // After this executes, other Ms may start creating trace buffers and emitting // data into them. trace.gen.Store(firstGen) // Wait for exitingSyscall to drain. // // It may not monotonically decrease to zero, but in the limit it will always become // zero because the world is stopped and there are no available Ps for syscall-exited // goroutines to run on. // // Because we set gen before checking this, and because exitingSyscall is always incremented // *after* traceAcquire (which checks gen), we can be certain that when exitingSyscall is zero // that any goroutine that goes to exit a syscall from then on *must* observe the new gen. // // The critical section on each goroutine here is going to be quite short, so the likelihood // that we observe a zero value is high. for trace.exitingSyscall.Load() != 0 { osyield() } // Record some initial pieces of information. // // N.B. This will also emit a status event for this goroutine. tl := traceAcquire() tl.Gomaxprocs(gomaxprocs) // Get this as early in the trace as possible. See comment in traceAdvance. tl.STWStart(stwStartTrace) // We didn't trace this above, so trace it now. // Record the fact that a GC is active, if applicable. if gcphase == _GCmark || gcphase == _GCmarktermination { tl.GCActive() } // Record the heap goal so we have it at the very beginning of the trace. tl.HeapGoal() // Make sure a ProcStatus is emitted for every P, while we're here. for _, pp := range allp { tl.writer().writeProcStatusForP(pp, pp == tl.mp.p.ptr()).end() } traceRelease(tl) unlock(&sched.sysmonlock) startTheWorld(stw) traceStartReadCPU() traceAdvancer.start() semrelease(&traceAdvanceSema) return nil } // StopTrace stops tracing, if it was previously enabled. // StopTrace only returns after all the reads for the trace have completed. func StopTrace() { traceAdvance(true) } // traceAdvance moves tracing to the next generation, and cleans up the current generation, // ensuring that it's flushed out before returning. If stopTrace is true, it disables tracing // altogether instead of advancing to the next generation. // // traceAdvanceSema must not be held. func traceAdvance(stopTrace bool) { semacquire(&traceAdvanceSema) // Get the gen that we're advancing from. In this function we don't really care much // about the generation we're advancing _into_ since we'll do all the cleanup in this // generation for the next advancement. gen := trace.gen.Load() if gen == 0 { // We may end up here traceAdvance is called concurrently with StopTrace. semrelease(&traceAdvanceSema) return } // Write an EvFrequency event for this generation. // // N.B. This may block for quite a while to get a good frequency estimate, so make sure we do // this here and not e.g. on the trace reader. traceFrequency(gen) // Collect all the untraced Gs. type untracedG struct { gp *g goid uint64 mid int64 status uint32 waitreason waitReason inMarkAssist bool } var untracedGs []untracedG forEachGRace(func(gp *g) { // Make absolutely sure all Gs are ready for the next // generation. We need to do this even for dead Gs because // they may come alive with a new identity, and its status // traced bookkeeping might end up being stale. // We may miss totally new goroutines, but they'll always // have clean bookkeeping. gp.trace.readyNextGen(gen) // If the status was traced, nothing else to do. if gp.trace.statusWasTraced(gen) { return } // Scribble down information about this goroutine. ug := untracedG{gp: gp, mid: -1} systemstack(func() { me := getg().m.curg // We don't have to handle this G status transition because we // already eliminated ourselves from consideration above. casGToWaiting(me, _Grunning, waitReasonTraceGoroutineStatus) // We need to suspend and take ownership of the G to safely read its // goid. Note that we can't actually emit the event at this point // because we might stop the G in a window where it's unsafe to write // events based on the G's status. We need the global trace buffer flush // coming up to make sure we're not racing with the G. // // It should be very unlikely that we try to preempt a running G here. // The only situation that we might is that we're racing with a G // that's running for the first time in this generation. Therefore, // this should be relatively fast. s := suspendG(gp) if !s.dead { ug.goid = s.g.goid if s.g.m != nil { ug.mid = int64(s.g.m.procid) } ug.status = readgstatus(s.g) &^ _Gscan ug.waitreason = s.g.waitreason ug.inMarkAssist = s.g.inMarkAssist } resumeG(s) casgstatus(me, _Gwaiting, _Grunning) }) if ug.goid != 0 { untracedGs = append(untracedGs, ug) } }) if !stopTrace { // Re-register runtime goroutine labels and stop/block reasons. traceRegisterLabelsAndReasons(traceNextGen(gen)) } // Now that we've done some of the heavy stuff, prevent the world from stopping. // This is necessary to ensure the consistency of the STW events. If we're feeling // adventurous we could lift this restriction and add a STWActive event, but the // cost of maintaining this consistency is low. We're not going to hold this semaphore // for very long and most STW periods are very short. // Once we hold worldsema, prevent preemption as well so we're not interrupted partway // through this. We want to get this done as soon as possible. semacquire(&worldsema) mp := acquirem() // Advance the generation or stop the trace. trace.lastNonZeroGen = gen if stopTrace { systemstack(func() { // Ordering is important here. Set shutdown first, then disable tracing, // so that conditions like (traceEnabled() || traceShuttingDown()) have // no opportunity to be false. Hold the trace lock so this update appears // atomic to the trace reader. lock(&trace.lock) trace.shutdown.Store(true) trace.gen.Store(0) unlock(&trace.lock) }) } else { trace.gen.Store(traceNextGen(gen)) } // Emit a ProcsChange event so we have one on record for each generation. // Let's emit it as soon as possible so that downstream tools can rely on the value // being there fairly soon in a generation. // // It's important that we do this before allowing stop-the-worlds again, // because the procs count could change. if !stopTrace { tl := traceAcquire() tl.Gomaxprocs(gomaxprocs) traceRelease(tl) } // Emit a GCActive event in the new generation if necessary. // // It's important that we do this before allowing stop-the-worlds again, // because that could emit global GC-related events. if !stopTrace && (gcphase == _GCmark || gcphase == _GCmarktermination) { tl := traceAcquire() tl.GCActive() traceRelease(tl) } // Preemption is OK again after this. If the world stops or whatever it's fine. // We're just cleaning up the last generation after this point. // // We also don't care if the GC starts again after this for the same reasons. releasem(mp) semrelease(&worldsema) // Snapshot allm and freem. // // Snapshotting after the generation counter update is sufficient. // Because an m must be on either allm or sched.freem if it has an active trace // buffer, new threads added to allm after this point must necessarily observe // the new generation number (sched.lock acts as a barrier). // // Threads that exit before this point and are on neither list explicitly // flush their own buffers in traceThreadDestroy. // // Snapshotting freem is necessary because Ms can continue to emit events // while they're still on that list. Removal from sched.freem is serialized with // this snapshot, so either we'll capture an m on sched.freem and race with // the removal to flush its buffers (resolved by traceThreadDestroy acquiring // the thread's seqlock, which one of us must win, so at least its old gen buffer // will be flushed in time for the new generation) or it will have flushed its // buffers before we snapshotted it to begin with. lock(&sched.lock) mToFlush := allm for mp := mToFlush; mp != nil; mp = mp.alllink { mp.trace.link = mp.alllink } for mp := sched.freem; mp != nil; mp = mp.freelink { mp.trace.link = mToFlush mToFlush = mp } unlock(&sched.lock) // Iterate over our snapshot, flushing every buffer until we're done. // // Because trace writers read the generation while the seqlock is // held, we can be certain that when there are no writers there are // also no stale generation values left. Therefore, it's safe to flush // any buffers that remain in that generation's slot. const debugDeadlock = false systemstack(func() { // Track iterations for some rudimentary deadlock detection. i := 0 detectedDeadlock := false for mToFlush != nil { prev := &mToFlush for mp := *prev; mp != nil; { if mp.trace.seqlock.Load()%2 != 0 { // The M is writing. Come back to it later. prev = &mp.trace.link mp = mp.trace.link continue } // Flush the trace buffer. // // trace.lock needed for traceBufFlush, but also to synchronize // with traceThreadDestroy, which flushes both buffers unconditionally. lock(&trace.lock) bufp := &mp.trace.buf[gen%2] if *bufp != nil { traceBufFlush(*bufp, gen) *bufp = nil } unlock(&trace.lock) // Remove the m from the flush list. *prev = mp.trace.link mp.trace.link = nil mp = *prev } // Yield only if we're going to be going around the loop again. if mToFlush != nil { osyield() } if debugDeadlock { // Try to detect a deadlock. We probably shouldn't loop here // this many times. if i > 100000 && !detectedDeadlock { detectedDeadlock = true println("runtime: failing to flush") for mp := mToFlush; mp != nil; mp = mp.trace.link { print("runtime: m=", mp.id, "\n") } } i++ } } }) // At this point, the old generation is fully flushed minus stack and string // tables, CPU samples, and goroutines that haven't run at all during the last // generation. // Check to see if any Gs still haven't had events written out for them. statusWriter := unsafeTraceWriter(gen, nil) for _, ug := range untracedGs { if ug.gp.trace.statusWasTraced(gen) { // It was traced, we don't need to do anything. continue } // It still wasn't traced. Because we ensured all Ms stopped writing trace // events to the last generation, that must mean the G never had its status // traced in gen between when we recorded it and now. If that's true, the goid // and status we recorded then is exactly what we want right now. status := goStatusToTraceGoStatus(ug.status, ug.waitreason) statusWriter = statusWriter.writeGoStatus(ug.goid, ug.mid, status, ug.inMarkAssist) } statusWriter.flush().end() systemstack(func() { // Flush CPU samples, stacks, and strings for the last generation. This is safe, // because we're now certain no M is writing to the last generation. // // Ordering is important here. traceCPUFlush may generate new stacks and dumping // stacks may generate new strings. traceCPUFlush(gen) trace.stackTab[gen%2].dump(gen) trace.stringTab[gen%2].reset(gen) // That's it. This generation is done producing buffers. lock(&trace.lock) trace.flushedGen.Store(gen) unlock(&trace.lock) }) if stopTrace { semacquire(&traceShutdownSema) // Finish off CPU profile reading. traceStopReadCPU() } else { // Go over each P and emit a status event for it if necessary. // // We do this at the beginning of the new generation instead of the // end like we do for goroutines because forEachP doesn't give us a // hook to skip Ps that have already been traced. Since we have to // preempt all Ps anyway, might as well stay consistent with StartTrace // which does this during the STW. semacquire(&worldsema) forEachP(waitReasonTraceProcStatus, func(pp *p) { tl := traceAcquire() if !pp.trace.statusWasTraced(tl.gen) { tl.writer().writeProcStatusForP(pp, false).end() } traceRelease(tl) }) // Perform status reset on dead Ps because they just appear as idle. // // Holding worldsema prevents allp from changing. // // TODO(mknyszek): Consider explicitly emitting ProcCreate and ProcDestroy // events to indicate whether a P exists, rather than just making its // existence implicit. for _, pp := range allp[len(allp):cap(allp)] { pp.trace.readyNextGen(traceNextGen(gen)) } semrelease(&worldsema) } // Block until the trace reader has finished processing the last generation. semacquire(&trace.doneSema[gen%2]) if raceenabled { raceacquire(unsafe.Pointer(&trace.doneSema[gen%2])) } // Double-check that things look as we expect after advancing and perform some // final cleanup if the trace has fully stopped. systemstack(func() { lock(&trace.lock) if !trace.full[gen%2].empty() { throw("trace: non-empty full trace buffer for done generation") } if stopTrace { if !trace.full[1-(gen%2)].empty() { throw("trace: non-empty full trace buffer for next generation") } if trace.reading != nil || trace.reader.Load() != nil { throw("trace: reading after shutdown") } // Free all the empty buffers. for trace.empty != nil { buf := trace.empty trace.empty = buf.link sysFree(unsafe.Pointer(buf), unsafe.Sizeof(*buf), &memstats.other_sys) } // Clear trace.shutdown and other flags. trace.headerWritten = false trace.shutdown.Store(false) } unlock(&trace.lock) }) if stopTrace { // Clear the sweep state on every P for the next time tracing is enabled. // // It may be stale in the next trace because we may have ended tracing in // the middle of a sweep on a P. // // It's fine not to call forEachP here because tracing is disabled and we // know at this point that nothing is calling into the tracer, but we do // need to look at dead Ps too just because GOMAXPROCS could have been called // at any point since we stopped tracing, and we have to ensure there's no // bad state on dead Ps too. Prevent a STW and a concurrent GOMAXPROCS that // might mutate allp by making ourselves briefly non-preemptible. mp := acquirem() for _, pp := range allp[:cap(allp)] { pp.trace.inSweep = false pp.trace.maySweep = false pp.trace.swept = 0 pp.trace.reclaimed = 0 } releasem(mp) } // Release the advance semaphore. If stopTrace is true we're still holding onto // traceShutdownSema. // // Do a direct handoff. Don't let one caller of traceAdvance starve // other calls to traceAdvance. semrelease1(&traceAdvanceSema, true, 0) if stopTrace { // Stop the traceAdvancer. We can't be holding traceAdvanceSema here because // we'll deadlock (we're blocked on the advancer goroutine exiting, but it // may be currently trying to acquire traceAdvanceSema). traceAdvancer.stop() semrelease(&traceShutdownSema) } } func traceNextGen(gen uintptr) uintptr { if gen == ^uintptr(0) { // gen is used both %2 and %3 and we want both patterns to continue when we loop around. // ^uint32(0) and ^uint64(0) are both odd and multiples of 3. Therefore the next generation // we want is even and one more than a multiple of 3. The smallest such number is 4. return 4 } return gen + 1 } // traceRegisterLabelsAndReasons re-registers mark worker labels and // goroutine stop/block reasons in the string table for the provided // generation. Note: the provided generation must not have started yet. func traceRegisterLabelsAndReasons(gen uintptr) { for i, label := range gcMarkWorkerModeStrings[:] { trace.markWorkerLabels[gen%2][i] = traceArg(trace.stringTab[gen%2].put(gen, label)) } for i, str := range traceBlockReasonStrings[:] { trace.goBlockReasons[gen%2][i] = traceArg(trace.stringTab[gen%2].put(gen, str)) } for i, str := range traceGoStopReasonStrings[:] { trace.goStopReasons[gen%2][i] = traceArg(trace.stringTab[gen%2].put(gen, str)) } } // ReadTrace returns the next chunk of binary tracing data, blocking until data // is available. If tracing is turned off and all the data accumulated while it // was on has been returned, ReadTrace returns nil. The caller must copy the // returned data before calling ReadTrace again. // ReadTrace must be called from one goroutine at a time. func ReadTrace() []byte { top: var buf []byte var park bool systemstack(func() { buf, park = readTrace0() }) if park { gopark(func(gp *g, _ unsafe.Pointer) bool { if !trace.reader.CompareAndSwapNoWB(nil, gp) { // We're racing with another reader. // Wake up and handle this case. return false } if g2 := traceReader(); gp == g2 { // New data arrived between unlocking // and the CAS and we won the wake-up // race, so wake up directly. return false } else if g2 != nil { printlock() println("runtime: got trace reader", g2, g2.goid) throw("unexpected trace reader") } return true }, nil, waitReasonTraceReaderBlocked, traceBlockSystemGoroutine, 2) goto top } return buf } // readTrace0 is ReadTrace's continuation on g0. This must run on the // system stack because it acquires trace.lock. // //go:systemstack func readTrace0() (buf []byte, park bool) { if raceenabled { // g0 doesn't have a race context. Borrow the user G's. if getg().racectx != 0 { throw("expected racectx == 0") } getg().racectx = getg().m.curg.racectx // (This defer should get open-coded, which is safe on // the system stack.) defer func() { getg().racectx = 0 }() } // This function must not allocate while holding trace.lock: // allocation can call heap allocate, which will try to emit a trace // event while holding heap lock. lock(&trace.lock) if trace.reader.Load() != nil { // More than one goroutine reads trace. This is bad. // But we rather do not crash the program because of tracing, // because tracing can be enabled at runtime on prod servers. unlock(&trace.lock) println("runtime: ReadTrace called from multiple goroutines simultaneously") return nil, false } // Recycle the old buffer. if buf := trace.reading; buf != nil { buf.link = trace.empty trace.empty = buf trace.reading = nil } // Write trace header. if !trace.headerWritten { trace.headerWritten = true unlock(&trace.lock) return []byte("go 1.22 trace\x00\x00\x00"), false } // Read the next buffer. if trace.readerGen.Load() == 0 { trace.readerGen.Store(1) } var gen uintptr for { assertLockHeld(&trace.lock) gen = trace.readerGen.Load() // Check to see if we need to block for more data in this generation // or if we need to move our generation forward. if !trace.full[gen%2].empty() { break } // Most of the time readerGen is one generation ahead of flushedGen, as the // current generation is being read from. Then, once the last buffer is flushed // into readerGen, flushedGen will rise to meet it. At this point, the tracer // is waiting on the reader to finish flushing the last generation so that it // can continue to advance. if trace.flushedGen.Load() == gen { if trace.shutdown.Load() { unlock(&trace.lock) // Wake up anyone waiting for us to be done with this generation. // // Do this after reading trace.shutdown, because the thread we're // waking up is going to clear trace.shutdown. if raceenabled { // Model synchronization on trace.doneSema, which te race // detector does not see. This is required to avoid false // race reports on writer passed to trace.Start. racerelease(unsafe.Pointer(&trace.doneSema[gen%2])) } semrelease(&trace.doneSema[gen%2]) // We're shutting down, and the last generation is fully // read. We're done. return nil, false } // The previous gen has had all of its buffers flushed, and // there's nothing else for us to read. Advance the generation // we're reading from and try again. trace.readerGen.Store(trace.gen.Load()) unlock(&trace.lock) // Wake up anyone waiting for us to be done with this generation. // // Do this after reading gen to make sure we can't have the trace // advance until we've read it. if raceenabled { // See comment above in the shutdown case. racerelease(unsafe.Pointer(&trace.doneSema[gen%2])) } semrelease(&trace.doneSema[gen%2]) // Reacquire the lock and go back to the top of the loop. lock(&trace.lock) continue } // Wait for new data. // // We don't simply use a note because the scheduler // executes this goroutine directly when it wakes up // (also a note would consume an M). // // Before we drop the lock, clear the workAvailable flag. Work can // only be queued with trace.lock held, so this is at least true until // we drop the lock. trace.workAvailable.Store(false) unlock(&trace.lock) return nil, true } // Pull a buffer. tbuf := trace.full[gen%2].pop() trace.reading = tbuf unlock(&trace.lock) return tbuf.arr[:tbuf.pos], false } // traceReader returns the trace reader that should be woken up, if any. // Callers should first check (traceEnabled() || traceShuttingDown()). // // This must run on the system stack because it acquires trace.lock. // //go:systemstack func traceReader() *g { gp := traceReaderAvailable() if gp == nil || !trace.reader.CompareAndSwapNoWB(gp, nil) { return nil } return gp } // traceReaderAvailable returns the trace reader if it is not currently // scheduled and should be. Callers should first check that // (traceEnabled() || traceShuttingDown()) is true. func traceReaderAvailable() *g { // There are three conditions under which we definitely want to schedule // the reader: // - The reader is lagging behind in finishing off the last generation. // In this case, trace buffers could even be empty, but the trace // advancer will be waiting on the reader, so we have to make sure // to schedule the reader ASAP. // - The reader has pending work to process for it's reader generation // (assuming readerGen is not lagging behind). Note that we also want // to be careful *not* to schedule the reader if there's no work to do. // - The trace is shutting down. The trace stopper blocks on the reader // to finish, much like trace advancement. // // We also want to be careful not to schedule the reader if there's no // reason to. if trace.flushedGen.Load() == trace.readerGen.Load() || trace.workAvailable.Load() || trace.shutdown.Load() { return trace.reader.Load() } return nil } // Trace advancer goroutine. var traceAdvancer traceAdvancerState type traceAdvancerState struct { timer *wakeableSleep done chan struct{} } // start starts a new traceAdvancer. func (s *traceAdvancerState) start() { // Start a goroutine to periodically advance the trace generation. s.done = make(chan struct{}) s.timer = newWakeableSleep() go func() { for traceEnabled() { // Set a timer to wake us up s.timer.sleep(int64(debug.traceadvanceperiod)) // Try to advance the trace. traceAdvance(false) } s.done <- struct{}{} }() } // stop stops a traceAdvancer and blocks until it exits. func (s *traceAdvancerState) stop() { s.timer.wake() <-s.done close(s.done) s.timer.close() } // traceAdvancePeriod is the approximate period between // new generations. const defaultTraceAdvancePeriod = 1e9 // 1 second. // wakeableSleep manages a wakeable goroutine sleep. // // Users of this type must call init before first use and // close to free up resources. Once close is called, init // must be called before another use. type wakeableSleep struct { timer *timer // lock protects access to wakeup, but not send/recv on it. lock mutex wakeup chan struct{} } // newWakeableSleep initializes a new wakeableSleep and returns it. func newWakeableSleep() *wakeableSleep { s := new(wakeableSleep) lockInit(&s.lock, lockRankWakeableSleep) s.wakeup = make(chan struct{}, 1) s.timer = new(timer) s.timer.arg = s s.timer.f = func(s any, _ uintptr) { s.(*wakeableSleep).wake() } return s } // sleep sleeps for the provided duration in nanoseconds or until // another goroutine calls wake. // // Must not be called by more than one goroutine at a time and // must not be called concurrently with close. func (s *wakeableSleep) sleep(ns int64) { resetTimer(s.timer, nanotime()+ns) lock(&s.lock) if raceenabled { raceacquire(unsafe.Pointer(&s.lock)) } wakeup := s.wakeup if raceenabled { racerelease(unsafe.Pointer(&s.lock)) } unlock(&s.lock) <-wakeup stopTimer(s.timer) } // wake awakens any goroutine sleeping on the timer. // // Safe for concurrent use with all other methods. func (s *wakeableSleep) wake() { // Grab the wakeup channel, which may be nil if we're // racing with close. lock(&s.lock) if raceenabled { raceacquire(unsafe.Pointer(&s.lock)) } if s.wakeup != nil { // Non-blocking send. // // Others may also write to this channel and we don't // want to block on the receiver waking up. This also // effectively batches together wakeup notifications. select { case s.wakeup <- struct{}{}: default: } } if raceenabled { racerelease(unsafe.Pointer(&s.lock)) } unlock(&s.lock) } // close wakes any goroutine sleeping on the timer and prevents // further sleeping on it. // // Once close is called, the wakeableSleep must no longer be used. // // It must only be called once no goroutine is sleeping on the // timer *and* nothing else will call wake concurrently. func (s *wakeableSleep) close() { // Set wakeup to nil so that a late timer ends up being a no-op. lock(&s.lock) if raceenabled { raceacquire(unsafe.Pointer(&s.lock)) } wakeup := s.wakeup s.wakeup = nil // Close the channel. close(wakeup) if raceenabled { racerelease(unsafe.Pointer(&s.lock)) } unlock(&s.lock) return }
Upload File
Create Folder