2 JPC-RR: A x86 PC Hardware Emulator
5 Copyright (C) 2007-2009 Isis Innovation Limited
6 Copyright (C) 2009 H. Ilari Liusvaara
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License version 2 as published by
10 the Free Software Foundation.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 Based on JPC x86 PC Hardware emulator,
22 A project from the Physics Dept, The University of Oxford
24 Details about original JPC can be found at:
26 www-jpc.physics.ox.ac.uk
30 package org
.jpc
.emulator
;
34 public class OutputConnectorLocking
36 //State: Object hasn't called waitOutput yet. Transitions to this state are
38 private static final int WAITING_START
= 0;
39 //State: Object has called waitOutput but not releaseOutput.
40 private static final int WAITING_WAIT
= 1;
41 //State: Object has called releaseOutput. Transitions to this state are
43 private static final int WAITING_END
= 2;
44 //Number of objects in WAITING_START state.
45 private int inWaitingStart
;
46 //Number of objects in WAITING_WAIT state.
47 private int inWaitingWait
;
48 //Number of objects in WAITING_END state.
49 private int inWaitingEnd
;
50 //Output is held stable now.
51 private boolean holdingStable
;
52 //There's wait all in progress.
53 private boolean waitAllActive
;
54 //Lists of objects, indexed by java.lang.Object.hashCode()
55 private Map
<Integer
, ObjectNode
> nodeLists
;
57 public OutputConnectorLocking()
62 holdingStable
= false;
63 waitAllActive
= false;
64 nodeLists
= new HashMap
<Integer
, ObjectNode
>();
67 public class ObjectNode
73 //Waiting for output to stablize right now.
81 private ObjectNode
lookupNodeForKey(Object key
)
83 int hash
= System
.identityHashCode(key
);
84 ObjectNode node
= nodeLists
.get(hash
);
93 public synchronized void subscribeOutput(Object handle
)
95 if(lookupNodeForKey(handle
) != null)
96 throw new IllegalStateException("Trying to subcribe same object twice");
97 int hash
= System
.identityHashCode(handle
);
98 ObjectNode node
= nodeLists
.get(hash
);
99 ObjectNode newNode
= new ObjectNode();
100 newNode
.key
= handle
;
101 newNode
.waitState
= WAITING_START
;
107 nodeLists
.put(hash
, newNode
);
108 notifyAll(); //Conditions have changed.
111 public synchronized void unsubscribeOutput(Object handle
)
113 ObjectNode node
= lookupNodeForKey(handle
);
115 throw new IllegalStateException("Trying to unsubcribe nonexistent subscription");
117 throw new IllegalStateException("Trying to unsubcribe subscription that's waiting");
118 if(node
.prev
!= null)
119 node
.prev
.next
= node
.next
;
120 if(node
.next
!= null)
121 node
.next
.prev
= node
.prev
;
122 if(node
.prev
== null && node
.next
== null)
123 nodeLists
.remove(System
.identityHashCode(handle
));
124 else if(node
.prev
== null)
125 nodeLists
.put(System
.identityHashCode(handle
), node
.next
);
126 if(node
.waitState
== WAITING_START
)
128 if(node
.waitState
== WAITING_WAIT
)
130 if(node
.waitState
== WAITING_END
)
132 notifyAll(); //Conditions have changed.
135 public synchronized boolean waitOutput(Object handle
)
137 ObjectNode node
= lookupNodeForKey(handle
);
139 throw new IllegalStateException("Trying to wait with nonexistent subscription");
140 if(node
.waitState
== WAITING_WAIT
)
141 throw new IllegalStateException("Trying to wait twice with no release in between");
142 node
.aquiring
= true;
144 //Wait for object to become "START".
145 while(node
.waitState
!= WAITING_START
|| !holdingStable
)
148 } catch(InterruptedException e
) {
149 //Check for one final time.
150 if(node
.waitState
!= WAITING_START
|| !holdingStable
) {
151 node
.aquiring
= false;
157 //Send it to "WAIT" state.
158 node
.waitState
= WAITING_WAIT
;
162 //No need to inform others here. Only transitions to WAITING_START and WAITING_END are significant.
164 node
.aquiring
= false;
168 public synchronized void releaseOutput(Object handle
)
170 ObjectNode node
= lookupNodeForKey(handle
);
172 throw new IllegalStateException("Trying to release with nonexistent subscription");
173 if(node
.waitState
!= WAITING_WAIT
)
174 throw new IllegalStateException("Trying to release without wait");
176 //Send it to "END" state.
177 node
.waitState
= WAITING_END
;
181 notifyAll(); //Conditions change.
184 public synchronized void releaseOutputWaitAll(Object handle
)
186 waitAllActive
= true;
187 releaseOutput(handle
);
189 //Now wait for all objects to release.
193 } catch(InterruptedException e
) {
197 public synchronized void holdOutput()
199 holdingStable
= true;
201 //Move everything from "END" to "START".
202 for(Map
.Entry
<Integer
,ObjectNode
> lists
: nodeLists
.entrySet()) {
203 ObjectNode listNode
= lists
.getValue();
204 while(listNode
!= null) {
205 if(listNode
.waitState
== WAITING_END
) {
206 listNode
.waitState
= WAITING_START
;
210 listNode
= listNode
.next
;
214 notifyAll(); //Conditions change.
216 //Now wait for all objects to go to "END" state.
217 while(inWaitingStart
> 0 || inWaitingWait
> 0)
220 } catch(InterruptedException e
) {
223 waitAllActive
= false;
224 notifyAll(); //Conditions change.
225 holdingStable
= false;