| 
					
				 | 
			
			
				@@ -19,6 +19,58 @@ def get_id(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return hostname, pid, tid 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+class TimeoutTimer: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    A timer for timeout checks (can also deal with no timeout, give timeout=None [default]). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    It can also compute and optionally execute a reasonable sleep time (e.g. to avoid 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    polling too often or to support thread/process rescheduling). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def __init__(self, timeout=None, sleep=None): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Initialize a timer. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        :param timeout: time out interval [s] or None (no timeout) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        :param sleep: sleep interval [s] (>= 0: do sleep call, <0: don't call sleep) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      or None (autocompute: use 10% of timeout, or 1s for no timeout) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if timeout is not None and timeout < 0: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            raise ValueError("timeout must be >= 0") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.timeout_interval = timeout 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if sleep is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if timeout is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                sleep = 1.0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                sleep = timeout / 10.0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.sleep_interval = sleep 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.start_time = None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.end_time = None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def __repr__(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return "<%s: start=%r end=%r timeout=%r sleep=%r>" % ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self.__class__.__name__, self.start_time, self.end_time, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self.timeout_interval, self.sleep_interval) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def start(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.start_time = time.time() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if self.timeout_interval is not None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self.end_time = self.start_time + self.timeout_interval 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return self 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def sleep(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if self.sleep_interval >= 0: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            time.sleep(self.sleep_interval) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def timed_out(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return self.end_time is not None and time.time() >= self.end_time 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def timed_out_or_sleep(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if self.timed_out(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return True 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self.sleep() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 class ExclusiveLock: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     """An exclusive Lock based on mkdir fs operation being atomic""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     class LockError(Error): 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -55,23 +107,12 @@ class ExclusiveLock: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def __repr__(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return "<%s: %r>" % (self.__class__.__name__, self.unique_name) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    def _get_timing(self, timeout, sleep): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def acquire(self, timeout=None, sleep=None): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if timeout is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             timeout = self.timeout 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        start = end = time.time() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if timeout is not None and timeout > 0: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            end += timeout 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if sleep is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             sleep = self.sleep 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if sleep is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if timeout is None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                sleep = 1.0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                sleep = max(0, timeout / 10.0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return start, sleep, end, timeout 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    def acquire(self, timeout=None, sleep=None): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        start, sleep, end, timeout = self._get_timing(timeout, sleep) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        timer = TimeoutTimer(timeout, sleep).start() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         while True: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 os.mkdir(self.path) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -79,9 +120,8 @@ class ExclusiveLock: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 if err.errno == errno.EEXIST:  # already locked 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     if self.by_me(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         return self 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if timeout is not None and time.time() > end: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if timer.timed_out_or_sleep(): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         raise self.LockTimeout(self.path) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    time.sleep(sleep) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 else: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     raise self.LockFailed(self.path, str(err)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             else: 
			 |