All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.caucho.util.Alarm Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998-2012 Caucho Technology -- all rights reserved
 *
 * This file is part of Resin(R) Open Source
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Resin Open Source is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Resin Open Source 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, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Resin Open Source; if not, write to the
 *
 *   Free Software Foundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Scott Ferguson
 */

package com.caucho.util;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.caucho.env.thread.AbstractTaskWorker;
import com.caucho.loader.ClassLoaderListener;
import com.caucho.loader.DynamicClassLoader;

/**
 * The alarm class provides a lightweight event scheduler.  This allows
 * an objects to schedule a timeout without creating a new thread.
 *
 * 

A separate thread periodically tests the queue for alarms ready. */ public class Alarm implements ThreadTask, ClassLoaderListener { private static final Logger log = Logger.getLogger(Alarm.class.getName()); private static final ClassLoader _systemLoader; private static AtomicReferenceFieldUpdater _nextUpdater; private static AtomicLongFieldUpdater _wakeTimeUpdater; // private static final AlarmThread _alarmThread; private static final CoordinatorThread _coordinatorThread; /* private static volatile long _currentTime = System.currentTimeMillis(); private static volatile boolean _isCurrentTimeUsed; private static volatile boolean _isSlowTime; */ // private static final AlarmHeap _heap = new AlarmHeap(); private static final AlarmClock _clock = new AlarmClock(); private static final AtomicInteger _runningAlarmCount = new AtomicInteger(); private static final boolean _isStressTest; /* private static long _testTime; private static long _testNanoDelta; */ private volatile Alarm _next; private volatile long _wakeTime; private AlarmListener _listener; private ClassLoader _contextLoader; private String _name; private boolean _isPriority = true; // private int _heapIndex = 0; private int _bucket = -1; private volatile boolean _isRunning; /** * Create a new wakeup alarm with a designated listener as a callback. * The alarm is not scheduled. */ protected Alarm() { this("alarm"); } protected Alarm(String name) { if (_coordinatorThread == null) { throw new IllegalStateException("Alarm cannot be instantiated because Resin is running inside a foreign classloader." + "\n " + Alarm.class.getClassLoader()); } _name = name; addEnvironmentListener(); } /** * Create a new wakeup alarm with a designated listener as a callback. * The alarm is not scheduled. */ public Alarm(AlarmListener listener) { this("alarm[" + listener + "]", listener); } /** * Create a new wakeup alarm with a designated listener as a callback. * The alarm is not scheduled. */ public Alarm(String name, AlarmListener listener) { this(name, listener, Thread.currentThread().getContextClassLoader()); } /** * Create a new wakeup alarm with a designated listener as a callback. * The alarm is not scheduled. */ public Alarm(String name, AlarmListener listener, ClassLoader loader) { this(name); setListener(listener); setContextLoader(loader); } /** * Create a new wakeup alarm with a designated listener as a callback. * The alarm is not scheduled. */ public Alarm(String name, AlarmListener listener, long delta, ClassLoader loader) { this(name); setListener(listener); setContextLoader(loader); queue(delta); } /** * Creates a named alarm and schedules its wakeup. * * @param name the object prepared to receive the callback * @param listener the object prepared to receive the callback * @param delta the time in milliseconds to wake up */ public Alarm(String name, AlarmListener listener, long delta) { this(name, listener); queue(delta); } /** * Creates a new alarm and schedules its wakeup. * * @param listener the object prepared to receive the callback * @param delta the time in milliseconds to wake up */ public Alarm(AlarmListener listener, long delta) { this(listener); queue(delta); } /** * Returns the alarm name. */ public String getName() { return _name; } /** * Sets the alarm name. */ protected void setName(String name) { _name = name; } /* public static boolean isActive() { return _testTime == 0 && _alarmThread != null; } */ /** * Returns the approximate current time in milliseconds. * Convenient for minimizing system calls. */ /* public static long getCurrentTime() { // test avoids extra writes on multicore machines if (! _isCurrentTimeUsed) { if (_testTime > 0) return _testTime; if (_alarmThread == null) return System.currentTimeMillis(); if (_isSlowTime) { _isSlowTime = false; _currentTime = System.currentTimeMillis(); _isCurrentTimeUsed = true; LockSupport.unpark(_alarmThread); } else { _isCurrentTimeUsed = true; } } return _currentTime; } */ /** * Gets current time, handling test */ /* public static long getCurrentTimeActual() { if (_testTime > 0) return System.currentTimeMillis(); else return getCurrentTime(); } */ /** * Returns the exact current time in milliseconds. */ /* public static long getExactTime() { if (_testTime > 0) return _testTime; else { return System.currentTimeMillis(); } } */ /** * Returns the exact current time in nanoseconds. */ /* public static long getExactTimeNanoseconds() { if (_testTime > 0) { // php/190u // System.nanoTime() is not related to currentTimeMillis(), so return // a different offset. See System.nanoTime() javadoc return (_testTime - 10000000) * 1000000L + _testNanoDelta; } return System.nanoTime(); } */ /** * Returns true for testing. */ /* public static boolean isTest() { return _testTime > 0; } */ /** * Yield if in test mode to maintain ordering */ /* public static void yieldIfTest() { if (_testTime > 0) { // Thread.yield(); } } */ /** * Returns the wake time of this alarm. */ public long getWakeTime() { return _wakeTime; } public void setWakeTime(long wakeTime) { _wakeTime = wakeTime; } boolean setWakeTime(long prevWakeTime, long wakeTime) { return _wakeTimeUpdater.compareAndSet(this, prevWakeTime, wakeTime); } long getAndSetWakeTime(long wakeTime) { return _wakeTimeUpdater.getAndSet(this, wakeTime); } int getHeapIndex() { // return _heapIndex; return 0; } int getBucket() { return _bucket; } void setBucket(int bucket) { _bucket = bucket; } void setHeapIndex(int index) { // _heapIndex = index; } Alarm getNext() { return _next; } boolean setNext(Alarm prevNext, Alarm next) { return _nextUpdater.compareAndSet(this, prevNext, next); } void setNext(Alarm next) { _next = next; } /** * Return the alarm's listener. */ public AlarmListener getListener() { return _listener; } /** * Sets the alarm's listener. */ public void setListener(AlarmListener listener) { _listener = listener; } /** * Sets the alarm's context loader */ public void setContextLoader(ClassLoader loader) { _contextLoader = loader; } /** * Sets the alarm's context loader */ public ClassLoader getContextLoader() { return _contextLoader; } /** * Returns true if the alarm is currently queued. */ public boolean isQueued() { // return _heapIndex != 0; // return _wakeTime != 0; return _bucket >= 0; } /** * Returns true if the alarm is currently running */ boolean isRunning() { return _isRunning; } /** * True for a priority alarm (default) */ public void setPriority(boolean isPriority) { _isPriority = isPriority; } /** * True for a priority alarm (default) */ public boolean isPriority() { return _isPriority; } /** * Registers the alarm with the environment listener for auto-close */ protected void addEnvironmentListener() { // Environment.addClassLoaderListener(this); } /** * Queue the alarm for wakeup. * * @param delta time in milliseconds to wake */ public void queue(long delta) { long now = CurrentTime.getExactTime(); // boolean isNotify = _heap.queueAt(this, now + delta); boolean isNotify = _clock.queueAt(this, now + delta); if (isNotify) { _coordinatorThread.wake(); } } /** * Queue the alarm for wakeup. * * @param delta time in milliseconds to wake */ public void queueAt(long wakeTime) { // boolean isNotify = _heap.queueAt(this, wakeTime); boolean isNotify = _clock.queueAt(this, wakeTime); if (isNotify) { _coordinatorThread.wake(); } } /** * Remove the alarm from the wakeup queue. */ public void dequeue() { /* if (_heapIndex > 0) _heap.dequeue(this); */ _clock.dequeue(this); } /** * Runs the alarm. This is only called from the worker thread. */ @Override public void run() { try { handleAlarm(); } catch (Throwable e) { log.log(Level.WARNING, e.toString(), e); } finally { _isRunning = false; _runningAlarmCount.decrementAndGet(); } } /** * Handles the alarm. */ private void handleAlarm() { AlarmListener listener = getListener(); if (listener == null) return; Thread thread = Thread.currentThread(); ClassLoader loader = getContextLoader(); if (loader != null) thread.setContextClassLoader(loader); else thread.setContextClassLoader(_systemLoader); try { listener.handleAlarm(this); } finally { thread.setContextClassLoader(_systemLoader); } } /** * Handles the case where a class loader has completed initialization */ @Override public void classLoaderInit(DynamicClassLoader loader) { } /** * Handles the case where a class loader is dropped. */ @Override public void classLoaderDestroy(DynamicClassLoader loader) { close(); } /** * Closes the alarm instance */ public void close() { dequeue(); // server/16a{0,1} /* _listener = null; _contextLoader = null; */ } // test static void testClear() { // _heap.testClear(); _clock.testClear(); } static void setAlarmTestTime(long time) { // Alarm alarm; Thread thread = Thread.currentThread(); ClassLoader oldLoader = thread.getContextClassLoader(); try { long now = CurrentTime.getCurrentTime(); _clock.extractAlarm(now, true); /* while ((alarm = _heap.extractAlarm(now)) != null) { try { alarm.run(); } catch (Throwable e) { e.printStackTrace(); } } */ } finally { thread.setContextClassLoader(oldLoader); } } /* static void setTestNanoDelta(long delta) { _testNanoDelta = delta; } */ public String toString() { return "Alarm[" + _name + "]"; } /* static class AlarmThread extends Thread { AlarmThread() { super("resin-timer"); setDaemon(true); setPriority(Thread.MAX_PRIORITY); } @Override public void run() { int idleCount = 0; while (true) { try { if (_testTime > 0) { _currentTime = _testTime; LockSupport.park(); continue; } long now = System.currentTimeMillis(); _currentTime = now; boolean isCurrentTimeUsed = _isCurrentTimeUsed; _isCurrentTimeUsed = false; if (isCurrentTimeUsed) { idleCount = 0; _isSlowTime = false; } else { idleCount++; if (idleCount >= 10) { _isSlowTime = true; } } if (_isSlowTime) { long sleepTime = 1000L; LockSupport.parkNanos(sleepTime * 1000000L); } else { Thread.sleep(20); } } catch (Throwable e) { e.printStackTrace(); } } } } */ static class CoordinatorThread extends AbstractTaskWorker { private long _lastTime; @Override protected boolean isPermanent() { return true; } /** * Runs the coordinator task. */ @Override public long runTask() { if (CurrentTime.isTest()) { return -1; } _lastTime = CurrentTime.getExactTime(); while (true) { long now = CurrentTime.getExactTime(); long next = _clock.extractAlarm(now, false); // long next = _heap.nextAlarmTime(); // #3548 - getCurrentTime for consistency // long now = getCurrentTime(); if (next < 0) { return 120000L; } else if (now < next) { return Math.min(next - now, 120000L); } } } /* private void dispatchAlarm() { try { Alarm alarm; if ((alarm = _heap.extractAlarm(getCurrentTime())) != null) { _runningAlarmCount.incrementAndGet(); long now; if (_isStressTest) now = Alarm.getExactTime(); else now = CurrentTime.getCurrentTime(); long delta = now - alarm._wakeTime; if (delta > 10000) { log.warning(this + " slow alarm " + alarm + " " + delta + "ms" + " coordinator-delta " + (now - _lastTime) + "ms"); } else if (_isStressTest && delta > 100) { System.out.println(this + " slow alarm " + alarm + " " + delta + " coordinator-delta " + (now - _lastTime) + "ms"); } _lastTime = now; if (alarm.isPriority()) ThreadPool.getThreadPool().schedulePriority(alarm); else ThreadPool.getThreadPool().schedule(alarm); } } catch (Exception e) { log.log(Level.WARNING, e.toString(), e); } } */ } static { // AlarmThread alarmThread = null; CoordinatorThread coordinator = null; ClassLoader loader = Alarm.class.getClassLoader(); try { coordinator = new CoordinatorThread(); coordinator.wake(); } catch (Throwable e) { e.printStackTrace(); // should display for security manager issues log.fine("Alarm not started: " + e); } _nextUpdater = AtomicReferenceFieldUpdater.newUpdater(Alarm.class, Alarm.class, "_next"); _wakeTimeUpdater = AtomicLongFieldUpdater.newUpdater(Alarm.class, "_wakeTime"); // _systemLoader = systemLoader; _systemLoader = loader; // _alarmThread = alarmThread; _coordinatorThread = coordinator; _isStressTest = System.getProperty("caucho.stress.test") != null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy