]>
Commit | Line | Data |
---|---|---|
064af421 | 1 | /* |
92829687 | 2 | * Copyright (c) 2008, 2009, 2011, 2012, 2013 Nicira, Inc. |
064af421 | 3 | * |
a14bc59f BP |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
064af421 | 7 | * |
a14bc59f BP |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
064af421 BP |
15 | */ |
16 | ||
17 | #include <config.h> | |
18 | #include "signals.h" | |
064af421 BP |
19 | #include <errno.h> |
20 | #include <limits.h> | |
21 | #include <signal.h> | |
5a08f9b0 | 22 | #include <stdlib.h> |
064af421 BP |
23 | #include <unistd.h> |
24 | #include "poll-loop.h" | |
25 | #include "socket-util.h" | |
b725cf02 | 26 | #include "type-props.h" |
064af421 | 27 | #include "util.h" |
279c9e03 BP |
28 | #include "vlog.h" |
29 | ||
30 | VLOG_DEFINE_THIS_MODULE(signals); | |
064af421 BP |
31 | |
32 | #if defined(_NSIG) | |
33 | #define N_SIGNALS _NSIG | |
34 | #elif defined(NSIG) | |
35 | #define N_SIGNALS NSIG | |
36 | #else | |
37 | /* We could try harder to get the maximum signal number, but in practice we | |
38 | * only care about SIGHUP, which is normally signal 1 anyway. */ | |
39 | #define N_SIGNALS 32 | |
40 | #endif | |
41 | ||
42 | struct signal { | |
b173e167 | 43 | int fds[2]; |
064af421 BP |
44 | }; |
45 | ||
b173e167 | 46 | static struct signal signals[N_SIGNALS]; |
064af421 BP |
47 | |
48 | static void signal_handler(int signr); | |
49 | ||
064af421 BP |
50 | /* Sets up a handler for 'signr' and returns a structure that represents it. |
51 | * | |
b173e167 | 52 | * Only one handler for a given signal may be registered. */ |
064af421 BP |
53 | struct signal * |
54 | signal_register(int signr) | |
55 | { | |
56 | struct sigaction sa; | |
57 | struct signal *s; | |
58 | ||
b173e167 | 59 | ovs_assert(signr >= 1 && signr < N_SIGNALS); |
064af421 | 60 | |
b173e167 BP |
61 | /* Create a pipe. */ |
62 | s = &signals[signr]; | |
63 | ovs_assert(!s->fds[0] && !s->fds[1]); | |
64 | xpipe_nonblocking(s->fds); | |
5a08f9b0 | 65 | |
b173e167 | 66 | /* Install signal handler. */ |
064af421 BP |
67 | memset(&sa, 0, sizeof sa); |
68 | sa.sa_handler = signal_handler; | |
69 | sigemptyset(&sa.sa_mask); | |
70 | sa.sa_flags = SA_RESTART; | |
b173e167 | 71 | xsigaction(signr, &sa, NULL); |
064af421 | 72 | |
064af421 BP |
73 | return s; |
74 | } | |
75 | ||
76 | /* Returns true if signal 's' has been received since the last call to this | |
77 | * function with argument 's'. */ | |
78 | bool | |
79 | signal_poll(struct signal *s) | |
80 | { | |
81 | char buf[_POSIX_PIPE_BUF]; | |
b173e167 BP |
82 | |
83 | return read(s->fds[0], buf, sizeof buf) > 0; | |
064af421 BP |
84 | } |
85 | ||
86 | /* Causes the next call to poll_block() to wake up when signal_poll(s) would | |
87 | * return true. */ | |
88 | void | |
89 | signal_wait(struct signal *s) | |
90 | { | |
b173e167 | 91 | poll_fd_wait(s->fds[0], POLLIN); |
064af421 BP |
92 | } |
93 | \f | |
94 | static void | |
95 | signal_handler(int signr) | |
96 | { | |
97 | if (signr >= 1 && signr < N_SIGNALS) { | |
b173e167 | 98 | ignore(write(signals[signr].fds[1], "", 1)); |
064af421 BP |
99 | } |
100 | } | |
b725cf02 | 101 | |
eee8089c BP |
102 | /* Returns the name of signal 'signum' as a string. The return value is either |
103 | * a statically allocated constant string or the 'bufsize'-byte buffer | |
104 | * 'namebuf'. 'bufsize' should be at least SIGNAL_NAME_BUFSIZE. | |
b725cf02 BP |
105 | * |
106 | * The string is probably a (possibly multi-word) description of the signal | |
107 | * (e.g. "Hangup") instead of just the stringified version of the macro | |
108 | * (e.g. "SIGHUP"). */ | |
109 | const char * | |
eee8089c | 110 | signal_name(int signum, char *namebuf, size_t bufsize) |
b725cf02 | 111 | { |
22c4e104 | 112 | #if HAVE_DECL_SYS_SIGLIST |
70107327 | 113 | if (signum >= 0 && signum < N_SIGNALS) { |
eee8089c BP |
114 | const char *name = sys_siglist[signum]; |
115 | if (name) { | |
116 | return name; | |
117 | } | |
22c4e104 | 118 | } |
b725cf02 | 119 | #endif |
22c4e104 | 120 | |
eee8089c BP |
121 | snprintf(namebuf, bufsize, "signal %d", signum); |
122 | return namebuf; | |
b725cf02 | 123 | } |
279c9e03 BP |
124 | |
125 | void | |
126 | xsigaction(int signum, const struct sigaction *new, struct sigaction *old) | |
127 | { | |
128 | if (sigaction(signum, new, old)) { | |
eee8089c BP |
129 | char namebuf[SIGNAL_NAME_BUFSIZE]; |
130 | ||
279c9e03 | 131 | VLOG_FATAL("sigaction(%s) failed (%s)", |
eee8089c | 132 | signal_name(signum, namebuf, sizeof namebuf), |
10a89ef0 | 133 | ovs_strerror(errno)); |
279c9e03 BP |
134 | } |
135 | } | |
136 | ||
137 | void | |
92829687 | 138 | xpthread_sigmask(int how, const sigset_t *new, sigset_t *old) |
279c9e03 | 139 | { |
92829687 BP |
140 | int error = pthread_sigmask(how, new, old); |
141 | if (error) { | |
10a89ef0 | 142 | VLOG_FATAL("pthread_sigmask failed (%s)", ovs_strerror(error)); |
279c9e03 BP |
143 | } |
144 | } |