From 42208fe1863d58f0e7b50a72806346537b5f1fa6 Mon Sep 17 00:00:00 2001 From: ponchio Date: Sat, 26 Nov 2011 18:08:30 +0000 Subject: [PATCH] fixed changed and some docs --- wrap/gcache/cache.h | 56 +++++++++++++++++++++++----------------- wrap/gcache/controller.h | 22 ++++++++++------ wrap/gcache/door.h | 28 +++++++++++--------- wrap/gcache/provider.h | 18 ++++++------- 4 files changed, 71 insertions(+), 53 deletions(-) diff --git a/wrap/gcache/cache.h b/wrap/gcache/cache.h index c266524f..1bbad0fb 100644 --- a/wrap/gcache/cache.h +++ b/wrap/gcache/cache.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "provider.h" @@ -21,20 +22,24 @@ using namespace std; template class Cache: public Provider { - public: - bool final; //true if this is the last cache (the one we use the data from) - bool quit; //graceful exit - bool changed; +public: + ///true if this is the last cache (the one we use the data from) + bool final; + //if true the cache will exit at the first opportunity + bool quit; + ///keeps track of changes (if 1 then something was loaded or dropped + QAtomicInt changed; + ///data is fetched from here - Provider *input; + Provider *input; - protected: +protected: ///max space available - quint64 s_max; + quint64 s_max; ///current space used - quint64 s_curr; + quint64 s_curr; - public: +public: Cache(quint64 _capacity = INT_MAX): final(false), quit(false), changed(false), input(NULL), s_max(_capacity), s_curr(0) {} virtual ~Cache() {} @@ -43,15 +48,15 @@ class Cache: public Provider { quint64 capacity() { return s_max; } quint64 size() { return s_curr; } void setCapacity(quint64 c) { s_max = c; } + ///return true if the cache is waiting for priority to change bool isChanged() { - bool r = changed; - changed = false; + bool r = changed.testAndSetOrdered(1, 0); //if changed is 1, r is true return r; - //return input->check_queue.isWaiting(); } - ///empty the cache. Make sure no resource is locked before calling this. Require pause or stop before. + ///empty the cache. Make sure no resource is locked before calling this. + /// Require pause or stop before. Ensure there no locked item void flush() { std::vector tokens; { @@ -78,7 +83,8 @@ class Cache: public Provider { } } - ///ensure there no locked item + ///empty the cache. Make sure no resource is locked before calling this. + /// Require pause or stop before. Ensure there no locked item template void flush(FUNCTOR functor) { std::vector tokens; { @@ -106,15 +112,15 @@ class Cache: public Provider { } } - protected: +protected: ///return the space used in the cache by the loaded resource virtual int size(Token *token) = 0; ///returns amount of space used in cache -1 for failed transfer virtual int get(Token *token) = 0; ///return amount removed virtual int drop(Token *token) = 0; - /// - virtual Token *ready() { return NULL; } + + ///called in as first thing in run() virtual void begin() {} @@ -135,7 +141,7 @@ class Cache: public Provider { if(this->quit) break; if(unload() || load()) { - changed = true; //some modification happened + changed.testAndSetOrdered(0, 1); //if not changed, set as changed input->check_queue.open(); //we signal ourselves to check again } } @@ -146,7 +152,9 @@ class Cache: public Provider { - ///should be protected + /** Checks wether we need to make room in the cache because of: + size() - sizeof(lowest priority item) > capacity() + **/ bool unload() { Token *remove = NULL; //make room int the cache checking that: @@ -181,18 +189,18 @@ class Cache: public Provider { } if(remove) { - int size = drop(remove); - assert(size >= 0); - s_curr -= size; - { QMutexLocker input_locker(&(input->heap_lock)); + int size = drop(remove); + assert(size >= 0); + s_curr -= size; input->heap.push(remove); } return true; } return false; } + ///should be protected bool load() { Token *insert = NULL; @@ -215,7 +223,7 @@ class Cache: public Provider { if(input->heap.size()) { //we need something in input to tranfer. Token &first = input->heap.max(); if(first.count > Token::REMOVE && - (!last || last->priority < first.priority)) { //if !last we already decided we want a transfer., otherwise check for a swap + (!last || last->priority < first.priority)) { //if !last we already decided we want a transfer., otherwise check for a swap insert = input->heap.popMax(); //remove item from heap, while we transfer it. } } diff --git a/wrap/gcache/controller.h b/wrap/gcache/controller.h index f012df8f..3f8e59e3 100644 --- a/wrap/gcache/controller.h +++ b/wrap/gcache/controller.h @@ -10,10 +10,12 @@ template class Controller { public: - ///should be private - std::vector tokens; //tokens waiting to be added - bool quit; //gracefully terminate. + ///tokens waiting to be added, should be private + std::vector tokens; + /// threads still running, but no door is open in caches, + ///transfers might still be going on! bool paused; + ///all cache threads are stopped bool stopped; public: @@ -22,11 +24,11 @@ class Controller { ///should be protected std::vector *> caches; - Controller(): quit(false), paused(false), stopped(true) {} + Controller(): paused(false), stopped(true) {} ~Controller() { finish(); } ///called before the cache is started to add a cache in the chain - /** The order in which the caches are added is from the lowest to the highest. */ + /** The order in which the caches are added is from the lowest to the highest. */ void addCache(Cache *cache) { if(caches.size() == 0) cache->setInputCache(&provider); @@ -35,6 +37,7 @@ class Controller { assert(cache->input); caches.push_back(cache); } + ///insert the token in the cache if not already present (actual insertion is done on updatePriorities) bool addToken(Token *token) { if(token->count.testAndSetOrdered(Token::OUTSIDE, Token::CACHE)) { @@ -110,8 +113,9 @@ class Controller { void pause() { if(paused) return; provider.check_queue.lock(); - for(unsigned int i = 0; i < caches.size()-1; i++) + for(unsigned int i = 0; i < caches.size()-1; i++) { caches[i]->check_queue.lock(); + } /* provider.heap_lock.lock(); for(unsigned int i = 0; i < caches.size(); i++) caches[i]->heap_lock.lock(); */ @@ -131,11 +135,13 @@ class Controller { } ///empty all caches AND REMOVES ALL TOKENS! void flush() { - pause(); + bool running = !stopped; + stop(); for(int i = (int)caches.size()-1; i >= 0; i--) caches[i]->flush(); provider.heap.clear(); - resume(); + if(running) + start(); } bool isChanged() { bool c = false; diff --git a/wrap/gcache/door.h b/wrap/gcache/door.h index c095d42b..cdc24735 100644 --- a/wrap/gcache/door.h +++ b/wrap/gcache/door.h @@ -8,7 +8,7 @@ * * * All rights reserved. * * * -* This program is free software; you can redistribute it and/or modify * +* This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * @@ -42,6 +42,7 @@ class QDoor { QSemaphore _close; public: QDoor(): _open(0), _close(1) {} //this means closed + void open() { if(_close.tryAcquire(1)) //check it is not open _open.release(1); //open @@ -53,21 +54,23 @@ class QDoor { void enter(bool close = false) { _open.acquire(1); if(close) - _close.release(1); //and close door behind + _close.release(1); //close door behind else - _open.release(1); //and leave door opened - + _open.release(1); //leave door opened } bool isOpen() { return _open.available() == 1; } + void lock() { //door might be open or closed, but we might happen just in the middle //of someone opening, closing or entering it. while(!_open.tryAcquire(1) && !_close.tryAcquire(1)) {} - //no resources left + //no resources left, door is locked } - void unlock() { - //unlock will not open the door, but allow someone to open it. - _close.release(1); + void unlock(bool open = false) { + if(open) + _open.release(1) + else + _close.release(1); } }; @@ -96,15 +99,15 @@ class QDoor { } ///attempt to enter the door. if the door is closed the thread will wait until the door is opened. - /** if close is true, the door will be closed after the thread is awakened, this allows to + /** if close is true, the door will be closed after the thread is awakened, this allows to have only one thread entering the door each time open() is called */ void enter(bool close = false) { m.lock(); waiting = true; while (!doorOpen) c.wait(&(m)); - - if(close) + + if(close) doorOpen = false; waiting = false; m.unlock(); @@ -118,7 +121,8 @@ class QDoor { void lock() { //prevend door opening and entering m.lock(); } - void unlock() { //reverse effect of lock + void unlock(bool open = false) { //reverse effect of lock + doorOpen = open; m.unlock(); } private: diff --git a/wrap/gcache/provider.h b/wrap/gcache/provider.h index f51b68b6..cfc637a0 100644 --- a/wrap/gcache/provider.h +++ b/wrap/gcache/provider.h @@ -14,7 +14,7 @@ 2) set maximum number of tokens in the provider */ -/** Base class for Cache and last cache in the GCache system. +/** Base class for Cache and last cache in the GCache system. You should never interact with this class. */ @@ -22,17 +22,17 @@ template class Provider: public QThread { public: ///holds the resources in this cache but not in the cache above - PtrDHeap heap; + PtrDHeap heap; ///tokens above this number will be scheduled for deletion int max_tokens; ///signals we need to rebuild heap. - bool heap_dirty; - ///lock this before manipulating heap. - QMutex heap_lock; - ///used to sincronize priorities update - QMutex priority_lock; + bool heap_dirty; + ///lock this before manipulating heap. + QMutex heap_lock; + ///used to sincronize priorities update + QMutex priority_lock; ///signals (to next cache!) priorities have changed or something is available - QDoor check_queue; + QDoor check_queue; Provider(): max_tokens(-1), heap_dirty(false) {} virtual ~Provider() {} @@ -84,4 +84,4 @@ class Provider: public QThread { }; -#endif +#endif