Merge in util update
[awesomized/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 <libtest/common.h>
24
25 #include <csignal>
26
27 #include <libtest/signal.h>
28
29 using namespace libtest;
30
31 #define MAGIC_MEMORY 123569
32
33 bool SignalThread::is_shutdown()
34 {
35 bool ret;
36 pthread_mutex_lock(&shutdown_mutex);
37 ret= bool(__shutdown != SHUTDOWN_RUNNING);
38 pthread_mutex_unlock(&shutdown_mutex);
39
40 return ret;
41 }
42
43 void SignalThread::set_shutdown(shutdown_t arg)
44 {
45 pthread_mutex_lock(&shutdown_mutex);
46 __shutdown= arg;
47 pthread_mutex_unlock(&shutdown_mutex);
48
49 if (arg == SHUTDOWN_GRACEFUL)
50 {
51 if (pthread_kill(thread, SIGUSR2) == 0)
52 {
53 void *retval;
54 pthread_join(thread, &retval);
55 }
56 }
57 }
58
59 shutdown_t SignalThread::get_shutdown()
60 {
61 shutdown_t local;
62 pthread_mutex_lock(&shutdown_mutex);
63 local= __shutdown;
64 pthread_mutex_unlock(&shutdown_mutex);
65
66 return local;
67 }
68
69 void SignalThread::post()
70 {
71 sem_post(&lock);
72 }
73
74 void SignalThread::test()
75 {
76 assert(magic_memory == MAGIC_MEMORY);
77 if (not getenv("LIBTEST_IN_GDB"))
78 {
79 assert(sigismember(&set, SIGABRT));
80 assert(sigismember(&set, SIGQUIT));
81 assert(sigismember(&set, SIGINT));
82 }
83 assert(sigismember(&set, SIGUSR2));
84 }
85
86 SignalThread::~SignalThread()
87 {
88 if (not is_shutdown())
89 {
90 set_shutdown(SHUTDOWN_GRACEFUL);
91 }
92
93 #if 0
94 if (pthread_equal(thread, pthread_self()) != 0 and (pthread_kill(thread, 0) == ESRCH) == true)
95 {
96 void *retval;
97 pthread_join(thread, &retval);
98 }
99 #endif
100 sem_destroy(&lock);
101 }
102
103 extern "C" {
104
105 static void *sig_thread(void *arg)
106 {
107 SignalThread *context= (SignalThread*)arg;
108
109 context->test();
110 context->post();
111
112 while (context->get_shutdown() == SHUTDOWN_RUNNING)
113 {
114 int sig;
115
116 if (context->wait(sig) == -1)
117 {
118 Error << "sigwait() returned errno:" << strerror(errno);
119 continue;
120 }
121
122 switch (sig)
123 {
124 case SIGABRT:
125 case SIGUSR2:
126 case SIGINT:
127 case SIGQUIT:
128 if (context->is_shutdown() == false)
129 {
130 context->set_shutdown(SHUTDOWN_FORCED);
131 }
132 break;
133
134 default:
135 Error << "Signal handling thread got unexpected signal " << strsignal(sig);
136 break;
137 }
138 }
139
140 return NULL;
141 }
142
143 }
144
145 SignalThread::SignalThread() :
146 magic_memory(MAGIC_MEMORY),
147 thread(pthread_self())
148 {
149 pthread_mutex_init(&shutdown_mutex, NULL);
150 sigemptyset(&set);
151 if (not getenv("LIBTEST_IN_GDB"))
152 {
153 sigaddset(&set, SIGABRT);
154 sigaddset(&set, SIGQUIT);
155 sigaddset(&set, SIGINT);
156 }
157
158 sigaddset(&set, SIGUSR2);
159
160 sem_init(&lock, 0, 0);
161 }
162
163
164 bool SignalThread::setup()
165 {
166 set_shutdown(SHUTDOWN_RUNNING);
167
168 sigset_t old_set;
169 sigemptyset(&old_set);
170 pthread_sigmask(SIG_BLOCK, NULL, &old_set);
171
172 if (sigismember(&old_set, SIGQUIT))
173 {
174 Error << strsignal(SIGQUIT) << " has been previously set.";
175 }
176 if (sigismember(&old_set, SIGINT))
177 {
178 Error << strsignal(SIGINT) << " has been previously set.";
179 }
180 if (sigismember(&old_set, SIGUSR2))
181 {
182 Error << strsignal(SIGUSR2) << " has been previously set.";
183 }
184
185 int error;
186 if ((error= pthread_sigmask(SIG_BLOCK, &set, NULL)) != 0)
187 {
188 Error << "pthread_sigmask() died during pthread_sigmask(" << strerror(error) << ")";
189 return false;
190 }
191
192 if ((error= pthread_create(&thread, NULL, &sig_thread, this)) != 0)
193 {
194 Error << "pthread_create() died during pthread_create(" << strerror(error) << ")";
195 return false;
196 }
197
198 sem_wait(&lock);
199
200 return true;
201 }