/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2006-2009 Sun Microsystems, Inc.
* Portions copyright 2012-2015 ForgeRock AS.
*/
/**
* This class defines a daemon thread that will be used to monitor the server
* shutdown process and may help nudge it along if it appears to get hung.
*/
{
/**
* Time in milliseconds for the shutdown monitor to:
* <ol>
* <li>wait before sending interrupt to threads</li>
* <li>wait before final shutdown</li>
* </ol>
*/
/**
* Indicates whether the monitor has completed and the shutdown may be
* finalized with a call to {@link System#exit()}.
*/
private volatile boolean monitorDone;
/** The list of threads that need to be monitored. */
/**
* Creates a new instance of this shutdown monitor thread that will collect
* information about the threads that need to be watched to ensure that they
* shut down properly.
*/
public ServerShutdownMonitor()
{
super("Directory Server Shutdown Monitor");
setDaemon(true);
// Get the thread ID of the current thread, since it is the one that is
// actually processing the server shutdown and therefore shouldn't be
// interrupted or impeded.
// Get the Directory Server thread group and identify all of the non-daemon
// threads that are currently active. This can be an inexact science, so
// we'll make sure to allocate enough room for double the threads that we
// think are currently running.
threadList = new LinkedList<>();
for (int i=0; i < numThreads; i++)
{
Thread t = threadArray[i];
{
threadList.add(t);
}
}
monitorDone = true;
}
/**
* Operates in a loop, waiting for all threads to be stopped. At certain
* milestones, if there are threads still running then it will attempt to
* get them to stop.
*/
public void run()
{
monitorDone = false;
try
{
// First, check to see if we need to do anything at all. If all threads
// are stopped, then we don't have a problem.
if (threadList.isEmpty())
{
return;
}
// For the first milestone, we'll run for up to 30 seconds just checking
// to see whether all threads have stopped yet.
if (waitAllThreadsDied(WAIT_TIME))
{
return;
}
// Now we're at the second milestone, where we'll interrupt all threads
// that are still running and then wait for up to 30 more seconds for them
// to stop.
for (Thread t : threadList)
{
try
{
if (t.isAlive())
{
t.interrupt();
}
} catch (Exception e) {}
}
if (waitAllThreadsDied(WAIT_TIME))
{
return;
}
// At this time, we could try to stop or destroy any remaining threads,
// but we won't do that because we'll use a System.exit in the thread that
// initiated a shutdown and it should take care of anything else that
// might still be running. Nevertheless, we'll print an error message to
// standard error so that an administrator might see something that needs
// to be investigated further.
"after waiting up to 60 seconds for them to stop:");
for (Thread t : threadList)
{
for (StackTraceElement e : t.getStackTrace())
{
if (e.isNativeMethod())
{
}
else
{
}
}
}
}
finally
{
monitorDone = true;
}
}
{
{
if (threadList.isEmpty())
{
return true;
}
}
return false;
}
private void removeDeadThreads()
{
{
if (!t.isAlive())
{
}
}
}
/**
* Waits for the monitor thread to complete any necessary processing. This
* method will not return until the monitor thread has stopped running.
*/
public void waitForMonitor()
{
while (! monitorDone)
{
}
}
}