| | |
| | | * |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Portions copyright 2012 ForgeRock AS. |
| | | * Portions copyright 2012-2014 ForgeRock AS. |
| | | */ |
| | | package org.opends.server.core; |
| | | |
| | | |
| | | |
| | | import org.opends.server.api.DirectoryThread; |
| | | import java.util.Iterator; |
| | | import java.util.LinkedList; |
| | | |
| | | |
| | | import org.opends.server.api.DirectoryThread; |
| | | import org.opends.server.util.StaticUtils; |
| | | |
| | | /** |
| | | * 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. |
| | | */ |
| | | public class ServerShutdownMonitor |
| | | extends DirectoryThread |
| | | public class ServerShutdownMonitor extends DirectoryThread |
| | | { |
| | | // Indicates whether the monitor has completed and the shutdown may be |
| | | // finalized with a call to System.exit; |
| | | /** |
| | | * 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. |
| | | private LinkedList<Thread> threadList; |
| | | /** The list of threads that need to be monitored. */ |
| | | private final LinkedList<Thread> threadList; |
| | | |
| | | |
| | | |
| | |
| | | for (int i=0; i < numThreads; i++) |
| | | { |
| | | Thread t = threadArray[i]; |
| | | |
| | | if (t.isAlive() && (! t.isDaemon()) && (t.getId() != currentThreadID)) |
| | | if (t.isAlive() && !t.isDaemon() && t.getId() != currentThreadID) |
| | | { |
| | | threadList.add(t); |
| | | } |
| | |
| | | * milestones, if there are threads still running then it will attempt to |
| | | * get them to stop. |
| | | */ |
| | | @Override |
| | | public void run() |
| | | { |
| | | monitorDone = false; |
| | |
| | | { |
| | | // First, check to see if we need to do anything at all. If all threads |
| | | // are stopped, then we don't have a problem. |
| | | Iterator<Thread> iterator = threadList.iterator(); |
| | | while (iterator.hasNext()) |
| | | { |
| | | Thread t = iterator.next(); |
| | | if (! t.isAlive()) |
| | | { |
| | | iterator.remove(); |
| | | } |
| | | } |
| | | |
| | | removeDeadThreads(); |
| | | 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. |
| | | long stopTime = System.currentTimeMillis() + 30000; |
| | | while (System.currentTimeMillis() < stopTime) |
| | | if (waitAllThreadsDied(30000)) |
| | | { |
| | | iterator = threadList.iterator(); |
| | | while (iterator.hasNext()) |
| | | { |
| | | Thread t = iterator.next(); |
| | | if (! t.isAlive()) |
| | | { |
| | | iterator.remove(); |
| | | } |
| | | } |
| | | |
| | | if (threadList.isEmpty()) |
| | | { |
| | | return; |
| | | } |
| | | else |
| | | { |
| | | try |
| | | { |
| | | Thread.sleep(10); |
| | | } catch (Exception e) {} |
| | | } |
| | | 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. |
| | | iterator = threadList.iterator(); |
| | | while (iterator.hasNext()) |
| | | for (Thread t : threadList) |
| | | { |
| | | Thread t = iterator.next(); |
| | | try |
| | | { |
| | | if (t.isAlive()) |
| | |
| | | } catch (Exception e) {} |
| | | } |
| | | |
| | | if (threadList.isEmpty()) |
| | | if (waitAllThreadsDied(30000)) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | stopTime = System.currentTimeMillis() + 30000; |
| | | while (System.currentTimeMillis() < stopTime) |
| | | { |
| | | iterator = threadList.iterator(); |
| | | while (iterator.hasNext()) |
| | | { |
| | | Thread t = iterator.next(); |
| | | if (! t.isAlive()) |
| | | { |
| | | iterator.remove(); |
| | | } |
| | | } |
| | | |
| | | if (threadList.isEmpty()) |
| | | { |
| | | return; |
| | | } |
| | | else |
| | | { |
| | | try |
| | | { |
| | | Thread.sleep(10); |
| | | } catch (Exception e) {} |
| | | } |
| | | } |
| | | |
| | | |
| | | // 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 |
| | |
| | | System.err.println("WARNING: The following threads were still active " + |
| | | "after waiting up to 60 seconds for them to stop:"); |
| | | |
| | | iterator = threadList.iterator(); |
| | | while (iterator.hasNext()) |
| | | for (Thread t : threadList) |
| | | { |
| | | Thread t = iterator.next(); |
| | | System.err.println("Thread Name: " + t.getName()); |
| | | System.err.println("Stack Trace:"); |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | private boolean waitAllThreadsDied(final long maxWaitMillis) |
| | | { |
| | | final long stopTime = System.currentTimeMillis() + maxWaitMillis; |
| | | while (System.currentTimeMillis() < stopTime) |
| | | { |
| | | removeDeadThreads(); |
| | | if (threadList.isEmpty()) |
| | | { |
| | | return true; |
| | | } |
| | | |
| | | StaticUtils.sleep(10); |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | private void removeDeadThreads() |
| | | { |
| | | for (Iterator<Thread> iter = threadList.iterator(); iter.hasNext();) |
| | | { |
| | | final Thread t = iter.next(); |
| | | if (!t.isAlive()) |
| | | { |
| | | iter.remove(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Waits for the monitor thread to complete any necessary processing. This |
| | |
| | | { |
| | | while (! monitorDone) |
| | | { |
| | | try |
| | | { |
| | | Thread.sleep(10); |
| | | } catch (Exception e) {} |
| | | StaticUtils.sleep(10); |
| | | } |
| | | } |
| | | } |
| | | |