File: mtcpinterface.cpp

package info (click to toggle)
dmtcp 2.6.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 6,496 kB
  • sloc: cpp: 33,592; ansic: 28,099; sh: 6,735; makefile: 1,950; perl: 1,690; python: 1,241; asm: 138; java: 13
file content (216 lines) | stat: -rw-r--r-- 8,221 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/****************************************************************************
 *   Copyright (C) 2006-2013 by Jason Ansel, Kapil Arya, and Gene Cooperman *
 *   jansel@csail.mit.edu, kapil@ccs.neu.edu, gene@ccs.neu.edu              *
 *                                                                          *
 *  This file is part of DMTCP.                                             *
 *                                                                          *
 *  DMTCP is free software: you can redistribute it and/or                  *
 *  modify it under the terms of the GNU Lesser General Public License as   *
 *  published by the Free Software Foundation, either version 3 of the      *
 *  License, or (at your option) any later version.                         *
 *                                                                          *
 *  DMTCP is distributed in the hope that it will be useful,                *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
 *  GNU Lesser General Public License for more details.                     *
 *                                                                          *
 *  You should have received a copy of the GNU Lesser General Public        *
 *  License along with DMTCP:dmtcp/src.  If not, see                        *
 *  <http://www.gnu.org/licenses/>.                                         *
 ****************************************************************************/
#include "constants.h"
#include "mtcpinterface.h"
#include "syscallwrappers.h"
#include "dmtcpworker.h"
#include "processinfo.h"
#include "dmtcpmessagetypes.h"
#include "util.h"
#include "threadsync.h"
#include "ckptserializer.h"
#include "protectedfds.h"
#include "shareddata.h"
#include "threadlist.h"

#include "../jalib/jfilesystem.h"
#include "../jalib/jconvert.h"
#include "../jalib/jassert.h"
#include "../jalib/jalloc.h"

using namespace dmtcp;

int rounding_mode = 1;

extern void pathvirtInitialize() __attribute ((weak));

static char *_mtcpRestoreArgvStartAddr = NULL;
#ifdef RESTORE_ARGV_AFTER_RESTART
static void restoreArgvAfterRestart(char* mtcpRestoreArgvStartAddr);
#endif
static void unmapRestoreArgv();

extern "C" int dmtcp_update_ppid() __attribute__ ((weak));

void dmtcp::initializeMtcpEngine()
{
  ThreadSync::initMotherOfAll();
  ThreadList::init();
}

void dmtcp::callbackSleepBetweenCheckpoint ( int sec )
{
  ThreadSync::waitForUserThreadsToFinishPreResumeCB();
  DmtcpWorker::eventHook(DMTCP_EVENT_WAIT_FOR_SUSPEND_MSG, NULL);
  DmtcpWorker::waitForStage1Suspend();

  unmapRestoreArgv();
}

void dmtcp::callbackPreCheckpoint()
{
  //now user threads are stopped
  DmtcpWorker::waitForStage2Checkpoint();
}

void dmtcp::callbackPostCheckpoint(bool isRestart,
                                   char* mtcpRestoreArgvStartAddr)
{
  if (isRestart) {
    //restoreArgvAfterRestart(mtcpRestoreArgvStartAddr);

    JLOG(DMTCP)("begin postRestart()");
    WorkerState::setCurrentState(WorkerState::RESTARTING);
    if (dmtcp_update_ppid) {
      dmtcp_update_ppid();
    }
    if (pathvirtInitialize) {
      pathvirtInitialize();
    }
    DmtcpWorker::eventHook(DMTCP_EVENT_RESTART, NULL);
  } else {
    DmtcpWorker::eventHook(DMTCP_EVENT_RESUME, NULL);
  }

  DmtcpWorker::waitForStage3Refill(isRestart);

  DmtcpWorker::waitForStage4Resume(isRestart);

  increment_counters(isRestart);

  WorkerState::setCurrentState( WorkerState::RUNNING );

  DmtcpWorker::informCoordinatorOfRUNNINGState();
  // After this, the user threads will be unlocked in mtcp.c and will resume.
}

void dmtcp::callbackHoldsAnyLocks(int *retval)
{
  /* This callback is useful only for the ptrace plugin currently, but may be
   * used for other stuff as well.
   *
   * This is invoked as the first thing in stopthisthread() routine, which is
   * the signal handler for CKPT signal, to check if the current thread is
   * holding any of the wrapperExecLock or threadCreationLock. If the thread is
   * holding any of these locks, we return from the signal handler and wait for
   * the thread to release the lock. Once the thread has release the last lock,
   * it will send itself the CKPT signal and will return to the signal handler
   * and will proceed normally.
   */

  ThreadSync::unsetOkToGrabLock();
  *retval = ThreadSync::isThisThreadHoldingAnyLocks();
  // *retval should be true only if we are using the ptrace plugin.
  JASSERT(!*retval) .Text("Not implemented");
}

