about summary refs log tree commit diff
path: root/src/libstore
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2004-01-15T20·23+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2004-01-15T20·23+0000
commit447089a5f699f085661287dec4b3d88219f67068 (patch)
treee460c615181db3e6b6f8b48e4e934b372ecac043 /src/libstore
parent08719c6c97e25fb362eeb7463d8b764ecefc53cb (diff)
* 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.

Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/db.cc9
-rw-r--r--src/libstore/exec.cc4
-rw-r--r--src/libstore/normalise.cc6
-rw-r--r--src/libstore/pathlocks.cc7
-rw-r--r--src/libstore/references.cc3
-rw-r--r--src/libstore/store.cc2
6 files changed, 27 insertions, 4 deletions
diff --git a/src/libstore/db.cc b/src/libstore/db.cc
index c89d6b197d..d2a0026384 100644
--- a/src/libstore/db.cc
+++ b/src/libstore/db.cc
@@ -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); }
 }
diff --git a/src/libstore/exec.cc b/src/libstore/exec.cc
index b25423b444..01577143dc 100644
--- a/src/libstore/exec.cc
+++ b/src/libstore/exec.cc
@@ -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, 
diff --git a/src/libstore/normalise.cc b/src/libstore/normalise.cc
index 7ef45e2923..51f90207ea 100644
--- a/src/libstore/normalise.cc
+++ b/src/libstore/normalise.cc
@@ -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);
 
diff --git a/src/libstore/pathlocks.cc b/src/libstore/pathlocks.cc
index 321e965bb3..d4f980c648 100644
--- a/src/libstore/pathlocks.cc
+++ b/src/libstore/pathlocks.cc
@@ -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());
diff --git a/src/libstore/references.cc b/src/libstore/references.cc
index 2daf4d4f4d..9b20b980a1 100644
--- a/src/libstore/references.cc
+++ b/src/libstore/references.cc
@@ -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);
diff --git a/src/libstore/store.cc b/src/libstore/store.cc
index c1d95ab8c5..4cd77796ea 100644
--- a/src/libstore/store.cc
+++ b/src/libstore/store.cc
@@ -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);