|
From: <ls...@us...> - 2008-11-09 12:24:56
|
Revision: 4691
http://jnode.svn.sourceforge.net/jnode/?rev=4691&view=rev
Author: lsantha
Date: 2008-11-09 12:24:49 +0000 (Sun, 09 Nov 2008)
Log Message:
-----------
Support for releasing owned monitors on thread stop. Internal execution methods on behalf of an isolate. Improved isolate termination.
Modified Paths:
--------------
trunk/core/src/classpath/vm/java/lang/Thread.java
trunk/core/src/core/org/jnode/vm/isolate/VmIsolate.java
trunk/core/src/core/org/jnode/vm/scheduler/Monitor.java
trunk/core/src/core/org/jnode/vm/scheduler/MonitorManager.java
trunk/core/src/core/org/jnode/vm/scheduler/VmScheduler.java
trunk/core/src/core/org/jnode/vm/scheduler/VmThread.java
trunk/core/src/test/org/jnode/test/core/StatusLinkTest.java
Added Paths:
-----------
trunk/core/src/core/org/jnode/vm/isolate/IsolateThreadFactory.java
Modified: trunk/core/src/classpath/vm/java/lang/Thread.java
===================================================================
--- trunk/core/src/classpath/vm/java/lang/Thread.java 2008-11-09 10:31:21 UTC (rev 4690)
+++ trunk/core/src/classpath/vm/java/lang/Thread.java 2008-11-09 12:24:49 UTC (rev 4691)
@@ -408,9 +408,14 @@
* @param name
*/
protected Thread(ThreadGroup group, Runnable target, String name, VmIsolatedStatics isolatedStatics) {
+ /*
if (!(this instanceof IsolateThread)) {
throw new SecurityException("Constructor can only be called from IsolateThread");
}
+ */
+ if (!(this.getClass().getName().startsWith("org.jnode.vm.isolate"))) {
+ throw new SecurityException("Constructor can only be called from IsolateThread");
+ }
if (group == null) {
throw new InternalError("Isolate thread has invalid group: " + name);
}
Added: trunk/core/src/core/org/jnode/vm/isolate/IsolateThreadFactory.java
===================================================================
--- trunk/core/src/core/org/jnode/vm/isolate/IsolateThreadFactory.java (rev 0)
+++ trunk/core/src/core/org/jnode/vm/isolate/IsolateThreadFactory.java 2008-11-09 12:24:49 UTC (rev 4691)
@@ -0,0 +1,212 @@
+package org.jnode.vm.isolate;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.jnode.vm.classmgr.VmIsolatedStatics;
+import org.jnode.vm.Vm;
+import org.jnode.vm.VmSystem;
+import org.jnode.plugin.PluginManager;
+import org.jnode.naming.InitialNaming;
+import javax.naming.NameNotFoundException;
+import javax.isolate.IsolateStartupException;
+
+class IsolateThreadFactory implements ThreadFactory {
+ final ThreadGroup group;
+ final AtomicInteger threadNumber = new AtomicInteger(1);
+ final VmIsolatedStatics isolatedStatics;
+ final String namePrefix;
+
+ IsolateThreadFactory(final VmIsolate isolate) {
+ group = isolate.getThreadGroup();
+ namePrefix = "isolate-" + isolate.getId() + "-executor-";
+ isolatedStatics = isolate.getIsolatedStaticsTable();
+ }
+
+ public Thread newThread(final Runnable r) {
+ class IsolateFactoryThread extends Thread {
+ IsolateFactoryThread(ThreadGroup group, String name, VmIsolatedStatics isolatedStatics) {
+ super(group, r, name, isolatedStatics);
+ }
+ }
+
+ Thread t = new IsolateFactoryThread(group, namePrefix + threadNumber.getAndIncrement(), isolatedStatics){
+ public void start() {
+ org.jnode.vm.Unsafe.debug("factory 1 thread start() " + this.getName() +"\n");
+// getVmThread().switchToIsolate(isolatedStatics);
+ super.start();
+ }
+ };
+ /*
+ PluginManager piManager;
+ try {
+ piManager = InitialNaming.lookup(PluginManager.NAME);
+ } catch (NameNotFoundException ex) {
+ throw new RuntimeException("Cannot find PluginManager", ex);
+ }
+ */
+ //t.setContextClassLoader(piManager.getRegistry().getPluginsClassLoader());
+// if (t.isDaemon())
+ // t.setDaemon(false);
+ // if (t.getPriority() != Thread.NORM_PRIORITY)
+ // t.setPriority(Thread.NORM_PRIORITY + 2);
+ return t;
+ }
+}
+
+
+
+
+class IsolateThreadFactory2 implements ThreadFactory {
+ final ThreadGroup group;
+ final AtomicInteger threadNumber = new AtomicInteger(1);
+ final VmIsolatedStatics isolatedStatics;
+ final String namePrefix;
+ private final Thread factoryThread;
+ private Thread newThread;
+ private final Object lock = new Object();
+ private Runnable runnable;
+
+ IsolateThreadFactory2(final VmIsolate isolate) {
+ group = isolate.getThreadGroup();
+ namePrefix = "isolate-" + isolate.getId() + "-executor-";
+ isolatedStatics = isolate.getIsolatedStaticsTable();
+ factoryThread = new Thread(group, new Runnable(){
+ public void run() {
+ while(true) {
+ synchronized (lock) {
+ try {
+ while(runnable == null) {
+ lock.wait();
+ }
+
+ newThread = new Thread(group, runnable, namePrefix + threadNumber.getAndIncrement()){
+ public void start() {
+ org.jnode.vm.Unsafe.debug("factory thread start() " + this.getName() +"\n");
+ super.start();
+ }
+ };
+ runnable = null;
+ lock.notifyAll();
+ } catch (InterruptedException x) {
+ break;
+ }
+ }
+ }
+ }
+ },"isolate-" + isolate.getId() + "-thread-factory-");
+ factoryThread.start();
+ }
+
+ public synchronized Thread newThread(final Runnable r) {
+ Thread ret;
+ org.jnode.vm.Unsafe.debug("IsolateThreadFactory2.newThread() called\n");
+ org.jnode.vm.Unsafe.debugStackTrace();
+ synchronized (lock) {
+ newThread = null;
+ runnable = r;
+ lock.notifyAll();
+ while(newThread == null) {
+ try {
+ lock.wait();
+ } catch (InterruptedException x) {
+ break;
+ }
+ }
+ ret = newThread;
+ newThread = null;
+ lock.notifyAll();
+ }
+ org.jnode.vm.Unsafe.debug("IsolateThreadFactory2.newThread() returned\n");
+
+ return ret;
+ }
+}
+
+/* `
+package org.jnode.vm.isolate;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.jnode.vm.classmgr.VmIsolatedStatics;
+
+class IsolateThreadFactory implements ThreadFactory {
+ final ThreadGroup group;
+ final AtomicInteger threadNumber = new AtomicInteger(1);
+ final VmIsolatedStatics isolatedStatics;
+ final String namePrefix;
+
+ IsolateThreadFactory(final VmIsolate isolate) {
+ group = isolate.getThreadGroup();
+ namePrefix = "isolate-" + isolate.getId() + "-executor-";
+ isolatedStatics = isolate.getIsolatedStaticsTable();
+ }
+
+ public Thread newThread(final Runnable r) {
+
+ org.jnode.vm.Unsafe.debug("newThread Called - 0\n");
+ Thread t = new IsolateFactoryThread(group, r, namePrefix + threadNumber.getAndIncrement(), null);
+ org.jnode.vm.Unsafe.debug("newThread thread created - 0\n");
+// if (t.isDaemon())
+ // t.setDaemon(false);
+ // if (t.getPriority() != Thread.NORM_PRIORITY)
+ // t.setPriority(Thread.NORM_PRIORITY + 2);
+ return t;
+ }
+}
+
+class IsolateThreadFactory2 implements ThreadFactory {
+ final ThreadGroup group;
+ final AtomicInteger threadNumber = new AtomicInteger(1);
+ final VmIsolatedStatics isolatedStatics;
+ final String namePrefix;
+ private final Thread factoryThread;
+ private Thread newThread;
+ private final Object lock = new Object();
+ private boolean flag = false;
+
+ IsolateThreadFactory2(final VmIsolate isolate) {
+ group = isolate.getThreadGroup();
+ namePrefix = "isolate-" + isolate.getId() + "-executor-";
+ isolatedStatics = isolate.getIsolatedStaticsTable();
+ factoryThread = new Thread(new Runnable(){
+ public void run() {
+ while(true) {
+ synchronized (lock) {
+ try {
+ while(!flag) {
+ lock.wait();
+
+ }
+
+ newThread = new IsolateFactoryThread(group, null, namePrefix + threadNumber.getAndIncrement(), null);
+ } catch (Exception x) {
+ x.printStackTrace();
+ }
+ }
+ }
+ }
+ },"isolate-" + isolate.getId() + "-thread-factory-");
+ factoryThread.start();
+ }
+
+ public Thread newThread(final Runnable r) {
+
+ org.jnode.vm.Unsafe.debug("newThread Called - 0\n");
+ Thread t = new IsolateFactoryThread(group, r, namePrefix + threadNumber.getAndIncrement(), null);
+ org.jnode.vm.Unsafe.debug("newThread thread created - 0\n");
+// if (t.isDaemon())
+ // t.setDaemon(false);
+ // if (t.getPriority() != Thread.NORM_PRIORITY)
+ // t.setPriority(Thread.NORM_PRIORITY + 2);
+ return t;
+ }
+}
+
+
+class IsolateFactoryThread extends Thread {
+ IsolateFactoryThread(ThreadGroup group, Runnable r, String name, VmIsolatedStatics isolatedStatics) {
+ super(group, r, name, isolatedStatics);
+ }
+ }
+
+*/
\ No newline at end of file
Modified: trunk/core/src/core/org/jnode/vm/isolate/VmIsolate.java
===================================================================
--- trunk/core/src/core/org/jnode/vm/isolate/VmIsolate.java 2008-11-09 10:31:21 UTC (rev 4690)
+++ trunk/core/src/core/org/jnode/vm/isolate/VmIsolate.java 2008-11-09 12:24:49 UTC (rev 4691)
@@ -48,6 +48,7 @@
import org.jnode.vm.VmIOContext;
import org.jnode.vm.VmMagic;
import org.jnode.vm.VmSystem;
+import org.jnode.vm.scheduler.VmThread;
import org.jnode.vm.annotation.MagicPermission;
import org.jnode.vm.annotation.PrivilegedActionPragma;
import org.jnode.vm.annotation.SharedStatics;
@@ -153,7 +154,7 @@
*/
private BootableHashMap<VmIsolateLocal<?>, ?> isolateLocalMap = new BootableHashMap<VmIsolateLocal<?>, Object>();
- private List<VmIsolate> children = new LinkedList<VmIsolate>();
+ private final List<VmIsolate> children = new LinkedList<VmIsolate>();
/**
* Isolate states.
@@ -235,7 +236,9 @@
static final VmIsolate getRoot() {
if (rootIsolate == null) {
- rootIsolate = new VmIsolate();
+ rootIsolate = new VmIsolate(null/*Thread.currentThread().getVmThread().getIsolatedStatics()*/);
+// org.jnode.vm.Unsafe.debug("getRoot() istatics: " + rootIsolate.isolatedStaticsTable + "\n");
+// org.jnode.vm.Unsafe.debugStackTrace();
}
return rootIsolate;
}
@@ -265,7 +268,7 @@
/**
* Constructor for the root isolate.
*/
- private VmIsolate() {
+ private VmIsolate(VmIsolatedStatics isolatedStatics) {
this.id = StaticData.nextId();
this.isolate = new Isolate(this);
this.mainClass = null;
@@ -274,7 +277,7 @@
this.state = State.STARTED;
this.threadGroup = getRootThreadGroup();
this.creator = null;
- this.isolatedStaticsTable = null;
+ this.isolatedStaticsTable = isolatedStatics;
// Initialize currentHolder
IsolatedStaticData.current = this;
@@ -301,6 +304,14 @@
this.isolatedStaticsTable = new VmIsolatedStatics(VmMagic.currentProcessor().getIsolatedStatics(),
arch, new Unsafe.UnsafeObjectResolver());
this.creator = currentIsolate();
+ if(getRoot().executor == null && isRoot()) {
+ //initialize the root executor on the creation of the first child
+ getRoot().invokeAndWait(new Runnable(){
+ public void run() {
+ //org.jnode.vm.Unsafe.debug("Root executor ready\n");
+ }
+ });
+ }
StaticData.isolates.add(this);
}
@@ -381,7 +392,9 @@
this.exitReason = IsolateStatus.ExitReason.OTHER_EXIT;
}
- stopAllThreads();
+ disposeAppContext(this.exitReason == IsolateStatus.ExitReason.SELF_EXIT);
+
+ //stopAllThreads();
}
public final void isolateHalt(int status) {
@@ -394,7 +407,9 @@
this.exitReason = IsolateStatus.ExitReason.OTHER_HALT;
}
- stopAllThreads();
+ disposeAppContext(this.exitReason == IsolateStatus.ExitReason.SELF_HALT);
+
+ //stopAllThreads();
}
public final void systemExit(Isolate isolate, int status) {
@@ -406,7 +421,9 @@
this.exitReason = IsolateStatus.ExitReason.SELF_EXIT;
this.exitCode = status;
- stopAllThreads();
+ disposeAppContext(true);
+
+ //stopAllThreads();
}
public final void systemHalt(Isolate isolate, int status) {
@@ -418,11 +435,14 @@
this.exitReason = IsolateStatus.ExitReason.SELF_HALT;
this.exitCode = status;
- stopAllThreads();
+ disposeAppContext(true);
+
+ //stopAllThreads();
}
private void stopAllThreads() {
- // FIXME - this is probably unsafe because any of the threads being killed could
+ // TODO - investigate it
+ // TODO - this is probably unsafe because any of the threads being killed could
// be in the middle of updating a critical system data structure. I'm also
// unsure of the order in which we are killing the threads here. It might be
// better to kill the isolate's main thread first to give it the chance to
@@ -431,8 +451,6 @@
if (ac > 0) {
Thread[] ta = new Thread[ac];
int rc = threadGroup.enumerate(ta);
- // FIXME - notwithstanding the above comments, is the 'current' thread the
- // same one as the isolate's main thread? (Stephen Crawley - 2008-11-08)
Thread current = Thread.currentThread();
boolean found = false;
for (int i = 0; i < rc; i++) {
@@ -459,11 +477,11 @@
*
* @param status
*/
- public final void implicitExit(int status) {
+ public final void implicitExit(VmThread vmThread, int status) {
//on this isolate may call this method
testIsolate(currentIsolate().isolate);
- // FIXME - handle demon threads
+ // TODO - handle demon threads
if (threadGroup.activeCount() > 0 || threadGroup.activeGroupCount() > 0)
return;
@@ -473,7 +491,14 @@
this.exitCode = status;
}
- doExit();
+ if(vmThread.getName().indexOf("-AWT-stopper") > - 1) {
+ doExit();
+ } else {
+ disposeAppContext(true);
+ }
+
+ //doExit();
+ ///stopAllThreads();
}
/**
@@ -483,7 +508,7 @@
//on this isolate may call this method
testIsolate(currentIsolate().isolate);
- // FIXME - handle demon threads
+ // TODO - handle demon threads
if (threadGroup.activeCount() > 0 || threadGroup.activeGroupCount() > 0)
return;
@@ -492,13 +517,18 @@
exitReason = IsolateStatus.ExitReason.UNCAUGHT_EXCEPTION;
this.exitCode = -1;
- doExit();
+ disposeAppContext(true);
+
+ //doExit();
+
+ //stopAllThreads();
}
/**
* Force termination of this isolate.
*
* @param status
+ * @deprecated
*/
@SuppressWarnings("deprecation")
public final void halt(int status) {
@@ -522,7 +552,8 @@
private void doExit() {
try {
- threadGroup.destroy();
+ if(!threadGroup.isDestroyed())
+ threadGroup.destroy();
} catch (Throwable t) {
t.printStackTrace();
}
@@ -639,8 +670,7 @@
}
// Create a new ThreadGroup
- this.threadGroup = new ThreadGroup(StaticData.getRoot().threadGroup,
- mainClass);
+ this.threadGroup = new ThreadGroup(StaticData.getRoot().threadGroup, mainClass);
// Find plugin manager
PluginManager piManager;
@@ -677,7 +707,7 @@
private Thread executorThread;
*/
- public void invokeAndWait(final Runnable task) {
+// public void invokeAndWait(final Runnable task) {
//TODO implement VmIsolate.invokeAndWait(Runnable)
/*
if(this == StaticData.rootIsolate){
@@ -700,7 +730,7 @@
}
}
*/
- }
+// }
/*
private class TaskExecutor implements Runnable{
public void run() {
@@ -735,7 +765,161 @@
}
*/
+
+ private java.util.concurrent.ExecutorService executor;
+
/**
+ * Execute a task within this isolate and wait for completion.
+ *
+ * @param task the task as a Runnable object
+ */
+ public synchronized void invokeAndWait(final Runnable task) {
+ if(executor == null) {
+ executor = java.util.concurrent.Executors.newSingleThreadExecutor(new IsolateThreadFactory2(this));
+ }
+ if(task == null)
+ return;
+
+ try {
+ if(executor.submit(task).get() != null) {
+ throw new RuntimeException("Execution failed!");
+ }
+ } catch (Exception x) {
+ throw new RuntimeException(x);
+ }
+ }
+
+ /**
+ * Execute a task asynchronously within this isolate.
+ *
+ * @param task the task as a Runnable object
+ */
+ public synchronized void invokeLater(final Runnable task) {
+ org.jnode.vm.Unsafe.debug("invokeLater Called - 0\n");
+ if(executor == null) {
+ executor = java.util.concurrent.Executors.newSingleThreadExecutor(new IsolateThreadFactory(this));
+ org.jnode.vm.Unsafe.debug("invokeAndWait executor created - 0\n");
+ }
+ if(task == null)
+ return;
+
+ try {
+ org.jnode.vm.Unsafe.debug("invokeAndWait submitting task - 0\n");
+ executor.submit(task);
+ } catch (Exception x) {
+ throw new RuntimeException(x);
+ }
+ }
+
+ boolean isEDT(){
+ if(appContext == null)
+ return false;
+
+
+ try {
+ Object eq = appContext.getClass().getMethod("get", Object.class).
+ invoke(appContext, appContext.getClass().getField("EVENT_QUEUE_KEY").get(null));
+ if(eq == null)
+ return false;
+
+ org.jnode.vm.Unsafe.debug("isEDT - 1\n");
+
+ Object t = eq.getClass().getField("dispatchThread").get(eq);
+ if(t == null)
+ return false;
+
+ org.jnode.vm.Unsafe.debug("isEDT edt=" + t + "\n");
+ org.jnode.vm.Unsafe.debug("isEDT currenThread=" + Thread.currentThread() + "\n");
+
+ return t == Thread.currentThread();
+ }catch (Exception x) {
+ throw new RuntimeException(x);
+ }
+ /*
+ try {
+ return (Boolean) Class.forName("java.awt.EventQueue").
+ getMethod("isDispatchThread").invoke(null);
+ } catch (Exception x) {
+ throw new RuntimeException(x);
+
+ }
+ */
+ // return false;
+ }
+
+ private Object appContext;
+
+ private void disposeAppContext(boolean intraIsolate) {
+ if(appSupport != null) {
+ appSupport.stop(intraIsolate);
+ } else {
+ stopAllThreads();
+ }
+ }
+
+ /**
+ *
+ * @param intraIsolate
+ * @deprecated
+ */
+ private void disposeAppContext_old(boolean intraIsolate) {
+ final Object appContext;
+ final boolean is_edt;
+ synchronized (this) {
+ is_edt = isEDT();
+ appContext = this.appContext;
+ this.appContext = null;
+ }
+ org.jnode.vm.Unsafe.debug("disposeAppContextCalled - 000\n");
+ org.jnode.vm.Unsafe.debugStackTrace();
+ org.jnode.vm.Unsafe.debug("disposeAppContextCalled - 000 " + intraIsolate + "\n");
+ if(appContext != null) {
+ org.jnode.vm.Unsafe.debug("disposeAppContextCalled - 0001\n");
+ org.jnode.vm.Unsafe.debug("disposeAppContextCalled - 0002\n");
+ if(intraIsolate && is_edt) {
+ org.jnode.vm.Unsafe.debug("disposeAppContextCalled - 0003\n");
+ Thread t = new Thread(new Runnable() {
+ public void run() {
+ org.jnode.vm.Unsafe.debug("disposeAppContextCalled - 00\n");
+ getRoot().invokeAndWait(new Runnable() {
+ public void run() {
+ try {
+ org.jnode.vm.Unsafe.debug("disposeAppContextCalled - 01\n");
+ appContext.getClass().getMethod("dispose").invoke(appContext);
+ org.jnode.vm.Unsafe.debug("disposeAppContextCalled - 02\n");
+ } catch (Exception x) {
+ x.printStackTrace();
+ }
+ }
+ });
+ stopAllThreads();
+ doExit();
+ }
+ }, "isolate-" + getId() + "-AWT-stopper");
+ t.start();
+ } else {
+ org.jnode.vm.Unsafe.debug("disposeAppContextCalled - 0004\n");
+ org.jnode.vm.Unsafe.debug("disposeAppContextCalled - 0\n");
+ getRoot().invokeAndWait(new Runnable(){
+ public void run() {
+ try {
+ org.jnode.vm.Unsafe.debug("disposeAppContextCalled - 1\n");
+ org.jnode.vm.Unsafe.debug("disposeAppContextCalled appcontext: " + appContext + "\n");
+ org.jnode.vm.Unsafe.debug("disposeAppContextCalled appcontext.getClass(): " + appContext.getClass() + "\n");
+ org.jnode.vm.Unsafe.debug("disposeAppContextCalled appcontext.getClass().dispose: " + appContext.getClass().getMethod("dispose") + "\n");
+ appContext.getClass().getMethod("dispose").invoke(appContext);
+ org.jnode.vm.Unsafe.debug("disposeAppContextCalled - 2\n");
+ }catch (Exception x) {
+ x.printStackTrace();
+ }
+ }
+ });
+ stopAllThreads();
+ }
+ }
+ }
+
+ /**
* Run this isolate. This method is called from IsolateThread.
*/
@PrivilegedActionPragma
@@ -781,7 +965,9 @@
//create the appcontext for this isolate
// TODO - improve this
- Class.forName("sun.awt.SunToolkit").getMethod("createNewAppContext").invoke(null);
+ //appContext = Class.forName("sun.awt.SunToolkit").getMethod("createNewAppContext").invoke(null);
+ this.appSupport = new AppSupport(this);
+ this.appSupport.start();
// Update the state of this isolate.
changeState(State.STARTED);
@@ -812,6 +998,8 @@
} catch (Throwable ex2) {
Unsafe.debug("Exception in catch block.. giving up: ");
Unsafe.debug(ex2.getMessage());
+ } finally {
+ systemHalt(isolate, -1);
}
}
}
@@ -958,15 +1146,158 @@
}
}
- private synchronized void addChild(VmIsolate child) {
- this.children.add(child);
+ private void addChild(VmIsolate child) {
+ synchronized (children) {
+ children.add(child);
+ }
}
- private synchronized void removeChild(VmIsolate child) {
- this.children.remove(child);
+ private void removeChild(VmIsolate child) {
+ synchronized (children) {
+ children.remove(child);
+ }
}
- public synchronized VmIsolate[] getChildren() {
- return this.children.toArray(new VmIsolate[children.size()]);
+ public VmIsolate[] getChildren() {
+ synchronized (children) {
+ return children.toArray(new VmIsolate[children.size()]);
+ }
}
+
+ public ThreadGroup getThreadGroup() {
+ if(threadGroup == null) {
+ throw new IllegalStateException("Isolate not available");
+ }
+ return threadGroup;
+ }
+
+ private AppSupport appSupport;
+
+ @SharedStatics
+ private static class AppSupport {
+ private static boolean awtSupport;
+ static {
+ try {
+ Class.forName("java.awt.Toolkit");
+ awtSupport = true;
+ } catch (ClassNotFoundException x) {
+ awtSupport = false;
+ }
+ }
+
+ private final VmIsolate vmIsolate;
+ private Object appContext;
+
+ AppSupport(VmIsolate vmIsolate) {
+ this.vmIsolate = vmIsolate;
+ }
+
+ boolean isAWTReady() {
+ if(!awtSupport)
+ return false;
+
+ try {
+ return Class.forName("java.awt.Toolkit").getField("toolkit").get(null) != null;
+ } catch (Exception x) {
+ return false;
+ }
+ }
+
+ void start() throws Exception {
+ if(isAWTReady()) {
+ synchronized (this) {
+ appContext = Class.forName("sun.awt.SunToolkit").getMethod("createNewAppContext").invoke(null);
+ }
+ }
+ }
+
+ void stop(boolean intraIsolate) {
+ boolean done = false;
+ if(awtSupport) {
+ synchronized (this) {
+ if(appContext != null) {
+ disposeAppContext(intraIsolate);
+ done = true;
+ }
+ }
+ }
+
+ if(!done) {
+ vmIsolate.stopAllThreads();
+ vmIsolate.doExit();
+ }
+ }
+
+ boolean isEDT(){
+ if(appContext == null)
+ return false;
+
+
+ try {
+ Object eq = appContext.getClass().getMethod("get", Object.class).
+ invoke(appContext, appContext.getClass().getField("EVENT_QUEUE_KEY").get(null));
+ if(eq == null)
+ return false;
+
+ Object t = eq.getClass().getField("dispatchThread").get(eq);
+ if(t == null)
+ return false;
+
+ return t == Thread.currentThread();
+ }catch (Exception x) {
+ throw new RuntimeException(x);
+ }
+ /*
+ try {
+ return (Boolean) Class.forName("java.awt.EventQueue").
+ getMethod("isDispatchThread").invoke(null);
+ } catch (Exception x) {
+ throw new RuntimeException(x);
+
+ }
+ */
+ // return false;
+ }
+
+ private void disposeAppContext(boolean intraIsolate) {
+ final Object appContext;
+ final boolean is_edt;
+ synchronized (this) {
+ is_edt = isEDT();
+ appContext = this.appContext;
+ this.appContext = null;
+ }
+ if(appContext != null) {
+ if(intraIsolate && is_edt) {
+ Thread t = new Thread(new Runnable() {
+ public void run() {
+ getRoot().invokeAndWait(new Runnable() {
+ public void run() {
+ try {
+ appContext.getClass().getMethod("dispose").invoke(appContext);
+ } catch (Exception x) {
+ x.printStackTrace();
+ }
+ }
+ });
+ vmIsolate.stopAllThreads();
+ vmIsolate.doExit();
+ }
+ }, "isolate-" + vmIsolate.getId() + "-AWT-stopper");
+ t.start();
+ } else {
+ getRoot().invokeAndWait(new Runnable(){
+ public void run() {
+ try {
+ appContext.getClass().getMethod("dispose").invoke(appContext);
+ }catch (Exception x) {
+ x.printStackTrace();
+ }
+ }
+ });
+ vmIsolate.stopAllThreads();
+ }
+ }
+ }
+ }
}
Modified: trunk/core/src/core/org/jnode/vm/scheduler/Monitor.java
===================================================================
--- trunk/core/src/core/org/jnode/vm/scheduler/Monitor.java 2008-11-09 10:31:21 UTC (rev 4690)
+++ trunk/core/src/core/org/jnode/vm/scheduler/Monitor.java 2008-11-09 12:24:49 UTC (rev 4691)
@@ -67,6 +67,11 @@
private final VmThreadQueue.ScheduleQueue notifyQueue;
/**
+ * The previous monitor in a thread bound monitor chain
+ */
+ private Monitor previous;
+
+ /**
* Create a new instance
*/
public Monitor() {
@@ -86,6 +91,7 @@
Monitor(VmThread owner, int lockCount) {
this.monitorLock = 0;
this.owner = owner;
+ addToOwner();
this.lockCount = lockCount;
if (lockCount < 1) {
throw new IllegalArgumentException("LockCount must be >= 1");
@@ -101,7 +107,9 @@
* @param lockcount
*/
final void initialize(VmThread owner, int lockcount) {
+ dropFromOwner();
this.owner = owner;
+ addToOwner();
this.lockCount = lockcount;
}
@@ -139,7 +147,9 @@
// Try to claim this monitor
if (lcAddr.attempt(0, 1)) {
loop = false;
+ dropFromOwner();
this.owner = current;
+ addToOwner();
} else {
// Claim the lock for this monitor
lock();
@@ -178,6 +188,7 @@
lock();
try {
wakeupWaitingThreads(enterQueue, true);
+ dropFromOwner();
owner = null;
lockCount = 0;
} finally {
@@ -191,6 +202,37 @@
}
/**
+ * Giveup this monitor.
+ * Called from VmThread on thread stop.
+ *
+ * @throws org.vmmagic.pragma.UninterruptiblePragma
+ *
+ */
+ public final void release(VmThread thread) {
+ if (owner != thread) {
+ Unsafe.debug("Current thread is not the owner of this monitor\n");
+ return;
+ }
+
+ if (lockCount <= 0) {
+ Unsafe.debug("Monitor is not locked\n");
+ return;
+ }
+
+ // Monitor is locked by current thread, decrement lockcount
+ lockCount = 0;
+ lock();
+ try {
+ wakeupWaitingThreads(enterQueue, true);
+ dropFromOwner();
+ owner = null;
+ lockCount = 0;
+ } finally {
+ unlock();
+ }
+ }
+
+ /**
* Causes current thread to wait until another thread invokes the notify()
* method or the notifyAll() method for this monitor. In other words, this
* method behaves exactly as if it simply performs the call wait(0). The
@@ -232,6 +274,7 @@
current.wakeupTime = VmSystem.currentKernelMillis() + timeout;
VmMagic.currentProcessor().getScheduler().addToSleepQueue(current);
}
+ dropFromOwner();
owner = null;
lockCount = 0;
wakeupWaitingThreads(enterQueue, true);
@@ -498,4 +541,56 @@
private final void unlock() {
monitorLock = 0;
}
+
+ //monitor chaining to handle thread stop
+
+ /**
+ * Returns the monitor previously owned by the owner thread of this monitor.
+ *
+ * @return the previous monitor
+ */
+ Monitor getPrevious() {
+ return previous;
+ }
+
+ @Inline
+ private void addToOwner() {
+ Monitor lom = owner.getLastOwnedMonitor();
+ if(lom == null) {
+ //the first monitor
+ owner.setLastOwnedMonitor(this);
+ } else {
+ if(lom.owner != this.owner) {
+ //todo error
+ return;
+ } else {
+ if(lom == this) {
+ //no need to add it
+ return;
+ } else {
+ //add it
+ this.previous = lom;
+ owner.setLastOwnedMonitor(this);
+ }
+ }
+ }
+ }
+
+ @Inline
+ private void dropFromOwner() {
+ if(owner == null) {
+ //error
+ return;
+ }
+
+ Monitor lom = owner.getLastOwnedMonitor();
+ if(lom == null)
+ return;
+
+ if(lom != this)
+ return;
+
+ owner.setLastOwnedMonitor(lom.previous);
+ lom.previous = null;
+ }
}
Modified: trunk/core/src/core/org/jnode/vm/scheduler/MonitorManager.java
===================================================================
--- trunk/core/src/core/org/jnode/vm/scheduler/MonitorManager.java 2008-11-09 10:31:21 UTC (rev 4690)
+++ trunk/core/src/core/org/jnode/vm/scheduler/MonitorManager.java 2008-11-09 12:24:49 UTC (rev 4691)
@@ -26,6 +26,7 @@
import org.jnode.vm.VmMagic;
import org.jnode.vm.annotation.Internal;
import org.jnode.vm.annotation.MagicPermission;
+import org.jnode.vm.annotation.Uninterruptible;
import org.jnode.vm.classmgr.ObjectFlags;
import org.jnode.vm.classmgr.ObjectLayout;
import org.vmmagic.unboxed.Address;
@@ -36,6 +37,7 @@
* @author epr
*/
@MagicPermission
+@Uninterruptible
public final class MonitorManager {
/**
@@ -78,7 +80,7 @@
if (counter.EQ(Word.fromIntZeroExtend(ObjectFlags.LOCK_COUNT_MASK))) {
// thin lock entry counter == max, so we need to inflate
// ourselves.
- installInflatedLock(object).enter();
+ installInflatedLock(object, null).enter();
return;
} else {
// not-quite-so-fast path: locked by current thread.
@@ -98,8 +100,17 @@
} else {
// Another thread owns the lock
// thin lock owned by another thread.
- // install an inflated lock.
- installInflatedLock(object).enter();
+ int ownerId = oldlockword.and(Word.fromIntZeroExtend(ObjectFlags.THREAD_ID_MASK)).toInt();
+ VmThread thread = VmMagic.currentProcessor().getScheduler().getThreadById(ownerId);
+ if(thread == null) {
+ //the owner of the lock was destroyed
+ //aquire the lock in fast fashion
+ statusPtr.store(statusFlags.or(tid));
+ return;
+ } else {
+ // install an inflated lock.
+ installInflatedLock(object, thread).enter();
+ }
return;
}
@@ -217,7 +228,7 @@
*/
private static Monitor getOwnedInflatedMonitor(Object object)
throws IllegalMonitorStateException {
- final Monitor m = installInflatedLock(object);
+ final Monitor m = installInflatedLock(object, null);
if (!m.isOwner(VmMagic.currentProcessor().getCurrentThread())) {
// lock not owned by us!
String exMsg = "Object not locked by current thread";
@@ -233,7 +244,7 @@
* @param k
*/
static void setupInflatedLock(Object k) {
- installInflatedLock(k);
+ installInflatedLock(k, null);
}
/**
@@ -241,9 +252,10 @@
* until the object is unlocked or inflated.
*
* @param k the object for which the inflated lock is installed
+ * @param thread
* @return the Monitor object representing the lock
*/
- private static Monitor installInflatedLock(Object k) {
+ private static Monitor installInflatedLock(Object k, VmThread thread) {
Monitor m = null;
Word monAddr = null;
@@ -271,7 +283,10 @@
int lockcount = 1 + oldlockword.and(Word.fromIntZeroExtend(ObjectFlags.LOCK_COUNT_MASK)).
rshl(ObjectFlags.LOCK_COUNT_SHIFT).toInt();
int ownerId = oldlockword.and(Word.fromIntZeroExtend(ObjectFlags.THREAD_ID_MASK)).toInt();
- m.initialize(VmMagic.currentProcessor().getScheduler().getThreadById(ownerId), lockcount);
+ if(thread == null) {
+ thread = VmMagic.currentProcessor().getScheduler().getThreadById(ownerId);
+ }
+ m.initialize(thread, lockcount);
final Word statusFlags = oldlockword.and(Word.fromIntZeroExtend(ObjectFlags.STATUS_FLAGS_MASK));
final Word newlockword = monAddr.or(statusFlags).or(Word.fromIntZeroExtend(ObjectFlags.LOCK_EXPANDED));
Modified: trunk/core/src/core/org/jnode/vm/scheduler/VmScheduler.java
===================================================================
--- trunk/core/src/core/org/jnode/vm/scheduler/VmScheduler.java 2008-11-09 10:31:21 UTC (rev 4690)
+++ trunk/core/src/core/org/jnode/vm/scheduler/VmScheduler.java 2008-11-09 12:24:49 UTC (rev 4691)
@@ -73,6 +73,7 @@
*
* @param visitor
*/
+ @Uninterruptible
final VmThread getThreadById(int id) {
// final SpinLock lock = vm.allThreadsLock;
VmThreadQueueEntry e = this.allThreadsQueue.first;
Modified: trunk/core/src/core/org/jnode/vm/scheduler/VmThread.java
===================================================================
--- trunk/core/src/core/org/jnode/vm/scheduler/VmThread.java 2008-11-09 10:31:21 UTC (rev 4690)
+++ trunk/core/src/core/org/jnode/vm/scheduler/VmThread.java 2008-11-09 12:24:49 UTC (rev 4691)
@@ -143,6 +143,11 @@
private Monitor waitForMonitor;
/**
+ * The most recently owned monitor.
+ */
+ private Monitor lastOwnedMonitor;
+
+ /**
* My priority
*/
protected int priority = Thread.NORM_PRIORITY;
@@ -391,7 +396,7 @@
javaThread.onExit();
//exit the current isolate if needed
if (ex instanceof ThreadDeath) {
- VmIsolate.currentIsolate().implicitExit(0);
+ VmIsolate.currentIsolate().implicitExit(this, 0);
} else {
VmIsolate.currentIsolate().uncaughtExceptionExit();
}
@@ -433,6 +438,18 @@
*/
@Uninterruptible
private final void doStop() {
+ //release monitors
+ Monitor lom = lastOwnedMonitor;
+ while(lom != null) {
+ Monitor prev = lom.getPrevious();
+ lom.release(this);
+ if (prev == lom)
+ break;
+ lom = prev;
+ }
+ lastOwnedMonitor = null;
+
+
final VmProcessor proc = VmMagic.currentProcessor();
final VmThread current = proc.getCurrentThread();
proc.getScheduler().unregisterThread(this);
@@ -914,6 +931,7 @@
* @see ObjectFlags#THREAD_ID_SHIFT
*/
@KernelSpace
+ @Uninterruptible
public final int getId() {
return id;
}
@@ -1387,4 +1405,18 @@
+ state);
}
}
+
+ public VmIsolatedStatics getIsolatedStatics() {
+ return isolatedStatics;
+ }
+
+ @Uninterruptible
+ final Monitor getLastOwnedMonitor() {
+ return lastOwnedMonitor;
+ }
+
+ @Uninterruptible
+ final void setLastOwnedMonitor(Monitor lastOwnedMonitor) {
+ this.lastOwnedMonitor = lastOwnedMonitor;
+ }
}
Modified: trunk/core/src/test/org/jnode/test/core/StatusLinkTest.java
===================================================================
--- trunk/core/src/test/org/jnode/test/core/StatusLinkTest.java 2008-11-09 10:31:21 UTC (rev 4690)
+++ trunk/core/src/test/org/jnode/test/core/StatusLinkTest.java 2008-11-09 12:24:49 UTC (rev 4691)
@@ -213,7 +213,7 @@
Math.sin(i);
if (i % 100 == 0) {
org.jnode.vm.Unsafe.debug("i=" + i + "\n");
- //System.out.println("i=" + i);
+ System.out.println("i=" + i);
}
}
System.out.println("Child thread: exiting");
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|