Add wait for PC to stop function to Lua
[jpcrr.git] / org / jpc / emulator / OutputConnectorLocking.java
blobf82e0b05a578952b4251048117984c099ea1c58b
1 /*
2 JPC-RR: A x86 PC Hardware Emulator
3 Release 1
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;
32 import java.util.*;
34 public class OutputConnectorLocking
36 //State: Object hasn't called waitOutput yet. Transitions to this state are
37 //signaled.
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
42 //signaled.
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()
59 inWaitingStart = 0;
60 inWaitingWait = 0;
61 inWaitingEnd = 0;
62 holdingStable = false;
63 waitAllActive = false;
64 nodeLists = new HashMap<Integer, ObjectNode>();
67 public class ObjectNode
69 //The object.
70 Object key;
71 //Current wait state.
72 int waitState;
73 //Waiting for output to stablize right now.
74 boolean aquiring;
75 //Previous node.
76 ObjectNode prev;
77 //Next node.
78 ObjectNode next;
81 private ObjectNode lookupNodeForKey(Object key)
83 int hash = System.identityHashCode(key);
84 ObjectNode node = nodeLists.get(hash);
85 while(node != null) {
86 if(node.key == key)
87 return node;
88 node = node.next;
90 return null;
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;
102 newNode.prev = null;
103 if(node != null)
104 node.prev = newNode;
105 newNode.next = node;
106 inWaitingStart++;
107 nodeLists.put(hash, newNode);
108 notifyAll(); //Conditions have changed.
111 public synchronized void unsubscribeOutput(Object handle)
113 ObjectNode node = lookupNodeForKey(handle);
114 if(node == null)
115 throw new IllegalStateException("Trying to unsubcribe nonexistent subscription");
116 if(node.aquiring)
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)
127 inWaitingStart--;
128 if(node.waitState == WAITING_WAIT)
129 inWaitingWait--;
130 if(node.waitState == WAITING_END)
131 inWaitingEnd--;
132 notifyAll(); //Conditions have changed.
135 public synchronized boolean waitOutput(Object handle)
137 ObjectNode node = lookupNodeForKey(handle);
138 if(node == null)
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)
146 try {
147 wait();
148 } catch(InterruptedException e) {
149 //Check for one final time.
150 if(node.waitState != WAITING_START || !holdingStable) {
151 node.aquiring = false;
152 return false;
154 break;
157 //Send it to "WAIT" state.
158 node.waitState = WAITING_WAIT;
159 inWaitingStart--;
160 inWaitingWait++;
162 //No need to inform others here. Only transitions to WAITING_START and WAITING_END are significant.
164 node.aquiring = false;
165 return true;
168 public synchronized void releaseOutput(Object handle)
170 ObjectNode node = lookupNodeForKey(handle);
171 if(node == null)
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;
178 inWaitingWait--;
179 inWaitingEnd++;
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.
190 while(waitAllActive)
191 try {
192 wait();
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;
207 inWaitingEnd--;
208 inWaitingStart++;
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)
218 try {
219 wait();
220 } catch(InterruptedException e) {
223 waitAllActive = false;
224 notifyAll(); //Conditions change.
225 holdingStable = false;