Merge in build lp
[m6w6/libmemcached] / libtest / signal.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * uTest, libtest
4 *
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * * The names of its contributors may not be used to endorse or
20 * promote products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 */
36
37 #include <libtest/common.h>
38
39 #include <csignal>
40
41 #include <libtest/signal.h>
42
43 using namespace libtest;
44
45 #define MAGIC_MEMORY 123569
46
47 bool SignalThread::is_shutdown()
48 {
49 bool ret;
50 pthread_mutex_lock(&shutdown_mutex);
51 ret= bool(__shutdown != SHUTDOWN_RUNNING);
52 pthread_mutex_unlock(&shutdown_mutex);
53
54 return ret;
55 }
56
57 void SignalThread::set_shutdown(shutdown_t arg)
58 {
59 pthread_mutex_lock(&shutdown_mutex);
60 __shutdown= arg;
61 pthread_mutex_unlock(&shutdown_mutex);
62
63 if (arg == SHUTDOWN_GRACEFUL)
64 {
65 pthread_kill(thread, SIGUSR2);
66
67 void *retval;
68 pthread_join(thread, &retval);
69 }
70 }
71
72 shutdown_t SignalThread::get_shutdown()
73 {
74 shutdown_t local;
75 pthread_mutex_lock(&shutdown_mutex);
76 local= __shutdown;
77 pthread_mutex_unlock(&shutdown_mutex);
78
79 return local;
80 }
81
82 void SignalThread::post()
83 {
84 sem_post(&lock);
85 }
86
87 void SignalThread::test()
88 {
89 assert(magic_memory == MAGIC_MEMORY);
90 if (not getenv("LIBTEST_IN_GDB"))
91 {
92 assert(sigismember(&set, SIGABRT));
93 assert(sigismember(&set, SIGQUIT));
94 assert(sigismember(&set, SIGINT));
95 }
96 assert(sigismember(&set, SIGUSR2));
97 }
98
99 extern "C" {
100
101 static void *sig_thread(void *arg)
102 {
103 SignalThread *context= (SignalThread*)arg;
104
105 context->test();
106 context->post();
107
108 while (context->get_shutdown() == SHUTDOWN_RUNNING)
109 {
110 int sig;
111
112 if (context->wait(sig) == -1)
113 {
114 Error << "sigwait() returned errno:" << strerror(errno);
115 continue;
116 }
117
118 switch (sig)
119 {
120 case SIGABRT:
121 case SIGUSR2:
122 case SIGINT:
123 case SIGQUIT:
124 if (context->is_shutdown() == false)
125 {
126 Error << "Signal handling thread got signal " << strsignal(sig);
127 context->set_shutdown(SHUTDOWN_FORCED);
128 }
129 break;
130
131 default:
132 Error << "Signal handling thread got unexpected signal " << strsignal(sig);
133 break;
134 }
135 }
136
137 return NULL;
138 }
139
140 }
141
142 SignalThread::SignalThread() :
143 magic_memory(MAGIC_MEMORY)
144 {
145 pthread_mutex_init(&shutdown_mutex, NULL);
146 sigemptyset(&set);
147 if (not getenv("LIBTEST_IN_GDB"))
148 {
149 sigaddset(&set, SIGABRT);
150 sigaddset(&set, SIGQUIT);
151 sigaddset(&set, SIGINT);
152 }
153
154 sigaddset(&set, SIGUSR2);
155
156 sem_init(&lock, 0, 0);
157 }
158
159
160 bool SignalThread::setup()
161 {
162 set_shutdown(SHUTDOWN_RUNNING);
163
164 sigset_t old_set;
165 sigemptyset(&old_set);
166 pthread_sigmask(SIG_BLOCK, NULL, &old_set);
167
168 if (sigismember(&old_set, SIGQUIT))
169 {
170 Error << strsignal(SIGQUIT) << " has been previously set.";
171 }
172 if (sigismember(&old_set, SIGINT))
173 {
174 Error << strsignal(SIGINT) << " has been previously set.";
175 }
176 if (sigismember(&old_set, SIGUSR2))
177 {
178 Error << strsignal(SIGUSR2) << " has been previously set.";
179 }
180
181 int error;
182 if ((error= pthread_sigmask(SIG_BLOCK, &set, NULL)) != 0)
183 {
184 Error << "pthread_sigmask() died during pthread_sigmask(" << strerror(error) << ")";
185 return false;
186 }
187
188 if ((error= pthread_create(&thread, NULL, &sig_thread, this)) != 0)
189 {
190 Error << "pthread_create() died during pthread_create(" << strerror(error) << ")";
191 return false;
192 }
193
194 sem_wait(&lock);
195
196 return true;
197 }