deadlock

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 16, 2022 License: GPL-3.0 Imports: 8 Imported by: 0

README

Deadlock-Go: Dynamic Deadlock Detection in Go

What

Deadlock-Go implements Mutex and RW-Mutex drop-in replacements for sync.Mutex and sync.RWMutex with (R)Lock, (R)TryLock and (R)Unlock functionality to detect potential deadlocks.

The detector can detect potential or actually occurring recourse deadlocks which are caused by cyclic or double locking.

In some cases the detector can result in false-positiv or false-negative results. E.g., the detector is not able to detect cyclic locking in nested routines.

Only works from Go Version 1.18.

Installation

go get github.com/ErikKassubek/Deadlock-Go

Usage Examples

Example for Mutex
import "github.com/ErikKassubek/Deadlock-Go"

func main() {
	defer deadlock.FindPotentialDeadlocks()

	x := deadlock.NewLock()
	y := deadlock.NewLock()
	
	// make sure, that the program does not terminate
	// before all routines have terminated
	ch := make(chan bool, 2)

	go func() {
		x.Lock()
		y.Lock()
		y.Unlock()
		x.Unlock()
		ch <- true
	}()

	go func() {
		y.Lock()
		x.Lock()
		x.Unlock()
		y.Unlock()
		ch <- true
	}()
	<- ch
	<- ch
}
Example for RW-Mutex
import "github.com/ErikKassubek/Deadlock-Go"

func main() {
	defer deadlock.FindPotentialDeadlocks()

	x := NewRWLock()
	y := NewRWLock()

	// make sure, that the program does not terminate
	// before all routines have terminated
	ch := make(chan bool, 2)

	go func() {
		x.RLock()
		y.Lock()
		y.Unlock()
		x.Unlock()

		ch <- true
	}()

	go func() {
		y.RLock()
		x.Lock()
		x.Unlock()
		y.Unlock()

		ch <- true
	}()

	<-ch
	<-ch
}

Sample output

Cyclic Locking
POTENTIAL DEADLOCK

Initialization of locks involved in potential deadlock:

/home/***/selfWritten/deadlockGo.go 59
/home/***/selfWritten/deadlockGo.go 60
/home/***/selfWritten/deadlockGo.go 61

Calls of locks involved in potential deadlock:

Calls for lock created at: /home/***/selfWritten/deadlockGo.go:59
/home/***/selfWritten/deadlockGo.go 85
/home/***/selfWritten/deadlockGo.go 66

Calls for lock created at: /home/***/selfWritten/deadlockGo.go:60
/home/***/selfWritten/deadlockGo.go 75
/home/***/selfWritten/deadlockGo.go 67

Calls for lock created at: /home/***/selfWritten/deadlockGo.go:61
/home/***/selfWritten/deadlockGo.go 84
/home/***/selfWritten/deadlockGo.go 76
Double Locking
DEADLOCK (DOUBLE LOCKING)

Initialization of lock involved in deadlock:

/home/***/selfWritten/deadlockGo.go 205

Calls of lock involved in deadlock:

/home/***/selfWritten/deadlockGo.go 209
/home/***/selfWritten/deadlockGo.go 210

Options

The behavior of Deadlock-Go can be influenced by different options. They have to be set before the first lock was initialized.

SetActivated(enable bool): enable or disable all detections at once

SetPeriodicDetection(enable bool): enable or disable periodical detection, default: enabled

SetComprehensiveDetection(enable bool): enable or disable comprehensive detection, default: enabled

SetPeriodicDetectionTime(seconds int): set in which time intervals the periodical detection is started, default: 2s

SetCollectCallStacks(enable bool): if enabled, call-stacks for lock creation and acquisitions are collected. Otherwise only file and line information is collected, default: disabled

SetCollectSingleLevelLockInformation(enable bool): if enabled, information about single-level locks are collected, default enabled

SetDoubleLockingDetection(enable bool): if enabled, detection of double locking is active, default: enabled

Additionally the maximum numbers for the dependencies per Routine (default: 4096), the maximum number of mutexes a mutex can depend on (default: 128), the maximum number of routines (default: 1024) and the maximum length of a collected call stack in bytes (default 2048) can be set.

Acknowledgement

The detector is partially based on:

J. Zhou, S. Silvestro, H. Liu, Y. Cai und T. Liu, „UNDEAD: Detecting and preventing
deadlocks in production software“, in 2017 32nd IEEE/ACM International Conference
on Automated Software Engineering (ASE), Los Alamitos, CA, USA: IEEE Computer
Society, Nov. 2017, S. 729–740. doi: 10.1109/ASE.2017.8115684.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FindPotentialDeadlocks

func FindPotentialDeadlocks()

FindPotentialDeadlock is the main function to start the comprehensive detection of deadlocks. The comprehensive detection uses depth-first search to search for loop in the dependency chains of the created lock trees, which are represented by the dependency lists of the routines. It has to be run at the end of a program to detect potential deadlocks in the program. This can be one by calling it as a defer statement at the beginning of the main function of the program.

