| 
									
										
										
										
											2000-02-04 15:10:34 +00:00
										 |  |  | """Mutual exclusion -- for use with module sched
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | A mutex has two pieces of state -- a 'locked' bit and a queue. | 
					
						
							|  |  |  | When the mutex is not locked, the queue is empty. | 
					
						
							|  |  |  | Otherwise, the queue contains 0 or more (function, argument) pairs | 
					
						
							|  |  |  | representing functions (or methods) waiting to acquire the lock. | 
					
						
							|  |  |  | When the mutex is unlocked while the queue is not empty, | 
					
						
							|  |  |  | the first queue entry is removed and its function(argument) pair called, | 
					
						
							|  |  |  | implying it now has the lock. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Of course, no multi-threading is implied -- hence the funny interface | 
					
						
							|  |  |  | for lock, where a function is called once the lock is aquired. | 
					
						
							|  |  |  | """
 | 
					
						
							| 
									
										
										
										
											1991-04-21 19:32:43 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-01-29 06:37:52 +00:00
										 |  |  | from collections import deque | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1991-12-26 13:06:29 +00:00
										 |  |  | class mutex: | 
					
						
							| 
									
										
										
										
											2001-01-14 23:47:14 +00:00
										 |  |  |     def __init__(self): | 
					
						
							|  |  |  |         """Create a new mutex -- initially unlocked.""" | 
					
						
							|  |  |  |         self.locked = 0 | 
					
						
							| 
									
										
										
										
											2004-01-29 06:37:52 +00:00
										 |  |  |         self.queue = deque() | 
					
						
							| 
									
										
										
										
											2000-02-04 15:10:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-14 23:47:14 +00:00
										 |  |  |     def test(self): | 
					
						
							|  |  |  |         """Test the locked bit of the mutex.""" | 
					
						
							|  |  |  |         return self.locked | 
					
						
							| 
									
										
										
										
											2000-02-04 15:10:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-14 23:47:14 +00:00
										 |  |  |     def testandset(self): | 
					
						
							|  |  |  |         """Atomic test-and-set -- grab the lock if it is not set,
 | 
					
						
							| 
									
										
										
										
											2002-04-04 22:55:58 +00:00
										 |  |  |         return True if it succeeded."""
 | 
					
						
							| 
									
										
										
										
											2001-01-14 23:47:14 +00:00
										 |  |  |         if not self.locked: | 
					
						
							|  |  |  |             self.locked = 1 | 
					
						
							| 
									
										
										
										
											2002-04-04 22:55:58 +00:00
										 |  |  |             return True | 
					
						
							| 
									
										
										
										
											2001-01-14 23:47:14 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2002-04-04 22:55:58 +00:00
										 |  |  |             return False | 
					
						
							| 
									
										
										
										
											2000-02-04 15:10:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-14 23:47:14 +00:00
										 |  |  |     def lock(self, function, argument): | 
					
						
							|  |  |  |         """Lock a mutex, call the function with supplied argument
 | 
					
						
							|  |  |  |         when it is acquired.  If the mutex is already locked, place | 
					
						
							|  |  |  |         function and argument in the queue."""
 | 
					
						
							|  |  |  |         if self.testandset(): | 
					
						
							|  |  |  |             function(argument) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.queue.append((function, argument)) | 
					
						
							| 
									
										
										
										
											2000-02-04 15:10:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-14 23:47:14 +00:00
										 |  |  |     def unlock(self): | 
					
						
							|  |  |  |         """Unlock a mutex.  If the queue is not empty, call the next
 | 
					
						
							|  |  |  |         function with its argument."""
 | 
					
						
							|  |  |  |         if self.queue: | 
					
						
							| 
									
										
										
										
											2004-01-29 06:37:52 +00:00
										 |  |  |             function, argument = self.queue.popleft() | 
					
						
							| 
									
										
										
										
											2001-01-14 23:47:14 +00:00
										 |  |  |             function(argument) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.locked = 0 |