root/dmtcpworker.cpp
/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- restoreUserLDPRELOAD
- determineCkptSignal
- dmtcp_prepare_wrappers
- calculateArgvAndEnvSize
- getLogFilePath
- writeCurrentLogFileNameToPrevLogFile
- prepareLogAndProcessdDataFromSerialFile
- processRlimit
- segFaultHandler
- installSegFaultHandler
- resetOnFork
- cleanupWorker
- interruptCkpthread
- ckptThreadPerformExit
- waitForCoordinatorMsg
- informCoordinatorOfRUNNINGState
- waitForStage1Suspend
- waitForStage2Checkpoint
- waitForStage3Refill
- waitForStage4Resume
- eventHook
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 <sys/time.h>
24 #include <sys/resource.h>
25 #include "dmtcpworker.h"
26 #include "mtcpinterface.h"
27 #include "threadsync.h"
28 #include "processinfo.h"
29 #include "syscallwrappers.h"
30 #include "util.h"
31 #include "syslogwrappers.h"
32 #include "coordinatorapi.h"
33 #include "shareddata.h"
34 #include "threadlist.h"
35 #include "../jalib/jsocket.h"
36 #include "../jalib/jfilesystem.h"
37 #include "../jalib/jconvert.h"
38 #include "../jalib/jbuffer.h"
39
40 using namespace dmtcp;
41
42 LIB_PRIVATE int dmtcp_wrappers_initializing = 0;
43
44 LIB_PRIVATE void pthread_atfork_prepare();
45 LIB_PRIVATE void pthread_atfork_parent();
46 LIB_PRIVATE void pthread_atfork_child();
47
48 void pidVirt_pthread_atfork_child() __attribute__((weak));
49
50 /* This is defined by newer gcc version unique for each module. */
51 extern void *__dso_handle __attribute__ ((__weak__,
52 __visibility__ ("hidden")));
53
54 EXTERNC int __register_atfork(void (*prepare)(void), void (*parent)(void),
55 void (*child)(void), void *dso_handle);
56
57 EXTERNC void *ibv_get_device_list(void *) __attribute__((weak));
58
59 /* The following instance of the DmtcpWorker is just to trigger the constructor
60 * to allow us to hijack the process
61 */
62 DmtcpWorker DmtcpWorker::theInstance;
63 bool DmtcpWorker::_exitInProgress = false;
64
65 void restoreUserLDPRELOAD()
66 {
67 /* A call to setenv() can result in a call to malloc(). The setenv() call may
68 * also grab a low-level libc lock before calling malloc. The malloc()
69 * wrapper, if present, will try to acquire the wrapper lock. This can lead
70 * to a deadlock in the following scenario:
71 *
72 * T1 (main thread): fork() -> acquire exclusive lock
73 * T2 (ckpt thread): setenv() -> acquire low-level libc lock ->
74 * malloc -> wait for wrapper-exec lock.
75 * T1: setenv() -> block on low-level libc lock (held by T2).
76 *
77 * The simpler solution would have been to not call setenv from DMTCP, and
78 * use putenv instead. This would require larger change.
79 *
80 * The solution used here is to set LD_PRELOAD to "" before * user main().
81 * This is as good as unsetting it. Later, the ckpt-thread * can unset it
82 * if it is still NULL, but then there is a possibility of a race between
83 * user code and ckpt-thread.
84 */
85
86 // We have now successfully used LD_PRELOAD to execute prior to main()
87 // Next, hide our value of LD_PRELOAD, in a global variable.
88 // At checkpoint and restart time, we will no longer need our LD_PRELOAD.
89 // We will need it in only one place:
90 // when the user application makes an exec call:
91 // If anybody calls our execwrapper, we will reset LD_PRELOAD then.
92 // If they directly call _real_execve to get libc symbol, they will
93 // not be part of DMTCP computation.
94 // This has the advantage that our value of LD_PRELOAD will always come
95 // before any paths set by user application.
96 // Also, bash likes to keep its own envp, but we will interact with bash only
97 // within the exec wrapper.
98 // NOTE: If the user called exec("ssh ..."), we currently catch this in
99 // DmtcpWorker() due to LD_PRELOAD, unset LD_PRELOAD, and edit this into
100 // exec("dmtcp_launch ... ssh ..."), and re-execute.
101 // This way, we will unset LD_PRELOAD here and now, instead of at that time.
102 char *preload = getenv("LD_PRELOAD");
103 char *userPreload = getenv(ENV_VAR_ORIG_LD_PRELOAD);
104 preload[0] = '\0';
105 if (userPreload == NULL) {
106 //_dmtcp_unsetenv("LD_PRELOAD");
107 } else {
108 strcat(preload, userPreload);
109 //setenv("LD_PRELOAD", userPreload, 1);
110 }
111 JTRACE("LD_PRELOAD") (preload) (userPreload) (getenv(ENV_VAR_HIJACK_LIBS))
112 (getenv(ENV_VAR_HIJACK_LIBS_M32)) (getenv("LD_PRELOAD"));
113 }
114
115 // This should be visible to library only. DmtcpWorker will call
116 // this to initialize tmp (ckpt signal) at startup time. This avoids
117 // any later calls to getenv(), at which time the user app may have
118 // a wrapper around getenv, modified environ, or other tricks.
119 // (Matlab needs this or else it segfaults on restart, and bash plays
120 // similar tricks with maintaining its own environment.)
121 // Used in mtcpinterface.cpp and signalwrappers.cpp.
122 // FIXME: DO we still want it to be library visible only?
123 //__attribute__ ((visibility ("hidden")))
124 int DmtcpWorker::determineCkptSignal()
125 {
126 int sig = CKPT_SIGNAL;
127 char* endp = NULL;
128 static const char* tmp = getenv(ENV_VAR_SIGCKPT);
129 if (tmp != NULL) {
130 sig = strtol(tmp, &endp, 0);
131 if ((errno != 0) || (tmp == endp))
132 sig = CKPT_SIGNAL;
133 if (sig < 1 || sig > 31)
134 sig = CKPT_SIGNAL;
135 }
136 return sig;
137 }
138
139 /* This function is called at the very beginning of the DmtcpWorker constructor
140 * to do some initialization work so that DMTCP can later use _real_XXX
141 * functions reliably. Read the comment at the top of syscallsreal.c for more
142 * details.
143 */
144 static bool dmtcpWrappersInitialized = false;
145 extern "C" void dmtcp_prepare_wrappers(void)
146 {
147 if (!dmtcpWrappersInitialized) {
148 dmtcp_wrappers_initializing = 1;
149 initialize_libc_wrappers();
150 //DmtcpWorker::eventHook(DMTCP_EVENT_INIT_WRAPPERS, NULL);
151 dmtcp_wrappers_initializing = 0;
152 initialize_libpthread_wrappers();
153 dmtcpWrappersInitialized = true;
154
155 /* Register pidVirt_pthread_atfork_child() as the first post-fork handler
156 * for the child process. This needs to be the first function that is
157 * called by libc:fork() after the child process is created.
158 *
159 * pthread_atfork_child() needs to be the second post-fork handler for the
160 * child process.
161 *
162 * Some dmtcp plugin might also call pthread_atfork and so we call it right
163 * here before initializing the wrappers.
164 *
165 * NOTE: If this doesn't work and someone is able to call pthread_atfork
166 * before this call, we might want to install a pthread_atfork() wrappers.
167 */
168
169 /* If we use pthread_atfork here, it fails for Ubuntu 14.04 on ARM.
170 * To fix it, we use __register_atfork and use the __dso_handle provided by
171 * the gcc compiler.
172 */
173 JASSERT(__register_atfork(NULL, NULL,
174 pidVirt_pthread_atfork_child,
175 __dso_handle) == 0);
176
177 JASSERT(pthread_atfork(pthread_atfork_prepare,
178 pthread_atfork_parent,
179 pthread_atfork_child) == 0);
180 }
181 }
182
183 static void calculateArgvAndEnvSize()
184 {
185 size_t argvSize, envSize;
186
187 vector<string> args = jalib::Filesystem::GetProgramArgs();
188 argvSize = 0;
189 for (size_t i = 0; i < args.size(); i++) {
190 argvSize += args[i].length() + 1;
191 }
192 envSize = 0;
193 if (environ != NULL) {
194 char *ptr = environ[0];
195 while (*ptr != '\0' && args[0].compare(ptr) != 0) {
196 envSize += strlen(ptr) + 1;
197 ptr += strlen(ptr) + 1;
198 }
199 }
200 envSize += args[0].length();
201
202 ProcessInfo::instance().argvSize(argvSize);
203 ProcessInfo::instance().envSize(envSize);
204 }
205
206 static string getLogFilePath()
207 {
208 #ifdef DEBUG
209 ostringstream o;
210 o << "/proc/self/fd/" << PROTECTED_JASSERTLOG_FD;
211 return jalib::Filesystem::ResolveSymlink(o.str());
212 #else
213 return "";
214 #endif
215 }
216
217 static void writeCurrentLogFileNameToPrevLogFile(string& path)
218 {
219 #ifdef DEBUG
220 ostringstream o;
221 o << "========================================\n"
222 << "This process exec()'d into a new program\n"
223 << "Program Name: " << jalib::Filesystem::GetProgramName() << "\n"
224 << "New JAssertLog Path: " << getLogFilePath() << "\n"
225 << "========================================\n";
226
227 int fd = open(path.c_str(), O_WRONLY | O_APPEND, 0);
228 if (fd != -1) {
229 Util::writeAll(fd, o.str().c_str(), o.str().length());
230 }
231 _real_close(fd);
232 #endif
233 }
234
235 static void prepareLogAndProcessdDataFromSerialFile()
236 {
237
238 if (Util::isValidFd(PROTECTED_LIFEBOAT_FD)) {
239 // This process was under ckpt-control and exec()'d into a new program.
240 // Find out path of previous log file so that later, we can write the name
241 // of the new log file into that one.
242 string prevLogFilePath = getLogFilePath();
243
244 jalib::JBinarySerializeReaderRaw rd ("", PROTECTED_LIFEBOAT_FD);
245 rd.rewind();
246 UniquePid::serialize (rd);
247 Util::initializeLogFile(SharedData::getTmpDir(), "", prevLogFilePath);
248
249 writeCurrentLogFileNameToPrevLogFile(prevLogFilePath);
250
251 DmtcpEventData_t edata;
252 edata.serializerInfo.fd = PROTECTED_LIFEBOAT_FD;
253 DmtcpWorker::eventHook(DMTCP_EVENT_POST_EXEC, &edata);
254 _real_close(PROTECTED_LIFEBOAT_FD);
255 } else {
256 // Brand new process (was never under ckpt-control),
257 // Initialize the log file
258 Util::initializeLogFile(SharedData::getTmpDir());
259
260 JTRACE("Root of processes tree");
261 ProcessInfo::instance().setRootOfProcessTree();
262 }
263 }
264
265 static void processRlimit()
266 {
267 #ifdef __i386__
268 // Match work begun in dmtcpPrepareForExec()
269 # if 0
270 if (getenv("DMTCP_ADDR_COMPAT_LAYOUT")) {
271 _dmtcp_unsetenv("DMTCP_ADDR_COMPAT_LAYOUT");
272 // DMTCP had set ADDR_COMPAT_LAYOUT. Now unset it.
273 personality((unsigned long)personality(0xffffffff) ^ ADDR_COMPAT_LAYOUT);
274 JTRACE("unsetting ADDR_COMPAT_LAYOUT");
275 }
276 # else
277 { char * rlim_cur_char = getenv("DMTCP_RLIMIT_STACK");
278 if (rlim_cur_char != NULL) {
279 struct rlimit rlim;
280 getrlimit(RLIMIT_STACK, &rlim);
281 rlim.rlim_cur = atol(rlim_cur_char);
282 JTRACE("rlim_cur for RLIMIT_STACK being restored.") (rlim.rlim_cur);
283 setrlimit(RLIMIT_STACK, &rlim);
284 _dmtcp_unsetenv("DMTCP_RLIMIT_STACK");
285 }
286 }
287 # endif
288 #endif
289 }
290
291 static void segFaultHandler(int sig, siginfo_t* siginfo, void* context)
292 {
293 while (1) sleep(1);
294 }
295
296 static void installSegFaultHandler()
297 {
298 // install SIGSEGV handler
299 struct sigaction act;
300 memset(&act, 0, sizeof(act));
301 act.sa_sigaction = segFaultHandler;
302 act.sa_flags = SA_SIGINFO;
303 JASSERT (sigaction(SIGSEGV, &act, NULL) == 0) (JASSERT_ERRNO);
304 }
305
306 //called before user main()
307 //workerhijack.cpp initializes a static variable theInstance to DmtcpWorker obj
308 DmtcpWorker::DmtcpWorker()
309 {
310 WorkerState::setCurrentState(WorkerState::UNKNOWN);
311 initializeJalib();
312 dmtcp_prepare_wrappers();
313 prepareLogAndProcessdDataFromSerialFile();
314
315 JTRACE("libdmtcp.so: Running ")
316 (jalib::Filesystem::GetProgramName()) (getenv ("LD_PRELOAD"));
317
318 processRlimit();
319
320 if (getenv("DMTCP_SEGFAULT_HANDLER") != NULL) {
321 // Install a segmentation fault handler (for debugging).
322 installSegFaultHandler();
323 }
324
325 //This is called for side effect only. Force this function to call
326 // getenv(ENV_VAR_SIGCKPT) now and cache it to avoid getenv calls later.
327 determineCkptSignal();
328
329 // Also cache programName and arguments
330 string programName = jalib::Filesystem::GetProgramName();
331 vector<string> args = jalib::Filesystem::GetProgramArgs();
332
333 JASSERT(programName != "dmtcp_coordinator" &&
334 programName != "dmtcp_launch" &&
335 programName != "dmtcp_nocheckpoint" &&
336 programName != "dmtcp_comand" &&
337 programName != "dmtcp_restart" &&
338 programName != "mtcp_restart" &&
339 programName != "ssh")
340 (programName) .Text("This program should not be run under ckpt control");
341
342 calculateArgvAndEnvSize();
343 restoreUserLDPRELOAD();
344
345 WorkerState::setCurrentState (WorkerState::RUNNING);
346
347 if (ibv_get_device_list && !dmtcp_infiniband_enabled) {
348 JNOTE("\n\n*** InfiniBand library detected."
349 " Please use dmtcp_launch --ib ***\n");
350 }
351
352 // In libdmtcp.so, notify this event for each plugin.
353 eventHook(DMTCP_EVENT_INIT, NULL);
354
355 initializeMtcpEngine();
356 informCoordinatorOfRUNNINGState();
357 }
358
359 void DmtcpWorker::resetOnFork()
360 {
361 eventHook(DMTCP_EVENT_ATFORK_CHILD, NULL);
362
363 cleanupWorker();
364
365 /* If parent process had file connections and it fork()'d a child
366 * process, the child process would consider the file connections as
367 * pre-existing and hence wouldn't restore them. This is fixed by making sure
368 * that when a child process is forked, it shouldn't be looking for
369 * pre-existing connections because the parent has already done that.
370 *
371 * So, here while creating the instance, we do not want to execute everything
372 * in the constructor since it's not relevant. All we need to call is
373 * connectToCoordinatorWithHandshake() and initializeMtcpEngine().
374 */
375 //new ( &theInstance ) DmtcpWorker ( false );
376
377 ThreadList::resetOnFork();
378
379 DmtcpWorker::_exitInProgress = false;
380
381 WorkerState::setCurrentState ( WorkerState::RUNNING );
382
383 }
384
385 void DmtcpWorker::cleanupWorker()
386 {
387 ThreadSync::resetLocks();
388 WorkerState::setCurrentState(WorkerState::UNKNOWN);
389 JTRACE("disconnecting from dmtcp coordinator");
390 }
391
392 void DmtcpWorker::interruptCkpthread()
393 {
394 if (ThreadSync::destroyDmtcpWorkerLockTryLock() == EBUSY) {
395 ThreadList::killCkpthread();
396 ThreadSync::destroyDmtcpWorkerLockLock();
397 }
398 }
399
400 //called after user main()
401 DmtcpWorker::~DmtcpWorker()
402 {
403 /* If the destructor was called, we know that we are exiting
404 * After setting this, the wrapper execution locks will be ignored.
405 * FIXME: A better solution is to add a ZOMBIE state to DmtcpWorker,
406 * instead of using a separate variable, _exitInProgress.
407 */
408 setExitInProgress();
409 eventHook(DMTCP_EVENT_EXIT, NULL);
410 interruptCkpthread();
411 cleanupWorker();
412 }
413
414 static void ckptThreadPerformExit()
415 {
416 // Ideally, we would like to perform pthread_exit(), but we are in the middle
417 // of process cleanup (due to the user thread's exit() call) and as a result,
418 // the static objects are being destroyed. A call to pthread_exit() also
419 // results in execution of various cleanup routines. If the thread tries to
420 // access any static objects during some cleanup routine, it will cause a
421 // segfault.
422 //
423 // Our approach to loop here while we wait for the process to terminate.
424 // This guarantees that we never access any static objects from this point
425 // forward.
426 while (1) sleep(1);
427 }
428
429 void DmtcpWorker::waitForCoordinatorMsg(string msgStr,
430 DmtcpMessageType type)
431 {
432 if (dmtcp_no_coordinator()) {
433 if (type == DMT_DO_SUSPEND) {
434 string shmFile = jalib::Filesystem::GetDeviceName(PROTECTED_SHM_FD);
435 JASSERT(!shmFile.empty());
436 unlink(shmFile.c_str());
437 CoordinatorAPI::instance().waitForCheckpointCommand();
438 ProcessInfo::instance().numPeers(1);
439 ProcessInfo::instance().compGroup(SharedData::getCompId());
440 }
441 return;
442 }
443
444 if (type == DMT_DO_SUSPEND) {
445 if (ThreadSync::destroyDmtcpWorkerLockTryLock() != 0) {
446 JTRACE("User thread is performing exit()."
447 " ckpt thread exit()ing as well");
448 ckptThreadPerformExit();
449 }
450 if (exitInProgress()) {
451 ThreadSync::destroyDmtcpWorkerLockUnlock();
452 ckptThreadPerformExit();
453 }
454 }
455
456 DmtcpMessage msg;
457
458 if (type == DMT_DO_SUSPEND) {
459 // Make a dummy syscall to inform superior of our status before we go into
460 // select. If ptrace is disabled, this call has no significant effect.
461 _real_syscall(DMTCP_FAKE_SYSCALL);
462 } else {
463 msg.type = DMT_OK;
464 msg.state = WorkerState::currentState();
465 CoordinatorAPI::instance().sendMsgToCoordinator(msg);
466 }
467
468 JTRACE("waiting for " + msgStr + " message");
469 CoordinatorAPI::instance().recvMsgFromCoordinator(&msg);
470 if (type == DMT_DO_SUSPEND && exitInProgress()) {
471 ThreadSync::destroyDmtcpWorkerLockUnlock();
472 ckptThreadPerformExit();
473 }
474
475 msg.assertValid();
476 if (msg.type == DMT_KILL_PEER) {
477 JTRACE("Received KILL message from coordinator, exiting");
478 _exit (0);
479 }
480
481 JASSERT(msg.type == type) (msg.type) (type);
482
483 // Coordinator sends some computation information along with the SUSPEND
484 // message. Extracting that.
485 if (type == DMT_DO_SUSPEND) {
486 SharedData::updateGeneration(msg.compGroup.computationGeneration());
487 JASSERT(SharedData::getCompId() == msg.compGroup.upid())
488 (SharedData::getCompId()) (msg.compGroup);
489 } else if (type == DMT_DO_FD_LEADER_ELECTION) {
490 JTRACE("Computation information") (msg.compGroup) (msg.numPeers);
491 ProcessInfo::instance().compGroup(msg.compGroup);
492 ProcessInfo::instance().numPeers(msg.numPeers);
493 }
494 }
495
496 void DmtcpWorker::informCoordinatorOfRUNNINGState()
497 {
498 DmtcpMessage msg;
499
500 JASSERT(WorkerState::currentState() == WorkerState::RUNNING);
501
502 msg.type = DMT_OK;
503 msg.state = WorkerState::currentState();
504 CoordinatorAPI::instance().sendMsgToCoordinator(msg);
505 }
506
507 void DmtcpWorker::waitForStage1Suspend()
508 {
509 JTRACE("running");
510
511 WorkerState::setCurrentState (WorkerState::RUNNING);
512
513 waitForCoordinatorMsg ("SUSPEND", DMT_DO_SUSPEND);
514
515 JTRACE("got SUSPEND message, preparing to acquire all ThreadSync locks");
516 ThreadSync::acquireLocks();
517
518 JTRACE("Starting checkpoint, suspending...");
519 }
520
521 void DmtcpWorker::waitForStage2Checkpoint()
522 {
523 WorkerState::setCurrentState (WorkerState::SUSPENDED);
524 JTRACE("suspended");
525
526 if (exitInProgress()) {
527 ThreadSync::destroyDmtcpWorkerLockUnlock();
528 ckptThreadPerformExit();
529 }
530 ThreadSync::destroyDmtcpWorkerLockUnlock();
531
532 ThreadSync::releaseLocks();
533
534 eventHook(DMTCP_EVENT_THREADS_SUSPEND, NULL);
535
536 waitForCoordinatorMsg ("FD_LEADER_ELECTION", DMT_DO_FD_LEADER_ELECTION);
537
538 eventHook(DMTCP_EVENT_LEADER_ELECTION, NULL);
539
540 WorkerState::setCurrentState (WorkerState::FD_LEADER_ELECTION);
541
542 waitForCoordinatorMsg ("DRAIN", DMT_DO_DRAIN);
543
544 WorkerState::setCurrentState (WorkerState::DRAINED);
545
546 eventHook(DMTCP_EVENT_DRAIN, NULL);
547
548 waitForCoordinatorMsg ("CHECKPOINT", DMT_DO_CHECKPOINT);
549 JTRACE("got checkpoint message");
550
551 eventHook(DMTCP_EVENT_WRITE_CKPT, NULL);
552
553 // Unmap shared area
554 SharedData::preCkpt();
555 }
556
557 void DmtcpWorker::waitForStage3Refill(bool isRestart)
558 {
559 DmtcpEventData_t edata;
560 JTRACE("checkpointed");
561
562 WorkerState::setCurrentState (WorkerState::CHECKPOINTED);
563
564 #ifdef COORD_NAMESERVICE
565 waitForCoordinatorMsg("REGISTER_NAME_SERVICE_DATA",
566 DMT_DO_REGISTER_NAME_SERVICE_DATA);
567 edata.nameserviceInfo.isRestart = isRestart;
568 eventHook(DMTCP_EVENT_REGISTER_NAME_SERVICE_DATA, &edata);
569 JTRACE("Key Value Pairs registered with the coordinator");
570 WorkerState::setCurrentState(WorkerState::NAME_SERVICE_DATA_REGISTERED);
571
572 waitForCoordinatorMsg("SEND_QUERIES", DMT_DO_SEND_QUERIES);
573 eventHook(DMTCP_EVENT_SEND_QUERIES, &edata);
574 JTRACE("Queries sent to the coordinator");
575 WorkerState::setCurrentState(WorkerState::DONE_QUERYING);
576 #endif
577
578 waitForCoordinatorMsg ("REFILL", DMT_DO_REFILL);
579
580 edata.refillInfo.isRestart = isRestart;
581 DmtcpWorker::eventHook(DMTCP_EVENT_REFILL, &edata);
582 }
583
584 void DmtcpWorker::waitForStage4Resume(bool isRestart)
585 {
586 JTRACE("refilled");
587 WorkerState::setCurrentState (WorkerState::REFILLED);
588 waitForCoordinatorMsg ("RESUME", DMT_DO_RESUME);
589 JTRACE("got resume message");
590 DmtcpEventData_t edata;
591 edata.resumeInfo.isRestart = isRestart;
592 DmtcpWorker::eventHook(DMTCP_EVENT_THREADS_RESUME, &edata);
593 }
594
595 void dmtcp_CoordinatorAPI_EventHook(DmtcpEvent_t event, DmtcpEventData_t *data);
596 void dmtcp_SharedData_EventHook(DmtcpEvent_t event, DmtcpEventData_t *data);
597 void dmtcp_ProcessInfo_EventHook(DmtcpEvent_t event, DmtcpEventData_t *data);
598 void dmtcp_UniquePid_EventHook(DmtcpEvent_t event, DmtcpEventData_t *data);
599 void dmtcp_ProcName_EventHook(DmtcpEvent_t event, DmtcpEventData_t *data);
600 void dmtcp_Terminal_EventHook(DmtcpEvent_t event, DmtcpEventData_t *data);
601 void dmtcp_Syslog_EventHook(DmtcpEvent_t event, DmtcpEventData_t *data);
602 void dmtcp_Alarm_EventHook(DmtcpEvent_t event, DmtcpEventData_t *data);
603
604 void DmtcpWorker::eventHook(DmtcpEvent_t event, DmtcpEventData_t *data)
605 {
606 static jalib::JBuffer buf(0); // To force linkage of jbuffer.cpp
607 dmtcp_Syslog_EventHook(event, data);
608 dmtcp_Terminal_EventHook(event, data);
609 dmtcp_ProcName_EventHook(event, data);
610 dmtcp_UniquePid_EventHook(event, data);
611 dmtcp_CoordinatorAPI_EventHook(event, data);
612 dmtcp_SharedData_EventHook(event, data);
613 dmtcp_ProcessInfo_EventHook(event, data);
614 dmtcp_Alarm_EventHook(event, data);
615 if (dmtcp_event_hook != NULL) {
616 dmtcp_event_hook(event, data);
617 }
618 }