2 JPC-RR: A x86 PC Hardware Emulator
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
;
35 public class OutputStatic
40 public class OutputPair
43 public OutputFrame frame
;
44 public OutputPair(short ch
, OutputFrame f
)
51 LinkedList
<OutputPair
> frames
;
57 frames
= new LinkedList
<OutputPair
>();
58 clients
= new HashSet
<OutputClient
>();
61 public long getLastTime()
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];
93 head
[16] = (byte)((tab
.size() >>> 8) & 0xFF);
94 head
[17] = (byte)(tab
.size() & 0xFF);
97 for(Map
.Entry
<Short
, OutputChannel
> e
: tab
.entrySet())
98 hunks
.add(e
.getValue().channelHeader());
101 for(byte[] hunk
: hunks
)
103 byte[] raw
= new byte[size
];
105 for(byte[] hunk
: hunks
) {
106 System
.arraycopy(hunk
, 0, raw
, size
, hunk
.length
);
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
)
122 lastTime
= frame
.getTime();
123 frames
.add(new OutputPair(chan
, frame
));
126 //Signal subscribers.
128 if(frames
.size() > 0)
129 timeBase
= frames
.getLast().frame
.getTime();
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()))
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;
155 f
= filter
.doFilter(frame
.frame
, frame
.channel
);
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)
181 else if(c
.getState() == 1)
183 else if(c
.getState() == 2)
185 else if(c
.getState() == 3)
187 else if(c
.getState() == 4)
190 throw new IllegalStateException("Client in illegal state #" + c
.getState());
193 else if(newState
== 0)
195 else if(newState
== 1)
197 else if(newState
== 2)
199 else if(newState
== 3)
201 else if(newState
== 4)
204 throw new IllegalStateException("Trying to set illegal state #" + newState
);
205 c
.setState(newState
);
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);
218 //Wait until everyone is released.
219 while(clientsNew
> 0 || clientsAquiring
> 0 || clientsAquired
> 0 || clientsReleasing
> 0)
222 } catch(InterruptedException e
) {
227 protected synchronized void clientNew(OutputClient c
)
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)
252 } catch(InterruptedException e
) {
253 if(c
.getState() == 0 && waiting
) {
254 setClientState(c
, 2);
261 setClientState(c
, 2);
264 setClientState(c
, 1);
266 //Wait for us to get the lock.
270 } catch(InterruptedException e
) {
274 if(c
.getState() == 1)
275 setClientState(c
, waiting ?
2 : 0);
280 protected synchronized void clientRelease(OutputClient c
, boolean waitAll
)
282 int state
= c
.getState();
284 throw new IllegalStateException("Trying to unlock already unlocked lock");
286 setClientState(c
, 3);
287 //Wait for everybody to release the lock.
288 while(clientsNew
> 0 || clientsAquiring
> 0 || clientsAquired
> 0)
291 } catch(InterruptedException e
) {
294 setClientState(c
, 4);