extern "C" pid_t gettid()
{
  /* mtcpinterface.cpp:thread_start calls gettid() before calling
   * DmtcpWorker::decrementUninitializedThreadCount() and so the value is
   * cached before it is accessed by some other DMTCP code.
   */
  if (_dmtcp_thread_tid == -1) {
    _dmtcp_thread_tid = getpid();
    // Make sure this is the motherofall thread.
    JASSERT(_real_gettid() == _real_getpid()) (_real_gettid()) (_real_getpid());
  }
  return _dmtcp_thread_tid;
}
static void *my_malloc_hook (size_t size, const void *caller)
{
  _real_pthread_mutex_lock(&hook_lock);
  void *result;
  /* Restore all old hooks */
  __malloc_hook = old_malloc_hook;
  __realloc_hook = old_realloc_hook;
  __memalign_hook = old_memalign_hook;
  __free_hook = old_free_hook;
  result = _real_malloc (size);
  /* Save underlying hooks */
  old_malloc_hook = __malloc_hook;
  old_free_hook = __free_hook;
  if (log_all_allocs && strcmp(progname, "gdb") != 0) {
    static int tyler_pid = _real_getpid();
    printf ("<%d> malloc (%u) returns %p\n", tyler_pid, (unsigned int) size, result);
  }
  /*static int tyler_pid = _real_getpid();
  void *buffer[10];
  int nptrs;
  // NB: In order to use backtrace, you must disable log_all_allocs.
  // AND remove the locks around !log_all_allocs real_malloc in malloc wrapper
  nptrs = backtrace (buffer, 10);
  backtrace_symbols_fd ( buffer, nptrs, 1);
  printf ("<%d> malloc (%u) returns %p\n", tyler_pid, (unsigned int) size, result);*/
  /* Restore our own hooks */
  __malloc_hook = my_malloc_hook;
  __realloc_hook = my_realloc_hook;
  __memalign_hook = my_memalign_hook;
  __free_hook = my_free_hook;
  _real_pthread_mutex_unlock(&hook_lock);
  return result;
}
static void *my_memalign_hook (size_t boundary, size_t size, const void *caller)
{
  _real_pthread_mutex_lock(&hook_lock);
  void *result;
  /* Restore all old hooks */
  __malloc_hook = old_malloc_hook;
  __realloc_hook = old_realloc_hook;
  __memalign_hook = old_memalign_hook;
  __free_hook = old_free_hook;
  result = _real_libc_memalign (boundary, size);
  /* Save underlying hooks */
  old_malloc_hook = __malloc_hook;
  old_free_hook = __free_hook;
  if (log_all_allocs && strcmp(progname, "gdb") != 0) {
    static int tyler_pid = _real_getpid();
    printf ("<%d> memalign (%u,%u) returns %p\n", tyler_pid,
        (unsigned int)boundary, (unsigned int) size, result);
  }
  __malloc_hook = my_malloc_hook;
  __realloc_hook = my_realloc_hook;
  __memalign_hook = my_memalign_hook;
  __free_hook = my_free_hook;
  _real_pthread_mutex_unlock(&hook_lock);
  return result;

}
extern "C" LIB_PRIVATE
void dmtcpResetPidPpid()
{
  const char *pidstr = getenv(ENV_VAR_VIRTUAL_PID);
  char *ppidstr;
  if (pidstr == NULL) {
    fprintf(stderr, "ERROR at %s:%d: env var DMTCP_VIRTUAL_PID not set\n\n",
            __FILE__, __LINE__);
    sleep(5);
    _exit(0);
  }
  _dmtcp_pid = strtol(pidstr, &ppidstr, 10);
  dmtcp::VirtualPidTable::instance().updateMapping(_dmtcp_pid,
                                                   _real_getpid());

  if (ppidstr[0] != ':' && !isdigit(ppidstr[1])) {
    fprintf(stderr, "ERROR at %s:%d: env var DMTCP_VIRTUAL_PID invalid\n\n",
            __FILE__, __LINE__);
    sleep(5);
    _exit(0);
  }
  _dmtcp_ppid = strtol(ppidstr + 1, NULL, 10);

  dmtcp::VirtualPidTable::instance().updateMapping(_dmtcp_ppid,
                                                   _real_getppid());
}
void dmtcp::VirtualPidTable::resetOnFork()
{
  pthread_mutex_t newlock = PTHREAD_MUTEX_INITIALIZER;
  tblLock = newlock;
  _nextVirtualTid = INITIAL_VIRTUAL_TID;
  _numTids = 1;
  _pidMapTable[getpid()] = _real_getpid();
  refresh();
  printPidMaps();
}
void dmtcp::VirtualPidTable::postRestart()
{
  /*
   * PROTECTED_PIDMAP_FD corresponds to the file containg computation wide
   *  virtualPid -> realPid map to avoid pid/tid collisions.
   */
  _do_lock_tbl();
  _pidMapTable.clear();
  _pidMapTable[getpid()] = _real_getpid();
  _do_unlock_tbl();
}
void dmtcp::VirtualPidTable::refresh()
{
  pid_t pid = getpid();
  pid_iterator i;
  pid_iterator next;
  pid_t _real_pid = _real_getpid();

  _do_lock_tbl();
  for (i = _pidMapTable.begin(), next = i; i != _pidMapTable.end(); i = next) {
    next++;
    if (i->second > pid && i->second <= pid + MAX_VIRTUAL_TID
        && _real_tgkill(_real_pid, i->second, 0) == -1) {
      _pidMapTable.erase(i);
    }
  }
  _do_unlock_tbl();
  printPidMaps();
}
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;
}
static void my_free_hook (void *ptr, const void *caller)
{
  _real_pthread_mutex_lock(&hook_lock);
  /* Restore all old hooks */
  __malloc_hook = old_malloc_hook;
  __realloc_hook = old_realloc_hook;
  __memalign_hook = old_memalign_hook;
  __free_hook = old_free_hook;
  _real_free (ptr);
  /* Save underlying hooks */
  old_malloc_hook = __malloc_hook;
  old_free_hook = __free_hook;
  /* printf might call free, so protect it too. */
  if (log_all_allocs) {
    static int tyler_pid = _real_getpid();
    printf ("<%d> freed pointer %p\n", tyler_pid, ptr);
  }
  /* Restore our own hooks */
  __malloc_hook = my_malloc_hook;
  __realloc_hook = my_realloc_hook;
  __memalign_hook = my_memalign_hook;
  __free_hook = my_free_hook;
  _real_pthread_mutex_unlock(&hook_lock);
}