github.com/go-board/x-go@v0.1.2-0.20220610024734-db1323f6cb15/xos/interrupt_unix.go (about) 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 15 // +build !windows,!plan9 16 17 package xos 18 19 import ( 20 "log" 21 "os" 22 "os/signal" 23 "sync" 24 "syscall" 25 ) 26 27 // InterruptHandler is a function that is called on receiving a 28 // SIGTERM or SIGINT signal. 29 type InterruptHandler func() 30 31 var ( 32 interruptRegisterMu, interruptExitMu sync.Mutex 33 // interruptHandlers holds all registered InterruptHandlers in order 34 // they will be executed. 35 interruptHandlers []InterruptHandler 36 ) 37 38 // RegisterInterruptHandler registers a new InterruptHandler. Handlers registered 39 // after interrupt handing was initiated will not be executed. 40 func RegisterInterruptHandler(h InterruptHandler) { 41 interruptRegisterMu.Lock() 42 defer interruptRegisterMu.Unlock() 43 interruptHandlers = append(interruptHandlers, h) 44 } 45 46 // HandleInterrupts calls the handler functions on receiving a SIGINT or SIGTERM. 47 func HandleInterrupts(l *log.Logger) { 48 notifier := make(chan os.Signal, 1) 49 signal.Notify(notifier, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT) 50 51 go func() { 52 sig := <-notifier 53 54 interruptRegisterMu.Lock() 55 ihs := make([]InterruptHandler, len(interruptHandlers)) 56 copy(ihs, interruptHandlers) 57 interruptRegisterMu.Unlock() 58 59 interruptExitMu.Lock() 60 61 if l != nil { 62 l.Printf("received signal %s; shutting down\n", sig.String()) 63 } 64 65 for _, h := range ihs { 66 h() 67 } 68 signal.Stop(notifier) 69 pid := syscall.Getpid() 70 // exit directly if it is the "init" process, since the kernel will not help to kill pid 1. 71 if pid == 1 { 72 os.Exit(0) 73 } 74 setDflSignal(sig.(syscall.Signal)) 75 syscall.Kill(pid, sig.(syscall.Signal)) 76 }() 77 } 78 79 // Exit relays to os.Exit if no interrupt handlers are running, blocks otherwise. 80 func Exit(code int) { 81 interruptExitMu.Lock() 82 os.Exit(code) 83 }