void dmtcp::callbackPreSuspendUserThread()
{
  ThreadSync::incrNumUserThreads();
  DmtcpWorker::eventHook(DMTCP_EVENT_PRE_SUSPEND_USER_THREAD, NULL);
}

void dmtcp::callbackPreResumeUserThread(bool isRestart)
{
  DmtcpEventData_t edata;
  edata.resumeUserThreadInfo.isRestart = isRestart;
  DmtcpWorker::eventHook(DMTCP_EVENT_RESUME_USER_THREAD, &edata);
  ThreadSync::setOkToGrabLock();
  // This should be the last significant work before returning from this
  // function.
  ThreadSync::processPreResumeCB();
}

#ifdef RESTORE_ARGV_AFTER_RESTART
static void restoreArgvAfterRestart(char* mtcpRestoreArgvStartAddr)
{
  /*
   * The addresses where argv of mtcp_restart process starts. /proc/PID/cmdline
   * information is looked up from these addresses.  We observed that the
   * stack-base for mtcp_restart is always 0x7ffffffff000 in 64-bit system and
   * 0xc0000000 in case of 32-bit system.  Once we restore the checkpointed
   * process's memory, we will map the pages ending in these address into the
   * process's memory if they are unused i.e. not mapped by the process (which
   * is true for most processes running with ASLR).  Once we map them, we can
   * put the argv of the checkpointed process in there so that
   * /proc/self/cmdline shows the correct values.
   * Note that if compiled in 32-bit mode '-m32', the stack base address
   * is in still a different location, and so this logic is not valid.
   */
  JASSERT(mtcpRestoreArgvStartAddr != NULL);

  long page_size = sysconf(_SC_PAGESIZE);
  long page_mask = ~(page_size - 1);
  char *startAddr = (char*) ((unsigned long) mtcpRestoreArgvStartAddr & page_mask);

  size_t len;
  len = (ProcessInfo::instance().argvSize() + page_size) & page_mask;

  // Check to verify if any page in the given range is already mmap()'d.
  // It assumes that the given addresses may belong to stack only, and if
  // mapped, will have read+write permissions.
  for (size_t i = 0; i < len; i += page_size) {
    int ret = mprotect ((char*) startAddr + i, page_size,
                        PROT_READ | PROT_WRITE);
    if (ret != -1 || errno != ENOMEM) {
      _mtcpRestoreArgvStartAddr = NULL;
      return;
    }
  }

  //None of the pages are mapped -- it is safe to mmap() them
  void *retAddr = mmap((void*) startAddr, len, PROT_READ | PROT_WRITE,
                    MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
  if (retAddr != MAP_FAILED) {
    JLOG(DMTCP)("Restoring /proc/self/cmdline")
      (mtcpRestoreArgvStartAddr) (startAddr) (len) (JASSERT_ERRNO) ;
    vector<string> args = jalib::Filesystem::GetProgramArgs();
    char *addr = mtcpRestoreArgvStartAddr;
    // Do NOT change restarted process's /proc/self/cmdline.
    //args[0] = DMTCP_PRGNAME_PREFIX + args[0];
    for ( size_t i=0; i< args.size(); ++i ) {
      if (addr + args[i].length() >= startAddr + len)
        break;
      strcpy(addr, args[i].c_str());
      addr += args[i].length() + 1;
    }
    _mtcpRestoreArgvStartAddr = startAddr;
  } else {
    JLOG(DMTCP)("Unable to restore /proc/self/cmdline") (startAddr) (len) (JASSERT_ERRNO) ;
    _mtcpRestoreArgvStartAddr = NULL;
  }
  return;
}
#endif

static void unmapRestoreArgv()
{
  long page_size = sysconf(_SC_PAGESIZE);
  long page_mask = ~(page_size - 1);
  if (_mtcpRestoreArgvStartAddr != NULL) {
    JLOG(DMTCP)("Unmapping previously mmap()'d pages (that were mmap()'d for restoring argv");
    size_t len;
    len = (ProcessInfo::instance().argvSize() + page_size) & page_mask;
    JASSERT(_real_munmap(_mtcpRestoreArgvStartAddr, len) == 0)
      (_mtcpRestoreArgvStartAddr) (len)
      .Text ("Failed to munmap extra pages that were mapped during restart");
  }
}