diff src/org/eclipse/jetty/util/thread/Timeout.java @ 802:3428c60d7cfc

replace jetty jars with source
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 07 Sep 2016 21:15:48 -0600
parents
children 8e9db0bbf4f9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/eclipse/jetty/util/thread/Timeout.java	Wed Sep 07 21:15:48 2016 -0600
@@ -0,0 +1,380 @@
+//
+//  ========================================================================
+//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
+//  ------------------------------------------------------------------------
+//  All rights reserved. This program and the accompanying materials
+//  are made available under the terms of the Eclipse Public License v1.0
+//  and Apache License v2.0 which accompanies this distribution.
+//
+//      The Eclipse Public License is available at
+//      http://www.eclipse.org/legal/epl-v10.html
+//
+//      The Apache License v2.0 is available at
+//      http://www.opensource.org/licenses/apache2.0.php
+//
+//  You may elect to redistribute this code under either of these licenses.
+//  ========================================================================
+//
+
+package org.eclipse.jetty.util.thread;
+
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+/* ------------------------------------------------------------ */
+/** Timeout queue.
+ * This class implements a timeout queue for timers that are at least as likely to be cancelled as they are to expire.
+ * Unlike the util timeout class, the duration of the timeouts is shared by all scheduled tasks and if the duration 
+ * is changed, this affects all scheduled tasks.
+ * <p>
+ * The nested class Task should be extended by users of this class to obtain call back notification of 
+ * expires. 
+ */
+public class Timeout
+{
+    private static final Logger LOG = Log.getLogger(Timeout.class);
+    private Object _lock;
+    private long _duration;
+    private volatile long _now=System.currentTimeMillis();
+    private Task _head=new Task();
+
+    /* ------------------------------------------------------------ */
+    public Timeout()
+    {
+        _lock=new Object();
+        _head._timeout=this;
+    }
+
+    /* ------------------------------------------------------------ */
+    public Timeout(Object lock)
+    {
+        _lock=lock;
+        _head._timeout=this;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @return Returns the duration.
+     */
+    public long getDuration()
+    {
+        return _duration;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param duration The duration to set.
+     */
+    public void setDuration(long duration)
+    {
+        _duration = duration;
+    }
+
+    /* ------------------------------------------------------------ */
+    public long setNow()
+    {
+        return _now=System.currentTimeMillis();
+    }
+    
+    /* ------------------------------------------------------------ */
+    public long getNow()
+    {
+        return _now;
+    }
+
+    /* ------------------------------------------------------------ */
+    public void setNow(long now)
+    {
+        _now=now;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Get an expired tasks.
+     * This is called instead of {@link #tick()} to obtain the next
+     * expired Task, but without calling it's {@link Task#expire()} or
+     * {@link Task#expired()} methods.
+     * 
+     * @return the next expired task or null.
+     */
+    public Task expired()
+    {
+        synchronized (_lock)
+        {
+            long _expiry = _now-_duration;
+
+            if (_head._next!=_head)
+            {
+                Task task = _head._next;
+                if (task._timestamp>_expiry)
+                    return null;
+
+                task.unlink();
+                task._expired=true;
+                return task;
+            }
+            return null;
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    public void tick()
+    {
+        final long expiry = _now-_duration;
+
+        Task task=null;
+        while (true)
+        {
+            try
+            {
+                synchronized (_lock)
+                {
+                    task= _head._next;
+                    if (task==_head || task._timestamp>expiry)
+                        break;
+                    task.unlink();
+                    task._expired=true;
+                    task.expire();
+                }
+                
+                task.expired();
+            }
+            catch(Throwable th)
+            {
+                LOG.warn(Log.EXCEPTION,th);
+            }
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    public void tick(long now)
+    {
+        _now=now;
+        tick();
+    }
+
+    /* ------------------------------------------------------------ */
+    public void schedule(Task task)
+    {
+        schedule(task,0L);
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @param task
+     * @param delay A delay in addition to the default duration of the timeout
+     */
+    public void schedule(Task task,long delay)
+    {
+        synchronized (_lock)
+        {
+            if (task._timestamp!=0)
+            {
+                task.unlink();
+                task._timestamp=0;
+            }
+            task._timeout=this;
+            task._expired=false;
+            task._delay=delay;
+            task._timestamp = _now+delay;
+
+            Task last=_head._prev;
+            while (last!=_head)
+            {
+                if (last._timestamp <= task._timestamp)
+                    break;
+                last=last._prev;
+            }
+            last.link(task);
+        }
+    }
+
+
+    /* ------------------------------------------------------------ */
+    public void cancelAll()
+    {
+        synchronized (_lock)
+        {
+            _head._next=_head._prev=_head;
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isEmpty()
+    {
+        synchronized (_lock)
+        {
+            return _head._next==_head;
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    public long getTimeToNext()
+    {
+        synchronized (_lock)
+        {
+            if (_head._next==_head)
+                return -1;
+            long to_next = _duration+_head._next._timestamp-_now;
+            return to_next<0?0:to_next;
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public String toString()
+    {
+        StringBuffer buf = new StringBuffer();
+        buf.append(super.toString());
+        
+        Task task = _head._next;
+        while (task!=_head)
+        {
+            buf.append("-->");
+            buf.append(task);
+            task=task._next;
+        }
+        
+        return buf.toString();
+    }
+
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    /* ------------------------------------------------------------ */
+    /** Task.
+     * The base class for scheduled timeouts.  This class should be
+     * extended to implement the expire() method, which is called if the
+     * timeout expires.
+     * 
+     * 
+     *
+     */
+    public static class Task
+    {
+        Task _next;
+        Task _prev;
+        Timeout _timeout;
+        long _delay;
+        long _timestamp=0;
+        boolean _expired=false;
+
+        /* ------------------------------------------------------------ */
+        protected Task()
+        {
+            _next=_prev=this;
+        }
+
+        /* ------------------------------------------------------------ */
+        public long getTimestamp()
+        {
+            return _timestamp;
+        }
+
+        /* ------------------------------------------------------------ */
+        public long getAge()
+        {
+            final Timeout t = _timeout;
+            if (t!=null)
+            {
+                final long now=t._now;
+                if (now!=0 && _timestamp!=0)
+                    return now-_timestamp;
+            }
+            return 0;
+        }
+
+        /* ------------------------------------------------------------ */
+        private void unlink()
+        {
+            _next._prev=_prev;
+            _prev._next=_next;
+            _next=_prev=this;
+            _expired=false;
+        }
+
+        /* ------------------------------------------------------------ */
+        private void link(Task task)
+        {
+            Task next_next = _next;
+            _next._prev=task;
+            _next=task;
+            _next._next=next_next;
+            _next._prev=this;   
+        }
+        
+        /* ------------------------------------------------------------ */
+        /** Schedule the task on the given timeout.
+         * The task exiry will be called after the timeout duration.
+         * @param timer
+         */
+        public void schedule(Timeout timer)
+        {
+            timer.schedule(this);
+        }
+        
+        /* ------------------------------------------------------------ */
+        /** Schedule the task on the given timeout.
+         * The task exiry will be called after the timeout duration.
+         * @param timer
+         */
+        public void schedule(Timeout timer, long delay)
+        {
+            timer.schedule(this,delay);
+        }
+        
+        /* ------------------------------------------------------------ */
+        /** Reschedule the task on the current timeout.
+         * The task timeout is rescheduled as if it had been cancelled and
+         * scheduled on the current timeout.
+         */
+        public void reschedule()
+        {
+            Timeout timeout = _timeout;
+            if (timeout!=null)
+                timeout.schedule(this,_delay);
+        }
+        
+        /* ------------------------------------------------------------ */
+        /** Cancel the task.
+         * Remove the task from the timeout.
+         */
+        public void cancel()
+        {
+            Timeout timeout = _timeout;
+            if (timeout!=null)
+            {
+                synchronized (timeout._lock)
+                {
+                    unlink();
+                    _timestamp=0;
+                }
+            }
+        }
+        
+        /* ------------------------------------------------------------ */
+        public boolean isExpired() { return _expired; }
+
+        /* ------------------------------------------------------------ */
+	public boolean isScheduled() { return _next!=this; }
+        
+        /* ------------------------------------------------------------ */
+        /** Expire task.
+         * This method is called when the timeout expires. It is called
+         * in the scope of the synchronize block (on this) that sets 
+         * the {@link #isExpired()} state to true.
+         * @see #expired() For an unsynchronized callback.
+         */
+        protected void expire(){}
+
+        /* ------------------------------------------------------------ */
+        /** Expire task.
+         * This method is called when the timeout expires. It is called 
+         * outside of any synchronization scope and may be delayed. 
+         * 
+         */
+        public void expired(){}
+
+    }
+
+}