1
0
forked from 0ad/0ad
0ad/source/tools/atlas/GameInterface/MessagePasserImpl.cpp
Matei 08d3ff2952 Updates for OS X and gcc 4.0 compatibility.
- Fixed some invalid member function references in wxJS code that gcc
4.0 didn't like.
- Some conversion changes.
- Don't try to construct wxSound from memory in OS X (it's not
available).
- Added dependency on zlib in AtlasUI (something there uses _compress).
- Added Mac code for finding current executable's path.
- Added dummy code for getting display size that does not use X.
- Fixed dir_get_changed_file stub to return ERR::AGAIN (end of files)
instead of INFO::OK.

This was SVN commit r5312.
2007-09-02 16:50:20 +00:00

149 lines
3.9 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 = 0;
sem_t* psem = (sem_t*) SEM_FAILED;
//sem_t sem;
//psem = &sem;
//err = sem_init(psem, 0, 0);
const char* sem_name = "/tmp/atlas";
psem = sem_open(sem_name, O_CREAT, 0777, 0);
err = errno;
if (psem == (sem_t*) SEM_FAILED)
{
// Probably-fatal error
debug_printf("errno: %d (%s)\n", err, strerror(err));
debug_warn("sem_init failed");
return;
}
qry->m_Semaphore = (void*)psem;
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(psem)))
//
// while (0 != (err = sem_wait(psem)))
// #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(psem, &abs_timeout)))
// #endif
while (0 != (err = sem_wait(psem)))
{
// 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(psem);
sem_close(psem);
sem_unlink(sem_name);
}
bool MessagePasserImpl::IsEmpty()
{
m_Mutex.Lock();
bool empty = m_Queue.empty();
m_Mutex.Unlock();
return empty;
}
void MessagePasserImpl::SetTrace(bool t)
{
m_Trace = t;
}