releasing/blocks/framework/src/Blocks/filelock.py
changeset 632 934f9131337b
--- /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