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);
Event local_ptr_assign_local: Assigning: "set" = "&tmp" (address of local variable "tmp").
Also see events: [out_of_scope][use_invalid]
165  	    set = &tmp;
Event out_of_scope: Variable "tmp" goes out of scope.
Also see events: [local_ptr_assign_local][use_invalid]
166  	  }
167  	
Event use_invalid: Using "set", which points to an out-of-scope variable "tmp".
Also see events: [local_ptr_assign_local][out_of_scope]
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);
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  	}