forked from SeattleTestbed/seattlelib_v2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsemaphore.r2py
187 lines (128 loc) · 5.07 KB
/
semaphore.r2py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
"""
Author: Justin Cappos
Start date: May 15th, 2009
Purpose: A simple library that provides a semaphore abstration on top of repy's locks...
"""
uniqueid = dy_import_module('uniqueid.r2py')
# this dictionary stores private data about the semaphores. The format of an
# entry is: {'semcount' = 0, 'blockedlist' = [], 'semlock'=createlock()}.
# semcount is the number of nodes that can do a down before it blocks.
# blockedlist is the set of nodes that are already blocked.
# it will never be true that 'semcount' > 0 AND 'blockedlist' != []
semaphore_handle_dict = {}
def semaphore_create():
"""
<Purpose>
Create a new semaphore and return it to the user.
<Arguments>
None
<Exceptions>
None
<Side Effects>
None.
<Returns>
The semaphore handle
"""
thissemhandle = uniqueid.uniqueid_getid()
newlock = createlock()
semaphore_handle_dict[thissemhandle] = {'semcount':0, 'blockedlist':[],
'semlock':newlock}
return thissemhandle
def semaphore_destroy(semaphorehandle):
"""
<Purpose>
Clean up a semaphore that is no longer needed. All currently blocked
threads will be unblocked. All future uses of the semaphore will fail.
<Arguments>
semaphorehandle: The semaphore handle to destroy
<Exceptions>
None
<Side Effects>
None.
<Returns>
True if it cleaned up the semaphore handle, False if the handle was
already cleaned up
"""
# Acquire the lock. If this fails, assume the semaphore has already been
# cleaned up
try:
# I intentionally index both of these so that if the handle is removed by
# another call to semaphore_destroy in the mean time. All calls that
# acquire the lock need to do this.
semaphore_handle_dict[semaphorehandle]['semlock'].acquire(True)
except (IndexError, KeyError):
return False
# NOTE: We will release all parties that are blocking on the semaphore...
# Is this the right thing to do?
for blockedthreadlock in semaphore_handle_dict[semaphorehandle]['blockedlist']:
blockedthreadlock.release()
# I need to get (and release) the lock so that I can unblock anyone waiting
# to modify the semaphore. (They will then get an error)
mylock = semaphore_handle_dict[semaphorehandle]['semlock']
del semaphore_handle_dict[semaphorehandle]
return True
def semaphore_up(semaphorehandle):
"""
<Purpose>
Increment a sempahore (possibly unblocking a thread)
<Arguments>
semaphorehandle: The semaphore handle
<Exceptions>
ValueError if the semaphorehandle is invalid.
<Side Effects>
None.
<Returns>
None
"""
try:
# I intentionally index both of these so that if the handle is removed by
# another call to semaphore_destroy in the mean time. All calls that
# acquire the lock need to do this.
semaphore_handle_dict[semaphorehandle]['semlock'].acquire(True)
except (IndexError, KeyError):
raise ValueError("Invalid or destroyed semaphore handle")
# If someone is blocked, then release the first one
if semaphore_handle_dict[semaphorehandle]['blockedlist']:
assert(semaphore_handle_dict[semaphorehandle]['semcount'] == 0)
thefirstblockedthread = semaphore_handle_dict[semaphorehandle]['blockedlist'].pop(0)
thefirstblockedthread.release()
else:
# If no one is blocked, instead increment the count...
semaphore_handle_dict[semaphorehandle]['semcount'] = semaphore_handle_dict[semaphorehandle]['semcount'] + 1
semaphore_handle_dict[semaphorehandle]['semlock'].release()
def semaphore_down(semaphorehandle):
"""
<Purpose>
Decrement a sempahore (possibly blocking this thread)
<Arguments>
semaphorehandle: The semaphore handle
<Exceptions>
ValueError if the semaphorehandle is invalid.
<Side Effects>
None.
<Returns>
None.
"""
try:
# I intentionally index both of these so that if the handle is removed by
# another call to semaphore_destroy in the mean time. All calls that
# acquire the lock need to do this.
semaphore_handle_dict[semaphorehandle]['semlock'].acquire(True)
except (IndexError, KeyError):
raise ValueError("Invalid or destroyed semaphore handle")
# If the semaphore count is 0, we should block. The list is a queue, so
# we should append a lock for ourselves to the end.
if semaphore_handle_dict[semaphorehandle]['semcount'] == 0:
# get a lock for us and do an acquire so that the next acquire will block.
mylock = createlock()
mylock.acquire(True)
semaphore_handle_dict[semaphorehandle]['blockedlist'].append(mylock)
# release the semaphore lock...
semaphore_handle_dict[semaphorehandle]['semlock'].release()
# acquire my lock... (someone who does an up or destroy will release us)
mylock.acquire(True)
else:
# Since the count is > 0, we should decrement
semaphore_handle_dict[semaphorehandle]['semcount'] = semaphore_handle_dict[semaphorehandle]['semcount'] - 1
# release the semaphore lock...
semaphore_handle_dict[semaphorehandle]['semlock'].release()