diff options
author | Joey Hess <joey@kitenet.net> | 2014-01-28 13:33:47 -0400 |
---|---|---|
committer | Joey Hess <joey@kitenet.net> | 2014-01-28 13:43:43 -0400 |
commit | 4a923c3ee0e238ccc17881179bec77c6531e3ad4 (patch) | |
tree | b685e8be2bc358c9f4c416b4728105b4bdc82898 /Utility/WinLock.hs | |
parent | b1eef1745c8fe5c2f8f2bf87573b1bd8eeb805df (diff) |
Windows file locking (atrociously horrible)
Diffstat (limited to 'Utility/WinLock.hs')
-rw-r--r-- | Utility/WinLock.hs | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/Utility/WinLock.hs b/Utility/WinLock.hs new file mode 100644 index 000000000..ebdba2b85 --- /dev/null +++ b/Utility/WinLock.hs @@ -0,0 +1,70 @@ +{- Windows lock files + - + - Copyright 2014 Joey Hess <joey@kitenet.net> + - + - Licensed under the GNU GPL version 3 or higher. + -} + +module Utility.WinLock ( + lockShared, + lockExclusive, + dropLock, + waitToLock +) where + +import Common + +import System.Win32.Types +import System.Win32.File +import Control.Concurrent + +{- Locking is exclusive, and prevents the file from being opened for read + - or write by any other process. So for advisory locking of a file, a + - different LockFile should be used. -} +type LockFile = FilePath + +type LockHandle = HANDLE + +{- Tries to lock a file with a shared lock, which allows other processes to + - also lock it shared. Fails is the file is exclusively locked. -} +lockShared :: LockFile -> IO (Maybe LockHandle) +lockShared = openLock fILE_SHARE_READ + +{- Tries to take an exclusive lock on a file. Fails if another process has + - a shared or exclusive lock. -} +lockExclusive :: LockFile -> IO (Maybe LockHandle) +lockExclusive = openLock fILE_SHARE_NONE + +{- Windows considers just opening a file enough to lock it. This will + - create the LockFile if it does not already exist. + - + - Will fail if the file is already open with an incompatable ShareMode. + - Note that this may happen if an unrelated process, such as a virus + - scanner, even looks at the file. See http://support.microsoft.com/kb/316609 + - + - Note that createFile busy-waits to try to avoid failing when some other + - process briefly has a file open. But that would make checking locks + - much more expensive, so is not done here. Thus, the use of c_CreateFile. + -} +openLock :: ShareMode -> LockFile -> IO (Maybe LockHandle) +openLock sharemode f = do + h <- withTString f $ \c_f -> + c_CreateFile c_f gENERIC_READ sharemode (maybePtr Nothing) + oPEN_ALWAYS fILE_ATTRIBUTE_NORMAL (maybePtr Nothing) + return $ if h == iNVALID_HANDLE_VALUE + then Nothing + else Just h + +dropLock :: LockHandle -> IO () +dropLock = closeHandle + +{- If the initial lock fails, this is a BUSY wait, and does not + - guarentee FIFO order of waiters. In other news, Windows is a POS. -} +waitToLock :: IO (Maybe LockHandle) -> IO LockHandle +waitToLock locker = takelock + where + takelock = go =<< locker + go (Just lck) = return lck + go Nothing = do + threadDelay (500000) -- half a second + takelock |