From dbf6d7e783ff86c60d39f5000e341082d2604e85 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 20 Jun 2006 17:48:10 +0000 Subject: * Concurrent GC on Cygwin. --- src/libstore/pathlocks.cc | 129 ++++++++++++++++++++++++++++------------------ 1 file changed, 79 insertions(+), 50 deletions(-) (limited to 'src/libstore/pathlocks.cc') diff --git a/src/libstore/pathlocks.cc b/src/libstore/pathlocks.cc index bb1644a9a9fd..8d0e6c3299ac 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::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); } } -- cgit 1.4.1