Adding utils
[watersofshiloah] / src / util / concurrent.py
1 #!/usr/bin/env python
2
3 from __future__ import with_statement
4
5 import os
6 import errno
7 import time
8 import functools
9 import contextlib
10
11
12 def synchronized(lock):
13         """
14         Synchronization decorator.
15
16         >>> import misc
17         >>> misc.validate_decorator(synchronized(object()))
18         """
19
20         def wrap(f):
21
22                 @functools.wraps(f)
23                 def newFunction(*args, **kw):
24                         lock.acquire()
25                         try:
26                                 return f(*args, **kw)
27                         finally:
28                                 lock.release()
29                 return newFunction
30         return wrap
31
32
33 @contextlib.contextmanager
34 def qlock(queue, gblock = True, gtimeout = None, pblock = True, ptimeout = None):
35         """
36         Locking with a queue, good for when you want to lock an item passed around
37
38         >>> import Queue
39         >>> item = 5
40         >>> lock = Queue.Queue()
41         >>> lock.put(item)
42         >>> with qlock(lock) as i:
43         ...     print i
44         5
45         """
46         item = queue.get(gblock, gtimeout)
47         try:
48                 yield item
49         finally:
50                 queue.put(item, pblock, ptimeout)
51
52
53 @contextlib.contextmanager
54 def flock(path, timeout=-1):
55         WAIT_FOREVER = -1
56         DELAY = 0.1
57         timeSpent = 0
58
59         acquired = False
60
61         while timeSpent <= timeout or timeout == WAIT_FOREVER:
62                 try:
63                         fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR)
64                         acquired = True
65                         break
66                 except OSError, e:
67                         if e.errno != errno.EEXIST:
68                                 raise
69                 time.sleep(DELAY)
70                 timeSpent += DELAY
71
72         assert acquired, "Failed to grab file-lock %s within timeout %d" % (path, timeout)
73
74         try:
75                 yield fd
76         finally:
77                 os.unlink(path)