github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/libpod/shutdown/handler.go (about)

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