Add UpdateThread and use it for minimap and mesh threads

This commit is contained in:
est31 2015-06-29 11:06:03 +02:00
parent 4e28c8d3c8
commit 29dda9f356
5 changed files with 114 additions and 98 deletions

@ -139,7 +139,7 @@ void MeshUpdateQueue::addBlock(v3s16 p, MeshMakeData *data, bool ack_block_to_se
// Returned pointer must be deleted // Returned pointer must be deleted
// Returns NULL if queue is empty // Returns NULL if queue is empty
QueuedMeshUpdate * MeshUpdateQueue::pop() QueuedMeshUpdate *MeshUpdateQueue::pop()
{ {
JMutexAutoLock lock(m_mutex); JMutexAutoLock lock(m_mutex);
@ -162,26 +162,17 @@ QueuedMeshUpdate * MeshUpdateQueue::pop()
MeshUpdateThread MeshUpdateThread
*/ */
void * MeshUpdateThread::Thread() void MeshUpdateThread::enqueueUpdate(v3s16 p, MeshMakeData *data,
bool ack_block_to_server, bool urgent)
{ {
ThreadStarted(); m_queue_in.addBlock(p, data, ack_block_to_server, urgent);
deferUpdate();
}
log_register_thread("MeshUpdateThread"); void MeshUpdateThread::doUpdate()
{
DSTACK(__FUNCTION_NAME); QueuedMeshUpdate *q;
while ((q = m_queue_in.pop())) {
BEGIN_DEBUG_EXCEPTION_HANDLER
porting::setThreadName("MeshUpdateThread");
while(!StopRequested())
{
QueuedMeshUpdate *q = m_queue_in.pop();
if(q == NULL)
{
sleep_ms(3);
continue;
}
ScopeProfiler sp(g_profiler, "Client: Mesh making"); ScopeProfiler sp(g_profiler, "Client: Mesh making");
@ -196,10 +187,6 @@ void * MeshUpdateThread::Thread()
delete q; delete q;
} }
END_DEBUG_EXCEPTION_HANDLER(errorstream)
return NULL;
} }
/* /*
@ -230,7 +217,7 @@ Client::Client(
m_nodedef(nodedef), m_nodedef(nodedef),
m_sound(sound), m_sound(sound),
m_event(event), m_event(event),
m_mesh_update_thread(this), m_mesh_update_thread(),
m_env( m_env(
new ClientMap(this, this, control, new ClientMap(this, this, control,
device->getSceneManager()->getRootSceneNode(), device->getSceneManager()->getRootSceneNode(),
@ -1600,7 +1587,7 @@ void Client::addUpdateMeshTask(v3s16 p, bool ack_to_server, bool urgent)
} }
// Add task to queue // Add task to queue
m_mesh_update_thread.m_queue_in.addBlock(p, data, ack_to_server, urgent); m_mesh_update_thread.enqueueUpdate(p, data, ack_to_server, urgent);
} }
void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent) void Client::addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server, bool urgent)

@ -113,23 +113,27 @@ struct MeshUpdateResult
} }
}; };
class MeshUpdateThread : public JThread class MeshUpdateThread : public UpdateThread
{ {
private:
MeshUpdateQueue m_queue_in;
protected:
const char *getName()
{ return "MeshUpdateThread"; }
virtual void doUpdate();
public: public:
MeshUpdateThread(IGameDef *gamedef): MeshUpdateThread()
m_gamedef(gamedef)
{ {
} }
void * Thread(); void enqueueUpdate(v3s16 p, MeshMakeData *data,
bool ack_block_to_server, bool urgent);
MeshUpdateQueue m_queue_in;
MutexedQueue<MeshUpdateResult> m_queue_out; MutexedQueue<MeshUpdateResult> m_queue_out;
IGameDef *m_gamedef;
v3s16 m_camera_offset; v3s16 m_camera_offset;
}; };

@ -105,67 +105,31 @@ QueuedMinimapUpdate * MinimapUpdateQueue::pop()
Minimap update thread Minimap update thread
*/ */
void MinimapUpdateThread::Stop()
{
JThread::Stop();
// give us a nudge
m_queue_sem.Post();
}
void MinimapUpdateThread::enqueue_Block(v3s16 pos, MinimapMapblock *data) void MinimapUpdateThread::enqueue_Block(v3s16 pos, MinimapMapblock *data)
{ {
if (m_queue.addBlock(pos, data)) m_queue.addBlock(pos, data);
// we had to allocate a new block deferUpdate();
m_queue_sem.Post();
} }
void MinimapUpdateThread::forceUpdate() void MinimapUpdateThread::doUpdate()
{ {
m_queue_sem.Post(); while (m_queue.size()) {
} QueuedMinimapUpdate *q = m_queue.pop();
std::map<v3s16, MinimapMapblock *>::iterator it;
void *MinimapUpdateThread::Thread() it = m_blocks_cache.find(q->pos);
{ if (q->data) {
ThreadStarted(); m_blocks_cache[q->pos] = q->data;
} else if (it != m_blocks_cache.end()) {
log_register_thread("MinimapUpdateThread"); delete it->second;
m_blocks_cache.erase(it);
DSTACK(__FUNCTION_NAME); }
}
BEGIN_DEBUG_EXCEPTION_HANDLER if (data->map_invalidated) {
if (data->mode != MINIMAP_MODE_OFF) {
porting::setThreadName("MinimapUpdateThread"); getMap(data->pos, data->map_size, data->scan_height, data->radar);
data->map_invalidated = false;
while (!StopRequested()) {
m_queue_sem.Wait();
if (StopRequested()) break;
while (m_queue.size()) {
QueuedMinimapUpdate *q = m_queue.pop();
if (!q)
break;
std::map<v3s16, MinimapMapblock *>::iterator it;
it = m_blocks_cache.find(q->pos);
if (q->data) {
m_blocks_cache[q->pos] = q->data;
} else if (it != m_blocks_cache.end()) {
delete it->second;
m_blocks_cache.erase(it);
}
}
if (data->map_invalidated) {
if (data->mode != MINIMAP_MODE_OFF) {
getMap(data->pos, data->map_size, data->scan_height, data->radar);
data->map_invalidated = false;
}
} }
} }
END_DEBUG_EXCEPTION_HANDLER(errorstream)
return NULL;
} }
MinimapUpdateThread::~MinimapUpdateThread() MinimapUpdateThread::~MinimapUpdateThread()
@ -177,7 +141,7 @@ MinimapUpdateThread::~MinimapUpdateThread()
} }
} }
MinimapPixel *MinimapUpdateThread::getMinimapPixel (v3s16 pos, s16 height, s16 &pixel_height) MinimapPixel *MinimapUpdateThread::getMinimapPixel(v3s16 pos, s16 height, s16 &pixel_height)
{ {
pixel_height = height - MAP_BLOCKSIZE; pixel_height = height - MAP_BLOCKSIZE;
v3s16 blockpos_max, blockpos_min, relpos; v3s16 blockpos_max, blockpos_min, relpos;
@ -198,7 +162,7 @@ MinimapPixel *MinimapUpdateThread::getMinimapPixel (v3s16 pos, s16 height, s16 &
return NULL; return NULL;
} }
s16 MinimapUpdateThread::getAirCount (v3s16 pos, s16 height) s16 MinimapUpdateThread::getAirCount(v3s16 pos, s16 height)
{ {
s16 air_count = 0; s16 air_count = 0;
v3s16 blockpos_max, blockpos_min, relpos; v3s16 blockpos_max, blockpos_min, relpos;
@ -215,7 +179,7 @@ s16 MinimapUpdateThread::getAirCount (v3s16 pos, s16 height)
return air_count; return air_count;
} }
void MinimapUpdateThread::getMap (v3s16 pos, s16 size, s16 height, bool radar) void MinimapUpdateThread::getMap(v3s16 pos, s16 size, s16 height, bool radar)
{ {
v3s16 p = v3s16 (pos.X - size / 2, pos.Y, pos.Z - size / 2); v3s16 p = v3s16 (pos.X - size / 2, pos.Y, pos.Z - size / 2);
@ -327,7 +291,7 @@ void Mapper::setMinimapMode(MinimapMode mode)
data->scan_height = modeDefs[(int)mode * 3 + 1]; data->scan_height = modeDefs[(int)mode * 3 + 1];
data->map_size = modeDefs[(int)mode * 3 + 2]; data->map_size = modeDefs[(int)mode * 3 + 2];
data->mode = mode; data->mode = mode;
m_minimap_update_thread->forceUpdate(); m_minimap_update_thread->deferUpdate();
} }
void Mapper::setPos(v3s16 pos) void Mapper::setPos(v3s16 pos)
@ -336,7 +300,7 @@ void Mapper::setPos(v3s16 pos)
if (pos != data->old_pos) { if (pos != data->old_pos) {
data->old_pos = data->pos; data->old_pos = data->pos;
data->pos = pos; data->pos = pos;
m_minimap_update_thread->forceUpdate(); m_minimap_update_thread->deferUpdate();
} }
} }

