interrupt_unix.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // Copyright 2015 The etcd Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // +build !windows,!plan9
  15. package osutil
  16. import (
  17. "os"
  18. "os/signal"
  19. "sync"
  20. "syscall"
  21. )
  22. // InterruptHandler is a function that is called on receiving a
  23. // SIGTERM or SIGINT signal.
  24. type InterruptHandler func()
  25. var (
  26. interruptRegisterMu, interruptExitMu sync.Mutex
  27. // interruptHandlers holds all registered InterruptHandlers in order
  28. // they will be executed.
  29. interruptHandlers = []InterruptHandler{}
  30. )
  31. // RegisterInterruptHandler registers a new InterruptHandler. Handlers registered
  32. // after interrupt handing was initiated will not be executed.
  33. func RegisterInterruptHandler(h InterruptHandler) {
  34. interruptRegisterMu.Lock()
  35. defer interruptRegisterMu.Unlock()
  36. interruptHandlers = append(interruptHandlers, h)
  37. }
  38. // HandleInterrupts calls the handler functions on receiving a SIGINT or SIGTERM.
  39. func HandleInterrupts() {
  40. notifier := make(chan os.Signal, 1)
  41. signal.Notify(notifier, syscall.SIGINT, syscall.SIGTERM)
  42. go func() {
  43. sig := <-notifier
  44. interruptRegisterMu.Lock()
  45. ihs := make([]InterruptHandler, len(interruptHandlers))
  46. copy(ihs, interruptHandlers)
  47. interruptRegisterMu.Unlock()
  48. interruptExitMu.Lock()
  49. plog.Noticef("received %v signal, shutting down...", sig)
  50. for _, h := range ihs {
  51. h()
  52. }
  53. signal.Stop(notifier)
  54. pid := syscall.Getpid()
  55. // exit directly if it is the "init" process, since the kernel will not help to kill pid 1.
  56. if pid == 1 {
  57. os.Exit(0)
  58. }
  59. syscall.Kill(pid, sig.(syscall.Signal))
  60. }()
  61. }
  62. // Exit relays to os.Exit if no interrupt handlers are running, blocks otherwise.
  63. func Exit(code int) {
  64. interruptExitMu.Lock()
  65. os.Exit(code)
  66. }