// Package signal mediates access to POSIX signals.
//
// Signals are accessible by name and by semantic. If a process needs to know
// when it has received SIGINT, it can register that interest by calling the
// `SigInterrupt` function. If a process needs to know when to drain users in
// preparation for a graceful exit, it can register that interest by calling
// the `Graceful` function.
//
// It is recommended that users of this package register the semantics of
// their interest (when to drain users) rather than an interest in specific
// signals.
package signal

import (
	"os"
	"os/signal"
	"syscall"
)

const (
	// Processes can listen for particular lifecycle instructions without
	// needing to know the specifics of what triggered the lifecycle event.

	// To trigger a graceful shutdown of a tree, send SIGUSR2 to its root.
	signalGracefulShutdown = syscall.SIGUSR2
	// SIGINT is a convenient equivalent of SIGUSR2.
	signalGracefulShutdownAlternate = syscall.SIGINT
	// To trigger a quick shutdown of a process tree, send SIGTERM to its root.
	signalPromptShutdown = syscall.SIGTERM
	// To trigger a dangerously quick shutdown of a process tree, send SIGQUIT to its root.
	signalUncivilizedShutdown = syscall.SIGQUIT

	// To trigger a graceful reload of a tree, send SIGHUP to its root.
	signalReload = syscall.SIGHUP
)

// GracefulShutdown registers the channel for notifications of a graceful
// shutdown signal.
func GracefulShutdown(c chan<- os.Signal) {
	signal.Notify(c, signalGracefulShutdown)
	signal.Notify(c, signalGracefulShutdownAlternate)
}

// PromptShutdown registers the channel for notifications of a prompt shutdown
// signal.
func PromptShutdown(c chan<- os.Signal) {
	signal.Notify(c, signalPromptShutdown)
}

// UncivilizedShutdown registers the channel for notifications of an
// uncivilized shutdown signal.
func UncivilizedShutdown(c chan<- os.Signal) {
	signal.Notify(c, signalUncivilizedShutdown)
}

// Reload registers the channel for notifications of a config reload signal.
// Depending on the type of process, the correct action could be to reload a
// config file or to reexec the binary.
func Reload(c chan<- os.Signal) {
	signal.Notify(c, signalReload)
}

// Stop unregisters the channel from all notifications.
func Stop(c chan<- os.Signal) {
	signal.Stop(c)
}

// SigInterrupt registers the channel for notifications of SIGINT.
func SigInterrupt(c chan<- os.Signal) {
	signal.Notify(c, syscall.SIGINT)
}

// SigTerminate registers the channel for notifications of SIGTERM.
func SigTerminate(c chan<- os.Signal) {
	signal.Notify(c, syscall.SIGTERM)
}

// SigHangup registers the channel for notifications of SIGHUP.
func SigHangup(c chan<- os.Signal) {
	signal.Notify(c, syscall.SIGHUP)
}

// SigQuit registers the channel for notifications of SIGQUIT.
func SigQuit(c chan<- os.Signal) {
	signal.Notify(c, syscall.SIGQUIT)
}

// SigUser2 registers the channel for notifications of SIGUSR2.
func SigUser2(c chan<- os.Signal) {
	signal.Notify(c, syscall.SIGUSR2)
}