Returns:
 nil

func SetActivated

func SetActivated(enable bool) bool

Enable or disable all detections It is not possible to set options after the detector was initialized

Args:
 enable (bool): true to enable, false to disable
Returns:
 (bool): true, if the set was successful, false otherwise

func SetCollectCallStack

func SetCollectCallStack(enable bool) bool

Enable or disable collection of full call stacks If it is disabled only file and line numbers are collected It is not possible to set options after the detector was initialized

Args:
 enable (bool): true to enable, false to disable
Returns:
 (bool): true, if the set was successful, false otherwise

func SetCollectSingleLevelLockInformation

func SetCollectSingleLevelLockInformation(enable bool) bool

Enable or disable collection of call information for single level locks If it is disabled no caller information about single level locks will be collected. It is not possible to set options after the detector was initialized

Args:
 enable (bool): true to enable, false to disable
Returns:
 (bool): true, if the set was successful, false otherwise

func SetComprehensiveDetection

func SetComprehensiveDetection(enable bool) bool

Enable or disable comprehensive detection It is not possible to set options after the detector was initialized

Args:
 enable (bool): true to enable, false to disable
Returns:
 (bool): true, if the set was successful, false otherwise

func SetDoubleLockingDetection

func SetDoubleLockingDetection(enable bool) bool

Enable or disable checks for double locking It is not possible to set options after the detector was initialized

Args:
 enable (bool): true to enable, false to disable
Returns:
 (bool): true, if the set was successful, false otherwise

func SetMaxCallStackSize

func SetMaxCallStackSize(number int) bool

Set the max size of collected call stacks It is not possible to set options after the detector was initialized

Args:
 number (int): max size of the call stack in bytes
Returns:
 (bool): true, if the set was successful, false otherwise

func SetMaxDependencies

func SetMaxDependencies(number int) bool

Set the max number of dependencies It is not possible to set options after the detector was initialized

Args:
 number (int): max number of dependencies
Returns:
 (bool): true, if the set was successful, false otherwise

func SetMaxNumberOfDependentLocks

func SetMaxNumberOfDependentLocks(number int) bool

Set the max number of locks a lock can depend on It is not possible to set options after the detector was initialized

Args:
 number (int): max number of locks a lock can depend on
Returns:
 (bool): true, if the set was successful, false otherwise

func SetMaxRoutines

func SetMaxRoutines(number int) bool

Set the max number of routines It is not possible to set options after the detector was initialized

Args:
 number (int): max number of routines
Returns:
 (bool): true, if the set was successful, false otherwise

func SetPeriodicDetection

func SetPeriodicDetection(enable bool) bool

Enable or disable periodic detection It is not possible to set options after the detector was initialized

Args:
 enable (bool): true to enable, false to disable
Returns:
 (bool): true, if the set was successful, false otherwise

func SetPeriodicDetectionTime

func SetPeriodicDetectionTime(seconds int) bool

Set the temporal distance between the periodic detections It is not possible to set options after the detector was initialized

Args:
 seconds (int): temporal distance in seconds
Returns:
 (bool): true, if the set was successful, false otherwise

Types

type Mutex

type Mutex struct {
	// contains filtered or unexported fields
}

Type to implement a lock It can be used as an drop in replacement TODO: check if this can be lowercase

func NewLock

func NewLock() *Mutex

create and return a new lock, which can be used as a drop-in replacement for sync.Mutex

Returns:
 (*Mutex): the created lock

func (*Mutex) Lock

func (m *Mutex) Lock()

Lock mutex m

Returns:
 nil

func (*Mutex) TryLock

func (m *Mutex) TryLock() bool

TryLock mutex m

Returns:
 (bool): true if locking was successful, false otherwise

func (*Mutex) Unlock

func (m *Mutex) Unlock()

Unlock mutex m

Returns:
 nil

type RWMutex

type RWMutex struct {
	// contains filtered or unexported fields
}

type to implement a lock

func NewRWLock

func NewRWLock() *RWMutex

create a new rw-lock

func (*RWMutex) Lock

func (m *RWMutex) Lock()

Lock rw-mutex m

Returns:
 nil

func (*RWMutex) RLock

func (m *RWMutex) RLock()

R-Lock rw-mutex m

Returns:
 nil

func (*RWMutex) RTryLock

func (m *RWMutex) RTryLock() bool

TryLock rw-mutex m

Returns:
 (bool): true if locking was successful, false otherwise

func (*RWMutex) RUnlock

func (m *RWMutex) RUnlock()

Unlock rw-mutex m

Returns: nil

func (*RWMutex) TryLock

func (m *RWMutex) TryLock() bool

TryLock rw-mutex m

Returns:
 (bool): true if locking was successful, false otherwise

func (*RWMutex) Unlock

func (m *RWMutex) Unlock()

Unlock rw-mutex m

Returns:
 nil

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL