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