0ad/source/tools/atlas/GameInterface/MessagePasserImpl.cpp
Ykkrosh 35e91718c5 # Added tool for viewing models and animations outside the game.
Atlas: Added ActorViewer. Moved GL canvas into separate class for shared
use. Disabled message-handling callback while blocked on the game, and
stopped creating dialog boxes inside the game thread in order to avoid
deadlocks (hopefully). Support multiple Views (for independent sets of
camera/update/render code). Recalculate territory boundaries when
necessary. Changed default list of animations to match those currently
used by actors.
# Tidied up more code.
Moved some more #includes out of .h files, to minimise unnecessary
compilation.
MathUtil: Deleted unused/unuseful macros (M_PI (use PI instead), M_PI_2
(use PI/2), MAX3, ABS (use abs)).
ObjectManager: Removed some ScEd-specific things.
Unit: Moved creation out of UnitManager, so units can be created without
adding to the manager. Changed CStr8 to the more conventional CStr.
app_hooks: Removed warning for setting multiple times.
win: Restored SEH catcher.
GameSetup, GameView: Removed RenderNoCull, because it doesn't seem to do
what it says it does ("force renderer to load everything") since we're
loading-on-demand most stuff and it doesn't seem especially useful since
we'd prefer to minimise loading times (but feel free to correct me if
I'm wrong). (And because it crashes when things need to be initialised
in a different order, so it's easier to remove than to understand and
fix it.)
PatchRData, Renderer: Work sensibly when there's no game (hence no LOS
manager, water, etc).
LOSManager: Use entity position instead of actor position when possible.
TerritoryManager: Allow delayed recalculations (so Atlas can issue lots
of move+recalculate commands per frame).
Cinematic: Non-pointer wxTimer, so it doesn't leak and doesn't have to
be deleted manually.

This was SVN commit r4261.
2006-08-28 17:36:42 +00:00

141 lines
3.6 KiB
C++

#include "precompiled.h"
#include "MessagePasserImpl.h"
#include "Messages.h"
#include "lib/timer.h"
using namespace AtlasMessage;
MessagePasserImpl::MessagePasserImpl()
: m_Trace(false)
{
}
void MessagePasserImpl::Add(IMessage* msg)
{
debug_assert(msg);
debug_assert(msg->GetType() == IMessage::Message);
if (m_Trace)
debug_printf("%8.3f add message: %s\n", get_time(), msg->GetName());
m_Mutex.Lock();
m_Queue.push(msg);
m_Mutex.Unlock();
}
IMessage* MessagePasserImpl::Retrieve()
{
// (It should be fairly easy to use a more efficient thread-safe queue,
// since there's only one thread adding items and one thread consuming;
// but it's not worthwhile yet.)
m_Mutex.Lock();
IMessage* msg = NULL;
if (! m_Queue.empty())
{
msg = m_Queue.front();
m_Queue.pop();
}
m_Mutex.Unlock();
if (m_Trace && msg)
debug_printf("%8.3f retrieved message: %s\n", get_time(), msg->GetName());
return msg;
}
void MessagePasserImpl::Query(QueryMessage* qry, void(* UNUSED(timeoutCallback) )())
{
debug_assert(qry);
debug_assert(qry->GetType() == IMessage::Query);
if (m_Trace)
debug_printf("%8.3f add query: %s\n", get_time(), qry->GetName());
// Initialise a semaphore, so we can block until the query has been handled
int err;
sem_t sem;
err = sem_init(&sem, 0, 0);
if (err != 0)
{
// Probably-fatal error
debug_warn("sem_init failed");
return;
}
qry->m_Semaphore = (void*)&sem;
m_Mutex.Lock();
m_Queue.push(qry);
m_Mutex.Unlock();
// Wait until the query handler has handled the query and called sem_post:
// The following code was necessary to avoid deadlock, but it still breaks
// in some cases (e.g. when Atlas issues a query before its event loop starts
// running) and doesn't seem to be the simplest possible solution.
// So currently we're trying to not do anything like that at all, and
// just stop the game making windows (which is what seems (from experience) to
// deadlock things) by overriding ah_display_error. Hopefully it'll work like
// that, and the redundant code below/elsewhere can be removed, but it's
// left in here in case it needs to be reinserted in the future to make it
// work.
// (See http://www.wildfiregames.com/forum/index.php?s=&showtopic=10236&view=findpost&p=174617)
// // At least on Win32, it is necessary for the UI thread to run its event
// // loop to avoid deadlocking the system (particularly when the game
// // tries to show a dialog box); so timeoutCallback is called whenever we
// // think it's necessary for that to happen.
//
// #if OS_WIN
// // On Win32, use MsgWaitForMultipleObjects, which waits on the semaphore
// // but is also interrupted by incoming Windows-messages.
// // while (0 != (err = sem_msgwait_np(&sem)))
//
// while (0 != (err = sem_wait(&sem)))
// #else
// // TODO: On non-Win32, I have no idea whether the same problem exists; but
// // it might do, so call the callback every few seconds just in case it helps.
// struct timespec abs_timeout;
// clock_gettime(CLOCK_REALTIME, &abs_timeout);
// abs_timeout.tv_sec += 2;
// while (0 != (err = sem_timedwait(&sem, &abs_timeout)))
// #endif
while (0 != (err = sem_wait(&sem)))
{
// If timed out, call callback and try again
// if (errno == ETIMEDOUT)
// timeoutCallback();
// else
// Keep retrying while EINTR, but other errors are probably fatal
if (errno != EINTR)
{
debug_warn("Semaphore wait failed");
return; // (leaks the semaphore)
}
}
// Clean up
qry->m_Semaphore = NULL;
sem_destroy(&sem);
}
bool MessagePasserImpl::IsEmpty()
{
m_Mutex.Lock();
bool empty = m_Queue.empty();
m_Mutex.Unlock();
return empty;
}
void MessagePasserImpl::SetTrace(bool t)
{
m_Trace = t;
}