mirror of
https://github.com/rclone/rclone.git
synced 2025-01-09 15:58:28 +01:00
lib/atexit: fix deadlock calling Finalise while Run is running
This commit is contained in:
parent
1fe2460e38
commit
a2cd5d8fa3
@ -20,6 +20,7 @@ var (
|
|||||||
exitOnce sync.Once
|
exitOnce sync.Once
|
||||||
registerOnce sync.Once
|
registerOnce sync.Once
|
||||||
signalled int32
|
signalled int32
|
||||||
|
runCalled int32
|
||||||
)
|
)
|
||||||
|
|
||||||
// FnHandle is the type of the handle returned by function `Register`
|
// FnHandle is the type of the handle returned by function `Register`
|
||||||
@ -29,6 +30,9 @@ type FnHandle *func()
|
|||||||
// Register a function to be called on exit.
|
// Register a function to be called on exit.
|
||||||
// Returns a handle which can be used to unregister the function with `Unregister`.
|
// Returns a handle which can be used to unregister the function with `Unregister`.
|
||||||
func Register(fn func()) FnHandle {
|
func Register(fn func()) FnHandle {
|
||||||
|
if running() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
fnsMutex.Lock()
|
fnsMutex.Lock()
|
||||||
fns[&fn] = true
|
fns[&fn] = true
|
||||||
fnsMutex.Unlock()
|
fnsMutex.Unlock()
|
||||||
@ -58,8 +62,16 @@ func Signalled() bool {
|
|||||||
return atomic.LoadInt32(&signalled) != 0
|
return atomic.LoadInt32(&signalled) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// running returns true if run has been called
|
||||||
|
func running() bool {
|
||||||
|
return atomic.LoadInt32(&runCalled) != 0
|
||||||
|
}
|
||||||
|
|
||||||
// Unregister a function using the handle returned by `Register`
|
// Unregister a function using the handle returned by `Register`
|
||||||
func Unregister(handle FnHandle) {
|
func Unregister(handle FnHandle) {
|
||||||
|
if running() {
|
||||||
|
return
|
||||||
|
}
|
||||||
fnsMutex.Lock()
|
fnsMutex.Lock()
|
||||||
defer fnsMutex.Unlock()
|
defer fnsMutex.Unlock()
|
||||||
delete(fns, handle)
|
delete(fns, handle)
|
||||||
@ -67,6 +79,9 @@ func Unregister(handle FnHandle) {
|
|||||||
|
|
||||||
// IgnoreSignals disables the signal handler and prevents Run from being executed automatically
|
// IgnoreSignals disables the signal handler and prevents Run from being executed automatically
|
||||||
func IgnoreSignals() {
|
func IgnoreSignals() {
|
||||||
|
if running() {
|
||||||
|
return
|
||||||
|
}
|
||||||
registerOnce.Do(func() {})
|
registerOnce.Do(func() {})
|
||||||
if exitChan != nil {
|
if exitChan != nil {
|
||||||
signal.Stop(exitChan)
|
signal.Stop(exitChan)
|
||||||
@ -77,7 +92,10 @@ func IgnoreSignals() {
|
|||||||
|
|
||||||
// Run all the at exit functions if they haven't been run already
|
// Run all the at exit functions if they haven't been run already
|
||||||
func Run() {
|
func Run() {
|
||||||
// Take the lock here so we wait until all have run before returning
|
atomic.StoreInt32(&runCalled, 1)
|
||||||
|
// Take the lock here (not inside the exitOnce) so we wait
|
||||||
|
// until the exit handlers have run before any calls to Run()
|
||||||
|
// return.
|
||||||
fnsMutex.Lock()
|
fnsMutex.Lock()
|
||||||
defer fnsMutex.Unlock()
|
defer fnsMutex.Unlock()
|
||||||
exitOnce.Do(func() {
|
exitOnce.Do(func() {
|
||||||
|
Loading…
Reference in New Issue
Block a user