kernel_keeper.go 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. // package kernel_keeper -- сторож системных сигналов.
  2. package kernel_keeper
  3. import (
  4. "context"
  5. "os"
  6. "os/signal"
  7. "sync"
  8. "syscall"
  9. mL0 "gitp78su.ipnodns.ru/svi/kern/v4/lev0"
  10. "gitp78su.ipnodns.ru/svi/kern/v4/lev0/defs"
  11. mKs "gitp78su.ipnodns.ru/svi/kern/v4/lev0/kspec"
  12. mL1 "gitp78su.ipnodns.ru/svi/kern/v4/lev1"
  13. )
  14. // kernelKeeper -- сторож системных сигналов.
  15. type kernelKeeper struct {
  16. ctx context.Context
  17. fnCancel func()
  18. wg mKs.IKernelWg
  19. log mKs.ILogBuf
  20. chSys_ chan os.Signal
  21. }
  22. var (
  23. kernKeep *kernelKeeper
  24. block sync.Mutex
  25. qName = defs.NewStreamName("kernel_keeper")
  26. )
  27. // GetKernelKeeper -- возвращает новый сторож системных сигналов.
  28. func GetKernelKeeper(ctx context.Context, fnCancel func(),
  29. wg mKs.IKernelWg) *kernelKeeper {
  30. block.Lock()
  31. defer block.Unlock()
  32. if kernKeep != nil {
  33. kernKeep.log.Debug("GetKernelKeeper()")
  34. return kernKeep
  35. }
  36. mL0.Hassert(ctx != nil, "NewKernelCtx(): ctx==nil")
  37. mL0.Hassert(wg != nil, "NewKernelCtx(): IKernelWg==nil")
  38. mL0.Hassert(fnCancel != nil, "NewKernelCtx(): fnCancel==nil")
  39. sf := &kernelKeeper{
  40. ctx: ctx,
  41. fnCancel: fnCancel,
  42. wg: wg,
  43. log: mL1.NewLogBuf(mL1.OptIsTerm(true), mL1.OptPrefix("kernelKeeper")),
  44. chSys_: make(chan os.Signal, 2),
  45. }
  46. sf.log.Debug("GetKernelKeeper(): first run")
  47. sf.wg.Add(qName)
  48. go sf.run(sf.chSys_)
  49. kernKeep = sf
  50. _ = mKs.IKernelKeeper(sf)
  51. return sf
  52. }
  53. // Log -- возвращает лог сторожа системных сигналов.
  54. func (sf *kernelKeeper) Log() mKs.ILogBuf {
  55. return sf.log
  56. }
  57. // Работает в отдельном потоке и ждёт сигналов прерываний работы.
  58. func (sf *kernelKeeper) run(chSys chan os.Signal) {
  59. sf.log.Debug("run()")
  60. // Регистрируем сигналы SIGINT (Ctrl+C) и SIGTERM (завершение процесса)
  61. // syscall.SIGHUP: Сигнал, отправляемый при закрытии терминала.
  62. // syscall.SIGQUIT: Сигнал, отправляемый при нажатии **Ctrl+**.
  63. signal.Notify(chSys, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
  64. select {
  65. case sig := <-chSys: // системный сигнал
  66. sf.log.Debug("run(): system signal, sig=%v\n", sig)
  67. sf.fnCancel()
  68. case <-sf.ctx.Done(): // сигнал от приложения
  69. sf.log.Debug("run(): cancel app context, err=\n\t%v\n", sf.ctx.Err())
  70. }
  71. sf.wg.Done(qName)
  72. sf.log.Debug("run(): end")
  73. }