instrumentation: add next-share/
[cs-p2p-next.git] / instrumentation / next-share / BaseLib / UPnP / common / threadhotel.py
1 #############################################################
2 # Author: Ingar M. Arntzen
3 #############################################################
4
5 """
6 This implements a thread hotel where threads block for asynchronous replies 
7 after having made an non-blocking request. The thread hotel is typically used
8 to build a blocking API on top of a non-blocking.
9 """
10
11 import threading
12
13 #############################################################
14 # THREAD HOTEL
15 #############################################################
16
17 class ThreadHotel:
18
19     """Threads wait in the Thread Hotel until the reply associated with a given
20     request ID is available."""
21
22     class Room:
23         """Each thread is assigned his own room."""
24         def __init__(self):
25             self._bed = threading.Event()
26             self._reply = None
27             self._status = None
28         def goto_bed(self):
29             """Goto sleep."""
30             self._bed.wait()
31         def wakeup_call(self):
32             """Wake up sleeping thread."""
33             self._bed.set()
34         def get_reply(self):
35             """Get the asynchronous reply."""
36             return (self._status, self._reply)
37         def set_reply(self, status, reply):
38             """Leave the asynchronous reply."""
39             self._reply = reply
40             self._status = status
41
42     def __init__(self):
43         self._rooms = {}
44         self._lock = threading.Lock()
45
46     def _get_room(self, request_id):
47         """Get a room given a request_id. 
48         The request id is assumed to be unique. """
49         if not self._rooms.has_key(request_id):
50             self._rooms[request_id] = ThreadHotel.Room()
51         return self._rooms[request_id]
52         
53     def _leave_room(self, request_id):
54         """Leave room after having been woke up."""
55         del self._rooms[request_id]
56
57     def reserve(self, request_id):
58         """Reserve a room before the asynchronous request is
59         actually carried out."""
60         self._lock.acquire()
61         self._get_room(request_id)
62         self._lock.release()
63
64     def wait_reply(self, request_id):
65         """Wait for a reply given a unique request id."""
66         self._lock.acquire()
67         room = self._get_room(request_id)
68         status, reply = room.get_reply()
69         # Reply is available -> Return immedately
70         if not reply:
71             # Wait
72             self._lock.release()
73             room.goto_bed()            
74             # Wake up
75             self._lock.acquire()
76             status, reply = room.get_reply()
77         # Leave with Reply
78         self._leave_room(request_id)
79         self._lock.release()
80         return status, reply    
81
82     def wakeup(self, request_id, status, reply):
83         """Deliver reply for given request id, thereby waking up
84         sleeping thread."""
85         if self._rooms.has_key(request_id):
86             self._lock.acquire()
87             room = self._rooms[request_id]
88             room.set_reply(status, reply)
89             # Wake up potential visitor.
90             room.wakeup_call()
91             self._lock.release()
92             return True
93         else: return False
94
95     def is_waiting(self, request_id):
96         """Is threre a thread waiting for a given request id?"""
97         return self._rooms.has_key(request_id)
98