forked from nmcl/JavaSim
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSemaphore.java
More file actions
172 lines (145 loc) · 4.46 KB
/
Semaphore.java
File metadata and controls
172 lines (145 loc) · 4.46 KB
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
/*
* Copyright 1990-2008, Mark Little, University of Newcastle upon Tyne
* and others contributors as indicated
* by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* (C) 1990-2008,
*/
package org.javasim;
/**
* Classic semaphores can "accumulate" more resources than the starting
* value. The ceiling parameter is used to indicate whether or not the
* resource count should ever go beyond the initial value - the default
* is that it should.
*/
public class Semaphore
{
/**
* The result of various operations:
* DONE - succeeded.
* NOTDONE - failed.
* WOULD_BLOCK - the operation would block the thread.
*
* Note that for some operations only DONE and NOTDONE
* could be returned.
*/
public enum Outcome { DONE, NOTDONE, WOULD_BLOCK };
/**
* Create a new mutex (resources = 1).
*/
public Semaphore()
{
numberWaiting = 0;
numberOfResources = 1;
currentResources = 1;
waitingList = new TriggerQueue();
}
/**
* Create a new semaphore (resources = number).
*
* @param number the number of resources.
*/
public Semaphore(long number)
{
numberWaiting = 0;
numberOfResources = number;
currentResources = number;
waitingList = new TriggerQueue();
}
public void finalize ()
{
if (numberWaiting != 0)
System.out
.println("Warning: semaphore being removed with clients waiting.");
}
/**
* Number of entities blocked on the semaphore.
*
* @return the number of entities blocked.
*/
public long numberWaiting ()
{
return numberWaiting;
}
/**
* Try to acquire the semaphore. Caller will be blocked if there are no free
* resources.
*
* @param toWait the entity that will be blocked.
* @return an indication of the outcome (DONE, NOTDONE)
* @throws RestartException if a reset occurs while an entity is blocked.
*/
public Outcome get (SimulationEntity toWait)
throws RestartException
{
if (currentResources > 0)
currentResources--;
else
{
numberWaiting++;
try
{
waitingList.insert(toWait);
}
catch (SimulationException e)
{
}
toWait.cancel();
}
return Outcome.DONE;
}
/**
* Only acquire the semaphore if it would not block the caller.
*
* @param toWait the entity to block.
* @return the outcome (DONE, NOTDONE or WOULD_BLOCK)
*/
public Outcome tryGet (SimulationEntity toWait)
throws RestartException
{
if (currentResources == 0)
return Outcome.WOULD_BLOCK;
else
return get(toWait);
}
/**
* Release the semaphore. No check is made to ensure the caller has
* previously acquired the semaphore.
*
* @return the outcome (DONE or NOTDONE)
*/
public Outcome release ()
{
// if there are things waiting they get triggered right here
// and recomsume the resource that would have been freed otherwise
// by this release call
if (numberWaiting > 0)
{
numberWaiting--;
waitingList.triggerFirst(true);
return Outcome.DONE;
}
else
{
// There is nothing waiting so we can free up a resource
currentResources++;
return Outcome.DONE;
}
}
private TriggerQueue waitingList;
private long numberWaiting;
private long numberOfResources;
private long currentResources;
}