reSIProcate/stack  9694
ValueFifo.hxx
Go to the documentation of this file.
00001 #ifndef ValueFifo_hxx
00002 #define ValueFifo_hxx
00003 
00004 #include <cerrno>
00005 #include <iosfwd>
00006 #include <deque>
00007 
00008 #include "rutil/Condition.hxx"
00009 #include "rutil/Mutex.hxx"
00010 #include "rutil/Lock.hxx"
00011 #include "rutil/AbstractFifo.hxx"
00012 #include "resip/stack/CancelableTimerQueue.hxx"
00013 
00014 namespace resip
00015 {
00016 
00022 template <class T>
00023 class ValueFifo : public resip::FifoStatsInterface
00024 {
00025    public:
00026       typedef typename CancelableTimerQueue<T>::Id TimerId;
00027 
00028       ValueFifo(const Data& name) :
00029          myFifoSize(0), 
00030          myTimerSize(0) 
00031       {
00032       }
00033 
00034       ~ValueFifo() 
00035       {
00036       }
00037 
00038       void add(const T& t)
00039       {
00040          resip::Lock lock(myMutex);
00041          myList.push_back(t);
00042          myFifoSize++;
00043          wakeup();
00044       }
00045       
00046       TimerId addDelayMs(const T& t, int offsetInMs)
00047       {
00048          resip::Lock lock(myMutex);
00049          if (offsetInMs < 0)
00050          {
00051             offsetInMs = 0;
00052          }
00053 
00054          bool doWakeup = false;
00055          if (myTimerQueue.empty() ||
00056              offsetInMs < myTimerQueue.getTimeout())
00057          {
00058             doWakeup = true;
00059          }
00060 
00061          TimerId id = myTimerQueue.addRelative(t, offsetInMs);
00062          myTimerSize++;
00063 
00064          //wakeup if new timer is sooner than next timer that would have
00065          //fired, or no timer set
00066          if (doWakeup)
00067          {
00068 
00069             wakeup();
00070          }
00071          return id;
00072       }
00073       
00074       bool cancel(TimerId id)
00075       {
00076          resip::Lock lock(myMutex);
00077          if (myTimerQueue.cancel(id))
00078          {
00079             myTimerSize--;
00080             return true;
00081          }
00082          return false;
00083       }
00084       
00085       T getNext()
00086       {
00087          resip::Lock lock(myMutex);
00088 
00089          while (!messageAvailableNoLock())
00090          {
00091             if (myTimerQueue.empty())
00092             {
00093                myCondition.wait(&myMutex);
00094             }
00095             else
00096             {
00097                myCondition.wait(&myMutex, myTimerQueue.getTimeout());
00098             }            
00099          }
00100 
00101          while (myTimerQueue.available())
00102          {
00103             myList.push_back(myTimerQueue.getNext());
00104             myFifoSize++;
00105             myTimerSize--;
00106          }
00107 
00108          assert (myFifoSize > 0);
00109          assert (!myList.empty());
00110          
00111          T firstMessage = myList.front();
00112          
00113          myList.pop_front(); //dcm -- should do this with a guard to avoid extra copy
00114          myFifoSize--;
00115          return firstMessage;
00116       }
00117       
00118       void clear()
00119       {
00120          resip::Lock lock(myMutex);
00121          myFifoSize = 0;
00122          myTimerSize = 0;
00123          myTimerQueue.clear();
00124          myList.clear();
00125       }
00126 
00127       //size includes timer events
00128       unsigned int size() const
00129       {
00130          resip::Lock lock(myMutex);
00131          return myFifoSize + myTimerSize;
00132       }
00133 
00134       bool empty() const
00135       {
00136          return myFifoSize + myTimerSize == 0;
00137       }
00138 
00139       bool messageAvailable()
00140       {
00141          resip::Lock lock(myMutex);
00142          return messageAvailableNoLock();
00143       }
00144 
00145       virtual size_t getCountDepth() const
00146       {
00147          return size();
00148       }
00149 
00150       virtual time_t getTimeDepth() const
00151       {
00152          return 0;
00153       }
00154 
00155       virtual time_t expectedWaitTimeMilliSec() const
00156       {
00157          return 0;
00158       }
00159       
00160       virtual time_t averageServiceTimeMicroSec() const
00161       {
00162          return 1;
00163       }
00164 
00165    private:
00166       bool messageAvailableNoLock()
00167       {
00168          return myFifoSize > 0 || myTimerQueue.available(); 
00169       }
00170       
00171       void wakeup()
00172       {
00173          myCondition.signal();
00174       }
00175       
00176       std::deque<T> myList;
00177 
00178       CancelableTimerQueue<T> myTimerQueue;
00179 
00180       unsigned long myFifoSize;
00181       unsigned long myTimerSize;
00182       
00183       mutable resip::Mutex  myMutex;
00184       resip::Condition myCondition;
00185 
00186       // no value semantics
00187       ValueFifo(const ValueFifo&);
00188       ValueFifo& operator=(const ValueFifo&);
00189 };
00190  
00191 }
00192 #endif
00193 
00194 /* ====================================================================
00195  * The Vovida Software License, Version 1.0 
00196  * 
00197  * Copyright (c) 2004 PurpleComm, Inc.  All rights reserved.
00198  * 
00199  * Redistribution and use in source and binary forms, with or without
00200  * modification, are permitted provided that the following conditions
00201  * are met:
00202  * 
00203  * 1. Redistributions of source code must retain the above copyright
00204  *    notice, this list of conditions and the following disclaimer.
00205  * 
00206  * 2. Redistributions in binary form must reproduce the above copyright
00207  *    notice, this list of conditions and the following disclaimer in
00208  *    the documentation and/or other materials provided with the
00209  *    distribution.
00210  * 
00211  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00212  *    and "Vovida Open Communication Application Library (VOCAL)" must
00213  *    not be used to endorse or promote products derived from this
00214  *    software without prior written permission. For written
00215  *    permission, please contact vocal@vovida.org.
00216  *
00217  * 4. Products derived from this software may not be called "VOCAL", nor
00218  *    may "VOCAL" appear in their name, without prior written
00219  *    permission of Vovida Networks, Inc.
00220  * 
00221  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00222  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00223  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00224  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00225  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00226  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00227  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00228  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00229  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00230  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00231  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00232  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00233  * DAMAGE.
00234  * 
00235  */
00236