diff -r 9435b9008a58 -r 934f9131337b releasing/blocks/framework/src/Blocks/filelock.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/releasing/blocks/framework/src/Blocks/filelock.py Thu Sep 02 15:02:14 2010 +0800 @@ -0,0 +1,136 @@ +# +# Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +# All rights reserved. +# This component and the accompanying materials are made available +# under the terms of "Eclipse Public License v1.0" +# which accompanies this distribution, and is available +# at the URL "http://www.eclipse.org/legal/epl-v10.html". +# +# Initial Contributors: +# Nokia Corporation - initial contribution. +# +# Contributors: +# +# Description: +# Implements file locking mechanism +# + +# TODO: Prevent lock file deletion + +import os +import time +import errno +import logging +import platform +import tempfile +import atexit + +if platform.system() == "Windows": + import win32api + import win32process + +class AcquireError(Exception): + ''' Acquire Error ''' + +class FileLock(object): + ''' File lock ''' + POLL_INTERVAL = 0.1 + + def __init__(self, path): + logging.log(logging.DEBUG, "FileLock path: %s", path) + self.path = path + self.locked = False + self.creatorPid = os.getpid() + + def acquire(self, timeout=0): + '''Acquires lock on file + + Timeout in milliseconds, use None for no timeout + Returns True if succesful otherwise False + ''' + + if self.locked: + return True + + sleepcount = 0 + tmpname = atomicCreateTempFile(str(os.getpid())) + logging.log(logging.DEBUG, "FileLock acquire temp file name: %s", tmpname) + try: + while not self.locked: + try: + # Create file with pid atomically + os.rename(tmpname, self.path) + except OSError, ex: + # Lock in use? + if ex.errno == errno.EEXIST: + with open(self.path) as lockfile: + pid = int(lockfile.read()) + if processRunning(pid): + timeElapsed = sleepcount * (self.POLL_INTERVAL * 1000) + timeoutElapsed = timeout > 0 and timeElapsed >= timeout + if timeout == 0 or timeoutElapsed: + break + else: + time.sleep(self.POLL_INTERVAL) + sleepcount += 1 + else: + logging.info("Stale lock file detected with pid %s. Removing...", pid) + os.remove(self.path) + continue + raise + self.locked = True + # Call release on exit + atexit.register(self.release) + return self.locked + finally: + if not self.locked: + os.remove(tmpname) + return False + + def release(self): + if self.locked and os.getpid() == self.creatorPid: + if os.path.exists(self.path): + os.remove(self.path) + self.locked = False + +PROCESS_QUERY_INFORMATION = 0x0400 +STILL_ACTIVE = 259 +def processRunning(pid): + if platform.system() == "Windows": + running = False + try: + handle = win32api.OpenProcess(PROCESS_QUERY_INFORMATION, True, pid) + except win32api.error: + pass + else: + # code == 0 -> problem + code = win32process.GetExitCodeProcess(handle) + win32api.CloseHandle(handle) + running = code == STILL_ACTIVE + return running + else: + try: + os.kill(pid, 0) + except OSError: + return False + return True + +def atomicCreateTempFile(data): + tmpfile = tempfile.NamedTemporaryFile(bufsize=0, delete=False) + try: + tmpfile.write(data) + tmpfile.flush() + os.fsync(tmpfile.fileno()) + tmpfile.close() + return tmpfile.name + except Exception: # cleanup + tmpfile.close() + os.remove(tmpfile.name) + raise + +if __name__ == "__main__": + fl = FileLock(r"c:\temp\test123") + print "Acquiring..." + print fl.acquire(5000) + raw_input("press enter") + fl.release() \ No newline at end of file