1 /****************************************************************************
2 * Copyright (C) 2006-2010 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 the dmtcp/src module of DMTCP (DMTCP:dmtcp/src). *
6 * *
7 * DMTCP:dmtcp/src 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:dmtcp/src 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 "virtualpidtable.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include <string>
26 #include <sstream>
27 #include <fcntl.h>
28 #include <sys/syscall.h>
29 #include "constants.h"
30 #include "util.h"
31 #include "syscallwrappers.h"
32 #include "protectedfds.h"
33 #include "../jalib/jconvert.h"
34 #include "../jalib/jfilesystem.h"
35
36 #ifdef PID_VIRTUALIZATION
37
38 static pthread_mutex_t tblLock = PTHREAD_MUTEX_INITIALIZER;
39
40 static void _do_lock_tbl()
41 {
42 JASSERT(pthread_mutex_lock(&tblLock) == 0) (JASSERT_ERRNO);
43 }
44
45 static void _do_unlock_tbl()
46 {
47 JASSERT(pthread_mutex_unlock(&tblLock) == 0) (JASSERT_ERRNO);
48 }
49
50 dmtcp::VirtualPidTable::VirtualPidTable()
51 {
52 _do_lock_tbl();
53 _pid = _real_getpid();
54 _ppid = _real_getppid();
55 _sid = -1;
56 _gid = _real_getpgid(0);
57 _isRootOfProcessTree = false;
58 _childTable.clear();
59 _tidVector.clear();
60 _inferiorVector.clear();
61 _pidMapTable.clear();
62 _pidMapTable[_pid] = _pid;
63 _do_unlock_tbl();
|
Event uninit_member: |
Non-static class member _fgid is not initialized in this constructor nor in any functions that it calls. |
| Also see events: |
[member_decl] |
64 }
65
66 dmtcp::VirtualPidTable& dmtcp::VirtualPidTable::instance()
67 {
68 static VirtualPidTable *inst = new VirtualPidTable(); return *inst;
69 }
70
71 bool dmtcp::VirtualPidTable::isConflictingPid( pid_t pid)
72 {
73 /* If pid != originalToCurrentPid(pid), then there is a conflict because
74 * there is an original_pid same as this pid.
75 *
76 * If pid == originalToCurrentPid(pid), then there are two cases:
77 * 1. there is no mapping from some original_pid to pid ==> no conflict
78 * 2. there is a mapping from pid to pid in the table, in which case again
79 * there is not conflict because that mapping essentially is about the
80 * current pid.
81 */
82 if (pid == instance().originalToCurrentPid( pid ))
83 return false;
84
85 return true;
86 }
87
88 void dmtcp::VirtualPidTable::preCheckpoint()
89 {
90 // Update Group information before checkpoint
91 _ppid = getppid(); // refresh parent PID
92 _gid = getpgid(0);
93
94 _fgid = -1;
95 dmtcp::string controllingTerm = jalib::Filesystem::GetControllingTerm();
96 if (!controllingTerm.empty()) {
97 int tfd = _real_open(controllingTerm.c_str(), O_RDONLY, 0);
98 if (tfd >= 0) {
99 _fgid = tcgetpgrp(tfd);
100 _real_close(tfd);
101 }
102 }
103
104 /*
105 char s[ L_ctermid ];
106 // play around group ID
107 _fgid = -1;
108 if( ctermid(s) ){
109 int tfd = open(s,O_RDONLY);
110 if( tfd >= 0 ){
111 _fgid = tcgetpgrp(tfd);
112 close(tfd);
113 }
114 }
115 */
116
117 JTRACE("CHECK GROUP PID")(_gid)(_fgid)(_ppid)(pidExists(_gid));
118 }
119
120 void dmtcp::VirtualPidTable::postRestart()
121 {
122 //getenv ( ENV_VAR_PIDTBLFILE_INITIAL );
123 /*
124 * PROTECTED_PIDTBL_FD corresponds to the file containing the pids/uniquePids
125 * of all child processes, tids of all threads, and tids of all inferior
126 * process(threads) which are being traced by this process.
127 *
128 * PROTECTED_PIDMAP_FD corresponds to the file containg computation wide
129 * original_pid -> current_pid map to avoid pid/tid collisions.
130 */
131 dmtcp::string serialFile = "/proc/self/fd/" + jalib::XToString ( PROTECTED_PIDTBL_FD );
132
133 serialFile = jalib::Filesystem::ResolveSymlink ( serialFile );
134 JASSERT ( serialFile.length() > 0 ) ( serialFile );
135 _real_close ( PROTECTED_PIDTBL_FD );
136
137 JTRACE("Read originals pids from pid-table file") (serialFile);
138 jalib::JBinarySerializeReader rd ( serialFile );
139 serialize ( rd );
140 }
141
142 void dmtcp::VirtualPidTable::restoreProcessGroupInfo()
143 {
144 // Restore group assignment
145 if( pidExists(_gid) ){
146 pid_t cgid = getpgid(0);
147 // Group ID is known inside checkpointed processes
148 if( _gid != cgid && _pid != _gid ){
149 JTRACE("Restore Group Assignment")
150 ( _gid ) ( _fgid ) ( cgid ) ( _pid ) ( _ppid ) ( getppid() );
151 JWARNING( setpgid(0,_gid) == 0 ) (_gid) (JASSERT_ERRNO)
152 .Text("Cannot change group information");
153 }else{
154 JTRACE("Group is already assigned")(_gid)(cgid);
155 }
156 }else{
157 JTRACE("VirtualPidTable::postRestart SKIP Group information, GID unknown");
158 }
159 }
160
161 void dmtcp::VirtualPidTable::printPidMaps()
162 {
163 #ifdef DEBUG
164 JASSERT_STDERR << " originalPid" << " -> " << "currentPid" << "\n";
165 for ( pid_iterator i = _pidMapTable.begin(); i != _pidMapTable.end(); ++i ) {
166 pid_t originalPid = i->first;
167 pid_t currentPid = i->second;
168 JASSERT_STDERR << "\t" << originalPid << "\t->\t" << currentPid << "\n";
169 }
170 #endif
171 }
172
173 void dmtcp::VirtualPidTable::resetOnFork()
174 {
175 _pid = _real_getpid();
176 _ppid = currentToOriginalPid ( _real_getppid() );
177 _isRootOfProcessTree = false;
178 _childTable.clear();
179 _tidVector.clear();
180 _inferiorVector.clear();
181 //_pidMapTable[_pid] = _pid;
182 JTRACE("current original to current mappings:") (_pidMapTable.size());
183 printPidMaps();
184 }
185
186 pid_t dmtcp::VirtualPidTable::originalToCurrentPid( pid_t originalPid )
187 {
188 /* This code is called from MTCP while the checkpoint thread is holding
189 the JASSERT log lock. Therefore, don't call JTRACE/JASSERT/JINFO/etc. in
190 this function. */
191 _do_lock_tbl();
192 pid_iterator i = _pidMapTable.find(originalPid);
193 if ( i == _pidMapTable.end() ) {
194 _do_unlock_tbl();
195 return originalPid;
196 }
197
198 _do_unlock_tbl();
199 return i->second;
200 }
201
202 pid_t dmtcp::VirtualPidTable::currentToOriginalPid( pid_t currentPid )
203 {
204 /* This code is called from MTCP while the checkpoint thread is holding
205 the JASSERT log lock. Therefore, don't call JTRACE/JASSERT/JINFO/etc. in
206 this function. */
207 _do_lock_tbl();
208 for (pid_iterator i = _pidMapTable.begin(); i != _pidMapTable.end(); ++i)
209 {
210 if ( currentPid == i->second ) {
211 _do_unlock_tbl();
212 return i->first;
213 }
214 }
215
216 _do_unlock_tbl();
217 return currentPid;
218 }
219
220 void dmtcp::VirtualPidTable::insert ( pid_t originalPid, dmtcp::UniquePid uniquePid )
221 {
222 _do_lock_tbl();
223 iterator i = _childTable.find( originalPid );
224 if ( i != _childTable.end() ) {
225 _do_unlock_tbl();
226 JTRACE ( "originalPid -> currentPid mapping exists!") ( originalPid ) ( i->second );
227 }
228
229 _childTable[originalPid] = uniquePid;
230 _pidMapTable[originalPid] = originalPid;
231
232 _do_unlock_tbl();
233
234 JTRACE ( "Creating new originalPid -> currentPid mapping." ) ( originalPid ) ( uniquePid );
235 }
236
237 void dmtcp::VirtualPidTable::erase( pid_t originalPid )
238 {
239 _do_lock_tbl();
240 iterator i = _childTable.find ( originalPid );
241 if ( i != _childTable.end() )
242 _childTable.erase( originalPid );
243
244 pid_iterator j = _pidMapTable.find ( originalPid );
245 if ( j != _pidMapTable.end() )
246 _pidMapTable.erase( originalPid );
247 _do_unlock_tbl();
248 }
249
250 void dmtcp::VirtualPidTable::updateRootOfProcessTree()
251 {
252 if ( _real_getppid() == 1 )
253 _isRootOfProcessTree = true;
254 }
255
256 void dmtcp::VirtualPidTable::updateMapping( pid_t originalPid, pid_t currentPid )
257 {
258 _do_lock_tbl();
259 _pidMapTable[originalPid] = currentPid;
260 _do_unlock_tbl();
261 }
262
263 dmtcp::vector< pid_t > dmtcp::VirtualPidTable::getPidVector( )
264 {
265 dmtcp::vector< pid_t > pidVec;
266 for ( pid_iterator i = _pidMapTable.begin(); i != _pidMapTable.end(); ++i )
267 pidVec.push_back ( i->first );
268 return pidVec;
269 }
270
271 dmtcp::vector< pid_t > dmtcp::VirtualPidTable::getChildPidVector( )
272 {
273 dmtcp::vector< pid_t > childPidVec;
274 for ( iterator i = _childTable.begin(); i != _childTable.end(); ++i )
275 childPidVec.push_back ( i->first );
276 return childPidVec;
277 }
278
279 dmtcp::vector< pid_t > dmtcp::VirtualPidTable::getTidVector( )
280 {
281 return _tidVector;
282 }
283
284 dmtcp::vector< pid_t > dmtcp::VirtualPidTable::getInferiorVector( )
285 {
286 return _inferiorVector;
287 }
288
289 void dmtcp::VirtualPidTable::insertTid( pid_t tid )
290 {
291 eraseTid( tid );
292 _do_lock_tbl();
293 _tidVector.push_back ( tid );
294 _do_unlock_tbl();
295 return;
296 }
297
298 void dmtcp::VirtualPidTable::insertInferior( pid_t tid )
299 {
300 eraseInferior( tid );
301 _do_lock_tbl();
302 _inferiorVector.push_back ( tid );
303 _do_unlock_tbl();
304 return;
305 }
306
307 void dmtcp::VirtualPidTable::eraseTid( pid_t tid )
308 {
309 _do_lock_tbl();
310 dmtcp::vector< pid_t >::iterator iter = _tidVector.begin();
311 while ( iter != _tidVector.end() ) {
312 if ( *iter == tid ) {
313 _tidVector.erase( iter );
314 _pidMapTable.erase(tid);
315 break;
316 }
317 else
318 ++iter;
319 }
320 _do_unlock_tbl();
321 return;
322 }
323
324 void dmtcp::VirtualPidTable::postExec( )
325 {
326 JTRACE("Post-Exec. Emptying tidVector");
327 _do_lock_tbl();
328 for (size_t i = 0; i < _tidVector.size(); i++) {
329 _pidMapTable.erase( _tidVector[i] );
330 }
331 _tidVector.clear();
332 _do_unlock_tbl();
333 }
334
335 void dmtcp::VirtualPidTable::eraseInferior( pid_t tid )
336 {
337 _do_lock_tbl();
338 dmtcp::vector< pid_t >::iterator iter = _inferiorVector.begin();
339 while ( iter != _inferiorVector.end() ) {
340 if ( *iter == tid ) {
341 _inferiorVector.erase( iter );
342 break;
343 }
344 else
345 ++iter;
346 }
347 _do_unlock_tbl();
348 return;
349 }
350
351 bool dmtcp::VirtualPidTable::pidExists( pid_t pid )
352 {
353 bool retVal = false;
354 _do_lock_tbl();
355 pid_iterator j = _pidMapTable.find ( pid );
356 if ( j != _pidMapTable.end() )
357 retVal = true;
358
359 _do_unlock_tbl();
360 return retVal;
361 }
362
363 void dmtcp::VirtualPidTable::refresh()
364 {
365 updateRootOfProcessTree();// _isRootOfProcessTree = true;
366 refreshChildTable();
367 refreshTidVector();
368 }
369
370 void dmtcp::VirtualPidTable::refreshTidVector()
371 {
372 dmtcp::vector< pid_t >::iterator iter;
373 for (iter = _tidVector.begin(); iter != _tidVector.end(); ) {
374 int retVal = syscall(SYS_tgkill, _pid, *iter, 0);
375 if (retVal == -1 && errno == ESRCH) {
376 erase(*iter);
377 iter = _tidVector.erase( iter );
378 } else {
379 iter++;
380 }
381 }
382 return;
383 }
384
385 void dmtcp::VirtualPidTable::refreshChildTable()
386 {
387 for ( iterator i = _childTable.begin(); i != _childTable.end(); ++i ) {
388 pid_t originalPid = i->first;
389 int retVal = kill(originalPid, 0);
390 /* Check to see if the child process is alive*/
391 if (retVal == -1 && errno == ESRCH) {
392 erase(originalPid);
393 }
394 }
395 }
396
397 void dmtcp::VirtualPidTable::serialize ( jalib::JBinarySerializer& o )
398 {
399 JSERIALIZE_ASSERT_POINT ( "dmtcp::VirtualPidTable:" );
400
401 if (o.isWriter()){
402 updateRootOfProcessTree();// _isRootOfProcessTree = true;
403 //refreshChildTable();
404 //refreshTidVector();
405 }
406
407 JTRACE("Save pid information")(_sid)(_ppid)(_gid)(_fgid);
408 o & _isRootOfProcessTree & _pid & _sid & _ppid & _gid & _fgid;
409
410 if ( _isRootOfProcessTree )
411 JTRACE ( "This process is Root of Process Tree" );// ( UniquePid::ThisProcess() );
412
413 serializeChildTable ( o );
414
415 serializePidMap ( o );
416
417 JTRACE ("Serializing tidVector");
418 JSERIALIZE_ASSERT_POINT ( "TID Vector:[" );
419 o & _tidVector;
420 JSERIALIZE_ASSERT_POINT ( "}" );
421
422 JTRACE ("Serializing inferiorVector");
423 JSERIALIZE_ASSERT_POINT ( "Inferior Vector:[" );
424 o & _inferiorVector;
425 JSERIALIZE_ASSERT_POINT ( "]" );
426
427 JSERIALIZE_ASSERT_POINT( "EOF" );
428 }
429
430
431 void dmtcp::VirtualPidTable::serializeChildTable ( jalib::JBinarySerializer& o )
432 {
433 size_t numPids = _childTable.size();
434 serializeEntryCount(o, numPids);
435
436 JTRACE ("Serializing ChildPid Table") (numPids) (o.filename());
437 pid_t originalPid;
438 dmtcp::UniquePid uniquePid;
439
440 if ( o.isWriter() )
441 {
442 for ( iterator i = _childTable.begin(); i != _childTable.end(); ++i )
443 {
444 originalPid = i->first;
445 uniquePid = i->second;
446 serializeChildTableEntry ( o, originalPid, uniquePid );
447 }
448 }
449 else
450 {
451 while ( numPids-- > 0 )
452 {
453 serializeChildTableEntry ( o, originalPid, uniquePid );
454 _childTable[originalPid] = uniquePid;
455 }
456 }
457 }
458
459 void dmtcp::VirtualPidTable::serializeChildTableEntry (
460 jalib::JBinarySerializer& o, pid_t& originalPid, dmtcp::UniquePid& uniquePid )
461 {
462 JSERIALIZE_ASSERT_POINT ( "ChildPid:[" );
463 o & originalPid & uniquePid;
464 JSERIALIZE_ASSERT_POINT ( "]" );
465 }
466
467 void dmtcp::VirtualPidTable::serializePidMap ( jalib::JBinarySerializer& o )
468 {
469 size_t numMaps = _pidMapTable.size();
470 serializeEntryCount(o, numMaps);
471
472 pid_t originalPid;
473 pid_t currentPid;
474
475 if ( o.isWriter() )
476 {
477 for ( pid_iterator i = _pidMapTable.begin(); i != _pidMapTable.end(); ++i )
478 {
479 originalPid = i->first;
480 currentPid = i->second;
481 serializePidMapEntry ( o, originalPid, currentPid );
482 }
483 }
484 else
485 {
486 while ( numMaps-- > 0 )
487 {
488 serializePidMapEntry ( o, originalPid, currentPid );
489 _pidMapTable[originalPid] = currentPid;
490 }
491 }
492
493 JTRACE ("Serializing PidMap Table") (numMaps) (o.filename());
494 printPidMaps();
495 }
496
497 void dmtcp::VirtualPidTable::serializePidMapEntry (
498 jalib::JBinarySerializer& o, pid_t& originalPid, pid_t& currentPid )
499 {
500 JSERIALIZE_ASSERT_POINT ( "PidMap:[" );
501 o & originalPid & currentPid;
502 JSERIALIZE_ASSERT_POINT ( "]" );
503 }
504
505 void dmtcp::VirtualPidTable::serializeEntryCount ( jalib::JBinarySerializer& o,
506 size_t& count )
507 {
508 JSERIALIZE_ASSERT_POINT ( "NumEntries:[" );
509 o & count;
510 JSERIALIZE_ASSERT_POINT ( "]" );
511 JTRACE("Num PidMaps:")(count);
512 }
513
514 void dmtcp::VirtualPidTable::InsertIntoPidMapFile( pid_t originalPid, pid_t currentPid)
515 {
516
517 dmtcp::string pidMapFile = "/proc/self/fd/"
518 + jalib::XToString ( PROTECTED_PIDMAP_FD );
519 dmtcp::string pidMapCountFile = "/proc/self/fd/"
520 + jalib::XToString ( PROTECTED_PIDMAPCNT_FD );
521
522 pidMapFile = jalib::Filesystem::ResolveSymlink ( pidMapFile );
523 pidMapCountFile = jalib::Filesystem::ResolveSymlink ( pidMapCountFile );
524
525 JASSERT ( pidMapFile.length() > 0 && pidMapCountFile.length() > 0 )
526 ( pidMapFile )( pidMapCountFile );
527
528 // Create Serializers
529 jalib::JBinarySerializeWriterRaw mapwr( pidMapFile, PROTECTED_PIDMAP_FD );
530 jalib::JBinarySerializeWriterRaw countwr(pidMapCountFile, PROTECTED_PIDMAPCNT_FD );
531 jalib::JBinarySerializeReaderRaw countrd(pidMapCountFile, PROTECTED_PIDMAPCNT_FD );
532
533 // Lock fileset before any operations
534 Util::lockFile(PROTECTED_PIDMAP_FD);
535 _do_lock_tbl();
536
537 // Read old number of saved pid maps
538 countrd.rewind();
539 size_t numMaps;
540 serializeEntryCount (countrd,numMaps);
541 // Serialize new pair
542 serializePidMapEntry (mapwr, originalPid, currentPid );
543
544 // Commit changes into map count file
545 countwr.rewind();
546 numMaps++;
547 serializeEntryCount (countwr,numMaps);
548
549 _do_unlock_tbl();
550 Util::unlockFile(PROTECTED_PIDMAP_FD);
551 }
552
553 void dmtcp::VirtualPidTable::readPidMapsFromFile()
554 {
555 dmtcp::string pidMapFile = "/proc/self/fd/"
556 + jalib::XToString ( PROTECTED_PIDMAP_FD );
557 pidMapFile = jalib::Filesystem::ResolveSymlink ( pidMapFile );
558 dmtcp::string pidMapCountFile = "/proc/self/fd/"
559 + jalib::XToString ( PROTECTED_PIDMAPCNT_FD );
560 pidMapCountFile = jalib::Filesystem::ResolveSymlink ( pidMapCountFile );
561 JASSERT ( pidMapFile.length() > 0 && pidMapCountFile.length() > 0 )
562 ( pidMapFile )( pidMapCountFile );
563
564 JTRACE ( "Read PidMaps from file" ) ( pidMapCountFile ) ( pidMapFile );
565
566 _real_close( PROTECTED_PIDMAP_FD );
567 _real_close( PROTECTED_PIDMAPCNT_FD );
568
569 jalib::JBinarySerializeReader maprd( pidMapFile);
570 jalib::JBinarySerializeReader countrd(pidMapCountFile);
571
572 // Read number of PID mappings
573 size_t numMaps;
574 serializeEntryCount (countrd,numMaps);
575
576 // Read pidMapping content
577 pid_t originalPid;
578 pid_t currentPid;
579 while ( numMaps-- > 0 ){
580 serializePidMapEntry ( maprd, originalPid, currentPid );
581 _pidMapTable[originalPid] = currentPid;
582 }
583 printPidMaps();
584 }
585
586 #endif