NHMLFixup v10
[jpcrr.git] / org / jpc / output / OutputStatic.java
blobf1a031dbd0fd46b8c2c07932c85e1bb1e63642d0
1 /*
2 JPC-RR: A x86 PC Hardware Emulator
3 Release 1
5 Copyright (C) 2007-2009 Isis Innovation Limited
6 Copyright (C) 2009-2010 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.output;
32 import java.io.*;
33 import java.util.*;
35 public class OutputStatic
37 long timeBase;
38 long lastTime;
40 public class OutputPair
42 public short channel;
43 public OutputFrame frame;
44 public OutputPair(short ch, OutputFrame f)
46 channel = ch;
47 frame = f;
51 LinkedList<OutputPair> frames;
53 public OutputStatic()
55 timeBase = 0;
56 lastTime = 0;
57 frames = new LinkedList<OutputPair>();
58 clients = new HashSet<OutputClient>();
61 public long getLastTime()
63 return lastTime;
66 Map<Short, OutputChannel> activeChannelTable;
68 public byte[] makeChannelTable()
70 return makeChannelTable(activeChannelTable);
73 public byte[] makeChannelTable(Map<Short, OutputChannel> tab)
75 List<byte[]> hunks = new LinkedList<byte[]>();
76 byte[] head = new byte[18];
77 head[0] = (byte)0xFF;
78 head[1] = (byte)0xFF;
79 head[2] = (byte)'J';
80 head[3] = (byte)'P';
81 head[4] = (byte)'C';
82 head[5] = (byte)'R';
83 head[6] = (byte)'R';
84 head[7] = (byte)'M';
85 head[8] = (byte)'U';
86 head[9] = (byte)'L';
87 head[10] = (byte)'T';
88 head[11] = (byte)'I';
89 head[12] = (byte)'D';
90 head[13] = (byte)'U';
91 head[14] = (byte)'M';
92 head[15] = (byte)'P';
93 head[16] = (byte)((tab.size() >>> 8) & 0xFF);
94 head[17] = (byte)(tab.size() & 0xFF);
95 hunks.add(head);
97 for(Map.Entry<Short, OutputChannel> e : tab.entrySet())
98 hunks.add(e.getValue().channelHeader());
100 int size = 0;
101 for(byte[] hunk : hunks)
102 size += hunk.length;
103 byte[] raw = new byte[size];
104 size = 0;
105 for(byte[] hunk : hunks) {
106 System.arraycopy(hunk, 0, raw, size, hunk.length);
107 size += hunk.length;
109 return raw;
112 public void updateChannelTable(Map<Short, OutputChannel> tab)
114 byte[] raw = makeChannelTable(tab);
115 addFrame((short)-1, new OutputFrameRaw(raw), false);
116 activeChannelTable = tab;
119 public void addFrame(short chan, OutputFrame frame, boolean sync)
121 synchronized(this) {
122 lastTime = frame.getTime();
123 frames.add(new OutputPair(chan, frame));
125 if(sync) {
126 //Signal subscribers.
127 waitReaders();
128 if(frames.size() > 0)
129 timeBase = frames.getLast().frame.getTime();
130 frames.clear();
134 public synchronized OutputFrame lastFrame(Class<? extends OutputFrame> clazz)
136 OutputFrame f = null;
137 for(OutputPair p : frames)
138 if(clazz == null || clazz.isAssignableFrom(p.frame.getClass()))
139 f = p.frame;
140 return f;
143 static public interface FrameFilter
145 public OutputFrame doFilter(OutputFrame f, short channel);
148 public synchronized long writeFrames(OutputStream out, FrameFilter filter) throws IOException
150 long localTimeBase = timeBase;
151 for(OutputPair frame : frames) {
152 long newTime = frame.frame.getTime();
153 OutputFrame f = null;
154 if(filter != null)
155 f = filter.doFilter(frame.frame, frame.channel);
156 else
157 f = frame.frame;
158 if(f != null) {
159 out.write(f.dump(frame.channel, localTimeBase));
160 if(newTime >= localTimeBase)
161 localTimeBase = newTime;
164 return localTimeBase;
167 volatile int clientsNew;
168 volatile int clientsAquiring;
169 volatile int clientsAquired;
170 volatile int clientsReleasing;
171 volatile int clientsReleased;
172 volatile boolean waiting;
173 Set<OutputClient> clients;
175 private void setClientState(OutputClient c, int newState)
177 if(c.getState() == -1)
179 else if(c.getState() == 0)
180 clientsNew--;
181 else if(c.getState() == 1)
182 clientsAquiring--;
183 else if(c.getState() == 2)
184 clientsAquired--;
185 else if(c.getState() == 3)
186 clientsReleasing--;
187 else if(c.getState() == 4)
188 clientsReleased--;
189 else
190 throw new IllegalStateException("Client in illegal state #" + c.getState());
191 if(newState == -1)
193 else if(newState == 0)
194 clientsNew++;
195 else if(newState == 1)
196 clientsAquiring++;
197 else if(newState == 2)
198 clientsAquired++;
199 else if(newState == 3)
200 clientsReleasing++;
201 else if(newState == 4)
202 clientsReleased++;
203 else
204 throw new IllegalStateException("Trying to set illegal state #" + newState);
205 c.setState(newState);
206 notifyAll();
209 private synchronized void waitReaders()
211 //Set all relesed back to new.
212 for(OutputClient c : clients)
213 if(c.getState() == 4)
214 setClientState(c, 0);
216 waiting = true;
217 notifyAll();
218 //Wait until everyone is released.
219 while(clientsNew > 0 || clientsAquiring > 0 || clientsAquired > 0 || clientsReleasing > 0)
220 try {
221 wait();
222 } catch(InterruptedException e) {
224 waiting = false;
227 protected synchronized void clientNew(OutputClient c)
229 if(clients.add(c)) {
230 c.setState(-1);
231 setClientState(c, 0);
235 protected synchronized void clientDestroy(OutputClient c)
237 if(clients.remove(c)) {
238 setClientState(c, -1);
242 protected synchronized boolean clientAquire(OutputClient c)
244 int state = c.getState();
245 if(state != 0 && state != 4)
246 throw new IllegalStateException("Trying to lock already locked lock (state=" + state + ")");
248 //Wait for released state to get cleared.
249 while(c.getState() == 4)
250 try {
251 wait();
252 } catch(InterruptedException e) {
253 if(c.getState() == 0 && waiting) {
254 setClientState(c, 2);
255 return true;
256 } else
257 return false;
260 if(waiting) {
261 setClientState(c, 2);
262 return true;
263 } else
264 setClientState(c, 1);
266 //Wait for us to get the lock.
267 while(!waiting)
268 try {
269 wait();
270 } catch(InterruptedException e) {
271 break;
274 if(c.getState() == 1)
275 setClientState(c, waiting ? 2 : 0);
277 return waiting;
280 protected synchronized void clientRelease(OutputClient c, boolean waitAll)
282 int state = c.getState();
283 if(state != 2)
284 throw new IllegalStateException("Trying to unlock already unlocked lock");
285 if(waitAll) {
286 setClientState(c, 3);
287 //Wait for everybody to release the lock.
288 while(clientsNew > 0 || clientsAquiring > 0 || clientsAquired > 0)
289 try {
290 wait();
291 } catch(InterruptedException e) {
294 setClientState(c, 4);