csutil/scf_implementation.h
Go to the documentation of this file.00001 /* 00002 Crystal Space Shared Class Facility (SCF) 00003 This header contains the parts of SCF that is needed when creating 00004 new classes which implements SCF interfaces. 00005 00006 Copyright (C) 2005 by Marten Svanfeldt 00007 (C) 2005 by Michael Adams 00008 00009 This library is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU Library General Public 00011 License as published by the Free Software Foundation; either 00012 version 2 of the License, or (at your option) any later version. 00013 00014 This library is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 Library General Public License for more details. 00018 00019 You should have received a copy of the GNU Library General Public 00020 License along with this library; if not, write to the Free 00021 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00022 */ 00023 00024 #ifndef __CSUTIL_SCF_IMPLEMENTATION_H__ 00025 #define __CSUTIL_SCF_IMPLEMENTATION_H__ 00026 00027 #include "csextern.h" 00028 00029 #include "csutil/array.h" 00030 #include "csutil/customallocated.h" 00031 #include "csutil/ref.h" 00032 #include "csutil/reftrackeraccess.h" 00033 #include "csutil/threading/atomicops.h" 00034 #include "csutil/threading/mutex.h" 00035 #include "csutil/weakreferenced.h" 00036 00037 // Needs to have iBase etc 00038 #include "csutil/scf_interface.h" 00039 00040 // Control if we want to use preprocessed file or run generation each time 00041 #define SCF_IMPLGEN_PREPROCESSED 00042 // Track some simple SCF-related stats 00043 //#define SCF_TRACK_STATS 00044 00045 #ifndef CS_TYPENAME 00046 #ifdef CS_REF_TRACKER 00047 #include <typeinfo> 00048 #define CS_TYPENAME(x) typeid(x).name() 00049 #else 00050 #define CS_TYPENAME(x) 0 00051 #endif 00052 #endif 00053 00115 template<class If> 00116 class scfFakeInterface 00117 { 00118 public: 00119 struct InterfaceTraits 00120 { 00121 typedef If InterfaceType; 00122 CS_FORCEINLINE_TEMPLATEMETHOD 00123 static scfInterfaceVersion GetVersion() 00124 { return If::InterfaceTraits::GetVersion(); } 00125 CS_FORCEINLINE_TEMPLATEMETHOD static char const * GetName() 00126 { return If::InterfaceTraits::GetName(); } 00127 }; 00128 }; 00129 00131 class CS_CRYSTALSPACE_EXPORT scfImplementationHelper 00132 { 00133 protected: 00134 enum 00135 { 00136 scfstatTotal, 00137 scfstatParented, 00138 scfstatWeakreffed, 00139 scfstatMetadata, 00140 scfstatIncRef, 00141 scfstatDecRef, 00142 00143 scfstatsNum 00144 }; 00145 static uint64 stats[scfstatsNum]; 00146 static CS::Threading::Mutex statsLock; 00147 00148 CS_FORCEINLINE void BumpStat (int stat) 00149 { 00150 #ifdef SCF_TRACK_STATS 00151 CS::Threading::ScopedLock<CS::Threading::Mutex> l (statsLock); 00152 stats[stat]++; 00153 #endif 00154 } 00155 00156 struct ScfImplAuxData : public CS::Memory::CustomAllocated, 00157 public CS::Utility::AtomicRefCount, 00158 public CS::Utility::Implementation::WeakReferenced 00159 { 00160 CS::Threading::Mutex lock; 00161 iBase *scfParent; 00162 scfInterfaceMetadataList* metadataList; 00163 00164 ScfImplAuxData () : scfParent (0), metadataList (0) {} 00165 00166 bool HasWeakRefOwners() const { return weakref_owners != 0; } 00167 }; 00168 ScfImplAuxData* scfAuxData; 00169 00170 void EnsureAuxData(); 00171 void FreeAuxData(); 00172 00173 //-- Metadata handling 00174 void AllocMetadata (size_t numEntries); 00175 void CleanupMetadata (); 00176 00177 iBase* GetSCFParent(); 00178 00179 // Some virtual helpers for the metadata registry 00180 virtual size_t GetInterfaceMetadataCount () const; 00181 00182 scfImplementationHelper() : scfAuxData (0) {} 00183 virtual ~scfImplementationHelper(); 00184 }; 00185 00191 template<class Class> 00192 class scfImplementation : public virtual iBase, 00193 public scfImplementationHelper, 00194 public CS::Memory::CustomAllocated 00195 { 00196 struct WeakRefOwnersEmptyingHelper 00197 { 00198 CS::Utility::Implementation::WeakReferenced& weakReffed; 00199 bool doEmpty; 00200 00201 WeakRefOwnersEmptyingHelper (CS::Utility::Implementation::WeakReferenced& weakReffed) 00202 : weakReffed (weakReffed), doEmpty (false) {} 00203 ~WeakRefOwnersEmptyingHelper () 00204 { 00205 if (doEmpty) weakReffed.DeleteAllOwners(); 00206 } 00207 }; 00208 public: 00213 scfImplementation (Class *object, iBase *parent = 0) : 00214 scfRefCount (1) 00215 { 00216 BumpStat (scfstatTotal); 00217 if (parent) BumpStat (scfstatParented); 00218 csRefTrackerAccess::TrackConstruction (object); 00219 if (parent) 00220 { 00221 EnsureAuxData(); 00222 scfAuxData->scfParent = parent; 00223 parent->IncRef (); 00224 } 00225 } 00226 00235 scfImplementation (const scfImplementation& /*other*/) : iBase() 00236 { 00237 CS_ASSERT_MSG ("To allow copying SCF classes, create a copy " 00238 "constructor in the derived class, and initialize scfImplementation " 00239 "like in the normal constructor, i.e. use " 00240 "\"scfImplementation (this)\".", false); 00241 } 00242 00243 // Cleanup 00244 virtual ~scfImplementation() 00245 { 00246 csRefTrackerAccess::TrackDestruction (GetSCFObject(), scfRefCount); 00247 if (HasAuxData()) 00248 { 00249 scfAuxData->ClearRefOwners(); 00250 CleanupMetadata (); 00251 iBase *scfParent = scfAuxData->scfParent; 00252 if (scfParent) scfParent->DecRef(); 00253 } 00254 } 00255 00261 scfImplementation& operator= (const scfImplementation& /*other*/) 00262 { 00263 return *this; 00264 } 00265 00266 virtual void DecRef () 00267 { 00268 CS_ASSERT_MSG("Refcount decremented for destroyed object", 00269 scfRefCount != 0); 00270 csRefTrackerAccess::TrackDecRef (GetSCFObject(), scfRefCount); 00271 /* Keep a reference to the aux data so we can keep weak ref owner locks 00272 * past the destructor call */ 00273 csRef<ScfImplAuxData> keepAuxData (scfAuxData); 00274 int32 refcount; 00275 if (keepAuxData) 00276 { 00277 CS::Threading::ScopedLock<CS::Threading::Mutex> lockAuxData (keepAuxData->lock); 00278 /* The weak refs may need to be emptied after clearing and after the weak ref 00279 * locks have been released, but before the aux data lock is released */ 00280 WeakRefOwnersEmptyingHelper emptyWeakRefs (*keepAuxData); 00281 CS::Utility::Implementation::WeakReferenced::ScopedWeakRefOwnersLock lockWeakRefs (*keepAuxData); 00282 if ((refcount = CS::Threading::AtomicOperations::Decrement (&scfRefCount)) == 0) 00283 { 00284 /* Remove ref owners now, to avoid deadlock if the dtor triggers the 00285 * destruction of a ref owner */ 00286 scfAuxData->ClearRefOwners(); 00287 emptyWeakRefs.doEmpty = true; 00288 } 00289 } 00290 else 00291 { 00292 refcount = CS::Threading::AtomicOperations::Decrement (&scfRefCount); 00293 } 00294 if (refcount == 0) 00295 delete GetSCFObject(); 00296 BumpStat (scfstatDecRef); 00297 } 00298 00299 virtual void IncRef () 00300 { 00301 CS_ASSERT_MSG("Refcount incremented from inside dtor", 00302 scfRefCount != 0); 00303 csRefTrackerAccess::TrackIncRef (GetSCFObject(), scfRefCount); 00304 CS::Threading::AtomicOperations::Increment (&scfRefCount); 00305 BumpStat (scfstatIncRef); 00306 } 00307 00308 virtual int GetRefCount () 00309 { 00310 return CS::Threading::AtomicOperations::Read (&scfRefCount); 00311 } 00312 00313 virtual void AddRefOwner (void** ref_owner, CS::Threading::Mutex* mutex) 00314 { 00315 EnsureAuxData(); 00316 CS::Threading::ScopedLock<CS::Threading::Mutex> l (scfAuxData->lock); 00317 if (GetRefCount() <= 0) 00318 { 00319 /* In the case we are already in destruction, don't allow any new weak 00320 * references, just destroy it at once 00321 */ 00322 *ref_owner = 0; 00323 return; 00324 } 00325 scfAuxData->AddRefOwner (ref_owner, mutex); 00326 if (!scfAuxData->HasWeakRefOwners()) 00327 BumpStat (scfstatWeakreffed); 00328 } 00329 00330 virtual void RemoveRefOwner (void** ref_owner) 00331 { 00332 if (!HasAuxData()) return; 00333 00334 CS::Threading::ScopedLock<CS::Threading::Mutex> l (scfAuxData->lock); 00335 scfAuxData->RemoveRefOwner (ref_owner); 00336 } 00337 00338 virtual scfInterfaceMetadataList* GetInterfaceMetadata () 00339 { 00340 EnsureAuxData(); 00341 CS::Threading::ScopedLock<CS::Threading::Mutex> l (scfAuxData->lock); 00342 if (!scfAuxData->metadataList) 00343 { 00344 BumpStat (scfstatMetadata); 00345 // Need to set it up, do so 00346 AllocMetadata (GetInterfaceMetadataCount ()); 00347 FillInterfaceMetadata (0); 00348 } 00349 00350 return scfAuxData->metadataList; 00351 } 00352 00353 protected: 00354 Class* GetSCFObject() { return static_cast<Class*> (this); } 00355 const Class* GetSCFObject() const { return static_cast<const Class*> (this); } 00356 00357 int32 scfRefCount; 00358 00359 void *QueryInterface (scfInterfaceID iInterfaceID, 00360 scfInterfaceVersion iVersion) 00361 { 00362 // Default, just check iBase.. all objects have iBase 00363 if (iInterfaceID == scfInterfaceTraits<iBase>::GetID () && 00364 scfCompatibleVersion (iVersion, scfInterfaceTraits<iBase>::GetVersion ())) 00365 { 00366 GetSCFObject()->IncRef (); 00367 return static_cast<iBase*> (GetSCFObject()); 00368 } 00369 00370 // For embedded interfaces 00371 if (HasAuxData() && scfAuxData->scfParent) 00372 return scfAuxData->scfParent->QueryInterface (iInterfaceID, iVersion); 00373 00374 return 0; 00375 } 00376 00377 00378 // Fill in interface metadata in the metadata table, starting at offset N 00379 virtual void FillInterfaceMetadata (size_t n) 00380 { 00381 scfInterfaceMetadataList* metadataList = scfAuxData->metadataList; 00382 if (!metadataList) 00383 return; 00384 00385 FillInterfaceMetadataIf<iBase> (metadataList->metadata, n); 00386 } 00387 00388 template<typename IF> 00389 CS_FORCEINLINE_TEMPLATEMETHOD static void FillInterfaceMetadataIf ( 00390 scfInterfaceMetadata* metadataArray, size_t pos) 00391 { 00392 metadataArray[pos].interfaceName = scfInterfaceTraits<IF>::GetName (); 00393 metadataArray[pos].interfaceID = scfInterfaceTraits<IF>::GetID (); 00394 metadataArray[pos].interfaceVersion = scfInterfaceTraits<IF>::GetVersion (); 00395 } 00396 00397 /* Note: can't put this into scfImplementationHelper, breaks on MingW shared builds 00398 * (possibly a clash between the method being forced inlined and dllexported) */ 00399 CS_FORCEINLINE bool HasAuxData() 00400 { 00401 // Double-cast to cheat strict-aliasing rules 00402 return CS::Threading::AtomicOperations::Read ((void**)(void*)&scfAuxData) != 0; 00403 } 00404 }; 00405 00406 00407 /* Here the magic happens: generate scfImplementationN and 00408 * scfImplementationExtN classed */ 00409 #define SCF_IN_IMPLEMENTATION_H 1 00410 #if defined(DOXYGEN_RUN) || !defined(SCF_IMPLGEN_PREPROCESSED) 00411 // Generation is in separate file mostly for documentation generation purposes. 00412 #include "scf_implgen.h" 00413 #else 00414 #include "scf_implgen_p.h" 00415 #endif 00416 00417 #undef SCF_IN_IMPLEMENTATION_H 00418 #undef SCF_IMPLGEN_PREPROCESSED 00419 00422 #endif
Generated for Crystal Space 2.1 by doxygen 1.6.1
