root/signalwrappers.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bannedSignalNumber
  2. patchBSDMask
  3. patchBSDUserMask
  4. patchPOSIXMask
  5. patchPOSIXUserMaskWork
  6. patchPOSIXUserMask
  7. patchPOSIXUserMaskMT
  8. signal
  9. sigaction
  10. rt_sigaction
  11. sigvec
  12. sigblock
  13. sigsetmask
  14. siggetmask
  15. sigprocmask
  16. rt_sigprocmask
  17. sigsuspend
  18. sighold
  19. sigignore
  20. sigrelse
  21. __sigpause
  22. sigpause
  23. pthread_sigmask
  24. sigwait
  25. sigwaitinfo
  26. sigtimedwait

   1 /****************************************************************************
   2  *   Copyright (C) 2006-2013 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 DMTCP.                                             *
   6  *                                                                          *
   7  *  DMTCP 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 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 "dmtcpworker.h"
  23 #include "mtcpinterface.h"
  24 #include "syscallwrappers.h"
  25 #include  "../jalib/jassert.h"
  26 
  27 #include <stdio.h>
  28 #include <stdlib.h>
  29 #include <errno.h>
  30 
  31 #ifndef EXTERNC
  32 #define EXTERNC extern "C"
  33 #endif
  34 
  35 using namespace dmtcp;
  36 
  37 //gah!!! signals API is redundant
  38 
  39 static bool checkpointSignalBlockedForProcess = false;
  40 static __thread bool checkpointSignalBlockedForThread = false;
  41 static int stopSignal = -1;
  42 
  43 
  44 static int bannedSignalNumber()
  45 {
  46   if (stopSignal == -1) {
  47     stopSignal = DmtcpWorker::determineCkptSignal();
  48 
  49     // On some systems, the ckpt-signal may be blocked by default. Unblock it
  50     // now.
  51     sigset_t set;
  52     sigemptyset(&set);
  53     sigaddset(&set, stopSignal);
  54     JASSERT(_real_pthread_sigmask(SIG_UNBLOCK, &set, NULL) == 0)
  55       (strerror(_real_pthread_sigmask(SIG_UNBLOCK, &set, NULL))) (stopSignal);
  56   }
  57   return stopSignal;
  58 }
  59 
  60 static int patchBSDMask(int mask)
  61 {
  62   const int allowedMask = ~sigmask(bannedSignalNumber());
  63   return mask & allowedMask;
  64 }
  65 
  66 static inline void patchBSDUserMask(int how, const int mask, int *oldmask)
  67 {
  68   const int bannedMask = sigmask(bannedSignalNumber());
  69   if (checkpointSignalBlockedForProcess == true) {
  70     *oldmask |= bannedMask;
  71   } else {
  72     *oldmask &= ~bannedMask;
  73   }
  74 
  75   if (how == SIG_BLOCK && (mask & bannedMask)) {
  76     checkpointSignalBlockedForProcess = true;
  77   } else if (how == SIG_SETMASK) {
  78     checkpointSignalBlockedForProcess = ((mask & bannedMask) != 0);
  79   }
  80 }
  81 
  82 static inline sigset_t patchPOSIXMask(const sigset_t* mask)
  83 {
  84   JASSERT(mask != NULL);
  85   sigset_t t = *mask;
  86 
  87   sigdelset(&t, bannedSignalNumber());
  88   return t;
  89 }
  90 
  91 static inline void patchPOSIXUserMaskWork(int how, const sigset_t *set,
  92                                           sigset_t *oldset,
  93                                           bool *checkpointSignalBlocked)
  94 {
  95   if (oldset != NULL) {
  96     if (*checkpointSignalBlocked == true) {
  97       sigaddset(oldset, bannedSignalNumber());
  98     } else {
  99       sigdelset(oldset, bannedSignalNumber());
 100     }
 101   }
 102 
 103   if (set != NULL) {
 104     int bannedSignaIsMember = sigismember(set, bannedSignalNumber());
 105     if (how == SIG_BLOCK && bannedSignaIsMember) {
 106       *checkpointSignalBlocked = true;
 107     } else if (how == SIG_UNBLOCK && bannedSignaIsMember) {
 108       *checkpointSignalBlocked = false;
 109     } else if (how == SIG_SETMASK) {
 110       *checkpointSignalBlocked = bannedSignaIsMember;
 111     }
 112   }
 113 }
 114 
 115 static inline void patchPOSIXUserMask(int how, const sigset_t *set, sigset_t *oldset)
 116 {
 117   patchPOSIXUserMaskWork(how, set, oldset, &checkpointSignalBlockedForProcess);
 118 }
 119 
 120 /* Multi-threaded version of the above function */
 121 static inline void patchPOSIXUserMaskMT(int how, const sigset_t *set, sigset_t *oldset)
 122 {
 123   patchPOSIXUserMaskWork(how, set, oldset, &checkpointSignalBlockedForThread);
 124 }
 125 
 126 
 127 //set the handler
 128 EXTERNC sighandler_t signal(int signum, sighandler_t handler)
 129 {
 130   if(signum == bannedSignalNumber()) {
 131     return SIG_IGN;
 132   }
 133   return _real_signal( signum, handler );
 134 }
 135 
 136 
 137 EXTERNC int sigaction(int signum, const struct sigaction *act,
 138                       struct sigaction *oldact)
 139 {
 140   if(signum == bannedSignalNumber() && act != NULL) {
 141     JWARNING("Application trying to use DMTCP's signal for it's own use.\n"
 142              "  You should employ a different signal by setting the\n"
 143              "  environment variable DMTCP_SIGCKPT to the number\n"
 144              "  of the signal that DMTCP should use for checkpointing.")
 145       (stopSignal);
 146     act = NULL;
 147   }
 148   return _real_sigaction( signum, act, oldact);
 149 }
 150 
 151 EXTERNC int rt_sigaction(int signum, const struct sigaction *act,
 152                          struct sigaction *oldact)
 153 {
 154   return sigaction (signum, act, oldact);
 155   //if(signum == bannedSignalNumber()) {
 156   //  act = NULL;
 157   //}
 158   //return _real_rt_sigaction( signum, act, oldact);
 159 }
 160 
 161 #if !__GLIBC_PREREQ(2,21)
 162 EXTERNC int sigvec(int signum, const struct sigvec *vec, struct sigvec *ovec)
 163 {
 164   if(signum == bannedSignalNumber()) {
 165     vec = NULL;
 166   }
 167   return _real_sigvec( signum, vec, ovec );
 168 }
 169 #endif
 170 
 171 //set the mask
 172 EXTERNC int sigblock(int mask)
 173 {
 174   int oldmask = _real_sigblock( patchBSDMask(mask) );
 175   patchBSDUserMask(SIG_BLOCK, mask, &oldmask);
 176   return oldmask;
 177 }
 178 
 179 EXTERNC int sigsetmask(int mask)
 180 {
 181   int oldmask = _real_sigsetmask( patchBSDMask(mask) );
 182   patchBSDUserMask(SIG_SETMASK, mask, &oldmask);
 183   return oldmask;
 184 }
 185 
 186 EXTERNC int siggetmask(void)
 187 {
 188   int oldmask =  _real_siggetmask();
 189   patchBSDUserMask(SIG_BLOCK, 0, &oldmask);
 190   return oldmask;
 191 }
 192 
 193 EXTERNC int sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
 194 {
 195   sigset_t tmp;
 196   const sigset_t *orig = set;
 197   if (set != NULL) {
 198     tmp = patchPOSIXMask(set);
 199     set = &tmp;
 200   }
 201 
 202   int ret = _real_sigprocmask( how, set, oldset );
 203 
 204   if (ret != -1) {
 205     patchPOSIXUserMask(how, orig, oldset);
 206   }
 207   return ret;
 208 }
 209 
 210 EXTERNC int rt_sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
 211 {
 212   return sigprocmask(how, set, oldset);
 213 //  sigset_t tmp;
 214 //  const sigset_t *orig = set;
 215 //  if (set != NULL) {
 216 //    tmp = patchPOSIXMask(set);
 217 //    set = &tmp;
 218 //  }
 219 //
 220 //  int ret = _real_rt_sigprocmask( how, set, oldset );
 221 //
 222 //  if (ret != -1) {
 223 //    patchPOSIXUserMask(how, orig, oldset);
 224 //  }
 225 //  return ret;
 226 }
 227 
 228 EXTERNC int sigsuspend(const sigset_t *mask)
 229 {
 230   sigset_t tmp;
 231   if (mask != NULL) {
 232     tmp = patchPOSIXMask(mask);
 233     mask = &tmp;
 234   }
 235 
 236   int ret = _real_sigsuspend(mask);
 237   return ret;
 238 }
 239 
 240 /* FIXME: Reverify the logic of the following four wrappers:
 241  *          sighold, sigignore, sigrelse, sigpause
 242  *        These are deprecated according to manpage.
 243  */
 244 EXTERNC int sighold(int sig)
 245 {
 246   if (sig == bannedSignalNumber()) {
 247     return 0;
 248   }
 249   return _real_sighold(sig);
 250 }
 251 
 252 EXTERNC int sigignore(int sig)
 253 {
 254   if (sig == bannedSignalNumber()) {
 255     return 0;
 256   }
 257   return _real_sigignore(sig);
 258 }
 259 
 260 EXTERNC int sigrelse(int sig)
 261 {
 262   if (sig == bannedSignalNumber()) {
 263     return 0;
 264   }
 265   return _real_sigrelse(sig);
 266 }
 267 
 268 // signal.h can define sigpause as a macro expanding into __sigpause
 269 // That takes an extra arg to handle sigmask (BSD) or signal (System V)
 270 // So, we wrap both version.
 271 EXTERNC int __sigpause(int __sig_or_mask, int __is_sig)
 272 {
 273   JWARNING(false)
 274     .Text("This function is deprecated. Use sigsuspend instead." \
 275           "  The DMTCP wrappers for this function may not be fully tested");
 276   return _real__sigpause(__sig_or_mask, __is_sig);
 277 }
 278 
 279 // Remove any possible macro expansion from signal.h
 280 // sigpause must not be invoked after this in this file.
 281 #undef sigpause
 282 EXTERNC int sigpause(int sig)
 283 {
 284   JWARNING(false)
 285     .Text("This function is deprecated. Use sigsuspend instead." \
 286           "  The DMTCP wrappers for this function may not be fully tested");
 287   return _real_sigpause(sig);
 288 }
 289 
 290 /*
 291  * This wrapper should be thread safe so we use the multithreaded version of
 292  * patchPOSIXUserMask function. This will declare the static variables with
 293  * __thread to make them thread local.
 294  */
 295 EXTERNC int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldmask)
 296 {
 297   const sigset_t *orig = set;
 298   sigset_t tmp;
 299   if (set != NULL) {
 300     tmp = patchPOSIXMask(set);
 301     set = &tmp;
 302   }
 303 
 304   int ret = _real_pthread_sigmask( how, set, oldmask );
 305 
 306   if (ret != -1) {
 307     patchPOSIXUserMaskMT(how, orig, oldmask);
 308   }
 309 
 310   return ret;
 311 }
 312 
 313 /*
 314  * TODO: man page says that sigwait is implemented via sigtimedwait, however
 315  * sigtimedwait can return EINTR (acc. to man page) whereas sigwait won't.
 316  * Should we make the wrappers for sigwait/sigtimedwait homogeneous??
 317  *                                                          -- Kapil
 318  */
 319 EXTERNC int sigwait(const sigset_t *set, int *sig)
 320 {
 321   sigset_t tmp;
 322   if (set != NULL) {
 323     tmp = patchPOSIXMask(set);
 324     set = &tmp;
 325   }
 326 
 327   int ret = _real_sigwait( set, sig );
 328 
 329   return ret;
 330 }
 331 
 332 /*
 333  * In sigwaitinfo and sigtimedwait, it is not possible to differentiate between
 334  * a DMTCP_SIGCKPT and any other signal (that is outside the given signal set)
 335  * that might have occurred while executing the system call. These system call
 336  * will return -1 with errno set to EINTR.
 337  * To deal with the situation, we do not remove the DMTCP_SIGCKPT from the
 338  * signal set (if it is present); instead, we check the return value and if it
 339  * turns out to be DMTCP_SIGCKPT, we raise the signal once again for this
 340  * thread.
 341  * Also note that once sigwaitinfo/sigtimedwait returns DMTCP_SIGCKPT, we won't
 342  * be receiving another DMTCP_SIGCKPT until we have called _real_tkill due to
 343  * obvious reasons so I believe it is safe to call _real_gettid() here.
 344  *                                                              -- Kapil
 345  *
 346  * Update:
 347  * Another way to write this wrapper would be to remove the STOPSIGNAL from the
 348  * user supplied 'set' and then call sigwaitinfo and then we won't need to
 349  * raise the STOPSIGNAL ourselves. However, there is a catch. sigwaitinfo will
 350  * return 'EINTR' if the wait was interrupted by a signal handler (STOPSIGNAL
 351  * in our case), thus we can either call sigwaitinfo again or return the error
 352  * to the user code; I would like to do the former.
 353  *                                                              -- Kapil
 354  */
 355 EXTERNC int sigwaitinfo(const sigset_t *set, siginfo_t *info)
 356 {
 357   int ret;
 358   while ( 1 ) {
 359     ret = _real_sigwaitinfo( set, info );
 360     if ( ret != bannedSignalNumber() ) {
 361       break;
 362     }
 363     raise(bannedSignalNumber());
 364   }
 365   return ret;
 366 }
 367 
 368 EXTERNC int sigtimedwait(const sigset_t *set, siginfo_t *info,
 369                          const struct timespec *timeout)
 370 {
 371   int ret;
 372   while ( 1 ) {
 373     ret = _real_sigtimedwait( set, info, timeout );
 374     if ( ret != bannedSignalNumber() ) {
 375       break;
 376     }
 377     raise(bannedSignalNumber());
 378   }
 379   return ret;
 380 }

/* [<][>][^][v][top][bottom][index][help] */