/*
* @(#)ThreadRegistry.java 1.19 06/10/10
*
* Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*
*/
package sun.misc;
import java.util.Vector;
import java.security.AccessController;
import java.security.PrivilegedAction;
public class ThreadRegistry {
public static void add(Thread t) {
synchronized (staticLock) {
threadList.addElement(t);
dprintln("New thread " + t.getName());
}
}
public static void remove(Thread t) {
synchronized (staticLock) {
threadList.removeElement(t);
// ThreadRegistry.remove() is called when the thread is about to
// die, at the point after which no exceptions are to be expected.
// Hence, we have to make sure that the following (which allocate
// objects) do not result in a Throwable.
try {
dprintln("Thread " + t.getName() + " removed");
} catch (Throwable throwable) {
// Just discard the exception.
}
}
}
public static boolean threadCreationAllowed() {
return !threadCreationDisabled;
}
public static void waitAllUserThreadsExit() {
dprintln("Waiting for all user threads to exit");
waitThreadsExit(false);
}
public static void waitAllSystemThreadsExit() {
dprintln("Asking all SystemThreads to exit");
allExitRequestedFlag = true;
waitThreadsExit(true);
}
private static void waitThreadsExit(boolean systemThread) {
Thread current = Thread.currentThread();
boolean tryAgain;
do {
Vector snapshot;
tryAgain = false;
synchronized (staticLock) {
snapshot = (Vector)threadList.clone();
}
int n = snapshot.size();
if (systemThread) {
// ask all the system thread to exit
for (int i = 0; i < n; ++i) {
final Thread t = (Thread)snapshot.elementAt(i);
if (t == current) {
continue;
}
// shouldn't be a user thread, but check it just in case
dprintln("Asking " + (t.isDaemon() ? "system" : "user") +
" thread " + t.getName() + " to exit");
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
t.interrupt();
return null;
}
});
}
}
for (int i = 0; i < n; ++i) {
Thread t = (Thread)snapshot.elementAt(i);
if (t == current || (!systemThread && t.isDaemon())) {
continue;
}
dprintln("Waiting for " + (t.isDaemon() ? "system" : "user") +
" thread " + t.getName() + " to exit");
tryAgain = true;
while (t.isAlive()) {
try {
t.join();
break;
} catch (InterruptedException ie) {
}
}
}
} while (tryAgain);
}
public static boolean exitRequested() {
if (allExitRequestedFlag) {
dprintln("System thread " + Thread.currentThread().getName() +
" has recognized the request to exit");
}
return allExitRequestedFlag;
}
public static void resetExitRequest() {
allExitRequestedFlag = false;
}
private static synchronized void dprintln(String s) {
if (CVM.checkDebugFlags(CVM.DEBUGFLAG_TRACE_MISC) != 0) {
// Be careful of initialization order problems
if (System.err != null) {
if (debugBuffer != null) {
int n = debugBuffer.size();
for (int i = 0; i < n; ++i) {
String str = (String)debugBuffer.elementAt(i);
System.err.println(str);
}
}
debugBuffer = null;
System.err.println(s);
} else {
if (debugBuffer == null) {
debugBuffer = new Vector();
}
debugBuffer.addElement(s);
}
}
}
private static Object staticLock = new Object();
private static boolean allExitRequestedFlag = false;
private static Vector threadList = new Vector();
private static Vector debugBuffer;
// %begin lvm
// The following flag gets set from native code in LVM implementation.
// %end lvm
private static boolean threadCreationDisabled = false;
/*
* 4952560: These locks must always have an inflated monitor associated
* with them so we never have to worry about ThreadRegistry.remove
* failing under low memory conditions. Otherwise the VM will never
* shutdown.
*/
static {
if (!sun.misc.CVM.objectInflatePermanently(staticLock)) {
throw new OutOfMemoryError();
}
if (!sun.misc.CVM.objectInflatePermanently(threadList)) {
throw new OutOfMemoryError();
}
}
}