kernel_keeper.go 2.8 KB

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