Fawkes API  Fawkes Development Version
refcount.cpp
00001 
00002 /***************************************************************************
00003  *  refcount.cpp - reference counting base class
00004  *
00005  *  Created: Fri Oct 27 13:52:08 2006
00006  *  Copyright  2006  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include <core/utils/refcount.h>
00025 #include <core/threading/mutex.h>
00026 #include <core/exceptions/software.h>
00027 
00028 #include <unistd.h>
00029 
00030 namespace fawkes {
00031 
00032 /** @class RefCount core/utils/refcount.h
00033  * Reference counting base class.
00034  * Derive this class with your object if you need reference counting for the object
00035  * thus that it is not deleted while some code is still using an class instance.
00036  *
00037  * The RefCount class is NOT meant for direct usage. In most cases if you are aware
00038  * of the need of reference couting during the design of the software derive this
00039  * class. This is the recommended way. If you want to use reference counting with
00040  * a class that you cannot or do not want to modify you can use the RefCounter
00041  * template class to accomplish the desired task.
00042  * @see RefCounter
00043  *
00044  * @ingroup FCL
00045  * @author Tim Niemueller
00046  */
00047 
00048 
00049 /** Constructor. */
00050 RefCount::RefCount()
00051 {
00052   ref_mutex = new Mutex();
00053   refc = 1;
00054 }
00055 
00056 
00057 /** Destructor. */
00058 RefCount::~RefCount()
00059 {
00060   delete ref_mutex;
00061 }
00062 
00063 
00064 /** Increment reference count.
00065  * @exception DestructionInProgressException Thrown if the only other reference holder
00066  * for this instance was just deleting the instance when you tried to reference it.
00067  * @see recount();
00068  */
00069 void
00070 RefCount::ref()
00071 {
00072   ref_mutex->lock();
00073   if ( refc == 0 ) {
00074     throw DestructionInProgressException("Tried to reference that is currently being deleted");
00075   }
00076   ++refc;
00077   ref_mutex->unlock();
00078 }
00079 
00080 
00081 /** Decrement reference count and conditionally delete this instance.
00082  * This method will decrement the reference count of this message. If the reference count
00083  * reaches zero the message will be deleted automatically. So it is not safe to use this
00084  * instance after is has been unref()'ed.
00085  * For the code calling
00086  * @code
00087  * obj->unref();
00088  * @endcode
00089  * should be considered equivalent to
00090  * @code
00091  * delete obj;
00092  * @endcode.
00093  * There is no guarantee whatsover that the object can still be used afterwards.
00094  * It is however guaranteed, that the instance is not deleted/free from memory if
00095  * there are still other applications using this instance that properly ref()'ed
00096  * this instance before conditional delete was called.
00097  */
00098 void
00099 RefCount::unref()
00100 {
00101   
00102   ref_mutex->lock();
00103   if ( refc == 0 ) {
00104     throw DestructionInProgressException("Tried to reference that is currently being deleted");
00105   }
00106   if ( refc > 0 )  --refc;
00107   if ( refc == 0 ) {
00108     // commit suicide
00109     delete this;
00110     return;
00111   }
00112   ref_mutex->unlock();
00113 }
00114 
00115 
00116 /** Get reference count for this instance.
00117  * The reference count is used to determine if a message should really be destructed
00118  * or not.
00119  * Do not rely on this value, as race-conditions may ruin your code! Do only use the
00120  * atomic ref() and unref() operations. This function is only provided to output
00121  * informational debugging output!
00122  * @return reference count
00123  */
00124 unsigned int
00125 RefCount::refcount()
00126 {
00127   return refc;
00128 }
00129 
00130 
00131 } // end namespace fawkes