@ -96,7 +96,6 @@ public:
bool addBlock(v3s16 pos, MinimapMapblock *data); bool addBlock(v3s16 pos, MinimapMapblock *data);
// blocking!!
QueuedMinimapUpdate *pop(); QueuedMinimapUpdate *pop();
u32 size() u32 size()
@ -110,12 +109,16 @@ private:
JMutex m_mutex; JMutex m_mutex;
}; };
class MinimapUpdateThread : public JThread class MinimapUpdateThread : public UpdateThread
{ {
private: private:
JSemaphore m_queue_sem;
MinimapUpdateQueue m_queue; MinimapUpdateQueue m_queue;
protected:
const char *getName()
{ return "MinimapUpdateThread"; }
virtual void doUpdate();
public: public:
MinimapUpdateThread(IrrlichtDevice *device, Client *client) MinimapUpdateThread(IrrlichtDevice *device, Client *client)
{ {
@ -131,13 +134,10 @@ public:
video::SColor getColorFromId(u16 id); video::SColor getColorFromId(u16 id);
void enqueue_Block(v3s16 pos, MinimapMapblock *data); void enqueue_Block(v3s16 pos, MinimapMapblock *data);
void forceUpdate();
IrrlichtDevice *device; IrrlichtDevice *device;
Client *client; Client *client;
video::IVideoDriver *driver; video::IVideoDriver *driver;
ITextureSource *tsrc; ITextureSource *tsrc;
void Stop();
void *Thread();
MinimapData *data; MinimapData *data;
std::map<v3s16, MinimapMapblock *> m_blocks_cache; std::map<v3s16, MinimapMapblock *> m_blocks_cache;
}; };

@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "../jthread/jmutex.h" #include "../jthread/jmutex.h"
#include "../jthread/jmutexautolock.h" #include "../jthread/jmutexautolock.h"
#include "porting.h" #include "porting.h"
#include "log.h"
template<typename T> template<typename T>
class MutexedVariable class MutexedVariable
@ -208,5 +209,65 @@ private:
MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue; MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
}; };
class UpdateThread : public JThread
{
private:
JSemaphore m_update_sem;
protected:
virtual void doUpdate() = 0;
virtual const char *getName() = 0;
public:
UpdateThread()
{
}
~UpdateThread()
{}
void deferUpdate()
{
m_update_sem.Post();
}
void Stop()
{
JThread::Stop();
// give us a nudge
m_update_sem.Post();
}
void *Thread()
{
ThreadStarted();
const char *thread_name = getName();
log_register_thread(thread_name);
DSTACK(__FUNCTION_NAME);
BEGIN_DEBUG_EXCEPTION_HANDLER
porting::setThreadName(thread_name);
while (!StopRequested()) {
m_update_sem.Wait();
// Empty the queue, just in case doUpdate() is expensive
while (m_update_sem.GetValue()) m_update_sem.Wait();
if (StopRequested()) break;
doUpdate();
}
END_DEBUG_EXCEPTION_HANDLER(errorstream)
return NULL;
}
};
#endif #endif