* 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