/** * Copyright 2008 - CommonCrawl Foundation * * This program 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 3 of the License, or * (at your option) any later version. * * 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * **/ package org.commoncrawl.async; import java.util.Collections; import java.util.LinkedList; import java.util.Vector; /** * * A registry of timers that will fire inside an event loop * * @author rana * */ public final class TimerRegistry { private EventLoop _eventLoop; public TimerRegistry(EventLoop eventLoop) { _eventLoop = eventLoop; } public void setTimer(Timer t) { synchronized (t) { if (!t.isArmed()) { t.arm(); synchronized (this) { _active.add(t); _sort = true; } // wakeup event loop if current thread != event loop thread // and this timer is the timer with the earliest fire time ... if (Thread.currentThread() != _eventLoop.getEventThread()) { _eventLoop.wakeup(); } } } } public void cancelTimer(Timer t) { synchronized (t) { if (t.isArmed()) { t.disarm(); synchronized (this) { _sort = true; } } } } // fire the timer long fireTimers() { long currentTime = System.currentTimeMillis(); LinkedList<Timer> fireList = new LinkedList<Timer>(); int fired = 0; synchronized (this) { if (_sort) { Collections.sort(_active); _sort = false; } // first pass ... fire all timers in list (that need to be fired) for (int i = 0; i < _active.size(); ++i) { Timer t = _active.get(i); if (t.isArmed() && t.getNextFireTime() <= currentTime) { // add to fire list ... fireList.add(t); } else { break; } } } // now in an unblocked manner ... iterate list and fire timers ... for (Timer t : fireList) { synchronized (t) { if (t.isArmed() && t.getNextFireTime() <= currentTime) { t.fire(); fired++; } } } synchronized (this) { // now, second pass... walk entire array int activeCount = _active.size(); for (int i = 0; i < activeCount; ++i) { Timer t = _active.elementAt(i); // if not armed, remove from list ... if (!t.isArmed()) { _active.remove(i--); // reduce total count activeCount--; } } // now if something fired, or sort flag is true ... if (fired != 0 || _sort) { Collections.sort(_active); _sort = false; } // return the next fire time return (_active.size() != 0) ? _active.get(0).getNextFireTime() : 0; } } private Vector<Timer> _active = new Vector<Timer>(); private boolean _sort = false; }