go deadlock 源码

  • 2022-07-15
  • 浏览 (825)

golang deadlock 代码

文件路径:/src/runtime/testdata/testprog/deadlock.go

// Copyright 2015 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.

package main

import (
	"fmt"
	"runtime"
	"runtime/debug"
	"time"
)

func init() {
	registerInit("InitDeadlock", InitDeadlock)
	registerInit("NoHelperGoroutines", NoHelperGoroutines)

	register("SimpleDeadlock", SimpleDeadlock)
	register("LockedDeadlock", LockedDeadlock)
	register("LockedDeadlock2", LockedDeadlock2)
	register("GoexitDeadlock", GoexitDeadlock)
	register("StackOverflow", StackOverflow)
	register("ThreadExhaustion", ThreadExhaustion)
	register("RecursivePanic", RecursivePanic)
	register("RecursivePanic2", RecursivePanic2)
	register("RecursivePanic3", RecursivePanic3)
	register("RecursivePanic4", RecursivePanic4)
	register("RecursivePanic5", RecursivePanic5)
	register("GoexitExit", GoexitExit)
	register("GoNil", GoNil)
	register("MainGoroutineID", MainGoroutineID)
	register("Breakpoint", Breakpoint)
	register("GoexitInPanic", GoexitInPanic)
	register("PanicAfterGoexit", PanicAfterGoexit)
	register("RecoveredPanicAfterGoexit", RecoveredPanicAfterGoexit)
	register("RecoverBeforePanicAfterGoexit", RecoverBeforePanicAfterGoexit)
	register("RecoverBeforePanicAfterGoexit2", RecoverBeforePanicAfterGoexit2)
	register("PanicTraceback", PanicTraceback)
	register("GoschedInPanic", GoschedInPanic)
	register("SyscallInPanic", SyscallInPanic)
	register("PanicLoop", PanicLoop)
}

func SimpleDeadlock() {
	select {}
	panic("not reached")
}

func InitDeadlock() {
	select {}
	panic("not reached")
}

func LockedDeadlock() {
	runtime.LockOSThread()
	select {}
}

func LockedDeadlock2() {
	go func() {
		runtime.LockOSThread()
		select {}
	}()
	time.Sleep(time.Millisecond)
	select {}
}

func GoexitDeadlock() {
	F := func() {
		for i := 0; i < 10; i++ {
		}
	}

	go F()
	go F()
	runtime.Goexit()
}

func StackOverflow() {
	var f func() byte
	f = func() byte {
		var buf [64 << 10]byte
		return buf[0] + f()
	}
	debug.SetMaxStack(1474560)
	f()
}

func ThreadExhaustion() {
	debug.SetMaxThreads(10)
	c := make(chan int)
	for i := 0; i < 100; i++ {
		go func() {
			runtime.LockOSThread()
			c <- 0
			select {}
		}()
		<-c
	}
}

func RecursivePanic() {
	func() {
		defer func() {
			fmt.Println(recover())
		}()
		var x [8192]byte
		func(x [8192]byte) {
			defer func() {
				if err := recover(); err != nil {
					panic("wrap: " + err.(string))
				}
			}()
			panic("bad")
		}(x)
	}()
	panic("again")
}

// Same as RecursivePanic, but do the first recover and the second panic in
// separate defers, and make sure they are executed in the correct order.
func RecursivePanic2() {
	func() {
		defer func() {
			fmt.Println(recover())
		}()
		var x [8192]byte
		func(x [8192]byte) {
			defer func() {
				panic("second panic")
			}()
			defer func() {
				fmt.Println(recover())
			}()
			panic("first panic")
		}(x)
	}()
	panic("third panic")
}

// Make sure that the first panic finished as a panic, even though the second
// panic was recovered
func RecursivePanic3() {
	defer func() {
		defer func() {
			recover()
		}()
		panic("second panic")
	}()
	panic("first panic")
}

// Test case where a single defer recovers one panic but starts another panic. If
// the second panic is never recovered, then the recovered first panic will still
// appear on the panic stack (labeled '[recovered]') and the runtime stack.
func RecursivePanic4() {
	defer func() {
		recover()
		panic("second panic")
	}()
	panic("first panic")
}

