extern "C" int   setpgid(pid_t pid, pid_t pgid)
{
  DMTCP_PLUGIN_DISABLE_CKPT();

  pid_t currPid = VIRTUAL_TO_REAL_PID (pid);
  pid_t currPgid = VIRTUAL_TO_REAL_PID (pgid);

  int retVal = _real_setpgid (currPid, currPgid);

  DMTCP_PLUGIN_ENABLE_CKPT();

  return retVal;
}
LIB_PRIVATE
int tgkill(int tgid, int tid, int sig)
{
  // FIXME: Check the comments in kill()
//  DMTCP_PLUGIN_DISABLE_CKPT();

  int realTgid = VIRTUAL_TO_REAL_PID ( tgid );
  int realTid = VIRTUAL_TO_REAL_PID ( tid );

  int retVal = _real_tgkill ( realTgid, realTid, sig );

//  DMTCP_PLUGIN_ENABLE_CKPT();

  return retVal;
}
extern "C" int fcntl(int fd, int cmd, ...)
{
  va_list ap;
  // Handling the variable number of arguments
  void *arg_in = NULL;
  void *arg = NULL;
  va_start( ap, cmd );
  arg_in = va_arg(ap, void *);
  va_end(ap);

  arg = arg_in;

  DMTCP_PLUGIN_DISABLE_CKPT();

  if (cmd == F_SETOWN) {
    pid_t virtualPid = VIRTUAL_TO_REAL_PID((pid_t) (unsigned long) arg_in);
    arg = (void*) (unsigned long) virtualPid;
  }

  int result = _real_fcntl(fd, cmd, arg);
  int retval = result;

  if (cmd == F_GETOWN) {
    retval = REAL_TO_VIRTUAL_PID(result);
  }

  DMTCP_PLUGIN_ENABLE_CKPT();
  return retval;
}
extern "C" int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options)
{
  int retval = 0;
  struct timespec sleepTime = {0, 1000};
  siginfo_t siginfop;
  memset(&siginfop, 0, sizeof(siginfop));

  /* waitid returns 0 in case of success as well as when WNOHANG is specified
   * and we need to distinguish those two cases.man page for waitid says:
   *   If WNOHANG was specified in options and there were no children in a
   *   waitable  state, then waitid() returns 0 immediately and the state of
   *   the siginfo_t structure pointed to by infop is unspecified.  To
   *   distinguish this case from that where a child was in a  waitable state,
   *   zero out the si_pid field before the call and check for a nonzero value
   *   in this field after the call returns.
   *
   * See comments above wait4()
   */
  while (retval == 0) {
    DMTCP_PLUGIN_DISABLE_CKPT();
    pid_t currPid = VIRTUAL_TO_REAL_PID (id);
    retval = _real_waitid (idtype, currPid, &siginfop, options | WNOHANG);

    if (retval != -1) {
      pid_t virtualPid = REAL_TO_VIRTUAL_PID ( siginfop.si_pid );
      siginfop.si_pid = virtualPid;

      if ( siginfop.si_code == CLD_EXITED || siginfop.si_code == CLD_KILLED )
        dmtcp::VirtualPidTable::instance().erase(virtualPid);
    }
    DMTCP_PLUGIN_ENABLE_CKPT();

    if ((options & WNOHANG) ||
        retval == -1 ||
        siginfop.si_pid != 0) {
      break;
    } else {
      if (sleepTime.tv_sec == 0) {
        sleepTime.tv_nsec *= 2;
        if (sleepTime.tv_nsec >= 1000 * 1000 * 1000) {
          sleepTime.tv_sec++;
          sleepTime.tv_nsec = 0;
        }
      }
      nanosleep(&sleepTime, NULL);
    }
  }

  if (retval == 0 && infop != NULL) {
    *infop = siginfop;
  }

  return retval;
}
extern "C" pid_t getpgid(pid_t pid)
{
  DMTCP_PLUGIN_DISABLE_CKPT();

  pid_t realPid = VIRTUAL_TO_REAL_PID (pid);
  pid_t res = _real_getpgid (realPid);
  pid_t origPgid = REAL_TO_VIRTUAL_PID (res);

  DMTCP_PLUGIN_ENABLE_CKPT();

  return origPgid;
}
Exemplo n.º 6
0
// TODO: Add check for the below two functions in configure
int
sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags)
{
  DMTCP_PLUGIN_DISABLE_CKPT();
  int result = -1;
  pid_t real_pid = 0;
  if (pid != 0) {
    real_pid = VIRTUAL_TO_REAL_PID(pid);
  }
  result = _real_sched_setattr(real_pid, attr, flags);
  DMTCP_PLUGIN_ENABLE_CKPT();
  return result;
}
Exemplo n.º 7
0
int
sched_getparam(pid_t pid, struct sched_param *param)
{
  DMTCP_PLUGIN_DISABLE_CKPT();
  int result = -1;
  pid_t real_pid = 0;
  if (pid != 0) {
    real_pid = VIRTUAL_TO_REAL_PID(pid);
  }
  result = _real_sched_getparam(real_pid, param);
  DMTCP_PLUGIN_ENABLE_CKPT();
  return result;
}
Exemplo n.º 8
0
int
sched_getscheduler(pid_t pid)
{
  DMTCP_PLUGIN_DISABLE_CKPT();
  int result = -1;
  pid_t real_pid = 0;
  if (pid != 0) {
    real_pid = VIRTUAL_TO_REAL_PID(pid);
  }
  result = _real_sched_getscheduler(real_pid);
  DMTCP_PLUGIN_ENABLE_CKPT();
  return result;
}
Exemplo n.º 9
0
int
sched_setscheduler(pid_t pid, int policy, const struct sched_param *param)
{
  DMTCP_PLUGIN_DISABLE_CKPT();
  int result = -1;
  pid_t real_pid = 0;
  if (pid != 0) {
    real_pid = VIRTUAL_TO_REAL_PID(pid);
  }
  result = _real_sched_setscheduler(real_pid, policy, param);
  DMTCP_PLUGIN_ENABLE_CKPT();
  return result;
}
Exemplo n.º 10
0
int
sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask)
{
  DMTCP_PLUGIN_DISABLE_CKPT();
  int result = -1;
  pid_t real_pid = 0;
  if (pid != 0) {
    real_pid = VIRTUAL_TO_REAL_PID(pid);
  }
  result = _real_sched_getaffinity(real_pid, cpusetsize, mask);
  DMTCP_PLUGIN_ENABLE_CKPT();
  return result;
}
extern "C" pid_t tcsetpgrp(int fd, pid_t pgrp)
{
  DMTCP_PLUGIN_DISABLE_CKPT();

  pid_t currPgrp = VIRTUAL_TO_REAL_PID( pgrp );
//  JTRACE( "Inside tcsetpgrp wrapper" ) (fd) (pgrp) (currPgrp);
  pid_t realPid = _real_tcsetpgrp(fd, currPgrp);
  pid_t virtualPid = REAL_TO_VIRTUAL_PID(realPid);

  //JTRACE( "tcsetpgrp return value" ) (fd) (pgrp) (currPgrp) (retval);
  DMTCP_PLUGIN_ENABLE_CKPT();

  return virtualPid;
}
Exemplo n.º 12
0
// FIXME:  This function needs third argument newpathsize, or assume PATH_MAX
static void updateProcPathVirtualToReal(const char *path, char **newpath)
{
  if (dmtcp::Util::strStartsWith(path, PROC_PREFIX)) {
    int index = strlen(PROC_PREFIX);
    char *rest;
    pid_t virtualPid = strtol(&path[index], &rest, 0);
    if (virtualPid > 0 && *rest == '/') {
      pid_t realPid = VIRTUAL_TO_REAL_PID(virtualPid);
      sprintf(*newpath, "/proc/%d%s", realPid, rest);
      return;
    }
  }
  *newpath = (char *)path;
}
extern "C" long ptrace (int request, pid_t pid, void* addr, void* data)
#endif
{
#ifndef ANDROID
  va_list ap;
#endif
  pid_t virtualPid;
  pid_t realPid;
#ifndef ANDROID
  void *addr;
  void *data;

  va_start(ap, request);
  virtualPid = va_arg(ap, pid_t);
  addr = va_arg(ap, void *);
  data = va_arg(ap, void *);
  va_end(ap);
#else
  virtualPid = pid;
#endif

  realPid = VIRTUAL_TO_REAL_PID(virtualPid);
  long ptrace_ret =  _real_ptrace(request, realPid, addr, data);

  /*
   * PTRACE_GETEVENTMSG (since Linux 2.5.46)
   *          Retrieve  a message (as an unsigned long) about the ptrace event
   *          that just happened, placing it in the location data in the
   *          parent.  For PTRACE_EVENT_EXIT this is the child's exit status.
   *          For PTRACE_EVENT_FORK, PTRACE_EVENT_VFORK and PTRACE_EVENT_CLONE
   *          this is the PID  of the new process.  Since Linux 2.6.18, the PID
   *          of the new process is also available for PTRACE_EVENT_VFORK_DONE.
   *          (addr is ignored.)
   */

  if (ptrace_ret == 0 && request == PTRACE_GETEVENTMSG) {
    unsigned long *ldata = (unsigned long*) data;
    pid_t newRealPid =  (pid_t) *ldata;
    *ldata = (unsigned long) REAL_TO_VIRTUAL_PID(newRealPid);
  }

  return ptrace_ret;
}
extern "C" pid_t getsid(pid_t pid)
{
  DMTCP_PLUGIN_DISABLE_CKPT();

  pid_t currPid;

  // If !pid then we ask SID of this process
  if( pid )
    currPid = VIRTUAL_TO_REAL_PID (pid);
  else
    currPid = _real_getpid();

  pid_t res = _real_getsid (currPid);

  pid_t origSid = REAL_TO_VIRTUAL_PID (res);

  DMTCP_PLUGIN_ENABLE_CKPT();

  return origSid;
}
pid_t wait4(pid_t pid, __WAIT_STATUS status, int options, struct rusage *rusage)
{
  int stat;
  int saved_errno = errno;
  pid_t currPid;
  pid_t virtualPid;
  pid_t retval = 0;
  struct timespec sleepTime = {0, 10*000};

  if (status == NULL)
    status = (__WAIT_STATUS) &stat;

  while (retval == 0) {
    DMTCP_PLUGIN_DISABLE_CKPT();
    currPid = VIRTUAL_TO_REAL_PID(pid);
    retval = _real_wait4(currPid, status, options | WNOHANG, rusage);
    saved_errno = errno;
    virtualPid = REAL_TO_VIRTUAL_PID(retval);

    if (retval > 0 &&
        (WIFEXITED(*(int*)status) || WIFSIGNALED(*(int*)status))) {
      dmtcp::VirtualPidTable::instance().erase(virtualPid);
    }
    DMTCP_PLUGIN_ENABLE_CKPT();

    if ((options & WNOHANG) || retval != 0) {
      break;
    } else {
      if (sleepTime.tv_sec == 0) {
        sleepTime.tv_nsec *= 2;
        if (sleepTime.tv_nsec >= 1000 * 1000 * 1000) {
          sleepTime.tv_sec++;
          sleepTime.tv_nsec = 0;
        }
      }
      nanosleep(&sleepTime, NULL);
    }
  }
  errno = saved_errno;
  return virtualPid;
}
// FIXME:  This function needs third argument newpathsize, or assume PATH_MAX
// FIXME:  This does a lot of copying even if "/proc" doesn't appear.
static void updateProcPathVirtualToReal(const char *path, char *newpath)
{
  if (path == NULL || strlen(path) == 0) {
    strcpy(newpath, "");
    return;
  }

  if (dmtcp::Util::strStartsWith(path, "/proc/")) {
    int index = 6;
    char *rest;
    pid_t virtualPid = strtol(&path[index], &rest, 0);
    if (virtualPid > 0 && *rest == '/') {
      pid_t realPid = VIRTUAL_TO_REAL_PID(virtualPid);
      sprintf(newpath, "/proc/%d%s", realPid, rest);
    } else {
      strcpy(newpath, path);
    }
  } else {
    strcpy(newpath, path);
  }
  return;
}
//need to forward user clone
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)
{
  /*
   * struct MtcpRestartThreadArg
   *
   * DMTCP requires the virtualTids of the threads being created during
   *  the RESTARTING phase.  We use an MtcpRestartThreadArg structure to pass
   *  the virtualTid of the thread being created from MTCP to DMTCP.
   *
   * actual clone call: clone (fn, child_stack, flags, void *, ... )
   * new clone call   : clone (fn, child_stack, flags,
   *                           (struct MtcpRestartThreadArg *), ...)
   *
   * DMTCP automatically extracts arg from this structure and passes that
   * to the _real_clone call.
   *
   * IMPORTANT NOTE: While updating, this struct must be kept in sync
   * with the struct of the same name in mtcp.c
   */
  struct MtcpRestartThreadArg {
    void * arg;
    pid_t virtualTid;
  } *mtcpRestartThreadArg;

  pid_t virtualTid = -1;

  if (!dmtcp_is_running_state()) {
    mtcpRestartThreadArg = (struct MtcpRestartThreadArg *) arg;
    arg                  = mtcpRestartThreadArg -> arg;
    virtualTid           = mtcpRestartThreadArg -> virtualTid;
    if (virtualTid != VIRTUAL_TO_REAL_PID(virtualTid)) {
      dmtcp::VirtualPidTable::instance().postRestart();
    }
  } else {
    virtualTid = dmtcp::VirtualPidTable::instance().getNewVirtualTid();
    dmtcp::VirtualPidTable::instance().writeVirtualTidToFileForPtrace(virtualTid);
  }

  // We have to use DMTCP-specific memory allocator because using glibc:malloc
  // can interfere with user threads.
  // We use JALLOC_HELPER_FREE to free this memory in two places:
  //   1.  later in this function in case of failure on call to __clone; and
  //   2.  near the beginnging of clone_start (wrapper for start_routine).
  struct ThreadArg *threadArg =
    (struct ThreadArg *) JALLOC_HELPER_MALLOC(sizeof (struct ThreadArg));
  threadArg->fn = fn;
  threadArg->arg = arg;
  threadArg->virtualTid = virtualTid;

  JTRACE("Calling libc:__clone");
  pid_t tid = _real_clone(clone_start, child_stack, flags, threadArg,
                    parent_tidptr, newtls, child_tidptr);

  if (dmtcp_is_running_state() && dmtcp::Util::isPtraced()) {
    dmtcp::VirtualPidTable::instance().readVirtualTidFromFileForPtrace();
  }

  if (tid > 0) {
    JTRACE("New thread created") (tid);
    dmtcp::VirtualPidTable::instance().updateMapping(virtualTid, tid);
  } else {
    // Free memory previously allocated by calling JALLOC_HELPER_MALLOC
    JALLOC_HELPER_FREE(threadArg);
    virtualTid = tid;
  }
  return virtualTid;
}
extern "C" int   kill(pid_t pid, int sig)
{
  /* FIXME: When bash receives a SIGINT signal, the signal handler is
   * called to process the signal. Once the processing is done, bash
   * performs a longjmp to a much higher call frame. As a result, this
   * call frame never gets a chance to return and hence we fail to
   * perform DMTCP_PLUGIN_ENABLE_CKPT() WHICH RESULTS in the lock
   * being held but never released. Thus later on, when the ckpt-thread
   * tries to acquire this lock, it results in a deadlock.
   *
   *  To avoid the deadlock, FOR NOW, we shouldn't call WRAPPER_...()
   *  calls in this function or any kill() family of wrappers.
   *
   * Potential Solution: If the signal sending process is among the
   * potential signal receivers, it should MASK/BLOCK signal delivery
   * right before sending the signal (before calling _real_kill()). Once
   * the system call returns, it should then call
   * DMTCP_PLUGIN_ENABLE_CKPT() AND THEN RESTore the signal mask to
   * as it was prior to calling this wrapper. So this function will as
   * follows:
   *     DMTCP_PLUGIN_DISABLE_CKPT();
   *     // if this process is a potential receiver of this signal
   *     if (pid == getpid() || pid == 0 || pid == -1 ||
   *         getpgrp() == abs(pid)) {
   *       <SAVE_SIGNAL_MASK>;
   *       <BLOCK SIGNAL 'sig'>;
   *       sigmaskAltered = true;
   *     }
   *     pid_t currPid = VIRTUAL_TO_REAL_PID(pid);
   *     int retVal = _real_kill(currPid, sig);
   *     DMTCP_PLUGIN_ENABLE_CKPT();
   *     if (sigmaskAltered) {
   *       <RESTORE_SIGNAL_MASK>
   *     }
   *     return retVal;
   *
   *
   * This longjmp trouble can happen with any wrapper, whose execution my
   * end up in a call to user-code i.e. if the call frame looks sth like:
   *        ...
   *        user_func1(...)
   *        ...
   *        DMTCP_WRAPPER(...)
   *        ...
   *        user_func2(...)
   *        ...
   *
   * Another potential way would be to put a wrapper around longjmp() in
   * which the calling thread should release all the DMTCP-locks being
   * held at the moment. This would require us to keep a count of lock()
   * calls without a corresponding unlock() call. After the longjmp()
   * call, one need to make sure that an unlock() call is requested only
   * if there is a corresponding lock, because it might happen that
   * longjmp() was harmless in the sense that, it didn't cause a
   * callframe like the one mentioned above.
   *
   */
//  DMTCP_PLUGIN_DISABLE_CKPT();

  pid_t currPid = VIRTUAL_TO_REAL_PID (pid);

  int retVal = _real_kill (currPid, sig);

//  DMTCP_PLUGIN_ENABLE_CKPT();

  return retVal;
}