package sieveapplet;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
// import java.util.*;
// import java.util.List;
import com.sun.java.util.collections.*;
import com.sun.java.util.collections.List;
//------------------------------------------------------------------------
// Channels
//------------------------------------------------------------------------
class Cell {
public A value;
public Cell () {}
public String toString () { return "Cell"; }
}
class Action {
static abstract class Guard {
abstract void register ();
abstract void unregister ();
}
static class Writer extends Guard {
final Action action;
final int index;
final Channel channel;
final A value;
Writer (Action a, int i, Channel c, A v) {
action=a; index=i; channel=c; value=v;
}
void register () { channel.registerWriter(this); }
void unregister () { channel.unregisterWriter(); }
}
static class Reader extends Guard {
final Action action;
final int index;
final Channel channel;
final Cell cell;
Reader (Action a, int i, Channel c, Cell l) {
action=a; index=i; channel=c; cell=l;
}
void register () { channel.registerReader(this); }
void unregister () { channel.unregisterReader(); }
}
public final Thread thread;
protected List guards;
public Action () {
thread = Thread.currentThread();
guards = new ArrayList();
}
public void addWriter (int i, Channel c, A v) {
guards.add(new Writer(this,i,c,v));
}
public void addReader (int i, Channel c, Cell l) {
guards.add(new Reader(this,i,c,l));
}
public static void write (Channel chan, A value) {
Action a = new Action();
a.addWriter(0,chan,value);
a.choose();
}
public static A read (Channel chan) {
Cell cell = new Cell();
Action a = new Action();
a.addReader(0,chan,cell);
a.choose();
return cell.value;
}
final static int VOID = -1;
private int choice = VOID;
public int choose () {
if (!uncommitted()) throw new Error("choice already made");
ListIterator it = guards.listIterator();
while (it.hasNext() && uncommitted()) it.next().register();
try {
synchronized (this) { while (uncommitted()) wait(); }
} catch (InterruptedException e) {
throw new Error("Interrupted");
}
while (it.hasPrevious()) it.previous().unregister();
return choice;
}
/* synchronized */ boolean uncommitted() { // synchronized by Channel
return choice==VOID;
}
/* synchronized */ void commit(int index) { // synchronized by Channel
choice=index; notify();
}
}
final class Channel {
private Action.Writer writer;
private Action.Reader reader;
public Channel () { writer = null; reader = null; }
synchronized void registerWriter (Action.Writer w) {
if (writer!=null) throw new Error("multiple writers");
writer = w;
if (reader!=null) exchange();
}
synchronized void registerReader (Action.Reader r) {
if (reader!=null) throw new Error("multiple readers");
reader = r;
if (writer!=null) exchange();
}
/* synchronized */ void exchange () { // synchronised by register
if (reader.action==writer.action) throw new Error("read & write in one action");
Action act0 = reader.action;
Action act1 = writer.action;
if (act0.hashCode() processes =
Collections.synchronizedList(new ArrayList());
private Thread thread;
public Process (final String name) {
thread = new Thread(name) {
public void run () {
Monitor.monitor.startProcess(Process.this.getName());
Process.this.run();
Monitor.monitor.stopProcess(Process.this.getName());
processes.remove(Process.this);
}
};
}
public abstract void run ();
public String getName () { return thread.getName(); }
public void start () {
processes.add(this);
thread.start();
}
public void join () throws InterruptedException { thread.join(); }
public void drive () {
try {
this.start();
this.join();
while (processes.size()>0) Thread.yield();
// while (group.activeCount() > 0) Thread.yield();
} catch (InterruptedException e) {
System.err.println("error: interrupted");
e.printStackTrace();
}
Monitor.monitor.done();
}
}
//------------------------------------------------------------------------
// Sieve of Eratosthenes
//------------------------------------------------------------------------
final class Sieve {
private final int size;
public Sieve (int size) { this.size = size; }
public Process counter
(final Channel out, final Channel done)
{
return new Process ("counter") {
public void run () {
for (int i=2; i<=size; i++) {
Action.write(out,new Integer(i));
}
Action.write(done,"done");
}
};
}
public Process filter
(final int d, final Channel in, final Channel out,
final Channel donein, final Channel doneout)
{
return new Process ("filter("+d+")") {
public void run () {
loop: while (true) {
final int NEXT=0, DONE=1;
Cell icell = new Cell();
Cell scell = new Cell();
Action a = new Action();
a.addReader(NEXT, in, icell);
a.addReader(DONE, donein, scell);
switch (a.choose()) {
case NEXT:
int i = icell.value.intValue();
if (i%d != 0) Action.write(out, new Integer(i));
break;
case DONE:
String s = scell.value;
Action.write(doneout,s);
break loop;
}
}
}
};
}
public Process printer () {
return new Process ("printer") {
public void run () {
int count = 0;
Channel ch = new Channel();
Channel done = new Channel();
counter(ch,done).start();
loop: while (true) {
final int NEXT=0, DONE=1;
Cell icell = new Cell();
Cell scell = new Cell();
Action a = new Action();
a.addReader(NEXT, ch, icell);
a.addReader(DONE, done, scell);
switch (a.choose()) {
case NEXT:
count++;
int prime = icell.value.intValue();
Channel newch = new Channel();
Channel newdone = new Channel();
filter(prime,ch,newch,done,newdone).start();
ch = newch;
done = newdone;
break;
case DONE:
break loop;
}
}
}
};
}
}
//------------------------------------------------------------------------
// Monitors
//------------------------------------------------------------------------
abstract class Monitor {
public static Monitor monitor = new NullMonitor();
public abstract void startProcess (String name);
public abstract void stopProcess (String name);
public abstract void sendMessage
(Channel chan, A value, String writer, String reader);
public abstract void done ();
}
class NullMonitor extends Monitor {
public NullMonitor () {}
public void startProcess (String name) {}
public void stopProcess (String name) {}
public void sendMessage
(Channel chan, A value, String writer, String reader) {}
public void done () {}
}
class TraceMonitor extends Monitor {
protected final Trace trace;
public TraceMonitor (Trace trace) { this.trace = trace; }
public void startProcess (String name) { trace.startProcess(name); }
public void stopProcess (String name) { trace.stopProcess(name); }
public void sendMessage
(Channel chan, A value, String writer, String reader)
{
trace.sendMessage(value.toString(), writer, reader);
if (Math.random() < 0.5) Thread.yield();
}
public void done () {}
}
//------------------------------------------------------------------------
// Traces for monitoring
//------------------------------------------------------------------------
class ProcessData {
public static final int RUNNING = Integer.MAX_VALUE;
public final String name;
public final int index;
public final int start;
public int stop = RUNNING;
public ProcessData (String name, int index, int start) {
this.name = name;
this.index = index;
this.start = start;
}
}
class MessageData {
public final String message;
public final int writer;
public final int reader;
public MessageData (String message, int writer, int reader) {
this.message = message;
this.writer = writer;
this.reader = reader;
}
}
class Trace {
private Map processMap;
private List processes;
private List messages;
public Map processMap () { return processMap; }
public List processes () { return processes; }
public List messages () { return messages; }
public int now () { return messages.size(); }
public Trace () {
processMap = new HashMap();
processes = new ArrayList();
messages = new ArrayList();
}
public synchronized void clear () {
processMap.clear();
processes.clear();
messages.clear();
}
public synchronized void startProcess (String name) {
if (processMap.containsKey(name)) {
throw new Error("process "+name+" already registered");
}
ProcessData p = new ProcessData(name, processes.size(), now());
processMap.put(name, p);
processes.add(p);
}
public synchronized void stopProcess (String name) {
if (!processMap.containsKey(name)) {
throw new Error("process "+name+" not registered");
}
ProcessData p = processMap.get(name);
p.stop = now();
}
private synchronized int getIndex (String name) {
if (!processMap.containsKey(name)) {
throw new Error("process "+name+" not registered");
}
ProcessData p = processMap.get(name);
return p.index;
}
public synchronized void sendMessage
(String message, String writer, String reader)
{
MessageData m =
new MessageData(message, getIndex(writer), getIndex(reader));
messages.add(m);
}
public synchronized Trace cloneTrace () {
return new Trace(this);
}
private Trace (Trace t) {
// make an unmodifiable copy for use by display
processMap = Collections.unmodifiableMap(new HashMap(t.processMap));
processes = Collections.unmodifiableList(new ArrayList(t.processes));
messages = Collections.unmodifiableList(new ArrayList(t.messages));
}
public String toString () {
StringBuffer buf = new StringBuffer();
ListIterator i = processes.listIterator();
while (i.hasNext()) {
ProcessData p = i.next();
buf.append(
"process: "+p.name+", "+
"index: "+p.index+", "+
"start: "+p.start+", "+
(p.stop==ProcessData.RUNNING?"running":"stop: "+p.stop)+"\n"
);
}
Iterator j = messages.iterator();
while (j.hasNext()) {
MessageData m = j.next();
buf.append(m.message+" from "+m.writer+" to "+m.reader+"\n");
}
return buf.toString();
}
}
//------------------------------------------------------------------------
// Graphical monitoring
//------------------------------------------------------------------------
class Chart extends Canvas {
int threadWidth = 2;
int blockWidth = 6;
int blockHeight = 2;
int arrowWidth = 3;
int arrowHeight = 6;
int nameLength = 12;
FontMetrics metrics;
int descent;
int gapHeight;
int gapWidth;
int headHeight;
int tailHeight;
int bodyHeight;
int width;
int height;
Dimension size;
private Trace trace;
public Chart (Trace trace) {
this.trace = trace;
}
private void computeParameters () {
metrics = getFontMetrics(getFont());
descent = metrics.getDescent();
gapHeight = metrics.getHeight()+descent;
gapWidth = metrics.stringWidth("x")*nameLength;
headHeight = gapHeight + gapHeight/2;
tailHeight = gapHeight/2;
bodyHeight = gapHeight*(trace.messages().size()+1);
width = gapWidth*(trace.processes().size()+1);
height = headHeight+bodyHeight+tailHeight;
size = new Dimension(width,height);
}
public synchronized Dimension getPreferredSize() {
computeParameters();
return size;
}
public synchronized Dimension getMinimumSize() {
computeParameters();
return size;
}
public synchronized void paint (Graphics g) {
computeParameters();
Rectangle bounds = g.getClipBounds();
// render thread names and thread lines
int istart = bounds.x/gapWidth - 1;
int istop = (bounds.x+bounds.width)/gapWidth;
istart = Math.max(0, Math.min(trace.processes().size(), istart));
istop = Math.max(0, Math.min(trace.processes().size(), istop));
ListIterator i = trace.processes().listIterator(istart);
int x = gapWidth*(istart+1);
while (i.hasNext() && i.nextIndex() < istop) {
ProcessData p = i.next();
int ystart = headHeight + gapHeight*p.start;
int ystop = headHeight +
((p.stop!=ProcessData.RUNNING)?(gapHeight*p.stop+gapHeight/2):(gapHeight*trace.now()));
g.setColor(Color.black);
centerString(g, p.name, x, ystart-blockHeight-descent);
g.setColor(Color.red);
g.fillRect(x-blockWidth/2, ystart-blockHeight, blockWidth, blockHeight);
g.fillRect(x-threadWidth/2, ystart, threadWidth, ystop-ystart);
if (p.stop != ProcessData.RUNNING) {
g.fillRect(x-blockWidth/2, ystop, blockWidth, blockHeight);
}
x += gapWidth;
}
// compute which messages are of interest, given bounds
int jstart = (bounds.y-headHeight)/gapHeight - 1;
int jstop = (bounds.y+bounds.height-headHeight)/gapHeight + 1;
jstart = Math.max(0, Math.min(trace.messages().size(), jstart));
jstop = Math.max(0, Math.min(trace.messages().size(), jstop));
// render messages
ListIterator j = trace.messages().listIterator(jstart);
int y = headHeight+(jstart+1)*gapHeight;
while (j.hasNext() && j.nextIndex()");
}
}
}