diff --git a/src/tile.cpp b/src/tile.cpp index 4de2d00..010519c 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -73,17 +73,23 @@ void TextureSource::processQueue() /* Fetch textures */ - std::lock_guard guard(m_get_texture_queue_mutex); - while (!m_get_texture_queue.empty()) + if(m_get_texture_queue.size() > 0) { - std::string name = m_get_texture_queue.front().first; + GetRequest + request = m_get_texture_queue.pop(); + infostream<<"TextureSource::processQueue(): " <<"got texture request with " - <<"name=\""<< name <<"\"" + <<"name=\""< + result; + result.key = request.key; + result.callers = request.callers; + result.item = getTextureIdDirect(request.key); + + request.dest->push_back(result); } } @@ -110,21 +116,29 @@ u32 TextureSource::getTextureId(const std::string &name) }else{ infostream<<"getTextureId(): Queued: name=\""< future; - { - std::lock_guard guard(m_get_texture_queue_mutex); - // We're gonna ask the result to be put into here - std::promise promise; - future = promise.get_future(); + // We're gonna ask the result to be put into here + ResultQueue result_queue; - // Throw a request in - m_get_texture_queue.push(std::make_pair(name, std::move(promise))); - } + // Throw a request in + m_get_texture_queue.add(name, 0, 0, &result_queue); infostream<<"Waiting for texture from main thread, name=\"" < + result = result_queue.pop_front(1000); + + // Check that at least something worked OK + if (result.key != name) + return 0; + + return result.item; + }catch(ItemNotFoundException &e) { + infostream<<"Waiting for texture timed out."< -#include -#include -#include using namespace jthread; @@ -261,8 +258,7 @@ private: JMutex m_atlaspointer_cache_mutex; // Queued texture fetches (to be processed by the main thread) - std::queue>> m_get_texture_queue; - std::mutex m_get_texture_queue_mutex; + RequestQueue m_get_texture_queue; }; enum MaterialType{ diff --git a/src/utility.h b/src/utility.h index f4190ec..d0cbdf6 100644 --- a/src/utility.h +++ b/src/utility.h @@ -1128,6 +1128,127 @@ protected: }; /* + A single worker thread - multiple client threads queue framework. +*/ + +template +class CallerInfo +{ +public: + Caller caller; + Data data; +}; + +template +class GetResult +{ +public: + Key key; + T item; + core::list > callers; +}; + +template +class ResultQueue: public MutexedQueue< GetResult > +{ +}; + +template +class GetRequest +{ +public: + GetRequest() + { + dest = NULL; + } + GetRequest(ResultQueue *a_dest) + { + dest = a_dest; + } + GetRequest(ResultQueue *a_dest, + Key a_key) + { + dest = a_dest; + key = a_key; + } + ~GetRequest() + { + } + + Key key; + ResultQueue *dest; + core::list > callers; +}; + +template +class RequestQueue +{ +public: + u32 size() + { + return m_queue.size(); + } + + void add(Key key, Caller caller, CallerData callerdata, + ResultQueue *dest) + { + JMutexAutoLock lock(m_queue.getMutex()); + + /* + If the caller is already on the list, only update CallerData + */ + for(typename core::list< GetRequest >::Iterator + i = m_queue.getList().begin(); + i != m_queue.getList().end(); i++) + { + GetRequest &request = *i; + + if(request.key == key) + { + for(typename core::list< CallerInfo >::Iterator + i = request.callers.begin(); + i != request.callers.end(); i++) + { + CallerInfo &ca = *i; + if(ca.caller == caller) + { + ca.data = callerdata; + return; + } + } + CallerInfo ca; + ca.caller = caller; + ca.data = callerdata; + request.callers.push_back(ca); + return; + } + } + + /* + Else add a new request to the queue + */ + + GetRequest request; + request.key = key; + CallerInfo ca; + ca.caller = caller; + ca.data = callerdata; + request.callers.push_back(ca); + request.dest = dest; + + m_queue.getList().push_back(request); + } + + GetRequest pop(bool wait_if_empty=false) + { + return m_queue.pop_front(wait_if_empty); + } + +private: + MutexedQueue< GetRequest > m_queue; +}; + +/* Pseudo-random (VC++ rand() sucks) */ int myrand(void);