about summary refs log tree commit diff
path: root/src/libstore/pathlocks.cc
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2006-06-20T17·48+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2006-06-20T17·48+0000
commitdbf6d7e783ff86c60d39f5000e341082d2604e85 (patch)
tree34522d5619d43bfdc7ef1a87639a17ae2b1093de /src/libstore/pathlocks.cc
parentcc51f9c539a3822c84a2285efcec11b577727234 (diff)
* Concurrent GC on Cygwin.
Diffstat (limited to 'src/libstore/pathlocks.cc')
-rw-r--r--src/libstore/pathlocks.cc129
1 files changed, 79 insertions, 50 deletions
diff --git a/src/libstore/pathlocks.cc b/src/libstore/pathlocks.cc
index bb1644a9a9..8d0e6c3299 100644
--- a/src/libstore/pathlocks.cc
+++ b/src/libstore/pathlocks.cc
@@ -12,6 +12,79 @@
 #endif
 
 
+int openLockFile(const Path & path, bool create)
+{
+    AutoCloseFD fd;
+
+#ifdef __CYGWIN__
+    /* On Cygwin we have to open the lock file without "DELETE"
+       sharing mode; otherwise Windows will allow open lock files to
+       be deleted (which is almost but not quite what Unix does). */
+    char win32Path[MAX_PATH + 1];
+    cygwin_conv_to_full_win32_path(path.c_str(), win32Path);
+
+    SECURITY_ATTRIBUTES sa; /* required, otherwise inexplicably bad shit happens */
+    sa.nLength = sizeof sa;
+    sa.lpSecurityDescriptor = 0;
+    sa.bInheritHandle = TRUE;
+    HANDLE h = CreateFile(win32Path, GENERIC_READ | GENERIC_WRITE,
+        FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, 
+        (create ? OPEN_ALWAYS : OPEN_EXISTING), 
+        FILE_ATTRIBUTE_NORMAL, 0);
+    if (h == INVALID_HANDLE_VALUE) {
+        if (create || GetLastError() != ERROR_FILE_NOT_FOUND)
+            throw Error(format("opening lock file `%1%'") % path);
+        fd = -1;
+    }
+    else
+        fd = cygwin_attach_handle_to_fd((char *) path.c_str(), -1, h, 1, O_RDWR);
+#else        
+    fd = open(path.c_str(), O_RDWR | (create ? O_CREAT : 0), 0666);
+    if (fd == -1 && (create || errno != ENOENT))
+        throw SysError(format("opening lock file `%1%'") % path);
+#endif
+
+    return fd.borrow();
+}
+
+
+void deleteLockFilePreClose(const Path & path, int fd)
+{
+#ifndef __CYGWIN__
+    /* Get rid of the lock file.  Have to be careful not to introduce
+       races. */
+    /* On Unix, write a (meaningless) token to the file to indicate to
+       other processes waiting on this lock that the lock is stale
+       (deleted). */
+    unlink(path.c_str());
+    writeFull(fd, (const unsigned char *) "d", 1);
+    /* Note that the result of unlink() is ignored; removing the lock
+       file is an optimisation, not a necessity. */
+#endif
+}
+
+
+void deleteLockFilePostClose(const Path & path)
+{
+#ifdef __CYGWIN__
+    /* On Windows, just try to delete the lock file.  This will fail
+       if anybody still has the file open.  We cannot use unlink()
+       here, because Cygwin emulates Unix semantics of allowing an
+       open file to be deleted (but fakes it - the file isn't actually
+       deleted until later, so a file with the same name cannot be
+       created in the meantime). */
+    char win32Path[MAX_PATH + 1];
+    cygwin_conv_to_full_win32_path(path.c_str(), win32Path);
+    if (DeleteFile(win32Path))
+        debug(format("delete of `%1%' succeeded") % path.c_str());
+    else
+        /* Not an error: probably means that the lock is still opened
+           by someone else. */
+        debug(format("delete of `%1%' failed: %2%") % path.c_str() % GetLastError());
+#endif
+}
+
+
 bool lockFile(int fd, LockType lockType, bool wait)
 {
     struct flock lock;
@@ -94,26 +167,7 @@ void PathLocks::lockPaths(const PathSet & _paths, const string & waitMsg)
         while (1) {
 
             /* Open/create the lock file. */
-#ifdef __CYGWIN__
-	    char win32Path[MAX_PATH];
-	    cygwin_conv_to_full_win32_path(lockPath.c_str(), win32Path);
-
-	    SECURITY_ATTRIBUTES sa;
-	    sa.nLength = sizeof sa;
-	    sa.lpSecurityDescriptor = 0;
-	    sa.bInheritHandle = TRUE;
-	    HANDLE h = CreateFile(win32Path, GENERIC_READ, 
-	        FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_ALWAYS, 
-                FILE_ATTRIBUTE_NORMAL, 0);
-	    if (h == INVALID_HANDLE_VALUE)
-		throw Error(format("opening lock file `%1%'") % lockPath);
-
-	    fd = cygwin_attach_handle_to_fd((char *) lockPath.c_str(), -1, h, 1, O_RDWR);
-#else        
-            fd = open(lockPath.c_str(), O_WRONLY | O_CREAT, 0666);
-            if (fd == -1)
-                throw SysError(format("opening lock file `%1%'") % lockPath);
-#endif
+	    fd = openLockFile(lockPath, true);
 
             /* Acquire an exclusive lock. */
             if (!lockFile(fd, ltWrite, false)) {
@@ -148,40 +202,15 @@ void PathLocks::lockPaths(const PathSet & _paths, const string & waitMsg)
 PathLocks::~PathLocks()
 {
     for (list<FDPair>::iterator i = fds.begin(); i != fds.end(); i++) {
-#ifndef __CYGWIN__
-        if (deletePaths) {
-	    /* Get rid of the lock file.  Have to be careful not to
-	       introduce races. */
-            /* On Unix, write a (meaningless) token to the file to
-               indicate to other processes waiting on this lock that
-               the lock is stale (deleted). */
-            unlink(i->second.c_str());
-            writeFull(i->first, (const unsigned char *) "d", 1);
-            /* Note that the result of unlink() is ignored; removing
-               the lock file is an optimisation, not a necessity. */
-        }
-#endif
+        if (deletePaths) deleteLockFilePreClose(i->second, i->first);
+
         lockedPaths.erase(i->second);
         if (close(i->first) == -1)
             printMsg(lvlError,
                 format("error (ignored): cannot close lock file on `%1%'") % i->second);
-#ifdef __CYGWIN__
-	if (deletePaths) {
-	    /* On Windows, just try to delete the lock file.  This
-	       will fail if anybody still has the file open.  We
-	       cannot use unlink() here, because Cygwin emulates Unix
-	       semantics of allowing an open file to be deleted (but
-	       fakes it - the file isn't actually deleted until later,
-	       so a file with the same name cannot be created in the
-	       meantime). */
-	    char win32Path[MAX_PATH];
-	    cygwin_conv_to_full_win32_path(i->second.c_str(), win32Path);
-	    if (DeleteFile(win32Path))
-		debug(format("delete of `%1%' succeeded") % i->second.c_str());
-	    else
-		debug(format("delete of `%1%' failed: %2%") % i->second.c_str() % GetLastError());
-	}
-#endif
+
+	if (deletePaths) deleteLockFilePostClose(i->second);
+
         debug(format("lock released on `%1%'") % i->second);
     }
 }