]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/python/mutex.py
dist/mkfile: run binds in subshell
[plan9front.git] / sys / lib / python / mutex.py
1 """Mutual exclusion -- for use with module sched
2
3 A mutex has two pieces of state -- a 'locked' bit and a queue.
4 When the mutex is not locked, the queue is empty.
5 Otherwise, the queue contains 0 or more (function, argument) pairs
6 representing functions (or methods) waiting to acquire the lock.
7 When the mutex is unlocked while the queue is not empty,
8 the first queue entry is removed and its function(argument) pair called,
9 implying it now has the lock.
10
11 Of course, no multi-threading is implied -- hence the funny interface
12 for lock, where a function is called once the lock is aquired.
13 """
14
15 from collections import deque
16
17 class mutex:
18     def __init__(self):
19         """Create a new mutex -- initially unlocked."""
20         self.locked = 0
21         self.queue = deque()
22
23     def test(self):
24         """Test the locked bit of the mutex."""
25         return self.locked
26
27     def testandset(self):
28         """Atomic test-and-set -- grab the lock if it is not set,
29         return True if it succeeded."""
30         if not self.locked:
31             self.locked = 1
32             return True
33         else:
34             return False
35
36     def lock(self, function, argument):
37         """Lock a mutex, call the function with supplied argument
38         when it is acquired.  If the mutex is already locked, place
39         function and argument in the queue."""
40         if self.testandset():
41             function(argument)
42         else:
43             self.queue.append((function, argument))
44
45     def unlock(self):
46         """Unlock a mutex.  If the queue is not empty, call the next
47         function with its argument."""
48         if self.queue:
49             function, argument = self.queue.popleft()
50             function(argument)
51         else:
52             self.locked = 0