root/plugin/pid/pid_miscwrappers.cpp

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

DEFINITIONS

This source file includes following definitions.
  1. pidVirt_pthread_atfork_child
  2. __register_atfork
  3. fork
  4. clone_start
  5. __clone
  6. shmctl
  7. semctl
  8. msgctl
  9. clock_getcpuclockid
  10. timer_create
  11. mq_notify
  12. syscall

   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 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 <semaphore.h>
  23 #include <sys/syscall.h>
  24 #ifdef __aarch64__
  25 # define __ARCH_WANT_SYSCALL_DEPRECATED
  26 // SYS_getpgrp is a deprecated kernel call in aarch64, but in favor of what?
  27 # include <asm-generic/unistd.h>
  28 // SYS_getpgrp undefined in aarch64, but add extra insurance
  29 # undef SYS_getpgrp
  30 # define SYS_getpgrp __NR_getpgrp
  31 #endif
  32 #include <linux/version.h>
  33 
  34 #include "jassert.h"
  35 #include "jfilesystem.h"
  36 #include "jconvert.h"
  37 #include "pidwrappers.h"
  38 #include "virtualpidtable.h"
  39 #include "dmtcp.h"
  40 #include "shareddata.h"
  41 #include "util.h"
  42 #include "pid.h"
  43 
  44 using namespace dmtcp;
  45 
  46 LIB_PRIVATE pid_t getPidFromEnvVar();
  47 
  48 void pidVirt_pthread_atfork_child()
  49 {
  50   dmtcpResetPidPpid();
  51   dmtcpResetTid(getpid());
  52   VirtualPidTable::instance().resetOnFork();
  53 }
  54 
  55 extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void),
  56                                  void (*child)(void), void *dso_handle)
  57 {
  58   /* dmtcp_prepare_wrappers() must be called before __register_atfork().
  59    * NEXT_FNC() guarantees that dmtcp_prepare_wrappers() is called if
  60    * it was not called earlier. */
  61   return NEXT_FNC(__register_atfork)(prepare, parent, child, dso_handle);
  62 }
  63 
  64 extern "C" pid_t fork()
  65 {
  66   pid_t retval = 0;
  67   pid_t virtualPid = getPidFromEnvVar();
  68 
  69   VirtualPidTable::instance().writeVirtualTidToFileForPtrace(virtualPid);
  70 
  71   pid_t realPid = _real_fork();
  72 
  73   if (realPid > 0) { /* Parent Process */
  74     retval = virtualPid;
  75     VirtualPidTable::instance().updateMapping(virtualPid, realPid);
  76     SharedData::setPidMap(virtualPid, realPid);
  77   } else {
  78     retval = realPid;
  79     VirtualPidTable::instance().readVirtualTidFromFileForPtrace();
  80   }
  81 
  82   return retval;
  83 }
  84 
  85 struct ThreadArg {
  86   int (*fn) (void *arg);  // clone() calls fn that returns int
  87   void *arg;
  88   pid_t virtualTid;
  89   sem_t sem;
  90 };
  91 
  92 // Invoked via __clone
  93 LIB_PRIVATE
  94 int clone_start(void *arg)
  95 {
  96   struct ThreadArg *threadArg = (struct ThreadArg*) arg;
  97   int (*fn) (void *) = threadArg->fn;
  98   void *thread_arg = threadArg->arg;
  99   pid_t virtualTid = threadArg -> virtualTid;
 100 
 101   if (dmtcp_is_running_state()) {
 102     dmtcpResetTid(virtualTid);
 103   }
 104 
 105   VirtualPidTable::instance().updateMapping(virtualTid, _real_gettid());
 106   sem_post(&threadArg->sem);
 107 
 108   JTRACE("Calling user function") (virtualTid);
 109   return (*fn) (thread_arg);
 110 }
 111 
 112 
 113 typedef int (*clone_fptr_t)(int (*fn) (void *arg), void *child_stack, int
 114                             flags, void *arg, int *parent_tidptr,
 115                             struct user_desc *newtls, int *child_tidptr);
 116 //need to forward user clone
 117 extern "C" int __clone(int (*fn) (void *arg), void *child_stack, int flags,
 118                        void *arg, int *parent_tidptr, struct user_desc *newtls,
 119                        int *child_tidptr)
 120 {
 121   pid_t virtualTid = -1;
 122   struct MtcpRestartThreadArg *mtcpRestartThreadArg;
 123 
 124   if (!dmtcp_is_running_state()) {
 125     mtcpRestartThreadArg = (struct MtcpRestartThreadArg *) arg;
 126     arg                  = mtcpRestartThreadArg -> arg;
 127     virtualTid           = mtcpRestartThreadArg -> virtualTid;
 128     if (virtualTid != VIRTUAL_TO_REAL_PID(virtualTid)) {
 129       VirtualPidTable::instance().postRestart();
 130     }
 131   } else {
 132     virtualTid = VirtualPidTable::instance().getNewVirtualTid();
 133     VirtualPidTable::instance().writeVirtualTidToFileForPtrace(virtualTid);
 134   }
 135 
 136   // We have to use DMTCP-specific memory allocator because using glibc:malloc
 137   // can interfere with user threads.
 138   // We use JALLOC_HELPER_FREE to free this memory in two places:
 139   //   1.  later in this function in case of failure on call to __clone; and
 140   //   2.  near the beginnging of clone_start (wrapper for start_routine).
 141   struct ThreadArg *threadArg =
 142     (struct ThreadArg *) JALLOC_HELPER_MALLOC(sizeof (struct ThreadArg));
 143   threadArg->fn = fn;
 144   threadArg->arg = arg;
 145   threadArg->virtualTid = virtualTid;
 146   sem_init(&threadArg->sem, 0, 0);
 147 
 148   JTRACE("Calling libc:__clone");
 149   pid_t tid = _real_clone(clone_start, child_stack, flags, threadArg,
 150                     parent_tidptr, newtls, child_tidptr);
 151 
 152   if (dmtcp_is_running_state()) {
 153     VirtualPidTable::instance().readVirtualTidFromFileForPtrace();
 154   }
 155 
 156   if (tid > 0) {
 157     JTRACE("New thread created") (tid);
 158     /* Wait for child thread to finish intializing.
 159      * We must let the child thread insert original->current tid in the
 160      * virtualpidtable. If we don't wait for the child thread and update the
 161      * pidtable ourselves, there is a possible race if the child thread is
 162      * short lived. In that case, the parent thread might insert
 163      * original->current mapping well after the child thread has exited causing
 164      * stale entries in the virtualpidtable.
 165      */
 166     sem_wait(&threadArg->sem);
 167     sem_destroy(&threadArg->sem);
 168   } else {
 169     virtualTid = tid;
 170   }
 171   // Free memory previously allocated by calling JALLOC_HELPER_MALLOC
 172   JALLOC_HELPER_FREE(threadArg);
 173   return virtualTid;
 174 }
 175 
 176 extern "C"
 177 int shmctl(int shmid, int cmd, struct shmid_ds *buf)
 178 {
 179   DMTCP_PLUGIN_DISABLE_CKPT();
 180   int ret = _real_shmctl(shmid, cmd, buf);
 181   if (buf != NULL) {
 182     buf->shm_cpid = REAL_TO_VIRTUAL_PID(buf->shm_cpid);
 183     buf->shm_lpid = REAL_TO_VIRTUAL_PID(buf->shm_lpid);
 184   }
 185   DMTCP_PLUGIN_ENABLE_CKPT();
 186   return ret;
 187 }
 188 
 189 extern "C"
 190 int semctl(int semid, int semnum, int cmd, ...)
 191 {
 192   union semun uarg;
 193   va_list arg;
 194   va_start (arg, cmd);
 195   uarg = va_arg (arg, union semun);
 196   va_end (arg);
 197 
 198   DMTCP_PLUGIN_DISABLE_CKPT();
 199   int ret = _real_semctl(semid, semnum, cmd, uarg);
 200   if (ret != -1 && (cmd & GETPID)) {
 201     ret = REAL_TO_VIRTUAL_PID(ret);
 202   }
 203   DMTCP_PLUGIN_ENABLE_CKPT();
 204   return ret;
 205 }
 206 
 207 extern "C"
 208 int msgctl(int msqid, int cmd, struct msqid_ds *buf)
 209 {
 210   DMTCP_PLUGIN_DISABLE_CKPT();
 211   int ret = _real_msgctl(msqid, cmd, buf);
 212   if (ret != -1 && buf != NULL && ((cmd & IPC_STAT) || (cmd & MSG_STAT))) {
 213     buf->msg_lspid = REAL_TO_VIRTUAL_PID(buf->msg_lspid);
 214     buf->msg_lrpid = REAL_TO_VIRTUAL_PID(buf->msg_lrpid);
 215   }
 216   DMTCP_PLUGIN_ENABLE_CKPT();
 217   return ret;
 218 }
 219 
 220 extern "C"
 221 int clock_getcpuclockid(pid_t pid, clockid_t *clock_id)
 222 {
 223   DMTCP_PLUGIN_DISABLE_CKPT();
 224   pid_t realPid = VIRTUAL_TO_REAL_PID(pid);
 225   int ret = _real_clock_getcpuclockid(realPid, clock_id);
 226   DMTCP_PLUGIN_ENABLE_CKPT();
 227   return ret;
 228 }
 229 
 230 extern "C" int timer_create(clockid_t clockid,
 231                             struct sigevent *sevp,
 232                             timer_t *timerid)
 233 {
 234   if (sevp != NULL && (sevp->sigev_notify | SIGEV_THREAD_ID)) {
 235     DMTCP_PLUGIN_DISABLE_CKPT();
 236     pid_t virtPid = sevp->_sigev_un._tid;
 237     sevp->_sigev_un._tid  = VIRTUAL_TO_REAL_PID(virtPid);
 238     int ret = _real_timer_create(clockid, sevp, timerid);
 239     sevp->_sigev_un._tid  = virtPid;
 240     DMTCP_PLUGIN_ENABLE_CKPT();
 241     return ret;
 242   }
 243   return _real_timer_create(clockid, sevp, timerid);
 244 }
 245 
 246 
 247 #if 0
 248 extern "C"
 249 int mq_notify(mqd_t mqdes, const struct sigevent *sevp)
 250 {
 251   struct sigevent n;
 252   int ret;
 253   DMTCP_PLUGIN_DISABLE_CKPT();
 254   if (sevp != NULL) {
 255     n = *sevp;
 256     n.sigev_notify_thread_id = VIRTUAL_TO_REAL_PID(n.sigev_notify_thread_id);
 257     ret = _real_mq_notify(mqdes, &n);
 258   } else {
 259     ret = _real_mq_notify(mqdes, sevp);
 260   }
 261   DMTCP_PLUGIN_ENABLE_CKPT();
 262   return ret;
 263 }
 264 #endif
 265 
 266 extern "C" int __clone (int (*fn) (void *arg), void *child_stack, int flags, void *arg, int *parent_tidptr, struct user_desc *newtls, int *child_tidptr);
 267 
 268 #define SYSCALL_VA_START()                                              \
 269   va_list ap;                                                           \
 270   va_start(ap, sys_num)
 271 
 272 #define SYSCALL_VA_END()                                                \
 273   va_end(ap)
 274 
 275 #define SYSCALL_GET_ARG(type,arg) type arg = va_arg(ap, type)
 276 
 277 #define SYSCALL_GET_ARGS_2(type1,arg1,type2,arg2)                       \
 278   SYSCALL_GET_ARG(type1,arg1);                                          \
 279   SYSCALL_GET_ARG(type2,arg2)
 280 
 281 #define SYSCALL_GET_ARGS_3(type1,arg1,type2,arg2,type3,arg3)            \
 282   SYSCALL_GET_ARGS_2(type1,arg1,type2,arg2);                            \
 283   SYSCALL_GET_ARG(type3,arg3)
 284 
 285 #define SYSCALL_GET_ARGS_4(type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
 286   SYSCALL_GET_ARGS_3(type1,arg1,type2,arg2,type3,arg3);                 \
 287   SYSCALL_GET_ARG(type4,arg4)
 288 
 289 #define SYSCALL_GET_ARGS_5(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
 290                            type5,arg5)                                  \
 291   SYSCALL_GET_ARGS_4(type1,arg1,type2,arg2,type3,arg3,type4,arg4);      \
 292   SYSCALL_GET_ARG(type5,arg5)
 293 
 294 #define SYSCALL_GET_ARGS_6(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
 295                            type5,arg5,type6,arg6)                        \
 296   SYSCALL_GET_ARGS_5(type1,arg1,type2,arg2,type3,arg3,type4,arg4,       \
 297                      type5,arg5);                                       \
 298   SYSCALL_GET_ARG(type6,arg6)
 299 
 300 #define SYSCALL_GET_ARGS_7(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
 301                            type5,arg5,type6,arg6,type7,arg7)             \
 302   SYSCALL_GET_ARGS_6(type1,arg1,type2,arg2,type3,arg3,type4,arg4,       \
 303                      type5,arg5,type6,arg6);                             \
 304   SYSCALL_GET_ARG(type7,arg7)
 305 
 306 /* Comments by Gene:
 307  * Here, syscall is the wrapper, and the call to syscall would be _real_syscall
 308  * We would add a special case for SYS_gettid, while all others default as below
 309  * It depends on the idea that arguments are stored in registers, whose
 310  *  natural size is:  sizeof(void*)
 311  * So, we pass six arguments to syscall, and it will ignore any extra arguments
 312  * I believe that all Linux system calls have no more than 7 args.
 313  * clone() is an example of one with 7 arguments.
 314  * If we discover system calls for which the 7 args strategy doesn't work,
 315  *  we can special case them.
 316  *
 317  * XXX: DO NOT USE JTRACE/JNOTE/JASSERT in this function; even better, do not
 318  *      use any STL here.  (--Kapil)
 319  */
 320 extern "C" long syscall(long sys_num, ...)
 321 {
 322   long ret;
 323   va_list ap;
 324 
 325   va_start(ap, sys_num);
 326 
 327   switch (sys_num) {
 328     case SYS_gettid:
 329     {
 330       ret = dmtcp_gettid();
 331       break;
 332     }
 333     case SYS_tkill:
 334     {
 335       SYSCALL_GET_ARGS_2(int, tid, int, sig);
 336       ret = dmtcp_tkill(tid, sig);
 337       break;
 338     }
 339     case SYS_tgkill:
 340     {
 341       SYSCALL_GET_ARGS_3(int, tgid, int, tid, int, sig);
 342       ret = dmtcp_tgkill(tgid, tid, sig);
 343       break;
 344     }
 345 
 346     case SYS_getpid:
 347     {
 348       ret = getpid();
 349       break;
 350     }
 351     case SYS_getppid:
 352     {
 353       ret = getppid();
 354       break;
 355     }
 356 
 357     case SYS_getpgrp:
 358     {
 359       ret = getpgrp();
 360       break;
 361     }
 362 
 363     case SYS_getpgid:
 364     {
 365       SYSCALL_GET_ARG(pid_t,pid);
 366       ret = getpgid(pid);
 367       break;
 368     }
 369     case SYS_setpgid:
 370     {
 371       SYSCALL_GET_ARGS_2(pid_t,pid,pid_t,pgid);
 372       ret = setpgid(pid, pgid);
 373       break;
 374     }
 375 
 376     case SYS_getsid:
 377     {
 378       SYSCALL_GET_ARG(pid_t,pid);
 379       ret = getsid(pid);
 380       break;
 381     }
 382     case SYS_setsid:
 383     {
 384       ret = setsid();
 385       break;
 386     }
 387 
 388     case SYS_kill:
 389     {
 390       SYSCALL_GET_ARGS_2(pid_t,pid,int,sig);
 391       ret = kill(pid, sig);
 392       break;
 393     }
 394 
 395 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9))
 396     case SYS_waitid:
 397     {
 398       //SYSCALL_GET_ARGS_4(idtype_t,idtype,id_t,id,siginfo_t*,infop,int,options);
 399       SYSCALL_GET_ARGS_4(int,idtype,id_t,id,siginfo_t*,infop,int,options);
 400       ret = waitid((idtype_t)idtype, id, infop, options);
 401       break;
 402     }
 403 #endif
 404     case SYS_wait4:
 405     {
 406       SYSCALL_GET_ARGS_4(pid_t,pid,__WAIT_STATUS,status,int,options,
 407                          struct rusage*,rusage);
 408       ret = wait4(pid, status, options, rusage);
 409       break;
 410     }
 411 #ifdef __i386__
 412     case SYS_waitpid:
 413     {
 414       SYSCALL_GET_ARGS_3(pid_t,pid,int*,status,int,options);
 415       ret = waitpid(pid, status, options);
 416       break;
 417     }
 418 #endif
 419 
 420     case SYS_setgid:
 421     {
 422       SYSCALL_GET_ARG(gid_t,gid);
 423       ret = setgid(gid);
 424       break;
 425     }
 426     case SYS_setuid:
 427     {
 428       SYSCALL_GET_ARG(uid_t,uid);
 429       ret = setuid(uid);
 430       break;
 431     }
 432 
 433 #ifndef DISABLE_SYS_V_IPC
 434 # ifdef __x86_64__
 435 // These SYS_xxx are only defined for 64-bit Linux
 436     case SYS_shmget:
 437     {
 438       SYSCALL_GET_ARGS_3(key_t,key,size_t,size,int,shmflg);
 439       ret = shmget(key, size, shmflg);
 440       break;
 441     }
 442     case SYS_shmat:
 443     {
 444       SYSCALL_GET_ARGS_3(int,shmid,const void*,shmaddr,int,shmflg);
 445       ret = (unsigned long) shmat(shmid, shmaddr, shmflg);
 446       break;
 447     }
 448     case SYS_shmdt:
 449     {
 450       SYSCALL_GET_ARG(const void*,shmaddr);
 451       ret = shmdt(shmaddr);
 452       break;
 453     }
 454     case SYS_shmctl:
 455     {
 456       SYSCALL_GET_ARGS_3(int,shmid,int,cmd,struct shmid_ds*,buf);
 457       ret = shmctl(shmid, cmd, buf);
 458       break;
 459     }
 460 # endif
 461 #endif
 462 
 463     default:
 464     {
 465       SYSCALL_GET_ARGS_7(void*, arg1, void*, arg2, void*, arg3, void*, arg4,
 466                          void*, arg5, void*, arg6, void*, arg7);
 467       ret = _real_syscall(sys_num, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
 468       break;
 469     }
 470   }
 471   va_end(ap);
 472   return ret;
 473 }

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