Update
[m6w6/libmemcached] / libtest / signal.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * libtest
4 *
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 3 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22
23 #include <config.h>
24 #include <libtest/common.h>
25
26 #include <csignal>
27
28 #include <libtest/signal.h>
29
30 using namespace libtest;
31
32 #define MAGIC_MEMORY 123569
33
34 bool SignalThread::is_shutdown()
35 {
36 bool ret;
37 pthread_mutex_lock(&shutdown_mutex);
38 ret= bool(__shutdown != SHUTDOWN_RUNNING);
39 pthread_mutex_unlock(&shutdown_mutex);
40
41 return ret;
42 }
43
44 void SignalThread::set_shutdown(shutdown_t arg)
45 {
46 pthread_mutex_lock(&shutdown_mutex);
47 __shutdown= arg;
48 pthread_mutex_unlock(&shutdown_mutex);
49
50 if (arg == SHUTDOWN_GRACEFUL)
51 {
52 if (pthread_kill(thread, SIGUSR2) == 0)
53 {
54 void *retval;
55 pthread_join(thread, &retval);
56 }
57 }
58 }
59
60 shutdown_t SignalThread::get_shutdown()
61 {
62 shutdown_t local;
63 pthread_mutex_lock(&shutdown_mutex);
64 local= __shutdown;
65 pthread_mutex_unlock(&shutdown_mutex);
66
67 return local;
68 }
69
70 void SignalThread::post()
71 {
72 sem_post(&lock);
73 }
74
75 void SignalThread::test()
76 {
77 assert(magic_memory == MAGIC_MEMORY);
78 if (not getenv("LIBTEST_IN_GDB"))
79 {
80 assert(sigismember(&set, SIGABRT));
81 assert(sigismember(&set, SIGQUIT));
82 assert(sigismember(&set, SIGINT));
83 }
84 assert(sigismember(&set, SIGUSR2));
85 }
86
87 SignalThread::~SignalThread()
88 {
89 if (not is_shutdown())
90 {
91 set_shutdown(SHUTDOWN_GRACEFUL);
92 }
93
94 #if 0
95 if (pthread_equal(thread, pthread_self()) != 0 and (pthread_kill(thread, 0) == ESRCH) == true)
96 {
97 void *retval;
98 pthread_join(thread, &retval);
99 }
100 #endif
101 sem_destroy(&lock);
102
103 int error;
104 if ((error= pthread_sigmask(SIG_UNBLOCK, &set, NULL)) != 0)
105 {
106 Error << "While trying to reset signal mask to original set, pthread_sigmask() died during pthread_sigmask(" << strerror(error) << ")";
107 }
108 }
109
110 extern "C" {
111
112 static void *sig_thread(void *arg)
113 {
114 SignalThread *context= (SignalThread*)arg;
115
116 context->test();
117 context->post();
118
119 while (context->get_shutdown() == SHUTDOWN_RUNNING)
120 {
121 int sig;
122
123 if (context->wait(sig) == -1)
124 {
125 Error << "sigwait() returned errno:" << strerror(errno);
126 continue;
127 }
128
129 switch (sig)
130 {
131 case SIGABRT:
132 case SIGUSR2:
133 case SIGINT:
134 case SIGQUIT:
135 if (context->is_shutdown() == false)
136 {
137 context->set_shutdown(SHUTDOWN_FORCED);
138 }
139 break;
140 case SIGPIPE:
141 {
142 Error << "Ignoring SIGPIPE";
143 }
144 break;
145
146 default:
147 Error << "Signal handling thread got unexpected signal " << strsignal(sig);
148 break;
149 }
150 }
151
152 return NULL;
153 }
154
155 }
156
157 SignalThread::SignalThread() :
158 magic_memory(MAGIC_MEMORY),
159 thread(pthread_self())
160 {
161 pthread_mutex_init(&shutdown_mutex, NULL);
162 sigemptyset(&set);
163 if (bool(getenv("LIBTEST_IN_GDB")) == false)
164 {
165 sigaddset(&set, SIGABRT);
166 sigaddset(&set, SIGQUIT);
167 sigaddset(&set, SIGINT);
168 }
169 sigaddset(&set, SIGPIPE);
170
171 sigaddset(&set, SIGUSR2);
172
173 sem_init(&lock, 0, 0);
174
175 sigemptyset(&original_set);
176 pthread_sigmask(SIG_BLOCK, NULL, &original_set);
177 }
178
179
180 bool SignalThread::setup()
181 {
182 set_shutdown(SHUTDOWN_RUNNING);
183
184 if (sigismember(&original_set, SIGQUIT))
185 {
186 Error << strsignal(SIGQUIT) << " has been previously set.";
187 }
188 if (sigismember(&original_set, SIGINT))
189 {
190 Error << strsignal(SIGINT) << " has been previously set.";
191 }
192 if (sigismember(&original_set, SIGUSR2))
193 {
194 Error << strsignal(SIGUSR2) << " has been previously set.";
195 }
196
197 int error;
198 if ((error= pthread_sigmask(SIG_BLOCK, &set, NULL)) != 0)
199 {
200 Error << "pthread_sigmask() died during pthread_sigmask(" << strerror(error) << ")";
201 return false;
202 }
203
204 if ((error= pthread_create(&thread, NULL, &sig_thread, this)) != 0)
205 {
206 Error << "pthread_create() died during pthread_create(" << strerror(error) << ")";
207 return false;
208 }
209
210 sem_wait(&lock);
211
212 return true;
213 }