root/dmtcpplugin.cpp
/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- memfence
- memfence
- memfence
- dmtcp_is_enabled
- runCoordinatorCmd
- dmtcpRunCommand
- dmtcp_checkpoint
- dmtcp_get_coordinator_status
- dmtcp_get_local_status
- dmtcp_disable_ckpt
- dmtcp_enable_ckpt
- dmtcp_get_ckpt_signal
- dmtcp_get_tmpdir
- dmtcp_get_ckpt_dir
- dmtcp_set_ckpt_dir
- dmtcp_get_coord_ckpt_dir
- dmtcp_set_coord_ckpt_dir
- dmtcp_set_ckpt_file
- dmtcp_get_ckpt_filename
- dmtcp_get_ckpt_files_subdir
- dmtcp_should_ckpt_open_files
- dmtcp_get_executable_path
- dmtcp_get_uniquepid_str
- dmtcp_get_uniquepid
- dmtcp_get_computation_id
- dmtcp_get_computation_id_str
- dmtcp_get_coord_id
- dmtcp_unique_pids_equal
- dmtcp_get_coordinator_timestamp
- dmtcp_get_generation
- checkpoint_is_pending
- dmtcp_is_running_state
- dmtcp_is_initializing_wrappers
- dmtcp_is_protected_fd
- dmtcp_protected_environ_fd
- dmtcp_close_protected_fd
- dmtcp_get_restart_env
- dmtcp_get_readlog_fd
- dmtcp_get_ptrace_fd
- dmtcp_get_libc_dlsym_addr
- dmtcp_block_ckpt_signal
- dmtcp_unblock_ckpt_signal
- dmtcp_send_key_val_pair_to_coordinator
- dmtcp_send_key_val_pair_to_coordinator_sync
- dmtcp_send_query_to_coordinator
- dmtcp_get_local_ip_addr
- dmtcp_no_coordinator
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
22 #include <stdlib.h>
23 #include "dmtcp.h"
24 #include "dmtcpworker.h"
25 #include "coordinatorapi.h"
26 #include "syscallwrappers.h"
27 #include "processinfo.h"
28 #include "shareddata.h"
29 #include "threadsync.h"
30 #include "mtcpinterface.h"
31 #include "util.h"
32
33 #undef dmtcp_is_enabled
34 #undef dmtcp_checkpoint
35 #undef dmtcp_disable_ckpt
36 #undef dmtcp_enable_ckpt
37 #undef dmtcp_get_coordinator_status
38 #undef dmtcp_get_local_status
39 #undef dmtcp_get_uniquepid_str
40 #undef dmtcp_get_ckpt_filename
41
42 using namespace dmtcp;
43
44 //global counters
45 static int numCheckpoints = 0;
46 static int numRestarts = 0;
47
48 //I wish we could use pthreads for the trickery in this file, but much of our
49 //code is executed before the thread we want to wake is restored. Thus we do
50 //it the bad way.
51 #if defined(__i386__) || defined(__x86_64__)
52 static inline void memfence(){ asm volatile ("mfence" ::: "memory"); }
53 #elif defined(__arm__)
54 static inline void memfence(){ asm volatile ("dmb" ::: "memory"); }
55 #elif defined(__aarch64__)
56 # include "membarrier.h"
57 static inline void memfence(){ RMB; WMB; }
58 #else
59 # define memfence() __sync_synchronize()
60 #endif
61
62 EXTERNC int dmtcp_is_enabled() { return 1; }
63
64 static void runCoordinatorCmd(char c,
65 int *coordCmdStatus = NULL,
66 int *numPeers = NULL,
67 int *isRunning = NULL)
68 {
69 _dmtcp_lock();
70 {
71 CoordinatorAPI coordinatorAPI;
72
73 dmtcp_disable_ckpt();
74 coordinatorAPI.connectAndSendUserCommand(c, coordCmdStatus, numPeers,
75 isRunning);
76 dmtcp_enable_ckpt();
77 }
78 _dmtcp_unlock();
79 }
80
81 static int dmtcpRunCommand(char command)
82 {
83 int coordCmdStatus;
84 int i = 0;
85 while (i < 100) {
86 runCoordinatorCmd(command, &coordCmdStatus);
87 // if we got error result - check it
88 // There is possibility that checkpoint thread
89 // did not send state=RUNNING yet or Coordinator did not receive it
90 // -- Artem
91 if (coordCmdStatus == CoordCmdStatus::ERROR_NOT_RUNNING_STATE) {
92 struct timespec t;
93 t.tv_sec = 0;
94 t.tv_nsec = 1000000;
95 nanosleep(&t, NULL);
96 //printf("\nWAIT FOR CHECKPOINT ABLE\n\n");
97 } else {
98 // printf("\nEverything is OK - return\n");
99 break;
100 }
101 i++;
102 }
103 return coordCmdStatus == CoordCmdStatus::NOERROR;
104 }
105
106 EXTERNC int dmtcp_checkpoint()
107 {
108 int rv = 0;
109 int oldNumRestarts = numRestarts;
110 int oldNumCheckpoints = numCheckpoints;
111 memfence(); //make sure the reads above don't get reordered
112
113 if(dmtcpRunCommand('c')){ //request checkpoint
114 //and wait for the checkpoint
115 while(oldNumRestarts==numRestarts && oldNumCheckpoints==numCheckpoints){
116 //nanosleep should get interrupted by checkpointing with an EINTR error
117 //though there is a race to get to nanosleep() before the checkpoint
118 struct timespec t = {1,0};
119 nanosleep(&t, NULL);
120 memfence(); //make sure the loop condition doesn't get optimized
121 }
122 rv = (oldNumRestarts==numRestarts ? DMTCP_AFTER_CHECKPOINT : DMTCP_AFTER_RESTART);
123 }else{
124 /// TODO: Maybe we need to process it in some way????
125 /// EXIT????
126 /// -- Artem
127 // printf("\n\n\nError requesting checkpoint\n\n\n");
128 }
129
130 return rv;
131 }
132
133 EXTERNC int dmtcp_get_coordinator_status(int *numPeers, int *isRunning)
134 {
135 int coordCmdStatus;
136 runCoordinatorCmd('s', &coordCmdStatus, numPeers, isRunning);
137 return 1;
138 }
139
140 EXTERNC int dmtcp_get_local_status(int *nCheckpoints, int *nRestarts)
141 {
142 *nCheckpoints = numCheckpoints;
143 *nRestarts = numRestarts;
144 return 1;
145 }
146
147 EXTERNC int dmtcp_disable_ckpt()
148 {
149 ThreadSync::delayCheckpointsLock();
150 return 1;
151 }
152
153 EXTERNC int dmtcp_enable_ckpt()
154 {
155 ThreadSync::delayCheckpointsUnlock();
156 return 1;
157 }
158
159 EXTERNC int dmtcp_get_ckpt_signal(void)
160 {
161 const int ckpt_signal = DmtcpWorker::determineCkptSignal();
162 return ckpt_signal;
163 }
164
165 EXTERNC const char* dmtcp_get_tmpdir(void)
166 {
167 static char tmpdir[PATH_MAX];
168 JASSERT(SharedData::getTmpDir(tmpdir, sizeof(tmpdir)) != NULL);
169 return tmpdir;
170 }
171
172 //EXTERNC void dmtcp_set_tmpdir(const char* dir)
173 //{
174 // if (dir != NULL) {
175 // UniquePid::setTmpDir(dir);
176 // }
177 //}
178
179 EXTERNC const char* dmtcp_get_ckpt_dir()
180 {
181 static string tmpdir;
182 tmpdir = ProcessInfo::instance().getCkptDir();
183 return tmpdir.c_str();
184 }
185
186 EXTERNC void dmtcp_set_ckpt_dir(const char* dir)
187 {
188 if (dir != NULL) {
189 ProcessInfo::instance().setCkptDir(dir);
190 }
191 }
192
193 EXTERNC const char* dmtcp_get_coord_ckpt_dir(void)
194 {
195 static string dir;
196 dir = CoordinatorAPI::instance().getCoordCkptDir();
197 return dir.c_str();
198 }
199
200 EXTERNC void dmtcp_set_coord_ckpt_dir(const char* dir)
201 {
202 if (dir != NULL) {
203 CoordinatorAPI::instance().updateCoordCkptDir(dir);
204 }
205 }
206
207 EXTERNC void dmtcp_set_ckpt_file(const char *filename)
208 {
209 ProcessInfo::instance().setCkptFilename(filename);
210 }
211
212 EXTERNC const char* dmtcp_get_ckpt_filename(void)
213 {
214 static string filename;
215 filename = ProcessInfo::instance().getCkptFilename();
216 return filename.c_str();
217 }
218
219 EXTERNC const char* dmtcp_get_ckpt_files_subdir(void)
220 {
221 static string tmpdir;
222 tmpdir = ProcessInfo::instance().getCkptFilesSubDir();
223 return tmpdir.c_str();
224 }
225
226 EXTERNC int dmtcp_should_ckpt_open_files(void)
227 {
228 return getenv(ENV_VAR_CKPT_OPEN_FILES) != NULL;
229 }
230
231 EXTERNC const char* dmtcp_get_executable_path(void)
232 {
233 return ProcessInfo::instance().procSelfExe().c_str();
234 }
235
236 EXTERNC const char* dmtcp_get_uniquepid_str(void)
237 {
238 static string *uniquepid_str = NULL;
239 uniquepid_str =
240 new string(UniquePid::ThisProcess(true).toString());
241 return uniquepid_str->c_str();
242 }
243
244 EXTERNC DmtcpUniqueProcessId dmtcp_get_uniquepid(void)
245 {
246 return UniquePid::ThisProcess().upid();
247 }
248
249 EXTERNC DmtcpUniqueProcessId dmtcp_get_computation_id(void)
250 {
251 return SharedData::getCompId();
252 }
253
254 EXTERNC const char* dmtcp_get_computation_id_str(void)
255 {
256 static string *compid_str = NULL;
257 if (compid_str == NULL) {
258 UniquePid compId = SharedData::getCompId();
259 compid_str = new string(compId.toString());
260 }
261 return compid_str->c_str();
262 }
263
264 EXTERNC DmtcpUniqueProcessId dmtcp_get_coord_id(void)
265 {
266 return SharedData::getCoordId();
267 }
268
269 EXTERNC int dmtcp_unique_pids_equal(DmtcpUniqueProcessId a,
270 DmtcpUniqueProcessId b)
271 {
272 return a._hostid == b._hostid &&
273 a._pid == b._pid &&
274 a._time == b._time &&
275 a._computation_generation == b._computation_generation;
276 }
277
278 EXTERNC uint64_t dmtcp_get_coordinator_timestamp(void)
279 {
280 return SharedData::getCoordTimeStamp();
281 }
282
283 EXTERNC uint32_t dmtcp_get_generation(void)
284 {
285 return ProcessInfo::instance().get_generation();
286 }
287
288 EXTERNC int checkpoint_is_pending(void)
289 {
290 return SharedData::getCompId()._computation_generation >
291 ProcessInfo::instance().get_generation();
292 }
293
294 EXTERNC int dmtcp_is_running_state(void)
295 {
296 return WorkerState::currentState() == WorkerState::RUNNING;
297 }
298
299 EXTERNC int dmtcp_is_initializing_wrappers(void)
300 {
301 return dmtcp_wrappers_initializing;
302 }
303
304 EXTERNC int dmtcp_is_protected_fd(int fd)
305 {
306 return DMTCP_IS_PROTECTED_FD(fd);
307 }
308
309 EXTERNC int dmtcp_protected_environ_fd(void)
310 {
311 return PROTECTED_ENVIRON_FD;
312 }
313
314 EXTERNC void dmtcp_close_protected_fd(int fd)
315 {
316 JASSERT(DMTCP_IS_PROTECTED_FD(fd));
317 _real_close(fd);
318 }
319
320 // EXTERNC int dmtcp_get_restart_env(char *name, char *value, int maxvaluelen);
321 // USAGE:
322 // char value[MAXSIZE];
323 // dmtcp_get_restart_env(name, value, MAXSIZE);
324 // Returns 0 on success, -1 if name not found; -2 if value > MAXSIZE
325 // NOTE: This implementation assumes that a "name=value" string will be
326 // no more than MAXSIZE bytes.
327
328 EXTERNC int
329 dmtcp_get_restart_env(const char *name, // IN
330 char *value, // OUT
331 size_t maxvaluelen)
332 {
333 int env_fd = dup(dmtcp_protected_environ_fd());
334 JASSERT(env_fd != -1)(env_fd)(dmtcp_protected_environ_fd());
335 lseek(env_fd, 0, SEEK_SET);
336 int namelen = strlen(name);
337 *value = '\0'; // Default is null string
338
339 #define SUCCESS 0
340 #define NOTFOUND -1
341 #define TOOLONG -2
342 #define DMTCP_BUF_TOO_SMALL -3
343 #define INTERNAL_ERROR -4
344 #define NULL_PTR -5
345 #define MAXSIZE 3000
346
347 int rc = NOTFOUND; // Default is -1: name not found
348
349 char env_buf[MAXSIZE] = {0}; // All "name=val" strings must be shorter than this.
350
351 if (name == NULL || value == NULL) {
352 close(env_fd);
353 return NULL_PTR;
354 }
355
356 char *pos = NULL;
357
358 while (rc == NOTFOUND) {
359 memset(env_buf, 0, MAXSIZE);
360 // read a flattened name-value pairs list
361 int count = Util::readLine(env_fd, env_buf, MAXSIZE);
362 if (count == 0) {
363 break;
364 } else if (count == -1) {
365 rc = INTERNAL_ERROR;
366 } else if (count == -2) {
367 rc = DMTCP_BUF_TOO_SMALL;
368 } else {
369 char *start_ptr = env_buf;
370 // iterate over the flattened list of name-value pairs
371 while (start_ptr - env_buf < (int) sizeof(env_buf)) {
372 pos = NULL;
373 if (strncmp(start_ptr, name, namelen) == 0) {
374 if ((pos = strchr(start_ptr, '='))) {
375 strncpy(value, pos + 1, maxvaluelen);
376 if (strlen(pos+1) >= maxvaluelen) {
377 rc = TOOLONG; // value does not fit in the user-provided value buffer
378 break;
379 }
380 }
381 rc = SUCCESS;
382 break;
383 }
384 // skip over a name-value pair
385 start_ptr += strlen(start_ptr) + 1;
386 }
387 }
388 }
389
390 close(env_fd);
391 JWARNING (rc != DMTCP_BUF_TOO_SMALL)
392 (name) (sizeof(env_buf)) .Text("Resize env_buf[]");
393 return rc;
394 }
395
396 EXTERNC int dmtcp_get_readlog_fd(void)
397 {
398 return PROTECTED_READLOG_FD;
399 }
400
401 EXTERNC int dmtcp_get_ptrace_fd(void)
402 {
403 return PROTECTED_PTRACE_FD;
404 }
405
406 LIB_PRIVATE int32_t dmtcp_dlsym_offset = -1;
407 typedef void* (*dlsym_fnptr_t) (void *handle, const char *symbol);
408 EXTERNC void *dmtcp_get_libc_dlsym_addr(void)
409 {
410 static dlsym_fnptr_t _libc_dlsym_fnptr = NULL;
411 #ifndef CONFIG_M32
412 const char *evar = ENV_VAR_DLSYM_OFFSET;
413 #else
414 const char *evar = ENV_VAR_DLSYM_OFFSET_M32;
415 #endif
416
417 if (_libc_dlsym_fnptr == NULL) {
418 if (getenv(evar) == NULL) {
419 fprintf(stderr,
420 "%s:%d DMTCP Internal Error: Env var DMTCP_DLSYM_OFFSET not set.\n"
421 " Aborting.\n\n",
422 __FILE__, __LINE__);
423 abort();
424 }
425
426 dmtcp_dlsym_offset = (int32_t) strtol(getenv(evar), NULL, 10);
427
428 _libc_dlsym_fnptr = (dlsym_fnptr_t)((char *)&LIBDL_BASE_FUNC +
429 dmtcp_dlsym_offset);
430 }
431
432 return (void*) _libc_dlsym_fnptr;
433 }
434
435 EXTERNC void dmtcp_block_ckpt_signal(void)
436 {
437 static sigset_t signals_set;
438 static bool initialized = false;
439 if (!initialized) {
440 sigemptyset (&signals_set);
441 sigaddset (&signals_set, dmtcp_get_ckpt_signal());
442 initialized = true;
443 }
444
445 JASSERT(_real_pthread_sigmask (SIG_BLOCK, &signals_set, NULL) == 0);
446 }
447
448 EXTERNC void dmtcp_unblock_ckpt_signal(void)
449 {
450 static sigset_t signals_set;
451 static bool initialized = false;
452 if (!initialized) {
453 sigemptyset (&signals_set);
454 sigaddset (&signals_set, dmtcp_get_ckpt_signal());
455 initialized = true;
456 }
457
458 JASSERT(_real_pthread_sigmask (SIG_UNBLOCK, &signals_set, NULL) == 0);
459 }
460
461 EXTERNC int dmtcp_send_key_val_pair_to_coordinator(const char *id,
462 const void *key,
463 uint32_t key_len,
464 const void *val,
465 uint32_t val_len)
466 {
467 return CoordinatorAPI::instance().sendKeyValPairToCoordinator(id, key, key_len,
468 val, val_len);
469 }
470
471 EXTERNC int dmtcp_send_key_val_pair_to_coordinator_sync(const char *id,
472 const void *key,
473 uint32_t key_len,
474 const void *val,
475 uint32_t val_len)
476 {
477 return CoordinatorAPI::instance().sendKeyValPairToCoordinator(id, key, key_len,
478 val, val_len,
479 1);
480 }
481
482 // On input, val points to a buffer in user memory and *val_len is the maximum
483 // size of that buffer (the memory allocated by user).
484 // On output, we copy data to val, and set *val_len to the actual buffer size
485 // (to the size of the data that we copied to the user buffer).
486 EXTERNC int dmtcp_send_query_to_coordinator(const char *id,
487 const void *key, uint32_t key_len,
488 void *val, uint32_t *val_len)
489 {
490 return CoordinatorAPI::instance().sendQueryToCoordinator(id, key, key_len,
491 val, val_len);
492 }
493
494 EXTERNC void dmtcp_get_local_ip_addr(struct in_addr *in)
495 {
496 SharedData::getLocalIPAddr(in);
497 }
498
499 EXTERNC int dmtcp_no_coordinator(void)
500 {
501 return CoordinatorAPI::noCoordinator();
502 }