Пакет signal
Обзор
Пакет signal реализует доступ к входящим сигналам.
Сигналы используются преимущественно в Unix-подобных системах. Об использовании этого пакета в Windows и Plan 9 см. ниже.
Типы сигналов
Программа не может перехватывать сигналы SIGKILL и SIGSTOP, поэтому этот пакет не может влиять на них.
Синхронные сигналы — это сигналы, вызываемые ошибками при выполнении программы: SIGBUS, SIGFPE и SIGSEGV. Они считаются синхронными только в том случае, если вызваны выполнением программы, а не отправлены с помощью os.Process.Kill, программы kill или аналогичного механизма. Как правило, за исключением описанных ниже случаев, программы Go преобразуют синхронный сигнал в панику времени выполнения.
Остальные сигналы являются асинхронными. Они не вызываются ошибками программы, а отправляются ядром или другой программой.
Из асинхронных сигналов SIGHUP отправляется, когда программа теряет управляющий терминал. SIGINT отправляется, когда пользователь на управляющем терминале нажимает символ прерывания, которым по умолчанию является ^C (Control-C). SIGQUIT отправляется, когда пользователь на управляющем терминале нажимает символ выхода, которым по умолчанию является ^\ (Control-Backslash). Как правило, нажатие ^C позволяет просто завершить программу, а нажатие ^\ — завершить ее с дампом стека.
Поведение сигналов по умолчанию в программах Go
По умолчанию синхронный сигнал преобразуется в панику времени выполнения. Сигналы SIGHUP, SIGINT и SIGTERM приводят к завершению программы. Сигналы SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGSTKFLT, SIGEMT и SIGSYS приводят к завершению программы с дампом стека. Для сигналов SIGTSTP, SIGTTIN и SIGTTOU действует системное поведение по умолчанию (эти сигналы используются оболочкой для управления заданиями). Сигнал SIGPROF обрабатывается непосредственно средой выполнения Go для реализации runtime.CPUProfile. Остальные сигналы перехватываются, но никаких действий не предпринимается.
Если программа Go запущена с игнорированием SIGHUP или SIGINT (обработчик сигнала установлен в SIG_IGN), эти сигналы продолжат игнорироваться.
Если программа Go запущена с непустой маской сигналов, она, как правило, сохраняется. Однако некоторые сигналы явно разблокируются: синхронные сигналы, SIGILL, SIGTRAP, SIGSTKFLT, SIGCHLD, SIGPROF, а в Linux — сигналы 32 (SIGCANCEL) и 33 (SIGSETXID) (SIGCANCEL и SIGSETXID используются внутри glibc). Дочерние процессы, запущенные с помощью os.Exec или os/exec, наследуют измененную маску сигналов.
Изменение поведения сигналов в программах Go
Функции этого пакета позволяют программе изменить способ обработки сигналов в программах Go.
Notify отключает поведение по умолчанию для заданного набора асинхронных сигналов и вместо этого передает их в один или несколько зарегистрированных каналов. В частности, это относится к сигналам SIGHUP, SIGINT, SIGQUIT, SIGABRT и SIGTERM. Это также относится к сигналам управления заданиями SIGTSTP, SIGTTIN и SIGTTOU; в этом случае системное поведение по умолчанию не выполняется. Кроме того, это относится к сигналам, которые в противном случае не вызывают никаких действий: SIGUSR1, SIGUSR2, SIGPIPE, SIGALRM, SIGCHLD, SIGCONT, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGWINCH, SIGIO, SIGPWR, SIGINFO, SIGTHR, SIGWAITING, SIGLWP, SIGFREEZE, SIGTHAW, SIGLOST, SIGXRES, SIGJVM1, SIGJVM2 и любым сигналам реального времени, используемым в системе. Обратите внимание, что не все эти сигналы доступны во всех системах.
Если программа была запущена с игнорированием SIGHUP или SIGINT и для одного из этих сигналов вызывается Notify, для него будет установлен обработчик сигнала, и он перестанет игнорироваться. Если впоследствии для этого сигнала вызвать Reset или Ignore либо вызвать Stop для всех каналов, переданных в Notify для этого сигнала, сигнал снова будет игнорироваться. Reset восстановит системное поведение по умолчанию для сигнала, а Ignore приведет к тому, что система будет полностью игнорировать сигнал.
Если программа запущена с непустой маской сигналов, некоторые сигналы будут явно разблокированы, как описано выше. Если Notify вызывается для заблокированного сигнала, он будет разблокирован. Если впоследствии для этого сигнала вызвать Reset либо вызвать Stop для всех каналов, переданных в Notify для этого сигнала, сигнал снова будет заблокирован.
SIGPIPE
Когда программа Go записывает данные в разорванный канал, ядро отправляет сигнал SIGPIPE.
Если программа не вызывала Notify для получения сигналов SIGPIPE, поведение зависит от номера файлового дескриптора. Запись в разорванный канал через файловый дескриптор 1 или 2 (стандартный вывод или стандартный поток ошибок) приведет к завершению программы с сигналом SIGPIPE. При записи в разорванный канал через любой другой файловый дескриптор сигнал SIGPIPE не вызовет никаких действий, а запись завершится ошибкой syscall.EPIPE.
Если программа вызвала Notify для получения сигналов SIGPIPE, номер файлового дескриптора не имеет значения. Сигнал SIGPIPE будет передан в канал Notify, а запись завершится ошибкой syscall.EPIPE.
Это означает, что программы командной строки по умолчанию будут вести себя как обычные программы командной строки Unix, тогда как другие программы не будут аварийно завершаться из-за SIGPIPE при записи в закрытое сетевое соединение.
Программы Go, использующие cgo или SWIG
В программе Go, содержащей код не на Go, обычно код на C/C++, вызываемый с помощью cgo или SWIG, первым обычно выполняется код запуска Go. Он настраивает обработчики сигналов так, как ожидает среда выполнения Go, прежде чем запустится код не на Go. Если код запуска не на Go должен установить собственные обработчики сигналов, ему необходимо выполнить определенные действия, чтобы Go продолжал работать корректно. В этом разделе описаны эти действия и общее влияние изменений настроек обработчиков сигналов, внесенных кодом не на Go, на программы Go. В редких случаях код не на Go может выполниться раньше кода Go; в этом случае применим также следующий раздел.
Если код не на Go, вызываемый программой Go, не меняет обработчики или маски сигналов, поведение будет таким же, как у программы, полностью написанной на Go.
Если код не на Go устанавливает какие-либо обработчики сигналов, он должен использовать флаг SA_ONSTACK при вызове sigaction. Если этого не сделать, программа, скорее всего, аварийно завершится при получении сигнала. Программы Go обычно работают с ограниченным стеком и поэтому настраивают альтернативный стек сигналов.
Если код не на Go устанавливает обработчик для любого из синхронных сигналов (SIGBUS, SIGFPE, SIGSEGV), ему следует сохранить существующий обработчик сигналов Go. Если такие сигналы возникают при выполнении кода Go, следует вызвать обработчик сигналов Go (определить, выполняется ли в этот момент код Go, можно по значению PC, переданному обработчику сигнала). В противном случае некоторые паники времени выполнения Go не будут возникать ожидаемым образом.
Если код не на Go устанавливает обработчик для любого из асинхронных сигналов, он может по своему усмотрению вызывать обработчик сигналов Go или не вызывать его. Естественно, если он не вызывает обработчик сигналов Go, описанное выше поведение Go не будет выполняться. Это может быть особенно важно для сигнала SIGPROF.
Код не на Go не должен менять маску сигналов в потоках, созданных средой выполнения Go. Если код не на Go самостоятельно запускает новые потоки, в них можно задавать любую маску сигналов.
Если код не на Go запускает новый поток, меняет маску сигналов, а затем вызывает функцию Go в этом потоке, среда выполнения Go автоматически разблокирует некоторые сигналы: синхронные сигналы, SIGILL, SIGTRAP, SIGSTKFLT, SIGCHLD, SIGPROF, SIGCANCEL и SIGSETXID. Когда функция Go вернется, маска сигналов не на Go будет восстановлена.
Если обработчик сигналов Go вызывается в потоке не на Go, в котором не выполняется код Go, обработчик обычно передает сигнал коду не на Go следующим образом. Если сигнал — SIGPROF, обработчик Go ничего не делает. В противном случае обработчик Go удаляет себя, разблокирует сигнал и отправляет его повторно, чтобы вызвать любой обработчик не на Go или системный обработчик по умолчанию. Если программа не завершилась, обработчик Go устанавливает себя повторно, и выполнение программы продолжается.
Если получен сигнал SIGPIPE, программа Go применит описанную выше специальную обработку, если сигнал получен в потоке Go. Если сигнал SIGPIPE получен в потоке не на Go, он будет передан обработчику не на Go, если таковой имеется; если его нет, системный обработчик по умолчанию завершит программу.
Программы не на Go, вызывающие код Go
Когда код Go собирается с такими параметрами, как -buildmode=c-shared, он запускается как часть существующей программы не на Go. К моменту запуска кода Go код не на Go уже мог установить обработчики сигналов (это также может происходить в необычных случаях при использовании cgo или SWIG; тогда применимо изложенное здесь описание). При использовании -buildmode=c-archive среда выполнения Go инициализирует сигналы во время выполнения глобальных конструкторов. При использовании -buildmode=c-shared среда выполнения Go инициализирует сигналы при загрузке разделяемой библиотеки.
Если среда выполнения Go обнаруживает существующий обработчик сигналов SIGCANCEL или SIGSETXID (которые используются только в Linux), она включает флаг SA_ONSTACK и сохраняет обработчик без изменений.
Для синхронных сигналов и SIGPIPE среда выполнения Go установит обработчик сигнала. Она сохранит существующий обработчик сигнала. Если синхронный сигнал поступит во время выполнения кода не на Go, среда выполнения Go вызовет существующий обработчик сигнала вместо обработчика Go.
Код Go, собранный с параметром -buildmode=c-archive или -buildmode=c-shared, по умолчанию не устанавливает другие обработчики сигналов. Если существующий обработчик есть, среда выполнения Go включит флаг SA_ONSTACK и сохранит обработчик без изменений. Если для асинхронного сигнала вызывается Notify, для этого сигнала будет установлен обработчик Go. Если впоследствии для этого сигнала вызвать Reset, исходная обработка сигнала будет восстановлена, в том числе прежний обработчик не на Go, если он был установлен.
Код Go, собранный без параметра -buildmode=c-archive или -buildmode=c-shared, установит обработчики для перечисленных выше асинхронных сигналов и сохранит все существующие обработчики. Если сигнал будет доставлен потоку не на Go, обработка будет выполняться, как описано выше, за исключением того, что при наличии существующего обработчика не на Go этот обработчик будет установлен перед повторной отправкой сигнала.
Windows
В Windows ^C (Control-C) или ^BREAK (Control-Break) обычно приводят к завершению программы. Если вызвать Notify для os.Interrupt, ^C или ^BREAK приведут к отправке os.Interrupt в канал, и программа не завершится. os.Interrupt — единственный сигнал, который можно использовать в Windows. Если вызвать Reset или Stop для всех каналов, переданных в Notify, поведение по умолчанию будет восстановлено.
Кроме того, если вызвать Notify и Windows отправит процессу CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT или CTRL_SHUTDOWN_EVENT, Notify вернет syscall.SIGTERM. В отличие от Control-C и Control-Break, Notify не меняет поведение процесса при получении CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT или CTRL_SHUTDOWN_EVENT: процесс все равно будет завершен, если не выйдет самостоятельно. Однако получение syscall.SIGTERM дает процессу возможность выполнить очистку перед завершением.
Plan 9
В Plan 9 сигналы имеют тип syscall.Note, представляющий собой строку. Вызов Notify с syscall.Note приведет к отправке этого значения в канал, когда в качестве уведомления будет передана соответствующая строка.
Указатель
Примеры
Файлы пакета
doc.go signal.go signal_unix.go
func Ignore 1.5
func Ignore(sig ...os.Signal)
Ignore приводит к игнорированию указанных сигналов. Если программа получит их, ничего не произойдет. Ignore отменяет действие всех предыдущих вызовов Notify для указанных сигналов. Если сигналы не указаны, будут игнорироваться все входящие сигналы.
func Ignored 1.11
func Ignored(sig os.Signal) bool
Ignored сообщает, игнорируется ли в данный момент sig.
func Notify
func Notify(c chan<- os.Signal, sig ...os.Signal)
Notify заставляет пакет signal передавать входящие сигналы в канал c. Если сигналы не указаны, в канал c будут передаваться все входящие сигналы. В противном случае будут передаваться только указанные сигналы.
Пакет signal не блокирует отправку в канал c: вызывающий код должен обеспечить достаточный буфер канала, чтобы справляться с ожидаемой частотой сигналов. Для канала, используемого для уведомлений только об одном типе сигнала, достаточно буфера размером 1.
Допускается несколько раз вызывать Notify с одним и тем же каналом: каждый вызов расширяет набор сигналов, отправляемых в этот канал. Удалить сигналы из набора можно только вызовом Stop.
Допускается несколько раз вызывать Notify с разными каналами и одними и теми же сигналами: каждый канал независимо получает копии входящих сигналов.
Пример
Код:
// Set up channel on which to send signal notifications.
// We must use a buffered channel or risk missing the signal
// if we're not ready to receive when the signal is sent.
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
// Block until a signal is received.
s := <-c
fmt.Println("Got signal:", s)
Пример (Все сигналы)
Код:
// Set up channel on which to send signal notifications.
// We must use a buffered channel or risk missing the signal
// if we're not ready to receive when the signal is sent.
c := make(chan os.Signal, 1)
// Passing no signals to Notify means that
// all signals will be sent to the channel.
signal.Notify(c)
// Block until any signal is received.
s := <-c
fmt.Println("Got signal:", s)
func NotifyContext 1.16
func NotifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc)
NotifyContext возвращает копию родительского контекста, помечаемую как завершенную (его канал Done закрывается), когда поступает один из указанных сигналов, вызывается возвращенная функция stop или закрывается канал Done родительского контекста — в зависимости от того, что произойдет первым.
Функция stop отменяет регистрацию обработки сигнала и, как и signal.Reset, может восстановить поведение по умолчанию для заданного сигнала. Например, стандартное поведение программы Go при получении os.Interrupt — завершение. Вызов NotifyContext(parent, os.Interrupt) изменит поведение и приведет к отмене возвращенного контекста. Последующие прерывания не будут вызывать поведение по умолчанию (завершение), пока не будет вызвана возвращенная функция stop.
Если сигнал приводит к отмене возвращенного контекста, вызов context.Cause для него вернет ошибку с описанием сигнала.
Функция stop освобождает связанные с ней ресурсы, поэтому ее следует вызвать сразу после завершения операций, выполняющихся в этом контексте, когда перенаправлять сигналы в контекст больше не требуется.
Пример
В этом примере контекст с сигналом передается блокирующей функции, чтобы сообщить ей о необходимости прекратить работу после получения сигнала.
Код:
package signal_test
import (
"context"
"fmt"
"log"
"os"
"os/signal"
)
var neverReady = make(chan struct{}) // never closed
// This example passes a context with a signal to tell a blocking function that
// it should abandon its work after a signal is received.
func ExampleNotifyContext() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
p, err := os.FindProcess(os.Getpid())
if err != nil {
log.Fatal(err)
}
// On a Unix-like system, pressing Ctrl+C on a keyboard sends a
// SIGINT signal to the process of the program in execution.
//
// This example simulates that by sending a SIGINT signal to itself.
if err := p.Signal(os.Interrupt); err != nil {
log.Fatal(err)
}
select {
case <-neverReady:
fmt.Println("ready")
case <-ctx.Done():
fmt.Println(ctx.Err()) // prints "context canceled"
stop() // stop receiving signal notifications as soon as possible.
}
// Output:
// context canceled
}
func Reset 1.5
func Reset(sig ...os.Signal)
Reset отменяет действие всех предыдущих вызовов Notify для указанных сигналов. Если сигналы не указаны, будут сброшены все обработчики сигналов.
func Stop 1.1
func Stop(c chan<- os.Signal)
Stop заставляет пакет signal прекратить передачу входящих сигналов в канал c. Он отменяет действие всех предыдущих вызовов Notify с каналом c. После возврата Stop гарантируется, что в канал c больше не поступит ни одного сигнала.
© Google, Inc.
Licensed under the Creative Commons Attribution License 3.0.
http://golang.org/pkg/os/signal/