* Catch SIGINT to terminate cleanly when the user tries to interrupt
Nix. This is to prevent Berkeley DB from becoming wedged. Unfortunately it is not possible to throw C++ exceptions from a signal handler. In fact, you can't do much of anything except change variables of type `volatile sig_atomic_t'. So we set an interrupt flag in the signal handler and check it at various strategic locations in the code (by calling checkInterrupt()). Since this is unlikely to cover all cases (e.g., (semi-)infinite loops), sometimes SIGTERM may now be required to kill Nix.
This commit is contained in:
parent
08719c6c97
commit
447089a5f6
13 changed files with 86 additions and 4 deletions
|
|
@ -80,6 +80,7 @@ void Transaction::moveTo(Transaction & t)
|
|||
|
||||
void Database::requireEnv()
|
||||
{
|
||||
checkInterrupt();
|
||||
if (!env) throw Error("database environment not open");
|
||||
}
|
||||
|
||||
|
|
@ -310,6 +311,8 @@ TableId Database::openTable(const string & tableName)
|
|||
bool Database::queryString(const Transaction & txn, TableId table,
|
||||
const string & key, string & data)
|
||||
{
|
||||
checkInterrupt();
|
||||
|
||||
try {
|
||||
Db * db = getDb(table);
|
||||
|
||||
|
|
@ -367,6 +370,7 @@ bool Database::queryStrings(const Transaction & txn, TableId table,
|
|||
void Database::setString(const Transaction & txn, TableId table,
|
||||
const string & key, const string & data)
|
||||
{
|
||||
checkInterrupt();
|
||||
try {
|
||||
Db * db = getDb(table);
|
||||
Dbt kt((void *) key.c_str(), key.length());
|
||||
|
|
@ -402,6 +406,7 @@ void Database::setStrings(const Transaction & txn, TableId table,
|
|||
void Database::delPair(const Transaction & txn, TableId table,
|
||||
const string & key)
|
||||
{
|
||||
checkInterrupt();
|
||||
try {
|
||||
Db * db = getDb(table);
|
||||
Dbt kt((void *) key.c_str(), key.length());
|
||||
|
|
@ -423,9 +428,11 @@ void Database::enumTable(const Transaction & txn, TableId table,
|
|||
DestroyDbc destroyDbc(dbc);
|
||||
|
||||
Dbt kt, dt;
|
||||
while (dbc->get(&kt, &dt, DB_NEXT) != DB_NOTFOUND)
|
||||
while (dbc->get(&kt, &dt, DB_NEXT) != DB_NOTFOUND) {
|
||||
checkInterrupt();
|
||||
keys.push_back(
|
||||
string((char *) kt.get_data(), kt.get_size()));
|
||||
}
|
||||
|
||||
} catch (DbException e) { rethrow(e); }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,9 @@ void runProgram(const string & program,
|
|||
int status;
|
||||
if (waitpid(pid, &status, 0) != pid)
|
||||
throw Error("unable to wait for child");
|
||||
|
||||
|
||||
checkInterrupt();
|
||||
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
if (keepFailed) {
|
||||
printMsg(lvlTalkative,
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ Path normaliseStoreExpr(const Path & _nePath, PathSet pending)
|
|||
for (PathSet::iterator i = ne.derivation.inputs.begin();
|
||||
i != ne.derivation.inputs.end(); i++)
|
||||
{
|
||||
checkInterrupt();
|
||||
Path nfPath = normaliseStoreExpr(*i, pending);
|
||||
realiseClosure(nfPath, pending);
|
||||
/* !!! nfPath should be a root of the garbage collector while
|
||||
|
|
@ -193,6 +194,7 @@ Path normaliseStoreExpr(const Path & _nePath, PathSet pending)
|
|||
for (Paths::iterator j = refPaths.begin();
|
||||
j != refPaths.end(); j++)
|
||||
{
|
||||
checkInterrupt();
|
||||
Path path = *j;
|
||||
elem.refs.insert(path);
|
||||
if (inClosures.find(path) != inClosures.end())
|
||||
|
|
@ -209,6 +211,7 @@ Path normaliseStoreExpr(const Path & _nePath, PathSet pending)
|
|||
PathSet donePaths;
|
||||
|
||||
while (!usedPaths.empty()) {
|
||||
checkInterrupt();
|
||||
PathSet::iterator i = usedPaths.begin();
|
||||
Path path = *i;
|
||||
usedPaths.erase(i);
|
||||
|
|
@ -291,6 +294,7 @@ void ensurePath(const Path & path, PathSet pending)
|
|||
for (Paths::iterator i = subPaths.begin();
|
||||
i != subPaths.end(); i++)
|
||||
{
|
||||
checkInterrupt();
|
||||
try {
|
||||
normaliseStoreExpr(*i, pending);
|
||||
if (isValidPath(path)) return;
|
||||
|
|
@ -337,6 +341,8 @@ static void requisitesWorker(const Path & nePath,
|
|||
bool includeExprs, bool includeSuccessors,
|
||||
PathSet & paths, PathSet & doneSet)
|
||||
{
|
||||
checkInterrupt();
|
||||
|
||||
if (doneSet.find(nePath) != doneSet.end()) return;
|
||||
doneSet.insert(nePath);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,11 +19,14 @@ bool lockFile(int fd, LockType lockType, bool wait)
|
|||
lock.l_len = 0; /* entire file */
|
||||
|
||||
if (wait) {
|
||||
while (fcntl(fd, F_SETLKW, &lock) != 0)
|
||||
while (fcntl(fd, F_SETLKW, &lock) != 0) {
|
||||
checkInterrupt();
|
||||
if (errno != EINTR)
|
||||
throw SysError(format("acquiring/releasing lock"));
|
||||
}
|
||||
} else {
|
||||
while (fcntl(fd, F_SETLK, &lock) != 0) {
|
||||
checkInterrupt();
|
||||
if (errno == EACCES || errno == EAGAIN) return false;
|
||||
if (errno != EINTR)
|
||||
throw SysError(format("acquiring/releasing lock"));
|
||||
|
|
@ -55,6 +58,7 @@ PathLocks::PathLocks(const PathSet & _paths)
|
|||
|
||||
/* Acquire the lock for each path. */
|
||||
for (Paths::iterator i = paths.begin(); i != paths.end(); i++) {
|
||||
checkInterrupt();
|
||||
Path path = *i;
|
||||
Path lockPath = path + ".lock";
|
||||
|
||||
|
|
@ -87,6 +91,7 @@ PathLocks::~PathLocks()
|
|||
close(*i);
|
||||
|
||||
for (Paths::iterator i = paths.begin(); i != paths.end(); i++) {
|
||||
checkInterrupt();
|
||||
if (deletePaths) {
|
||||
/* This is not safe in general! */
|
||||
unlink(i->c_str());
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ static void search(const string & s,
|
|||
for (Strings::iterator i = ids.begin();
|
||||
i != ids.end(); )
|
||||
{
|
||||
checkInterrupt();
|
||||
if (s.find(*i) == string::npos)
|
||||
i++;
|
||||
else {
|
||||
|
|
@ -31,6 +32,8 @@ static void search(const string & s,
|
|||
void checkPath(const string & path,
|
||||
Strings & ids, Strings & seen)
|
||||
{
|
||||
checkInterrupt();
|
||||
|
||||
struct stat st;
|
||||
if (lstat(path.c_str(), &st))
|
||||
throw SysError(format("getting attributes of path `%1%'") % path);
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ void copyPath(const Path & src, const Path & dst)
|
|||
source.fd = fds[0];
|
||||
restorePath(dst, source);
|
||||
_exit(0);
|
||||
} catch (exception & e) {
|
||||
} catch (exception & e) {
|
||||
cerr << "error: " << e.what() << endl;
|
||||
}
|
||||
_exit(1);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue