1 /****************************************************************************
2 * Copyright (C) 2006-2010 by Jason Ansel, Kapil Arya, and Gene Cooperman *
3 * jansel@csail.mit.edu, kapil@ccs.neu.edu, gene@ccs.neu.edu *
4 * *
5 * This file is part of the dmtcp/src module of DMTCP (DMTCP:dmtcp/src). *
6 * *
7 * DMTCP:dmtcp/src is free software: you can redistribute it and/or *
8 * modify it under the terms of the GNU Lesser General Public License as *
9 * published by the Free Software Foundation, either version 3 of the *
10 * License, or (at your option) any later version. *
11 * *
12 * DMTCP:dmtcp/src 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 *
15 * GNU 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 DMTCP:dmtcp/src. If not, see *
19 * <http://www.gnu.org/licenses/>. *
20 ****************************************************************************/
21
22 #include "mtcpinterface.h"
23 #include "syscallwrappers.h"
24 #include "../jalib/jassert.h"
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29
30 #ifndef EXTERNC
31 #define EXTERNC extern "C"
32 #endif
33
34 //gah!!! signals API is redundant
35
36 static bool checkpointSignalBlockedForProcess = false;
37 static __thread bool checkpointSignalBlockedForThread = false;
38
39
40 static int bannedSignalNumber(){
41 int _determineMtcpSignal(); // from signalwrappers.cpp
42 const int cache = _determineMtcpSignal();
43 return cache;
44 }
45
46 static int patchBSDMask(int mask){
47 const int allowedMask = ~sigmask(bannedSignalNumber());
48 return mask & allowedMask;
49 }
50
51 static inline void patchBSDUserMask(int how, const int mask, int *oldmask)
52 {
53 const int bannedMask = sigmask(bannedSignalNumber());
54 if (checkpointSignalBlockedForProcess == true) {
55 *oldmask |= bannedMask;
56 } else {
57 *oldmask &= ~bannedMask;
58 }
59
60 if (how == SIG_BLOCK && (mask & bannedMask)) {
61 checkpointSignalBlockedForProcess = true;
62 } else if (how == SIG_SETMASK) {
63 checkpointSignalBlockedForProcess = ((mask & bannedMask) != 0);
64 }
65 }
66
67 static inline sigset_t patchPOSIXMask(const sigset_t* mask){
68 JASSERT(mask != NULL);
69 sigset_t t = *mask;
70
71 sigdelset(&t, bannedSignalNumber());
72 return t;
73 }
74
75 static inline void patchPOSIXUserMaskWork(int how, const sigset_t *set, sigset_t *oldset,
76 bool checkpointSignalBlocked)
77 {
78 if (oldset != NULL) {
79 if (checkpointSignalBlocked == true) {
80 sigaddset(oldset, bannedSignalNumber());
81 } else {
82 sigdelset(oldset, bannedSignalNumber());
83 }
84 }
85
86 if (set != NULL) {
87 if (how == SIG_BLOCK && sigismember(set, bannedSignalNumber())) {
88 checkpointSignalBlocked = true;
89 } else if (how == SIG_UNBLOCK && sigismember(set,bannedSignalNumber())) {
90 checkpointSignalBlocked = false;
91 } else if (how == SIG_SETMASK) {
92 checkpointSignalBlocked = sigismember(set, bannedSignalNumber());
93 }
94 }
95 }
96
97 static inline void patchPOSIXUserMask(int how, const sigset_t *set, sigset_t *oldset)
98 {
99 patchPOSIXUserMaskWork(how, set, oldset, checkpointSignalBlockedForProcess);
100 }
101
102 /* Multi-threaded version of the above function */
103 static inline void patchPOSIXUserMaskMT(int how, const sigset_t *set, sigset_t *oldset)
104 {
105 patchPOSIXUserMaskWork(how, set, oldset, checkpointSignalBlockedForThread);
106 }
107
108
109 //set the handler
110 EXTERNC sighandler_t signal(int signum, sighandler_t handler){
111 if(signum == bannedSignalNumber()){
112 return SIG_IGN;
113 }
114 return _real_signal( signum, handler );
115 }
116 EXTERNC int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact){
117 if(signum == bannedSignalNumber()){
118 act = NULL;
119 }
120 return _real_sigaction( signum, act, oldact);
121 }
122 EXTERNC int rt_sigaction(int signum, const struct sigaction *act, struct sigaction *oldact){
123 return sigaction (signum, act, oldact);
124 //if(signum == bannedSignalNumber()){
125 // act = NULL;
126 //}
127 //return _real_rt_sigaction( signum, act, oldact);
128 }
129 EXTERNC int sigvec(int signum, const struct sigvec *vec, struct sigvec *ovec){
130 if(signum == bannedSignalNumber()){
131 vec = NULL;
132 }
133 return _real_sigvec( signum, vec, ovec );
134 }
135
136 //set the mask
137 EXTERNC int sigblock(int mask){
138 int oldmask = _real_sigblock( patchBSDMask(mask) );
139
140 patchBSDUserMask(SIG_BLOCK, mask, &oldmask);
141
142 return oldmask;
143 }
144
145 EXTERNC int sigsetmask(int mask){
146 int oldmask = _real_sigsetmask( patchBSDMask(mask) );
147
148 patchBSDUserMask(SIG_SETMASK, mask, &oldmask);
149
150 return oldmask;
151 }
152
153 EXTERNC int siggetmask(void){
154 int oldmask = _real_siggetmask();
155
156 patchBSDUserMask(SIG_BLOCK, 0, &oldmask);
157
158 return oldmask;
159 }
160
161 EXTERNC int sigprocmask(int how, const sigset_t *set, sigset_t *oldset){
162 const sigset_t *orig = set;
163 if (set != NULL) {
164 sigset_t tmp = patchPOSIXMask(set);
165 set = &tmp;
166 }
167
168 int ret = _real_sigprocmask( how, set, oldset );
169
170 if (ret != -1) {
171 patchPOSIXUserMask(how, orig, oldset);
172 }
173 return ret;
174 }
175
176 EXTERNC int rt_sigprocmask(int how, const sigset_t *set, sigset_t *oldset){
177 return sigprocmask(how, set, oldset);
178 // const sigset_t *orig = set;
179 // if (set != NULL) {
180 // sigset_t tmp = patchPOSIXMask(set);
181 // set = &tmp;
182 // }
183 //
184 // int ret = _real_rt_sigprocmask( how, set, oldset );
185 //
186 // if (ret != -1) {
187 // patchPOSIXUserMask(how, orig, oldset);
188 // }
189 // return ret;
190 }
191
192 /*
193 * This wrapper should be thread safe so we use the multithreaded version of
194 * patchPOSIXUserMask function. This will declare the static variables with
195 * __thread to make them thread local.
196 */
197 EXTERNC int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldmask){
198 const sigset_t *orig = set;
199 if (set != NULL) {
200 sigset_t tmp = patchPOSIXMask(set);
201 set = &tmp;
202 }
203
204 int ret = _real_pthread_sigmask( how, set, oldmask );
205
206 if (ret != -1) {
207 patchPOSIXUserMaskMT(how, orig, oldmask);
208 }
209
210 return ret;
211 }
212
213 /*
214 * TODO: man page says that sigwait is implemented via sigtimedwait, however
215 * sigtimedwait can return EINTR (acc. to man page) whereas sigwait won't.
216 * Should we make the wrappers for sigwait/sigtimedwait homogenious??
217 * -- Kapil
218 */
219 EXTERNC int sigwait(const sigset_t *set, int *sig) {
220 if (set != NULL) {
221 sigset_t tmp = patchPOSIXMask(set);
|
Event local_ptr_assign_local: |
Assigning: "set" = "&tmp" (address of local variable "tmp"). |
| Also see events: |
[out_of_scope][use_invalid] |
222 set = &tmp;
223 }
224
225 int ret = _real_sigwait( set, sig );
226
227 return ret;
228 }
229
230 /*
231 * In sigwaitinfo and sigtimedwait, it is not possible to differentiate between
232 * a MTCP_SIGCKPT and any other signal (that is outside the given signal set)
233 * that might have occured while executing the system call. These system call
234 * will return -1 with errno set to EINTR.
235 * To deal with the situation, we do not remove the MTCP_SIGCKPT from the
236 * signal set (if it is present); instead, we check the return value and if it
237 * turns out to be MTCP_SIGCKPT, we raise the signal once again for this
238 * thread.
239 * Also note that once sigwaitinfo/sigtimedwait returns MTCP_SIGCKPT, we won't
240 * be receiving another MTCP_SIGCKPT until we have called _real_tkill due to
241 * obvious reasons so I believe it is safe to call _real_gettid() here.
242 * -- Kapil
243 *
244 * Update:
245 * Another way to write this wrapper would be to remove the STOPSIGNAL from the
246 * user supplied 'set' and then call sigwaitinfo and then we won't need to
247 * raise the STOPSIGNAL ourselves. However, there is a catch. sigwaitinfo will
248 * return 'EINTR' if the wait was interrupted by a signal handler (STOPSIGNAL
249 * in our case), thus we can either call sigwaitinfo again or return the error
250 * to the user code; I would like to do the former.
251 * -- Kapil
252 */
253 EXTERNC int sigwaitinfo(const sigset_t *set, siginfo_t *info)
254 {
255 int ret;
256 while ( 1 ) {
257 ret = _real_sigwaitinfo( set, info );
258 if ( ret != bannedSignalNumber() ) {
259 break;
260 }
261 raise(bannedSignalNumber());
262 }
263 return ret;
264 }
265
266 EXTERNC int sigtimedwait(const sigset_t *set, siginfo_t *info,
267 const struct timespec *timeout)
268 {
269 int ret;
270 while ( 1 ) {
271 ret = _real_sigtimedwait( set, info, timeout );
272 if ( ret != bannedSignalNumber() ) {
273 break;
274 }
275 raise(bannedSignalNumber());
276 }
277 return ret;
278 }