blob: 9271d346caa862b904267ee36fe5915aabe06d89 [file] [log] [blame]
Guido van Rossum54f22ed2000-02-04 15:10:34 +00001"""Mutual exclusion -- for use with module sched
Guido van Rossume2e162e1991-04-21 19:32:43 +00002
Guido van Rossum54f22ed2000-02-04 15:10:34 +00003A mutex has two pieces of state -- a 'locked' bit and a queue.
4When the mutex is not locked, the queue is empty.
5Otherwise, the queue contains 0 or more (function, argument) pairs
6representing functions (or methods) waiting to acquire the lock.
7When the mutex is unlocked while the queue is not empty,
8the first queue entry is removed and its function(argument) pair called,
9implying it now has the lock.
10
11Of course, no multi-threading is implied -- hence the funny interface
12for lock, where a function is called once the lock is aquired.
13"""
14
Guido van Rossumce084481991-12-26 13:06:29 +000015class mutex:
Guido van Rossum7bc817d1993-12-17 15:25:27 +000016 def __init__(self):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000017 """Create a new mutex -- initially unlocked."""
Guido van Rossume2e162e1991-04-21 19:32:43 +000018 self.locked = 0
19 self.queue = []
Guido van Rossum54f22ed2000-02-04 15:10:34 +000020
Guido van Rossume2e162e1991-04-21 19:32:43 +000021 def test(self):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000022 """Test the locked bit of the mutex."""
Guido van Rossume2e162e1991-04-21 19:32:43 +000023 return self.locked
Guido van Rossum54f22ed2000-02-04 15:10:34 +000024
Guido van Rossume2e162e1991-04-21 19:32:43 +000025 def testandset(self):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000026 """Atomic test-and-set -- grab the lock if it is not set,
27 return true if it succeeded."""
Guido van Rossume2e162e1991-04-21 19:32:43 +000028 if not self.locked:
29 self.locked = 1
30 return 1
31 else:
32 return 0
Guido van Rossum54f22ed2000-02-04 15:10:34 +000033
Guido van Rossum89a78691992-12-14 12:57:56 +000034 def lock(self, function, argument):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000035 """Lock a mutex, call the function with supplied argument
36 when it is acquired. If the mutex is already locked, place
37 function and argument in the queue."""
Guido van Rossume2e162e1991-04-21 19:32:43 +000038 if self.testandset():
39 function(argument)
40 else:
Guido van Rossumb7f48e31996-10-08 14:06:17 +000041 self.queue.append((function, argument))
Guido van Rossum54f22ed2000-02-04 15:10:34 +000042
Guido van Rossume2e162e1991-04-21 19:32:43 +000043 def unlock(self):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000044 """Unlock a mutex. If the queue is not empty, call the next
45 function with its argument."""
Guido van Rossume2e162e1991-04-21 19:32:43 +000046 if self.queue:
47 function, argument = self.queue[0]
48 del self.queue[0]
49 function(argument)
50 else:
51 self.locked = 0