github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/libpod/shutdown/handler.go (about) 1 package shutdown 2 3 import ( 4 "os" 5 "os/signal" 6 "sync" 7 "syscall" 8 9 "github.com/pkg/errors" 10 "github.com/sirupsen/logrus" 11 ) 12 13 var ( 14 ErrHandlerExists error = errors.New("handler with given name already exists") 15 ) 16 17 var ( 18 stopped bool 19 sigChan chan os.Signal 20 cancelChan chan bool 21 // Definitions of all on-shutdown handlers 22 handlers map[string]func(os.Signal) error 23 // Ordering that on-shutdown handlers will be invoked. 24 handlerOrder []string 25 shutdownInhibit sync.RWMutex 26 ) 27 28 // Start begins handling SIGTERM and SIGINT and will run the given on-signal 29 // handlers when one is called. This can be cancelled by calling Stop(). 30 func Start() error { 31 if sigChan != nil { 32 // Already running, do nothing. 33 return nil 34 } 35 36 sigChan = make(chan os.Signal, 1) 37 cancelChan = make(chan bool, 1) 38 stopped = false 39 40 signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) 41 42 go func() { 43 select { 44 case <-cancelChan: 45 signal.Stop(sigChan) 46 close(sigChan) 47 close(cancelChan) 48 stopped = true 49 return 50 case sig := <-sigChan: 51 logrus.Infof("Received shutdown signal %v, terminating!", sig) 52 shutdownInhibit.Lock() 53 for _, name := range handlerOrder { 54 handler, ok := handlers[name] 55 if !ok { 56 logrus.Errorf("Shutdown handler %s definition not found!", name) 57 continue 58 } 59 logrus.Infof("Invoking shutdown handler %s", name) 60 if err := handler(sig); err != nil { 61 logrus.Errorf("Error running shutdown handler %s: %v", name, err) 62 } 63 } 64 shutdownInhibit.Unlock() 65 return 66 } 67 }() 68 69 return nil 70 } 71 72 // Stop the shutdown signal handler. 73 func Stop() error { 74 if cancelChan == nil { 75 return errors.New("shutdown signal handler has not yet been started") 76 } 77 if stopped { 78 return nil 79 } 80 81 cancelChan <- true 82 83 return nil 84 } 85 86 // Temporarily inhibit signals from shutting down Libpod. 87 func Inhibit() { 88 shutdownInhibit.RLock() 89 } 90 91 // Stop inhibiting signals from shutting down Libpod. 92 func Uninhibit() { 93 shutdownInhibit.RUnlock() 94 } 95 96 // Register registers a function that will be executed when Podman is terminated 97 // by a signal. Handlers are invoked LIFO - the last handler registered is the 98 // first run. 99 func Register(name string, handler func(os.Signal) error) error { 100 if handlers == nil { 101 handlers = make(map[string]func(os.Signal) error) 102 } 103 104 if _, ok := handlers[name]; ok { 105 return ErrHandlerExists 106 } 107 108 handlers[name] = handler 109 handlerOrder = append([]string{name}, handlerOrder...) 110 111 return nil 112 } 113 114 // Unregister un-registers a given shutdown handler. 115 func Unregister(name string) error { 116 if handlers == nil { 117 return nil 118 } 119 120 if _, ok := handlers[name]; !ok { 121 return nil 122 } 123 124 delete(handlers, name) 125 126 newOrder := []string{} 127 for _, checkName := range handlerOrder { 128 if checkName != name { 129 newOrder = append(newOrder, checkName) 130 } 131 } 132 handlerOrder = newOrder 133 134 return nil 135 }