7
* ==========================
9
* yasper - A non-intrusive reference counted pointer.
12
* Many ideas borrowed from Yonat Sharon and
13
* Andrei Alexandrescu.
16
* ----------------------------------------------------------------------------------
17
* Copyright (C) 2005-2007 Alex Rubinsteyn
19
* This software is provided 'as-is', without any express or implied
20
* warranty. In no event will the authors be held liable for any damages
21
* arising from the use of this software.
23
* Permission is granted to anyone to use this software for any purpose,
24
* including commercial applications, and to alter it and redistribute it
25
* freely, subject to the following restrictions:
27
* 1. The origin of this software must not be misrepresented; you must not
28
* claim that you wrote the original software. If you use this software
29
* in a product, an acknowledgment in the product documentation would be
30
* appreciated but is not required.
31
* 2. Altered source versions must be plainly marked as such, and must not be
32
* misrepresented as being the original software.
33
* 3. This notice may not be removed or altered from any source distribution.
35
* -----------------------------------------------------------------------------------
37
* Send all questions, comments and bug reports to:
38
* Alex Rubinsteyn (alex.rubinsteyn {at-nospam} gmail {dot} com)
46
#define GLOC() (__FILE__ ":" TOSTRING(__LINE__))
47
#define STRINGIFY(x) #x
48
#define TOSTRING(x) STRINGIFY(x)
51
#define SUSPEND_WAKEUP()
52
#define RESUME_WAKEUP()
60
#define SUSPEND_WAKEUP()\
61
siginterrupt(SIGUSR2, 0)
63
#define RESUME_WAKEUP()\
64
siginterrupt(SIGUSR2, 1)
70
class GCriticalSection
75
::InitializeCriticalSection(&m_buffer);
81
::DeleteCriticalSection(&m_buffer);
87
::EnterCriticalSection(&m_buffer);
93
::LeaveCriticalSection(&m_buffer);
96
CRITICAL_SECTION m_buffer;
101
class GCriticalSection
106
int err = pthread_mutex_init(&m_mutex, NULL);
110
std::cerr << "pthread_mutex_init() error: " << err << std::endl;
118
int err = pthread_mutex_destroy(&m_mutex);
121
std::cerr << "pthread_mutex_destroy() error: " << err << std::endl;
125
std::cerr << "pthread_mutex_destroy() error: Mutex no creado correctamente" << std::endl;
132
int err = pthread_mutex_lock(&m_mutex);
136
std::cerr << "pthread_mutex_lock() error: deadlock prevenido" << std::endl;
140
std::cerr << "pthread_mutex_lock() error: No inicializado" << std::endl;
147
std::cerr << "pthread_mutex_lock() error: " << err << std::endl;
152
std::cerr << "pthread_mutex_lock() error: Mutex no creado correctamente" << std::endl;
159
int err = pthread_mutex_unlock(&m_mutex);
163
std::cerr << "pthread_mutex_unlock() error: No adquirido por el invocador" << std::endl;
167
std::cerr << "pthread_mutex_unlock() error: No inicializado" << std::endl;
174
std::cerr << "pthread_mutex_unlock() error: " << err << std::endl;
179
std::cerr << "pthread_mutex_unlock() error: Mutex no creado correctamente" << std::endl;
184
pthread_mutex_t m_mutex;
194
//----------------------------------------------------------------------------------------------------
195
//region Interfaz de soporte de cerrojos
196
//----------------------------------------------------------------------------------------------------
199
//----------------------------------------------------------------------------------------------------
200
//region Constructor y destructor
209
//----------------------------------------------------------------------------------------------------
210
//region Interfaz de exclusion mutua
213
inline void Lock(const std::string& loc );
215
inline void UnLock(const std::string& loc );
219
//----------------------------------------------------------------------------------------------------
220
//region Interfaz de exclusion mutua desde automatico
223
inline void AutoLock(GLocker* pLocker, const std::string& loc = "");
225
inline void AutoUnLock(GLocker* pLocker);
229
//----------------------------------------------------------------------------------------------------
230
//region Interfaz de subscripcion
233
GLocker* m_pLocker; // ILocker que ha bloqueado el cerrojo.
236
//----------------------------------------------------------------------------------------------------
241
std::string m_LocBloqueo;
242
GCriticalSection* m_pCS; // El cerrojo real.
243
GCriticalSection* m_pCSRegistro; // Cerrojo para registrar el ocasionador del bloqueo.
246
friend class GLocker;
250
//----------------------------------------------------------------------------------------------------
251
//region Helper de bloqueo automatico
252
//----------------------------------------------------------------------------------------------------
255
//----------------------------------------------------------------------------------------------------
256
//region Construccion y destruccion
259
inline GLocker( GLockable& pLockable, const std::string& loc = "" )
261
m_pLockable = &pLockable;
262
m_LocInstanciacion = loc;
263
//GTRACE("GNC::GCS::ILockable()");
264
m_pLockable->AutoLock(this, m_LocInstanciacion);
267
inline GLocker( GLockable* pLockable, const std::string& loc = "" )
269
m_pLockable = pLockable;
270
m_LocInstanciacion = loc;
271
//GTRACE("GNC::GCS::ILockable()");
272
m_pLockable->AutoLock(this, loc);
277
m_pLockable->AutoUnLock(this);
278
//GTRACE("GNC::GCS::~ILockable()");
283
//----------------------------------------------------------------------------------------------------
287
GLockable* m_pLockable;
288
std::string m_LocInstanciacion;
291
friend class GLockable;
296
//----------------------------------------------------------------------------------------------------
297
//region Implementacion de GLockable
298
inline GLockable::GLockable()
302
m_pCS = new GCriticalSection();
305
inline GLockable::~GLockable()
308
if (m_pLocker != NULL) {
309
std::cerr << "Error al destruir GLockable: El cerrojo continua autobloqueado por " << m_pLocker << " instanciado en " << m_pLocker->m_LocInstanciacion.c_str() << std::endl;
311
else if (m_LocBloqueo.size() != 0) {
312
std::cerr << "Error al destruir GLockable: El cerrojo continua bloqueado por una llamada en " << m_LocBloqueo.c_str() << std::endl;
315
std::cerr << "Error al destruir GLockable: El cerrojo continua bloqueado por una llamada sin registrar" << std::endl;
324
inline void GLockable::Lock(const std::string& loc )
327
//----------------------------------------------------------------------------------------------------
328
// Entrada a la seccion Critica
329
//----------------------------------------------------------------------------------------------------
331
//GTRACE("GNC::GCS::Lock() en " << loc.c_str() << " Esperando liberacion desde bloqueo previo en " << m_LocBloqueo.c_str());
335
//GTRACE("GNC::GCS::Lock() en " << loc.c_str());
341
//GTRACE("GNC::GCS::Lock() en " << loc.c_str());
344
//----------------------------------------------------------------------------------------------------
345
//----------------------------------------------------------------------------------------------------
349
inline void GLockable::UnLock(const std::string& loc )
351
//----------------------------------------------------------------------------------------------------
352
// Salida de la seccion Critica
353
//----------------------------------------------------------------------------------------------------
355
std::cerr << "Error: El cerrojo no estaba bloqueado. (Tratado de liberar en " << loc.c_str() << ")" ;
357
else if (m_pLocker != NULL) {
358
std::cerr << "Error: El cerrojo estaba auto bloqueado previamente por " << m_pLocker << " instanciado en " << m_pLocker->m_LocInstanciacion.c_str() << std::endl;
362
//GTRACE("GNC::GCS::UnLock() en " << loc.c_str());
363
//GTRACE(" >> Liberado bloqueo desde " << m_LocBloqueo.c_str());
368
//----------------------------------------------------------------------------------------------------
369
//----------------------------------------------------------------------------------------------------
373
inline void GLockable::AutoLock(GLocker* pLocker, const std::string& loc)
375
//----------------------------------------------------------------------------------------------------
376
// Entrada a la seccion Critica
377
//----------------------------------------------------------------------------------------------------
383
#if defined(_GINKGO_TRACE)
384
if (pLocker != NULL) {
385
//GTRACE("GNC::GCS::Lock() automatico por " << pLocker << " instanciado en " << pLocker->m_LocInstanciacion.c_str());
388
//GTRACE("GNC::GCS::Lock() automatico por NULL (ĀæError?)");
392
//----------------------------------------------------------------------------------------------------
393
//----------------------------------------------------------------------------------------------------
397
inline void GLockable::AutoUnLock(GLocker* pLocker)
399
//----------------------------------------------------------------------------------------------------
400
// Salida de la seccion Critica
401
//----------------------------------------------------------------------------------------------------
403
std::cerr << "Error: El cerrojo no estaba bloqueado. (Tratado de liberar automaticamente por " << pLocker;
404
if (pLocker != NULL) {
405
std::cerr << " instanciado en " << pLocker->m_LocInstanciacion.c_str() << ")" << std::endl;
408
std::cerr << ")" << std::endl;
411
else if (m_pLocker != pLocker) {
412
std::cerr << "Error: Se ha liberado un bloqueo desde un Locker automatico distinto del que lo inicio: " << std::endl;
413
std::cerr << "\tIniciado por " << m_pLocker;
414
if (m_pLocker != NULL) {
415
std::cerr << " instanciado en " << m_pLocker->m_LocInstanciacion.c_str() << std::endl;
418
std::cerr << std::endl;
420
std::cerr << "\tTratado de liberar por " << pLocker;
421
if (pLocker != NULL) {
422
std::cerr << " instanciado en " << pLocker->m_LocInstanciacion.c_str() << std::endl;
425
std::cerr << std::endl;
429
#if defined (_GINKGO_TRACE)
430
if (pLocker != NULL) {
431
//GTRACE("GNC::GCS::UnLock() automatico por " << pLocker << " instanciado en " << pLocker->m_LocInstanciacion.c_str());
434
//GTRACE("GNC::GCS::UnLock() automatico por " << pLocker);
441
//----------------------------------------------------------------------------------------------------
442
//----------------------------------------------------------------------------------------------------
448
struct GnkNullPointerException : public std::exception
450
GnkNullPointerException() throw() {}
451
~GnkNullPointerException() throw() {}
453
const char* what() const throw()
455
return "[Yasper Exception] Attempted to dereference null pointer";
459
class GnkCounter : public GLockable
462
GnkCounter(unsigned c = 1) : count(c) {}
467
template <typename X>
468
class GnkPtr : public GLockable
472
typedef X element_type;
475
GnkPtr needs to be its own friend so GnkPtr< X > and GnkPtr< Y > can access
476
each other's private data members
478
template <class Y> friend class GnkPtr;
481
- don't create GnkCounter
483
GnkPtr() : rawPtr(0), counter(0) { }
486
Construct from a raw pointer
488
GnkPtr(X* raw, GnkCounter* c = 0) : rawPtr(0), counter(0)
500
counter = new GnkCounter;
507
template <typename Y>
508
explicit GnkPtr(Y* raw, GnkCounter* c = 0) : rawPtr(0), counter(0)
516
rawPtr = static_cast<X*>( raw );
520
rawPtr = static_cast<X*>( raw );
521
counter = new GnkCounter;
531
GnkPtr(const GnkPtr< X >& otherPtr)
534
( (GnkPtr<X>*) &otherPtr)->Lock(GLOC());
536
if (otherPtr.counter) {
537
otherPtr.counter->Lock(GLOC());
539
acquire( otherPtr.counter );
540
rawPtr = otherPtr.rawPtr;
541
otherPtr.counter->UnLock(GLOC());
548
( (GnkPtr<X>*) &otherPtr)->UnLock(GLOC());
552
template <typename Y>
553
explicit GnkPtr(const GnkPtr< Y >& otherPtr) : rawPtr(0), counter(0)
556
( (GnkPtr<Y>*) &otherPtr)->Lock(GLOC());
558
if (otherPtr.counter) {
559
otherPtr.counter->Lock(GLOC());
561
acquire(otherPtr.counter);
562
rawPtr = static_cast<X*>( otherPtr.rawPtr );
564
otherPtr.counter->UnLock(GLOC());
567
( (GnkPtr<Y>*) &otherPtr)->UnLock(GLOC());
583
Assignment to another GnkPtr
586
GnkPtr& operator=(const GnkPtr< X >& otherPtr)
590
( (GnkPtr<X>*) &otherPtr)->Lock(GLOC());
592
if (this != &otherPtr)
596
if (otherPtr.counter) {
597
otherPtr.counter->Lock(GLOC());
599
acquire(otherPtr.counter);
600
rawPtr = static_cast<X*> (otherPtr.rawPtr);
602
otherPtr.counter->UnLock(GLOC());
612
( (GnkPtr<X>*) &otherPtr)->UnLock(GLOC());
619
template <typename Y>
620
GnkPtr& operator=(const GnkPtr< Y >& otherPtr)
623
( (GnkPtr<Y>*) &otherPtr)->Lock(GLOC());
625
if ( this != (GnkPtr< X >*) &otherPtr )
629
if (otherPtr.counter) {
630
otherPtr.counter->Lock(GLOC());
632
acquire(otherPtr.counter);
633
rawPtr = static_cast<X*> (otherPtr.rawPtr);
635
otherPtr.counter->UnLock(GLOC());
639
( (GnkPtr<Y>*) &otherPtr)->UnLock(GLOC());
645
Assignment to raw pointers is really dangerous business.
646
If the raw pointer is also being used elsewhere,
647
we might prematurely delete it, causing much pain.
648
Use sparingly/with caution.
651
GnkPtr& operator=(X* raw)
658
GnkCounter* c = new GnkCounter;
671
template <typename Y>
672
GnkPtr& operator=(Y* raw)
679
GnkCounter* c = new GnkCounter();
684
rawPtr = static_cast<X*>(raw);
694
assignment to long to allow GnkPtr< X > = NULL,
695
also allows raw pointer assignment by conversion.
696
Raw pointer assignment is really dangerous!
697
If the raw pointer is being used elsewhere,
698
it will get deleted prematurely.
700
GnkPtr& operator=(long num)
703
if (num == 0) //pointer set to null
708
else //assign raw pointer by conversion
711
GnkCounter* c = new GnkCounter();
716
rawPtr = reinterpret_cast<X*>(num);
729
X* operator->() const
731
return GetRawPointer();
736
Dereference the pointer
738
X& operator* () const
740
return *GetRawPointer();
745
Conversion/casting operators
749
operator bool() const
756
implicit casts to base types of the
757
the pointer we're storing
760
template <typename Y>
765
( (GnkPtr<Y>*) this)->Lock(GLOC());
766
r = static_cast<Y*>(rawPtr);
767
( (GnkPtr<Y>*) this)->UnLock(GLOC());
772
template <typename Y>
773
operator const Y*() const
776
( (GnkPtr<Y>*) this)->Lock(GLOC());
777
r = static_cast<const Y*>(rawPtr);
778
( (GnkPtr<Y>*) this)->UnLock(GLOC());
782
template <typename Y>
785
//new GnkPtr must also take our counter or else the reference counts
786
//will go out of sync
787
return GnkPtr<Y>(rawPtr, counter);
792
Provide access to the raw pointer
795
X* GetRawPointer() const
802
throw new GnkNullPointerException;
810
Is there only one reference on the counter?
812
bool IsUnique() const
818
counter->Lock(GLOC());
819
unique = (counter->count == 1);
820
counter->UnLock(GLOC());
835
counter->Lock(GLOC());
836
valid = (rawPtr != NULL);
837
counter->UnLock(GLOC());
843
unsigned GetCount() const
849
counter->Lock(GLOC());
850
count = counter->count;
851
counter->UnLock(GLOC());
862
// increment the count
863
void acquire(GnkCounter* c)
869
// decrement the count, delete if it is 0
874
GnkCounter* c = counter;
902
template <typename X, typename Y>
903
bool operator==(const GnkPtr< X >& lGnkPtr, const GnkPtr< Y >& rGnkPtr)
905
return lGnkPtr.GetRawPointer() == rGnkPtr.GetRawPointer();
908
template <typename X, typename Y>
909
bool operator==(const GnkPtr< X >& lGnkPtr, Y* raw)
911
return lGnkPtr.GetRawPointer() == raw ;
914
template <typename X>
915
bool operator==(const GnkPtr< X >& lGnkPtr, long num)
917
if (num == 0 && !lGnkPtr.IsValid()) //both pointer and address are null
922
else //convert num to a pointer, compare addresses
924
return lGnkPtr == reinterpret_cast<X*>(num);
929
template <typename X, typename Y>
930
bool operator!=(const GnkPtr< X >& lGnkPtr, const GnkPtr< Y >& rGnkPtr)
932
return ( !operator==(lGnkPtr, rGnkPtr) );
935
template <typename X, typename Y>
936
bool operator!=(const GnkPtr< X >& lGnkPtr, Y* raw)
938
return ( !operator==(lGnkPtr, raw) );
941
template <typename X>
942
bool operator!=(const GnkPtr< X >& lGnkPtr, long num)
944
return (!operator==(lGnkPtr, num) );
947
template <typename X, typename Y>
948
bool operator&&(const GnkPtr< X >& lGnkPtr, const GnkPtr< Y >& rGnkPtr)
950
return lGnkPtr.IsValid() && rGnkPtr.IsValid();
953
template <typename X>
954
bool operator&&(const GnkPtr< X >& lGnkPtr, bool rval)
956
return lGnkPtr.IsValid() && rval;
959
template <typename X>
960
bool operator&&(bool lval, const GnkPtr< X >& rGnkPtr)
962
return lval && rGnkPtr.IsValid();
965
template <typename X, typename Y>
966
bool operator||(const GnkPtr< X >& lGnkPtr, const GnkPtr< Y >& rGnkPtr)
968
return lGnkPtr.IsValid() || rGnkPtr.IsValid();
971
template <typename X>
972
bool operator||(const GnkPtr< X >& lGnkPtr, bool rval)
974
return lGnkPtr.IsValid() || rval;
977
template <typename X>
978
bool operator||(bool lval, const GnkPtr< X >& rGnkPtr)
980
return lval || rGnkPtr.IsValid();
983
template <typename X>
984
bool operator!(const GnkPtr< X >& p)
986
return (!p.IsValid());
990
/* less than comparisons for storage in containers */
991
template <typename X, typename Y>
992
bool operator< (const GnkPtr< X >& lGnkPtr, const GnkPtr < Y >& rGnkPtr)
994
return lGnkPtr.GetRawPointer() < rGnkPtr.GetRawPointer();
997
template <typename X, typename Y>
998
bool operator< (const GnkPtr< X >& lGnkPtr, Y* raw)
1000
return lGnkPtr.GetRawPointer() < raw;
1003
template <typename X, typename Y>
1004
bool operator< (X* raw, const GnkPtr< Y >& rGnkPtr)
1006
return raw < rGnkPtr.GetRawPointer();