home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Software Money Savers / VirtualDub / Source / VirtualDub-1.7.7-src.7z / src / system / source / cache.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-11-05  |  9.7 KB  |  423 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    System library component
  3. //    Copyright (C) 1998-2005 Avery Lee, All Rights Reserved.
  4. //
  5. //    Beginning with 1.6.0, the VirtualDub system library is licensed
  6. //    differently than the remainder of VirtualDub.  This particular file is
  7. //    thus licensed as follows (the "zlib" license):
  8. //
  9. //    This software is provided 'as-is', without any express or implied
  10. //    warranty.  In no event will the authors be held liable for any
  11. //    damages arising from the use of this software.
  12. //
  13. //    Permission is granted to anyone to use this software for any purpose,
  14. //    including commercial applications, and to alter it and redistribute it
  15. //    freely, subject to the following restrictions:
  16. //
  17. //    1.    The origin of this software must not be misrepresented; you must
  18. //        not claim that you wrote the original software. If you use this
  19. //        software in a product, an acknowledgment in the product
  20. //        documentation would be appreciated but is not required.
  21. //    2.    Altered source versions must be plainly marked as such, and must
  22. //        not be misrepresented as being the original software.
  23. //    3.    This notice may not be removed or altered from any source
  24. //        distribution.
  25.  
  26. #include "stdafx.h"
  27. #include <vd2/system/cache.h>
  28.  
  29. ///////////////////////////////////////////////////////////////////////////
  30.  
  31. VDCache::VDCache(IVDCacheAllocator *pAllocator)
  32.     : mpAllocator(pAllocator)
  33.     , mObjectCount(0)
  34.     , mObjectLimit(16)
  35. {
  36. }
  37.  
  38. VDCache::~VDCache() {
  39.     Shutdown();
  40. }
  41.  
  42. void VDCache::Shutdown() {
  43.     for(int i=0; i<kVDCacheStateCount; ++i) {
  44.         ObjectList& ol = mLists[i];
  45.  
  46.         while(!ol.empty()) {
  47.             VDCachedObject *pObject = static_cast<VDCachedObject *>(ol.back());
  48.             ol.pop_back();
  49.  
  50.             pObject->OnCacheEvict();
  51.             pObject->SetCache(NULL);    // will release object
  52.  
  53.             if (i != kVDCacheStateFree) {
  54.                 VDASSERT((int)--mObjectCount >= 0);
  55.             }
  56.         }
  57.     }
  58. }
  59.  
  60. int VDCache::GetStateCount(int state) {
  61.     vdsynchronized(mLock) {
  62.         return mLists[state].size();
  63.     }
  64. }
  65.  
  66. void VDCache::DumpListStatus(int state) {
  67.     vdsynchronized(mLock) {
  68.         ObjectList& ol = mLists[state];
  69.  
  70.         for(ObjectList::iterator it(ol.begin()), itEnd(ol.end()); it!=itEnd; ++it) {
  71.             VDCachedObject *pObj = static_cast<VDCachedObject *>(*it);
  72.  
  73.             pObj->DumpStatus();
  74.         }
  75.     }
  76. }
  77.  
  78. VDCachedObject *VDCache::Allocate(sint64 key) {
  79.     VDCachedObject *pObj = NULL;
  80.  
  81.     vdsynchronized(mLock) {
  82.         if (mObjectCount >= mObjectLimit - 1)
  83.             Evict(mObjectLimit - 1);
  84.  
  85.         ObjectList& fl = mLists[kVDCacheStateFree];
  86.         ObjectList& pl = mLists[kVDCacheStatePending];
  87.  
  88.         if (fl.empty()) {
  89.             VDCachedObject *pNewObject = mpAllocator->OnCacheAllocate();
  90.  
  91.             pNewObject->SetCache(this);
  92.             pNewObject->SetState(kVDCacheStateFree);
  93.  
  94.             fl.push_front(pNewObject);
  95.         }
  96.  
  97.         ++mObjectCount;
  98.  
  99.         pObj = static_cast<VDCachedObject *>(fl.front());
  100.         VDASSERT(pObj->GetState() == kVDCacheStateFree);
  101.         pObj->AddRef();
  102.         pObj->SetState(kVDCacheStatePending);
  103.         pObj->mHashKey = key;
  104.         pl.splice(pl.begin(), fl, fl.fast_find(pObj));
  105.         mHash.insert(pObj);
  106.     }
  107.  
  108.     return pObj;
  109. }
  110.  
  111. VDCachedObject *VDCache::Create(sint64 key, bool& is_new) {
  112.     // The pending, ready, active, and complete lists are eligible for lookup.
  113.     // The free and aborted lists are not.
  114.  
  115.     VDCachedObject *pObj = NULL;
  116.  
  117.     is_new = false;
  118.  
  119.     vdsynchronized(mLock) {
  120.         pObj = static_cast<VDCachedObject *>(mHash[key]);
  121.  
  122.         if (pObj) {
  123.             pObj->AddRef();
  124.  
  125.             VDASSERT(pObj->GetState() != kVDCacheStateFree);
  126.  
  127.             if (pObj->GetState() == kVDCacheStateIdle) {
  128.                 pObj->SetState(kVDCacheStateComplete);
  129.  
  130.                 ObjectList& il = mLists[kVDCacheStateIdle];
  131.                 ObjectList& cl = mLists[kVDCacheStateComplete];
  132.  
  133.                 cl.splice(cl.begin(), il, il.fast_find(pObj));
  134.             }
  135.         }
  136.  
  137.         if (!pObj) {
  138.             is_new = true;
  139.             pObj = Allocate(key);
  140.         }
  141.     }
  142.  
  143.     return pObj;
  144. }
  145.  
  146. void VDCache::Evict(uint32 level) {
  147.     if (mObjectCount <= level)
  148.         return;
  149.  
  150.     int maxfree = mObjectCount - level;
  151.  
  152.     ObjectList& il = mLists[kVDCacheStateIdle];
  153.     ObjectList& al = mLists[kVDCacheStateAborting];
  154.  
  155.     while(maxfree-- > 0 && mObjectCount >= level && !il.empty()) {
  156.         VDCachedObject *pObject = static_cast<VDCachedObject *>(il.back());
  157.         VDASSERT(pObject->GetState() == kVDCacheStateIdle);
  158.         
  159.         pObject->SetState(kVDCacheStateAborting);
  160.         al.splice(al.begin(), il, pObject);
  161.  
  162.         pObject->WeakAddRef();
  163.  
  164.         mLock.Unlock();
  165.  
  166.         pObject->OnCacheEvict();
  167.         pObject->WeakRelease();            // Will move to free list.
  168.  
  169.         mLock.Lock();
  170.     }
  171. }
  172.  
  173. void VDCache::NotifyFree(VDCachedObject *pObject) {
  174.     vdsynchronized(mLock) {
  175.         int rc = pObject->GetRefCount();
  176.  
  177.         // This check is required because it is possible for a call to
  178.         // Allocate() to sneak in before we acquire the lock.
  179.         if (rc < 0x10000) {
  180.             VDCacheState oldState = pObject->GetState();
  181.             VDCacheState newState = oldState;
  182.  
  183.             if (rc & 0xfffe)
  184.                 newState = kVDCacheStateAborting;
  185.             else if (pObject->IsValid())
  186.                 newState = kVDCacheStateIdle;
  187.             else {
  188.                 VDVERIFY((int)--mObjectCount >= 0);
  189.                 newState = kVDCacheStateFree;
  190.                 mHash.erase(pObject);
  191.             }
  192.  
  193.             if (newState != oldState) {
  194.                 pObject->SetState(newState);
  195.  
  196.                 ObjectList& nl = mLists[newState];
  197.                 ObjectList& ol = mLists[oldState];
  198.                 nl.splice(nl.begin(), ol, ol.fast_find(pObject));
  199.             }
  200.  
  201.             if (oldState == kVDCacheStatePending || oldState == kVDCacheStateReady)
  202.                 pObject->OnCacheAbortPending();
  203.         }
  204.     }
  205. }
  206.  
  207. void VDCache::Schedule(VDCachedObject *pObject) {
  208.     vdsynchronized(mLock) {
  209.         VDCacheState oldState = pObject->GetState();
  210.  
  211.         VDASSERT(oldState == kVDCacheStatePending || oldState == kVDCacheStateActive);
  212.  
  213.         ObjectList& ol = mLists[oldState];
  214.         ObjectList& nl = mLists[kVDCacheStateReady];
  215.  
  216.         nl.splice(nl.back(), ol, ol.fast_find(pObject));
  217.         pObject->SetState(kVDCacheStateReady);
  218.     }
  219. }
  220.  
  221. VDCachedObject *VDCache::GetNextReady() {
  222.     VDCachedObject *pObject = NULL;
  223.  
  224.     vdsynchronized(mLock) {
  225.         ObjectList& rl = mLists[kVDCacheStateReady];
  226.         ObjectList& al = mLists[kVDCacheStateActive];
  227.  
  228.         if (!rl.empty()) {
  229.             pObject = static_cast<VDCachedObject *>(rl.front());
  230.             VDASSERT(pObject->GetState() == kVDCacheStateReady);
  231.  
  232.             al.splice(al.end(), rl, rl.begin());
  233.  
  234.             pObject->SetState(kVDCacheStateActive);
  235.             pObject->AddRef();
  236.         }
  237.     }
  238.  
  239.     return pObject;
  240. }
  241.  
  242. void VDCache::MarkCompleted(VDCachedObject *pObject) {
  243.     vdsynchronized(mLock) {
  244.         VDCacheState oldState = pObject->GetState();
  245.         VDASSERT(oldState == kVDCacheStatePending || oldState == kVDCacheStateActive);
  246.  
  247.         ObjectList& al = mLists[oldState];
  248.         ObjectList& cl = mLists[kVDCacheStateComplete];
  249.  
  250.         if (!al.empty()) {
  251.             cl.splice(cl.end(), al, al.fast_find(pObject));
  252.  
  253.             pObject = static_cast<VDCachedObject *>(cl.back());
  254.             pObject->SetState(kVDCacheStateComplete);
  255.         }
  256.     }
  257. }
  258.  
  259. ///////////////////////////////////////////////////////////////////////////
  260.  
  261. VDCachedObject::VDCachedObject()
  262.     : mRefCount(0)
  263.     , mpCache(NULL)
  264. {
  265. }
  266.  
  267. int VDCachedObject::AddRef() {
  268.     int rv = (mRefCount += 0x10000);
  269.  
  270.     return rv >> 16;
  271. }
  272.  
  273. int VDCachedObject::Release() {
  274.     int rv = (mRefCount -= 0x10000);
  275.  
  276.     VDASSERT(rv >= 0);
  277.  
  278.     if (rv < 0x10000) {
  279.         if (!rv)
  280.             delete this;
  281.         else if (mpCache)
  282.             mpCache->NotifyFree(this);
  283.     }
  284.  
  285.     return rv >> 16;
  286. }
  287.  
  288. void VDCachedObject::WeakAddRef() {
  289.     mRefCount += 2;
  290. }
  291.  
  292. void VDCachedObject::WeakRelease() {
  293.     int rv = (mRefCount -= 2);
  294.  
  295.     VDASSERT((rv & 0xffff) < 0x8000);
  296.  
  297.     if (rv < 2) {
  298.         if (!rv)
  299.             delete this;
  300.         else
  301.             mpCache->NotifyFree(this);
  302.     }
  303. }
  304.  
  305. void VDCachedObject::SetCache(VDCache *pCache) {
  306.     mpCache = pCache;
  307.     if (pCache)
  308.         ++mRefCount;
  309.     else {
  310.         if (!--mRefCount)
  311.             delete this;
  312.     }
  313. }
  314.  
  315. ///////////////////////////////////////////////////////////////////////////
  316.  
  317. VDPool::VDPool(IVDPoolAllocator *pAllocator)
  318.     : mpAllocator(pAllocator)
  319.     , mObjectCount(0)
  320.     , mObjectLimit(16)
  321. {
  322. }
  323.  
  324. VDPool::~VDPool() {
  325.     Shutdown();
  326. }
  327.  
  328. void VDPool::Shutdown() {
  329.     for(int i=0; i<kVDPoolStateCount; ++i) {
  330.         ObjectList& ol = mLists[i];
  331.  
  332.         while(!ol.empty()) {
  333.             VDPooledObject *pObject = static_cast<VDPooledObject *>(ol.back());
  334.             ol.pop_back();
  335.  
  336.             pObject->SetPool(NULL);    // will release object
  337.  
  338.             VDASSERT((int)--mObjectCount >= 0);
  339.         }
  340.     }
  341. }
  342.  
  343. VDPooledObject *VDPool::Allocate() {
  344.     VDPooledObject *pObj = NULL;
  345.  
  346.     vdsynchronized(mLock) {
  347.         ObjectList& fl = mLists[kVDPoolStateFree];
  348.         ObjectList& pl = mLists[kVDPoolStateActive];
  349.  
  350.         if (fl.empty()) {
  351.             VDPooledObject *pNewObject = mpAllocator->OnPoolAllocate();
  352.  
  353.             pNewObject->SetPool(this);
  354.  
  355.             fl.push_front(pNewObject);
  356.             ++mObjectCount;
  357.         }
  358.  
  359.         pObj = static_cast<VDPooledObject *>(fl.front());
  360.         pObj->AddRef();
  361.         pl.splice(pl.begin(), fl, fl.fast_find(pObj));
  362.     }
  363.  
  364.     return pObj;
  365. }
  366.  
  367. void VDPool::NotifyFree(VDPooledObject *pObject) {
  368.     vdsynchronized(mLock) {
  369.         // This check is required because it is possible for a call to
  370.         // Allocate() to sneak in before we acquire the lock.
  371.  
  372.         if (pObject->GetRefCount() < 2) {
  373.             VDPoolState oldState = kVDPoolStateActive;
  374.             VDPoolState newState = kVDPoolStateFree;
  375.  
  376.             mLists[kVDPoolStateActive].erase(pObject);
  377.  
  378.             if (mObjectCount > mObjectLimit) {
  379.                 delete pObject;
  380.                 --mObjectCount;
  381.             } else
  382.                 mLists[kVDPoolStateFree].push_back(pObject);
  383.         }
  384.     }
  385. }
  386.  
  387. ///////////////////////////////////////////////////////////////////////////
  388.  
  389. VDPooledObject::VDPooledObject()
  390.     : mRefCount(0)
  391.     , mpPool(NULL)
  392. {
  393. }
  394.  
  395. int VDPooledObject::AddRef() {
  396.     return (mRefCount += 2) >> 1;
  397. }
  398.  
  399. int VDPooledObject::Release() {
  400.     int rv = (mRefCount -= 2);
  401.  
  402.     VDASSERT(rv >= 0);
  403.  
  404.     if (rv < 2) {
  405.         if (!rv)
  406.             delete this;
  407.         else if (mpPool)
  408.             mpPool->NotifyFree(this);
  409.     }
  410.  
  411.     return rv >> 1;
  412. }
  413.  
  414. void VDPooledObject::SetPool(VDPool *pPool) {
  415.     mpPool = pPool;
  416.     if (pPool)
  417.         ++mRefCount;
  418.     else {
  419.         if (!--mRefCount)
  420.             delete this;
  421.     }
  422. }
  423.