1
0
Fork 0

Linux/macOS: use flock() to implement exclusive launch.

Previous implementation wasn’t correct, use a better one now. In the
case of a non-clean exit we will leave a stale .pid file in FG_HOME,
but we clear stale files on the next launch.
This commit is contained in:
James Turner 2020-03-17 16:05:24 +00:00
parent a22d7943a4
commit f903cdfa50
2 changed files with 54 additions and 27 deletions

View file

@ -473,35 +473,56 @@ bool fgInitHome()
}
#else
// write our PID, and check writeability
SGPath pidPath(dataPath, "fgfs.pid");
if (pidPath.exists()) {
SG_LOG(SG_GENERAL, SG_ALERT, "flightgear instance already running, switching to FG_HOME read-only.");
// set a marker property so terrasync/navcache don't try to write
// from secondary instances
fgSetBool("/sim/fghome-readonly", true);
return true;
}
char buf[16];
SGPath pidPath(dataPath, "fgfs_lock.pid");
std::string ps = pidPath.utf8Str();
// do open+unlink trick to the file is deleted on exit, even if we
// crash or exit(-1)
ssize_t len = snprintf(buf, 16, "%d", getpid());
int fd = ::open(ps.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644);
if (fd >= 0) {
result = ::write(fd, buf, len) == len;
if( ::unlink(ps.c_str()) != 0 ) // delete file when app quits
result = false;
}
if (pidPath.exists()) {
int fd = ::open(ps.c_str(), O_RDONLY, 0644);
if (fd < 0) {
SG_LOG(SG_GENERAL, SG_ALERT, "failed to open local file:" << pidPath
<< "\n\tdue to:" << simgear::strutils::error_string(errno));
return false;
}
if (!result) {
flightgear::fatalMessageBoxWithoutExit(
"File permissions problem",
"Can't write to user-data storage folder, check file permissions "
"and FG_HOME.",
"User-data at '" + dataPath.utf8Str() + "'.");
return false;
int err = ::flock(fd, LOCK_EX | LOCK_NB);
if (err < 0) {
if ( errno == EWOULDBLOCK) {
SG_LOG(SG_GENERAL, SG_ALERT, "flightgear instance already running, switching to FG_HOME read-only.");
// set a marker property so terrasync/navcache don't try to write
// from secondary instances
fgSetBool("/sim/fghome-readonly", true);
return true;
} else {
SG_LOG(SG_GENERAL, SG_ALERT, "failed to lock file:" << pidPath
<< "\n\tdue to:" << simgear::strutils::error_string(errno));
return false;
}
}
// we locked it!
result = true;
} else {
char buf[16];
std::string ps = pidPath.utf8Str();
ssize_t len = snprintf(buf, 16, "%d\n", getpid());
int fd = ::open(ps.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
SG_LOG(SG_GENERAL, SG_ALERT, "failed to open local file:" << pidPath
<< "\n\tdue to:" << simgear::strutils::error_string(errno));
return false;
}
write(fd, buf, len);
int err = flock(fd, LOCK_EX);
if (err != 0) {
SG_LOG(SG_GENERAL, SG_ALERT, "failed to lock file:" << pidPath
<< "\n\tdue to:" << simgear::strutils::error_string(errno));
return false;
}
result = true;
}
#endif
fgSetBool("/sim/fghome-readonly", false);
@ -514,6 +535,11 @@ void fgShutdownHome()
if (static_fgHomeWriteMutex) {
CloseHandle(static_fgHomeWriteMutex);
}
#else
if (fgGetBool("/sim/fghome-readonly") == false) {
SGPath pidPath = globals->get_fg_home() / "fgfs_lock.pid";
pidPath.remove();
}
#endif
}

View file

@ -706,6 +706,7 @@ int fgMainInit( int argc, char **argv )
int result = fgOSMainLoop();
frame_signal.clear();
fgOSCloseWindow();
fgShutdownHome();
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(mln_stopped);