// Test case where we have an open-coded defer higher up the stack (in two), and
// in the current function (three) we recover in a defer while we still have
// another defer to be processed.
func RecursivePanic5() {
	one()
	panic("third panic")
}

//go:noinline
func one() {
	two()
}

//go:noinline
func two() {
	defer func() {
	}()

	three()
}

//go:noinline
func three() {
	defer func() {
	}()

	defer func() {
		fmt.Println(recover())
	}()

	defer func() {
		fmt.Println(recover())
		panic("second panic")
	}()

	panic("first panic")
}

func GoexitExit() {
	println("t1")
	go func() {
		time.Sleep(time.Millisecond)
	}()
	i := 0
	println("t2")
	runtime.SetFinalizer(&i, func(p *int) {})
	println("t3")
	runtime.GC()
	println("t4")
	runtime.Goexit()
}

func GoNil() {
	defer func() {
		recover()
	}()
	var f func()
	go f()
	select {}
}

func MainGoroutineID() {
	panic("test")
}

func NoHelperGoroutines() {
	i := 0
	runtime.SetFinalizer(&i, func(p *int) {})
	time.AfterFunc(time.Hour, func() {})
	panic("oops")
}

func Breakpoint() {
	runtime.Breakpoint()
}

func GoexitInPanic() {
	go func() {
		defer func() {
			runtime.Goexit()
		}()
		panic("hello")
	}()
	runtime.Goexit()
}

type errorThatGosched struct{}

func (errorThatGosched) Error() string {
	runtime.Gosched()
	return "errorThatGosched"
}

func GoschedInPanic() {
	panic(errorThatGosched{})
}

type errorThatPrint struct{}

func (errorThatPrint) Error() string {
	fmt.Println("1")
	fmt.Println("2")
	return "3"
}

func SyscallInPanic() {
	panic(errorThatPrint{})
}

func PanicAfterGoexit() {
	defer func() {
		panic("hello")
	}()
	runtime.Goexit()
}

func RecoveredPanicAfterGoexit() {
	defer func() {
		defer func() {
			r := recover()
			if r == nil {
				panic("bad recover")
			}
		}()
		panic("hello")
	}()
	runtime.Goexit()
}

func RecoverBeforePanicAfterGoexit() {
	// 1. defer a function that recovers
	// 2. defer a function that panics
	// 3. call goexit
	// Goexit runs the #2 defer. Its panic
	// is caught by the #1 defer.  For Goexit, we explicitly
	// resume execution in the Goexit loop, instead of resuming
	// execution in the caller (which would make the Goexit disappear!)
	defer func() {
		r := recover()
		if r == nil {
			panic("bad recover")
		}
	}()
	defer func() {
		panic("hello")
	}()
	runtime.Goexit()
}

func RecoverBeforePanicAfterGoexit2() {
	for i := 0; i < 2; i++ {
		defer func() {
		}()
	}
	// 1. defer a function that recovers
	// 2. defer a function that panics
	// 3. call goexit
	// Goexit runs the #2 defer. Its panic
	// is caught by the #1 defer.  For Goexit, we explicitly
	// resume execution in the Goexit loop, instead of resuming
	// execution in the caller (which would make the Goexit disappear!)
	defer func() {
		r := recover()
		if r == nil {
			panic("bad recover")
		}
	}()
	defer func() {
		panic("hello")
	}()
	runtime.Goexit()
}

func PanicTraceback() {
	pt1()
}

func pt1() {
	defer func() {
		panic("panic pt1")
	}()
	pt2()
}

func pt2() {
	defer func() {
		panic("panic pt2")
	}()
	panic("hello")
}

type panicError struct{}

func (*panicError) Error() string {
	panic("double error")
}

func PanicLoop() {
	panic(&panicError{})
}

相关信息

go 源码目录

相关文章

go abort 源码

go badtraceback 源码

go checkptr 源码

go crash 源码

go crashdump 源码

go gc 源码

go lockosthread 源码

go main 源码

go map 源码

go memprof 源码

0  赞