1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-28 17:51:15 +02:00

* Concurrent GC on Cygwin.

This commit is contained in:
Eelco Dolstra 2006-06-20 17:48:10 +00:00
parent cc51f9c539
commit dbf6d7e783
3 changed files with 146 additions and 73 deletions

View file

@ -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);
}
}