root/mtcpinterface.cpp
/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- initializeMtcpEngine
- callbackSleepBetweenCheckpoint
- callbackPreCheckpoint
- callbackPostCheckpoint
- callbackHoldsAnyLocks
- callbackPreSuspendUserThread
- callbackPreResumeUserThread
- restoreArgvAfterRestart
- unmapRestoreArgv
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 #include "constants.h"
22 #include "mtcpinterface.h"
23 #include "syscallwrappers.h"
24 #include "dmtcpworker.h"
25 #include "processinfo.h"
26 #include "dmtcpmessagetypes.h"
27 #include "util.h"
28 #include "threadsync.h"
29 #include "ckptserializer.h"
30 #include "protectedfds.h"
31 #include "shareddata.h"
32 #include "threadlist.h"
33
34 #include "../jalib/jfilesystem.h"
35 #include "../jalib/jconvert.h"
36 #include "../jalib/jassert.h"
37 #include "../jalib/jalloc.h"
38
39 using namespace dmtcp;
40
41 int rounding_mode = 1;
42
43 static char *_mtcpRestoreArgvStartAddr = NULL;
44 #ifdef RESTORE_ARGV_AFTER_RESTART
45 static void restoreArgvAfterRestart(char* mtcpRestoreArgvStartAddr);
46 #endif
47 static void unmapRestoreArgv();
48
49
50 extern "C" int dmtcp_is_ptracing() __attribute__ ((weak));
51 extern "C" int dmtcp_update_ppid() __attribute__ ((weak));
52
53 void dmtcp::initializeMtcpEngine()
54 {
55 ThreadSync::initMotherOfAll();
56 ThreadList::init();
57 }
58
59 void dmtcp::callbackSleepBetweenCheckpoint ( int sec )
60 {
61 ThreadSync::waitForUserThreadsToFinishPreResumeCB();
62 DmtcpWorker::eventHook(DMTCP_EVENT_WAIT_FOR_SUSPEND_MSG, NULL);
63 if (dmtcp_is_ptracing && dmtcp_is_ptracing()) {
64 // FIXME: Add a test to make check that can insert a delay of a couple of
65 // seconds in here. This helps testing the initialization routines
66 // of various plugins.
67 // Inform coordinator of our RUNNING state;
68 DmtcpWorker::informCoordinatorOfRUNNINGState();
69 }
70 DmtcpWorker::waitForStage1Suspend();
71
72 unmapRestoreArgv();
73 }
74
75 void dmtcp::callbackPreCheckpoint()
76 {
77 //now user threads are stopped
78 DmtcpWorker::waitForStage2Checkpoint();
79 }
80
81 void dmtcp::callbackPostCheckpoint(int isRestart,
82 char* mtcpRestoreArgvStartAddr)
83 {
84 if (isRestart) {
85 //restoreArgvAfterRestart(mtcpRestoreArgvStartAddr);
86
87 JTRACE("begin postRestart()");
88 WorkerState::setCurrentState(WorkerState::RESTARTING);
89 if (dmtcp_update_ppid) {
90 dmtcp_update_ppid();
91 }
92 DmtcpWorker::eventHook(DMTCP_EVENT_RESTART, NULL);
93 } else {
94 DmtcpWorker::eventHook(DMTCP_EVENT_RESUME, NULL);
95 }
96
97 DmtcpWorker::waitForStage3Refill(isRestart);
98
99 DmtcpWorker::waitForStage4Resume(isRestart);
100
101 WorkerState::setCurrentState( WorkerState::RUNNING );
102
103 if (dmtcp_is_ptracing == NULL || !dmtcp_is_ptracing()) {
104 // Inform coordinator of our RUNNING state;
105 // If running under ptrace, let's do this in sleep-between-ckpt callback.
106 DmtcpWorker::informCoordinatorOfRUNNINGState();
107 }
108 // After this, the user threads will be unlocked in mtcp.c and will resume.
109 }
110
111 void dmtcp::callbackHoldsAnyLocks(int *retval)
112 {
113 /* This callback is useful only for the ptrace plugin currently, but may be
114 * used for other stuff as well.
115 *
116 * This is invoked as the first thing in stopthisthread() routine, which is
117 * the signal handler for CKPT signal, to check if the current thread is
118 * holding any of the wrapperExecLock or threadCreationLock. If the thread is
119 * holding any of these locks, we return from the signal handler and wait for
120 * the thread to release the lock. Once the thread has release the last lock,
121 * it will send itself the CKPT signal and will return to the signal handler
122 * and will proceed normally.
123 */
124
125 ThreadSync::unsetOkToGrabLock();
126 *retval = ThreadSync::isThisThreadHoldingAnyLocks();
127 if (*retval) {
128 JASSERT(dmtcp_is_ptracing && dmtcp_is_ptracing());
129 ThreadSync::setSendCkptSignalOnFinalUnlock();
130 }
131 }
132
133 void dmtcp::callbackPreSuspendUserThread()
134 {
135 ThreadSync::incrNumUserThreads();
136 DmtcpWorker::eventHook(DMTCP_EVENT_PRE_SUSPEND_USER_THREAD, NULL);
137 }
138
139 void dmtcp::callbackPreResumeUserThread(int isRestart)
140 {
141 DmtcpEventData_t edata;
142 edata.resumeUserThreadInfo.isRestart = isRestart;
143 DmtcpWorker::eventHook(DMTCP_EVENT_RESUME_USER_THREAD, &edata);
144 ThreadSync::setOkToGrabLock();
145 // This should be the last significant work before returning from this
146 // function.
147 ThreadSync::processPreResumeCB();
148 // Make a dummy syscall to inform superior of our status before we resume. If
149 // ptrace is disabled, this call has no significant effect.
150 syscall(DMTCP_FAKE_SYSCALL);
151 }
152
153 #ifdef RESTORE_ARGV_AFTER_RESTART
154 static void restoreArgvAfterRestart(char* mtcpRestoreArgvStartAddr)
155 {
156 /*
157 * The addresses where argv of mtcp_restart process starts. /proc/PID/cmdline
158 * information is looked up from these addresses. We observed that the
159 * stack-base for mtcp_restart is always 0x7ffffffff000 in 64-bit system and
160 * 0xc0000000 in case of 32-bit system. Once we restore the checkpointed
161 * process's memory, we will map the pages ending in these address into the
162 * process's memory if they are unused i.e. not mapped by the process (which
163 * is true for most processes running with ASLR). Once we map them, we can
164 * put the argv of the checkpointed process in there so that
165 * /proc/self/cmdline shows the correct values.
166 * Note that if compiled in 32-bit mode '-m32', the stack base address
167 * is in still a different location, and so this logic is not valid.
168 */
169 JASSERT(mtcpRestoreArgvStartAddr != NULL);
170
171 long page_size = sysconf(_SC_PAGESIZE);
172 long page_mask = ~(page_size - 1);
173 char *startAddr = (char*) ((unsigned long) mtcpRestoreArgvStartAddr & page_mask);
174
175 size_t len;
176 len = (ProcessInfo::instance().argvSize() + page_size) & page_mask;
177
178 // Check to verify if any page in the given range is already mmap()'d.
179 // It assumes that the given addresses may belong to stack only, and if
180 // mapped, will have read+write permissions.
181 for (size_t i = 0; i < len; i += page_size) {
182 int ret = mprotect ((char*) startAddr + i, page_size,
183 PROT_READ | PROT_WRITE);
184 if (ret != -1 || errno != ENOMEM) {
185 _mtcpRestoreArgvStartAddr = NULL;
186 return;
187 }
188 }
189
190 //None of the pages are mapped -- it is safe to mmap() them
191 void *retAddr = mmap((void*) startAddr, len, PROT_READ | PROT_WRITE,
192 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
193 if (retAddr != MAP_FAILED) {
194 JTRACE("Restoring /proc/self/cmdline")
195 (mtcpRestoreArgvStartAddr) (startAddr) (len) (JASSERT_ERRNO) ;
196 vector<string> args = jalib::Filesystem::GetProgramArgs();
197 char *addr = mtcpRestoreArgvStartAddr;
198 // Do NOT change restarted process's /proc/self/cmdline.
199 //args[0] = DMTCP_PRGNAME_PREFIX + args[0];
200 for ( size_t i=0; i< args.size(); ++i ) {
201 if (addr + args[i].length() >= startAddr + len)
202 break;
203 strcpy(addr, args[i].c_str());
204 addr += args[i].length() + 1;
205 }
206 _mtcpRestoreArgvStartAddr = startAddr;
207 } else {
208 JTRACE("Unable to restore /proc/self/cmdline") (startAddr) (len) (JASSERT_ERRNO) ;
209 _mtcpRestoreArgvStartAddr = NULL;
210 }
211 return;
212 }
213 #endif
214
215 static void unmapRestoreArgv()
216 {
217 long page_size = sysconf(_SC_PAGESIZE);
218 long page_mask = ~(page_size - 1);
219 if (_mtcpRestoreArgvStartAddr != NULL) {
220 JTRACE("Unmapping previously mmap()'d pages (that were mmap()'d for restoring argv");
221 size_t len;
222 len = (ProcessInfo::instance().argvSize() + page_size) & page_mask;
223 JASSERT(_real_munmap(_mtcpRestoreArgvStartAddr, len) == 0)
224 (_mtcpRestoreArgvStartAddr) (len)
225 .Text ("Failed to munmap extra pages that were mapped during restart");
226 }
227 }