2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
2016-04-03 18:18:29 +00:00
* Copyright ( c ) 2009 - 2016 , The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2009-05-08 13:28:41 +00:00
*/
# include "C4Include.h"
2016-04-03 18:07:56 +00:00
# include "network/C4InteractiveThread.h"
2009-05-08 13:28:41 +00:00
2017-04-30 08:49:09 +00:00
# include "game/C4Application.h"
2009-05-08 13:28:41 +00:00
// *** C4InteractiveThread
C4InteractiveThread : : C4InteractiveThread ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Add head-item
pFirstEvent = pLastEvent = new Event ( ) ;
pFirstEvent - > Type = Ev_None ;
2016-11-02 23:58:02 +00:00
pFirstEvent - > Next = nullptr ;
2010-03-27 16:05:02 +00:00
// reset event handlers
ZeroMem ( & pCallbacks , sizeof ( pCallbacks ) ) ;
2009-05-08 13:28:41 +00:00
// Set notify proc
NotifyProc . SetNotify ( this ) ;
Application . Add ( & NotifyProc ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4InteractiveThread : : ~ C4InteractiveThread ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
CStdLock PushLock ( & EventPushCSec ) , PopLock ( & EventPopCSec ) ;
// Remove all items. This may leak data, if pData was allocated on the heap.
2016-11-02 23:58:02 +00:00
while ( PopEvent ( nullptr , nullptr ) ) { }
2010-03-27 16:05:02 +00:00
// Delete head-item
2009-05-08 13:28:41 +00:00
delete pFirstEvent ;
2016-11-02 23:58:02 +00:00
pFirstEvent = pLastEvent = nullptr ;
2009-05-08 13:28:41 +00:00
// Unregister notify
Application . Remove ( & NotifyProc ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4InteractiveThread : : AddProc ( StdSchedulerProc * pProc )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
bool fFirst = ! Scheduler . getProcCnt ( ) ;
// Add the proc
Scheduler . Add ( pProc ) ;
// Not started yet?
2010-03-28 18:58:01 +00:00
if ( fFirst )
if ( ! Scheduler . Start ( ) )
2010-03-27 16:05:02 +00:00
return false ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4InteractiveThread : : RemoveProc ( StdSchedulerProc * pProc )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Process not in list?
2010-03-28 18:58:01 +00:00
if ( ! Scheduler . hasProc ( pProc ) )
2009-05-08 13:28:41 +00:00
return ;
2010-03-27 16:05:02 +00:00
// Last proc to be removed?
2010-03-28 18:58:01 +00:00
if ( Scheduler . getProcCnt ( ) = = 1 )
2010-03-27 16:05:02 +00:00
Scheduler . Stop ( ) ;
// Remove
Scheduler . Remove ( pProc ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4InteractiveThread : : PushEvent ( C4InteractiveEventType eEvent , void * pData )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
CStdLock PushLock ( & EventPushCSec ) ;
2010-03-28 18:58:01 +00:00
if ( ! pLastEvent ) return false ;
2009-05-08 13:28:41 +00:00
// create event
Event * pEvent = new Event ;
pEvent - > Type = eEvent ;
pEvent - > Data = pData ;
# ifdef _DEBUG
2013-12-07 14:27:01 +00:00
pEvent - > Time = C4TimeMilliseconds : : Now ( ) ;
2009-05-08 13:28:41 +00:00
# endif
2016-11-02 23:58:02 +00:00
pEvent - > Next = nullptr ;
2009-05-08 13:28:41 +00:00
// add item (at end)
pLastEvent - > Next = pEvent ;
pLastEvent = pEvent ;
PushLock . Clear ( ) ;
// notify main thread
NotifyProc . Notify ( ) ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
# ifdef _DEBUG
double AvgNetEvDelay = 0 ;
# endif
bool C4InteractiveThread : : PopEvent ( C4InteractiveEventType * pEventType , void * * ppData ) // (by main thread)
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
CStdLock PopLock ( & EventPopCSec ) ;
2010-03-28 18:58:01 +00:00
if ( ! pFirstEvent ) return false ;
2009-05-08 13:28:41 +00:00
// get event
Event * pEvent = pFirstEvent - > Next ;
2010-03-28 18:58:01 +00:00
if ( ! pEvent ) return false ;
2009-05-08 13:28:41 +00:00
// return
2010-03-28 18:58:01 +00:00
if ( pEventType )
2010-03-27 16:05:02 +00:00
* pEventType = pEvent - > Type ;
2010-03-28 18:58:01 +00:00
if ( ppData )
2010-03-27 16:05:02 +00:00
* ppData = pEvent - > Data ;
2009-05-08 13:28:41 +00:00
# ifdef _DEBUG
2010-03-28 18:58:01 +00:00
if ( Game . IsRunning )
2013-12-07 14:27:01 +00:00
AvgNetEvDelay + = ( ( C4TimeMilliseconds : : Now ( ) - pEvent - > Time ) - AvgNetEvDelay ) / 100 ;
2009-05-08 13:28:41 +00:00
# endif
// remove
delete pFirstEvent ;
pFirstEvent = pEvent ;
pFirstEvent - > Type = Ev_None ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4InteractiveThread : : ProcessEvents ( ) // by main thread
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
C4InteractiveEventType eEventType ; void * pEventData ;
2010-03-28 18:58:01 +00:00
while ( PopEvent ( & eEventType , & pEventData ) )
switch ( eEventType )
{
2010-03-27 16:05:02 +00:00
// Logging
2012-01-21 01:04:14 +00:00
case Ev_Log : case Ev_LogSilent : case Ev_LogFatal : case Ev_LogDebug :
2010-03-28 18:58:01 +00:00
{
// Reconstruct the StdStrBuf which allocated the data.
StdStrBuf pLog ;
pLog . Take ( reinterpret_cast < char * > ( pEventData ) ) ;
switch ( eEventType )
{
case Ev_Log :
Log ( pLog . getData ( ) ) ; break ;
case Ev_LogSilent :
LogSilent ( pLog . getData ( ) ) ; break ;
case Ev_LogFatal :
LogFatal ( pLog . getData ( ) ) ; break ;
2012-01-21 01:04:14 +00:00
case Ev_LogDebug :
DebugLog ( pLog . getData ( ) ) ; break ;
default : assert ( eEventType = = Ev_Log | | eEventType = = Ev_LogSilent | | eEventType = = Ev_LogFatal | | eEventType = = Ev_LogDebug ) ; // obviously will not happen, but someone tell gcc
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
break ;
2010-04-02 14:06:45 +00:00
case Ev_Function :
{
2015-09-29 08:32:54 +00:00
std : : unique_ptr < std : : function < void ( ) > > func ( static_cast < std : : function < void ( ) > * > ( pEventData ) ) ;
2010-04-02 14:06:45 +00:00
( * func ) ( ) ;
}
2010-03-28 18:58:01 +00:00
// Other events: check for a registered handler
default :
if ( eEventType > = Ev_None & & eEventType < = Ev_Last )
if ( pCallbacks [ eEventType ] )
pCallbacks [ eEventType ] - > OnThreadEvent ( eEventType , pEventData ) ;
// Note that memory might leak if the event wasn't processed....
}
}
2009-05-08 13:28:41 +00:00
bool C4InteractiveThread : : ThreadLog ( const char * szMessage , . . . )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// format message
2010-03-27 16:05:02 +00:00
va_list lst ; va_start ( lst , szMessage ) ;
StdStrBuf Msg = FormatStringV ( szMessage , lst ) ;
2009-05-08 13:28:41 +00:00
// send to main thread
2010-03-27 16:05:02 +00:00
return PushEvent ( Ev_Log , Msg . GrabPointer ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4InteractiveThread : : ThreadLogFatal ( const char * szMessage , . . . )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// format message
2010-03-27 16:05:02 +00:00
va_list lst ; va_start ( lst , szMessage ) ;
StdStrBuf Msg = FormatStringV ( szMessage , lst ) ;
2009-05-08 13:28:41 +00:00
// send to main thread
2010-03-27 16:05:02 +00:00
return PushEvent ( Ev_LogFatal , Msg . GrabPointer ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4InteractiveThread : : ThreadLogS ( const char * szMessage , . . . )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// format message
2010-03-27 16:05:02 +00:00
va_list lst ; va_start ( lst , szMessage ) ;
StdStrBuf Msg = FormatStringV ( szMessage , lst ) ;
2009-05-08 13:28:41 +00:00
// send to main thread
2010-03-27 16:05:02 +00:00
return PushEvent ( Ev_LogSilent , Msg . GrabPointer ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2012-01-21 01:04:14 +00:00
bool C4InteractiveThread : : ThreadLogDebug ( const char * szMessage , . . . )
{
// format message
va_list lst ; va_start ( lst , szMessage ) ;
StdStrBuf Msg = FormatStringV ( szMessage , lst ) ;
// send to main thread
return PushEvent ( Ev_LogDebug , Msg . GrabPointer ( ) ) ;
}
2009-05-08 13:28:41 +00:00
bool C4InteractiveThreadNotifyProc : : Execute ( int , pollfd * )
2010-03-28 18:58:01 +00:00
{
if ( CheckAndReset ( ) )
2009-05-08 13:28:41 +00:00
pNotify - > ProcessEvents ( ) ;
return true ;
2010-03-28 18:58:01 +00:00
}