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 "uniquepid.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include <string>
26 #include <pwd.h>
27 #include <sstream>
28 #include <fcntl.h>
29 #include <sys/stat.h>
30 #include "constants.h"
31 #include "../jalib/jconvert.h"
32 #include "../jalib/jfilesystem.h"
33 #include "../jalib/jserialize.h"
34 #include "syscallwrappers.h"
35 #include "protectedfds.h"
36
37 static dmtcp::string checkpointFilename_str;
38 static dmtcp::string ckptFilesDirName_str;
39
40 inline static long theUniqueHostId(){
41 #ifdef USE_GETHOSTID
42 return ::gethostid()
43 #else
44 //gethostid() calls socket() on some systems, which we don't want
45 char buf[512];
46 JASSERT(::gethostname(buf, sizeof(buf))==0)(JASSERT_ERRNO);
47 //so return a bad hash of our hostname
48 long h = 0;
49 for(char* i=buf; *i!='\0'; ++i)
50 h = (*i) + (331*h);
51 //make it positive for good measure
52 return h>0 ? h : -1*h;
53 #endif
54 }
55
56
57 static dmtcp::UniquePid& nullProcess()
58 {
59 static char buf[sizeof(dmtcp::UniquePid)];
60 static dmtcp::UniquePid* t=NULL;
61 if(t==NULL) t = new (buf) dmtcp::UniquePid(0,0,0);
62 return *t;
63 }
64 static dmtcp::UniquePid& theProcess()
65 {
66 static char buf[sizeof(dmtcp::UniquePid)];
67 static dmtcp::UniquePid* t=NULL;
68 if(t==NULL) t = new (buf) dmtcp::UniquePid(0,0,0);
69 return *t;
70 }
71 static dmtcp::UniquePid& parentProcess()
72 {
73 static char buf[sizeof(dmtcp::UniquePid)];
74 static dmtcp::UniquePid* t=NULL;
75 if(t==NULL) t = new (buf) dmtcp::UniquePid(0,0,0);
76 return *t;
77 }
78
79 // _generation field of return value may later have to be modified.
80 // So, it can't return a const dmtcp::UniquePid
81 dmtcp::UniquePid& dmtcp::UniquePid::ThisProcess(bool disableJTrace /*=false*/)
82 {
83 if ( theProcess() == nullProcess() )
84 {
85 theProcess() = dmtcp::UniquePid ( theUniqueHostId() ,
86 ::_real_getpid(),
87 ::time(NULL) );
88 if (disableJTrace == false)
89 JTRACE ( "recalculated process UniquePid..." ) ( theProcess() );
90 }
91
92 return theProcess();
93 }
94
95 dmtcp::UniquePid& dmtcp::UniquePid::ParentProcess()
96 {
97 return parentProcess();
98 }
99
100 /*!
101 \fn dmtcp::UniquePid::UniquePid()
102 */
103 dmtcp::UniquePid::UniquePid()
104 :_pid ( 0 )
105 ,_hostid ( 0 )
106 {
107 memset ( &_time,0,sizeof ( _time ) );
108 }
109
110 dmtcp::UniquePid::UniquePid(pid_t pid)
111 :_pid ( pid )
112 {
113 _hostid = theUniqueHostId();
114 memset ( &_time,0,sizeof ( _time ) );
|
Event uninit_member: |
Non-static class member _generation is not initialized in this constructor nor in any functions that it calls. |
| Also see events: |
[member_decl] |
115 }
116
117
118 long dmtcp::UniquePid::hostid() const
119 {
120 return _hostid;
121 }
122
123
124 pid_t dmtcp::UniquePid::pid() const
125 {
126 return _pid;
127 }
128
129
130 time_t dmtcp::UniquePid::time() const
131 {
132 return _time;
133 }
134
135 int dmtcp::UniquePid::generation() const
136 {
137 return _generation;
138 }
139 void dmtcp::UniquePid::incrementGeneration()
140 {
141 _generation++;
142 }
143
144
145 const char* dmtcp::UniquePid::checkpointFilename()
146 {
147 if ( checkpointFilename_str.empty() )
148 {
149 dmtcp::ostringstream os;
150
151 const char* dir = getenv ( ENV_VAR_CHECKPOINT_DIR );
152 if ( dir != NULL ){
153 os << dir << '/';
154 }
155
156 os << CKPT_FILE_PREFIX
157 << jalib::Filesystem::GetProgramName()
158 << '_' << ThisProcess()
159 #ifdef UNIQUE_CHECKPOINT_FILENAMES
160 << "_XXXXX"
161 #endif
162 << CKPT_FILE_SUFFIX;
163
164 checkpointFilename_str = os.str();
165 }
166
167 #ifdef UNIQUE_CHECKPOINT_FILENAMES
168 // Include 5-digit generation number in filename, which changes
169 // after each checkpoint, during same process
170 JASSERT( Util::strEndsWith(checkpointFilename_str, CKPT_FILE_SUFFIX) )
171 ( checkpointFilename_str )
172 .Text ( "checkpointFilename_str doesn't end in .dmtcp" );
173 sprintf((char *)checkpointFilename_str.c_str()
174 + checkpointFilename_str.length() - strlen("XXXXX" CKPT_FILE_SUFFIX),
175 "%5.5d%s", ThisProcess().generation(), CKPT_FILE_SUFFIX);
176 #endif
177 return checkpointFilename_str.c_str();
178 }
179
180 dmtcp::string dmtcp::UniquePid::checkpointFilesDirName()
181 {
182 if ( ckptFilesDirName_str.empty() ) {
183 ckptFilesDirName_str = jalib::Filesystem::FileBaseName(checkpointFilename());
184 ckptFilesDirName_str.erase(ckptFilesDirName_str.length() -
185 strlen(CKPT_FILE_SUFFIX));
186 ckptFilesDirName_str += CKPT_FILES_SUBDIR_SUFFIX;
187 }
188 return ckptFilesDirName_str;
189 }
190
191 dmtcp::string dmtcp::UniquePid::dmtcpTableFilename()
192 {
193 static int count = 0;
194 dmtcp::ostringstream os;
195
196 os << getTmpDir() << "/dmtcpConTable." << ThisProcess()
197 << '_' << jalib::XToString ( count++ );
198 return os.str();
199 }
200
201 #ifdef PID_VIRTUALIZATION
202 dmtcp::string dmtcp::UniquePid::pidTableFilename()
203 {
204 static int count = 0;
205 dmtcp::ostringstream os;
206
207 os << getTmpDir() << "/dmtcpPidTable." << ThisProcess()
208 << '_' << jalib::XToString ( count++ );
209 return os.str();
210 }
211 #endif
212
213 const char* dmtcp::UniquePid::ptsSymlinkFilename ( char *ptsname )
214 {
215 char *devicename = ptsname + strlen ( "/dev/pts/" );
216
217 //this must be static so dmtcp::string isn't destructed
218 static dmtcp::string ptsSymlinkFilename_str;
219
220 ptsSymlinkFilename_str = getTmpDir();
221 ptsSymlinkFilename_str += "/pts_" + ThisProcess().toString() + '_';
222 ptsSymlinkFilename_str += devicename;
223
224 return ptsSymlinkFilename_str.c_str();
225 }
226
227 dmtcp::string dmtcp::UniquePid::getTmpDir()
228 {
229 dmtcp::string device = jalib::Filesystem::ResolveSymlink ( "/proc/self/fd/"
230 + jalib::XToString ( PROTECTED_TMPDIR_FD ) );
231 if ( device.empty() ) {
232 JWARNING ( false ) .Text ("Unable to determine DMTCP TMPDIR, retrying.");
233 setTmpDir(getenv(ENV_VAR_TMPDIR));
234 device = jalib::Filesystem::ResolveSymlink ( "/proc/self/fd/"
235 + jalib::XToString ( PROTECTED_TMPDIR_FD ) );
236 JASSERT ( !device.empty() )
237 .Text ( "Still unable to determine DMTCP_TMPDIR" );
238 }
239 return device;
240 }
241
242 /*
243 * setTmpDir() computes the TmpDir to be used by DMTCP. It does so by using
244 * DMTCP_TMPDIR env, current username, and hostname. Once computed, we open the
245 * directory on file descriptor PROTECTED_TMPDIR_FD. The getTmpDir() routine
246 * finds the TmpDir from looking at PROTECTED_TMPDIR_FD in proc file system.
247 *
248 * This mechanism was introduced to avoid calls to gethostname(), getpwuid()
249 * etc. while DmtcpWorker was still initializing (in constructor) or the
250 * process was restarting. gethostname(), getpwuid() will create a socket
251 * connect to some DNS server to find out hostname and username. The socket is
252 * closed only at next exec() and thus it leaves a dangling socket in the
253 * worker process. To resolve this issue, we make sure to call setTmpDir() only
254 * from dmtcp_checkpoint and dmtcp_restart process and once the user process
255 * has been exec()ed, we use getTmpDir() only.
256 */
257 void dmtcp::UniquePid::setTmpDir(const char* envVarTmpDir) {
258 dmtcp::string tmpDir;
259 #define HOSTNAME_MAX_CHARS 255
260
261 char hostname[HOSTNAME_MAX_CHARS + 1];
262 bzero(hostname, HOSTNAME_MAX_CHARS + 1);
263
264 JASSERT ( gethostname(hostname, HOSTNAME_MAX_CHARS) == 0 || errno == ENAMETOOLONG)
265 .Text ( "gethostname() failed" );
266
267 dmtcp::ostringstream o;
268
269 char *userName = const_cast<char *>("");
270 if ( getpwuid ( getuid() ) != NULL ) {
271 userName = getpwuid ( getuid() ) -> pw_name;
272 } else if ( getenv("USER") != NULL ) {
273 userName = getenv("USER");
274 }
275
276 if (envVarTmpDir) {
277 o << envVarTmpDir;
278 } else if (getenv("TMPDIR")) {
279 o << getenv("TMPDIR") << "/dmtcp-" << userName << "@" << hostname;
280 } else {
281 o << "/tmp/dmtcp-" << userName << "@" << hostname;
282 }
283
284 JASSERT(mkdir(o.str().c_str(), S_IRWXU) == 0 || errno == EEXIST)
285 (JASSERT_ERRNO) (o.str())
286 .Text("Error creating tmp directory");
287
288 JASSERT(0 == access(o.str().c_str(), X_OK|W_OK)) (o.str())
289 .Text("ERROR: Missing execute- or write-access to tmp dir");
290
291 int tmpFd = open ( o.str().c_str(), O_RDONLY );
292 JASSERT(tmpFd != -1);
293 JASSERT(dup2(tmpFd, PROTECTED_TMPDIR_FD)==PROTECTED_TMPDIR_FD);
294 close ( tmpFd );
295 }
296
297 /*!
298 \fn dmtcp::UniquePid::operator<() const
299 */
300 bool dmtcp::UniquePid::operator< ( const UniquePid& that ) const
301 {
302 #define TRY_LEQ(param) if(this->param != that.param) return this->param < that.param;
303 TRY_LEQ ( _hostid );
304 TRY_LEQ ( _pid );
305 TRY_LEQ ( _time );
306 return false;
307 }
308
309 bool dmtcp::UniquePid::operator== ( const UniquePid& that ) const
310 {
311 return _hostid==that.hostid()
312 && _pid==that.pid()
313 && _time==that.time();
314 }
315
316 dmtcp::ostream& dmtcp::operator<< ( dmtcp::ostream& o,const dmtcp::UniquePid& id )
317 {
318 o << std::hex << id.hostid() << '-' << std::dec << id.pid() << '-' << std::hex << id.time() << std::dec;
319 return o;
320 }
321
322 dmtcp::string dmtcp::UniquePid::toString() const{
323 dmtcp::ostringstream o;
324 o << *this;
325 return o.str();
326 }
327
328
329 void dmtcp::UniquePid::resetOnFork ( const dmtcp::UniquePid& newId )
330 {
331 // parentProcess() is for inspection tools
332 parentProcess() = ThisProcess();
333 JTRACE ( "Explicitly setting process UniquePid" ) ( newId );
334 theProcess() = newId;
335 checkpointFilename_str.clear();
336 ckptFilesDirName_str.clear();
337 }
338
339 bool dmtcp::UniquePid::isNull() const
340 {
341 return (*this == nullProcess());
342 }
343
344 void dmtcp::UniquePid::serialize ( jalib::JBinarySerializer& o )
345 {
346 UniquePid theCurrentProcess, theParentProcess;
347
348 if ( o.isWriter() )
349 {
350 theCurrentProcess = ThisProcess();
351 theParentProcess = ParentProcess();
352 }
353
354 o & theCurrentProcess & theParentProcess;
355
356 if ( o.isReader() )
357 {
358 theProcess() = theCurrentProcess;
359 parentProcess() = theParentProcess;
360 }
361 }
362