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:
parent
cc51f9c539
commit
dbf6d7e783
3 changed files with 146 additions and 73 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue