about summary refs log tree commit diff
path: root/src/pathlocks.cc
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2003-08-01T14·11+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2003-08-01T14·11+0000
commit545145cd582cd80b857760ec11bb5a91b6271506 (patch)
treee992edea7a634ed268ac10444add5dcfac6a4f05 /src/pathlocks.cc
parent9df93f30bda81ffa3cf040c146347e02d3a56666 (diff)
* normaliseFState() now locks all output paths prior to building, thus
  ensuring that simultaneous invocations of Nix don't clobber
  each other's  builds.

* Fixed a bug in `make install'.

Diffstat (limited to 'src/pathlocks.cc')
-rw-r--r--src/pathlocks.cc48
1 files changed, 48 insertions, 0 deletions
diff --git a/src/pathlocks.cc b/src/pathlocks.cc
new file mode 100644
index 000000000000..ac53dc6437d0
--- /dev/null
+++ b/src/pathlocks.cc
@@ -0,0 +1,48 @@
+#include <fcntl.h>
+
+#include "pathlocks.hh"
+
+
+PathLocks::PathLocks(const Strings & _paths)
+{
+    /* Note that `fds' is built incrementally so that the destructor
+       will only release those locks that we have already acquired. */
+
+    /* Sort the paths.  This assures that locks are always acquired in
+       the same order, thus preventing deadlocks. */
+    Strings paths(_paths);
+    paths.sort();
+    
+    /* Acquire the lock for each path. */
+    for (Strings::iterator i = paths.begin(); i != paths.end(); i++) {
+        string path = *i;
+        string lockPath = path + ".lock";
+
+        debug(format("locking path `%1%'") % path);
+        
+        /* Open/create the lock file. */
+        int fd = open(lockPath.c_str(), O_WRONLY | O_CREAT, 0666);
+        if (fd == -1)
+            throw SysError(format("opening lock file `%1%'") % lockPath);
+
+        fds.push_back(fd);
+
+        /* Lock it. */
+        struct flock lock;
+        lock.l_type = F_WRLCK; /* exclusive lock */
+        lock.l_whence = SEEK_SET;
+        lock.l_start = 0;
+        lock.l_len = 0; /* entire file */
+
+        while (fcntl(fd, F_SETLKW, &lock) == -1)
+            if (errno != EINTR)
+                throw SysError(format("acquiring lock on `%1%'") % lockPath);
+    }
+}
+
+
+PathLocks::~PathLocks()
+{
+    for (list<int>::iterator i = fds.begin(); i != fds.end(); i++)
+        close(*i);
+}