
Hi, for a program of mine (darcswatch[1]), a rather long running process is run at certain events (by cron, and by new emails). I want to achieve that: * Only one instance of the program runs at a time. * If new events come in while the program runs, it should re-run itself * There is information attached to the events (only one Bool ATM) So I’d like to implement something with this, or a similar, interface: ======================================================================= module MyLocking where -- | tries to get the lock. If it fails, notifies the running process -- to re-start itself afterwards, with the given information -- returns True if the lock was aquired lockOrMark :: Show a => FilePath -> a -> IO Bool -- | release the lock. If new events have come in, they are returned -- in the list, and the lock is still kept. If the list is empty, -- the lock was successfully released. releaseLock :: Read a => FilePath -> IO [a] ======================================================================= I would use this module in this way: realWork args = do someStuff args newArgs <- releaseLock "someDir/" unless (null newArgs) $ do -- we missed some events, so re-run and then try again. let newArg = combineInSomeWay newArgs realWork newArg main = do args <- getArgs l <- lockOrMark "someDir/" args when l $ do -- we got the lock, so lets work realWork args I hope this makes the idea clear. How could a possible implementation look like, when all operations should be atomic? I was considering this, would it work fine? lockOrMark would try to create a directory in the path. Whoever creates the directory has the lock. If it works, create. If it fails, because the directory already exists, then write the given args to a temporary file with a unique name, and move it into that directory. If that fails (because the directory has disappeared, i.e. the lock released), start over with trying to create the directory. If it works, then you are done. releaseLock would try to rmdir the directory. If that succeeds, no files have been in there, so no events were missed. If it does not succeed, then there were files. Read and delete them and return the list of arguments contained in them. Greetings, Joachim [1] http://darcswatch.nomeata.de/ -- Joachim Breitner e-Mail: mail@joachim-breitner.de Homepage: http://www.joachim-breitner.de ICQ#: 74513189 Jabber-ID: nomeata@joachim-breitner.de

Hello Joachim, Thursday, June 5, 2008, 7:22:44 PM, you wrote:
* Only one instance of the program runs at a time. * If new events come in while the program runs, it should re-run itself * There is information attached to the events (only one Bool ATM)
So I’d like to implement something with this, or a similar, interface:
isn't it better to provide os-independent interface to semaphores? named semaphores both on windows and unix may be used to implement functionality you required and it's a more natural way there is useful article [1] which describes both windows and unix way to threads/events/semaphores/mutexes. how about implementing lightweight library which abstracts over these differences? OTOH, i've just recalled one C++ library which does exactly this job [2]. may be providing Haskell interface for it will be a better idea? [1] http://www.ibm.com/developerworks/linux/library/l-ipc2lin1.html [2] Abstraction of multitasking, file IO and socket IO for Unix and Windows systems http://www.garret.ru/~knizhnik/sal-108.zip -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

Hi again, Am Donnerstag, den 05.06.2008, 17:22 +0200 schrieb Joachim Breitner:
Hi,
for a program of mine (darcswatch[1]), a rather long running process is run at certain events (by cron, and by new emails). I want to achieve that: * Only one instance of the program runs at a time. * If new events come in while the program runs, it should re-run itself * There is information attached to the events (only one Bool ATM)
So I’d like to implement something with this, or a similar, interface:
======================================================================= module MyLocking where
-- | tries to get the lock. If it fails, notifies the running process -- to re-start itself afterwards, with the given information -- returns True if the lock was aquired lockOrMark :: Show a => FilePath -> a -> IO Bool
-- | release the lock. If new events have come in, they are returned -- in the list, and the lock is still kept. If the list is empty, -- the lock was successfully released. releaseLock :: Read a => FilePath -> IO [a] =======================================================================
I wrote a module that provides this API. It can be found here: http://darcs.nomeata.de/darcswatch/src/LockRestart.hs I use it for darcswatch, you can see the relevant change here: http://darcs.nomeata.de/cgi-bin/darcsweb.cgi?r=darcswatch;a=filediff;h=20080... Actually, since only the call to "or" in the third changed line from the bottom is special to darcswatch, this can be moved into LockRestart, so the change to the program is reduced to this: config <- read `fmap` readFile (confdir ++ "config") + + lockRestart (cOutput config) patchNew or True (do_work config) + +do_work config patchNew = do putStrLn "Reading repositories..." or even config <- read `fmap` readFile (confdir ++ "config") + + lockRestart (cOutput config) patchNew or True $ \patchNew -> do + putStrLn "Reading repositories..." if you prefer. Enjoy, Joachim Breitner -- Joachim Breitner e-Mail: mail@joachim-breitner.de Homepage: http://www.joachim-breitner.de ICQ#: 74513189 Jabber-ID: nomeata@joachim-breitner.de
participants (2)
-
Bulat Ziganshin
-
Joachim Breitner