add new type C4TimeMilliseconds for time measurements to solve problems when GetTime() overflows (#251)

The new type C4TimeMilliseconds behaves for the most part like a uint32_t but is overflow-proof in comparisons.
In some places, a 0-value (or uint_max) of the variable storing the time had the special meaning "not set yet". This has been resolved by having it as a pointer to C4TimeMilliseconds with NULL meaning that it has not been set yet.
stable-5.4
Tobias Zwick 2013-12-04 19:35:07 +07:00
parent c03effd104
commit 94c618d153
32 changed files with 320 additions and 148 deletions

View File

@ -456,6 +456,7 @@ set(OC_CLONK_SOURCES
src/platform/C4SoundLoaders.h
src/platform/C4SoundSystem.cpp
src/platform/C4SoundSystem.h
src/platform/C4TimeMilliseconds.h
src/platform/C4StdInProc.cpp
src/platform/C4StdInProc.h
src/platform/C4Video.cpp

View File

@ -108,4 +108,6 @@ inline void operator delete(void *p, const char *, long)
#include "C4Game.h"
#include "C4TimeMilliseconds.h"
#endif // INC_C4Include

View File

@ -362,7 +362,7 @@ bool C4PlayerControlAssignment::IsComboMatched(const C4PlayerControlRecentKeyLis
// check if combo is currently fulfilled (assuming TriggerKey is already matched)
if (fComboIsSequence)
{
time_t tKeyLast = GetTime();
C4TimeMilliseconds tKeyLast = GetTime();
// combo is a sequence: The last keys of RecentKeys must match the sequence
// the last ComboKey is the TriggerKey, which is omitted because it has already been matched and is not to be found in RecentKeys yet
KeyComboVec::const_reverse_iterator i = KeyCombo.rbegin()+1;
@ -372,7 +372,7 @@ bool C4PlayerControlAssignment::IsComboMatched(const C4PlayerControlRecentKeyLis
if (ri == RecentKeys.rend()) return false;
const C4PlayerControlRecentKey &rk = *ri;
// user waited for too long?
time_t tKeyRecent = rk.tTime;
C4TimeMilliseconds tKeyRecent = rk.tTime;
if (tKeyLast - tKeyRecent > C4PlayerControl::MaxSequenceKeyDelay) return false;
// key doesn't match?
const KeyComboItem &k = *i;
@ -1288,8 +1288,8 @@ void C4PlayerControl::Execute()
}
}
// cleanup old recent keys
C4TimeMilliseconds tNow = GetTime();
C4PlayerControlRecentKeyList::iterator irk;
time_t tNow = GetTime();
for (irk = RecentKeys.begin(); irk != RecentKeys.end(); ++irk)
{
C4PlayerControlRecentKey &rk = *irk;

View File

@ -25,6 +25,7 @@
#include "C4KeyboardInput.h"
#include "C4LangStringTable.h"
#include "C4Id.h"
#include "C4TimeMilliseconds.h"
#include <list>
@ -134,8 +135,8 @@ public:
struct C4PlayerControlRecentKey
{
C4KeyCodeEx pressed_key, matched_key;
time_t tTime;
C4PlayerControlRecentKey(const C4KeyCodeEx &pressed_key, const C4KeyCodeEx &matched_key, time_t tTime) : pressed_key(pressed_key), matched_key(matched_key), tTime(tTime) {}
C4TimeMilliseconds tTime;
C4PlayerControlRecentKey(const C4KeyCodeEx &pressed_key, const C4KeyCodeEx &matched_key, C4TimeMilliseconds tTime) : pressed_key(pressed_key), matched_key(matched_key), tTime(tTime) {}
bool operator ==(const C4KeyCodeEx &cmp) { return pressed_key==cmp; } // comparison op for finding items in lists: Search for the pressed key only
};

View File

@ -868,7 +868,7 @@ bool C4ApplicationGameTimer::Execute(int iTimeout, pollfd *)
{
// Check timer and reset
if (!CheckAndReset()) return true;
time_t tNow = GetTime();
C4TimeMilliseconds tNow = GetTime();
// Execute
if (tNow >= tLastGameTick + iGameTickDelay || Game.GameGo)
{

View File

@ -112,7 +112,7 @@ class C4ApplicationGameTimer : public CStdMultimediaTimerProc
public:
C4ApplicationGameTimer();
private:
time_t tLastGameTick;
C4TimeMilliseconds tLastGameTick;
unsigned int iGameTickDelay;
public:
void SetGameTickDelay(uint32_t iDelay);

View File

@ -1479,7 +1479,7 @@ static long FnGetTime(C4PropList * _this)
{
// check network, record, etc
if (::Control.SyncMode()) return 0;
return GetTime();
return GetTime().AsInt();
}
static C4Value FnSetPlrExtraData(C4PropList * _this, int iPlayer, C4String * DataName, const C4Value & Data)

View File

@ -524,7 +524,9 @@ namespace C4GUI
{
private:
time_t tAutoScrollDelay; // if set and text is longer than would fit, the label will automatically start moving if not changed and displayed for a while
time_t tLastChangeTime; // time when the label text was changed last. 0 if not initialized; set upon first drawing
// Time when the label text was changed last. NULL if not initialized; set upon first drawing
C4TimeMilliseconds *tLastChangeTime;
int32_t iScrollPos, iScrollDir;
int32_t iRightIndent;
protected:
@ -537,14 +539,16 @@ namespace C4GUI
public:
WoodenLabel(const char *szLblText, const C4Rect &rcBounds, DWORD dwFClr=0xffffffff, CStdFont *pFont=NULL, int32_t iAlign=ACenter, bool fMarkup=true) // ctor
: Label(szLblText, rcBounds, iAlign, dwFClr, pFont, true, true, fMarkup), tAutoScrollDelay(0), tLastChangeTime(0), iScrollPos(0), iScrollDir(0), iRightIndent(0)
: Label(szLblText, rcBounds, iAlign, dwFClr, pFont, true, true, fMarkup), tAutoScrollDelay(0), tLastChangeTime(NULL), iScrollPos(0), iScrollDir(0), iRightIndent(0)
{ SetAutosize(false); this->rcBounds=rcBounds; }// ctor - re-sets bounds after SetText
~WoodenLabel() { delete tLastChangeTime; }
static int32_t GetDefaultHeight(CStdFont *pUseFont=NULL);
void SetIcon(const C4Facet &rfctIcon);
void SetAutoScrollTime(time_t tDelay) { tAutoScrollDelay=tDelay; ResetAutoScroll(); }
void ResetAutoScroll() { tLastChangeTime=0; iScrollPos=iScrollDir=0; }
void ResetAutoScroll();
void SetRightIndent(int32_t iNewIndent) { iRightIndent = iNewIndent; }
};
@ -1233,7 +1237,7 @@ namespace C4GUI
int32_t iCursorPos; // cursor position: char, before which the cursor is located
int32_t iSelectionStart, iSelectionEnd; // selection range (start may be larger than end)
int32_t iMaxTextLength; // maximum number of characters to be input here
time_t tLastInputTime; // time of last input (for cursor flashing)
C4TimeMilliseconds tLastInputTime; // time of last input (for cursor flashing)
int32_t iXScroll; // horizontal scrolling
char cPasswordMask; // character to be used for masking the contents. 0 for none.
@ -1567,7 +1571,7 @@ namespace C4GUI
int32_t iSheetSpacing, iSheetOff; // distances of sheet captions
int32_t iCaptionLengthTotal, iCaptionScrollPos; // scrolling in captions (top only)
bool fScrollingLeft, fScrollingRight, fScrollingLeftDown, fScrollingRightDown; // scrolling in captions (top only)
time_t tLastScrollTime; // set when fScrollingLeftDown or fScrollingRightDown are true: Time for next scrolling if mouse is held down
C4TimeMilliseconds tLastScrollTime; // set when fScrollingLeftDown or fScrollingRightDown are true: Time for next scrolling if mouse is held down
int iSheetMargin;
bool fDrawSelf; // if border and bg shall be drawn
@ -2448,7 +2452,7 @@ namespace C4GUI
int32_t LDownX, LDownY; // position where left button was pressed last
DWORD dwKeys; // shift, ctrl, etc.
bool fActive;
time_t tLastMovementTime; // GetTime() when the mouse pos changed last
C4TimeMilliseconds tLastMovementTime; // GetTime() when the mouse pos changed last
// whether last input was done by mouse
// set to true whenever mouse pos changes or buttons are pressed

View File

@ -153,10 +153,10 @@ namespace C4GUI
if (iAlign == ALeft) iXOff += 5;
if (tAutoScrollDelay)
{
time_t tNow = GetTime();
C4TimeMilliseconds tNow = GetTime();
if (!tLastChangeTime)
tLastChangeTime = tNow;
else if (tNow - tLastChangeTime >= tAutoScrollDelay)
tLastChangeTime = new C4TimeMilliseconds(tNow);
else if (tNow - *tLastChangeTime >= tAutoScrollDelay)
{
if (!iScrollDir) iScrollDir=1;
int32_t iMaxScroll = Max<int32_t>(pFont->GetTextWidth(sText.getData(), true) + (x0 - rcBounds.x) + iXOff + GetRightIndent() - rcBounds.Wdt, 0);
@ -167,7 +167,7 @@ namespace C4GUI
{
iScrollDir = -iScrollDir;
iScrollPos += iScrollDir;
tLastChangeTime = tNow;
*tLastChangeTime = tNow;
}
}
}
@ -198,6 +198,15 @@ namespace C4GUI
UpdateOwnPos();
}
void WoodenLabel::ResetAutoScroll()
{
if(tLastChangeTime)
{
delete tLastChangeTime;
tLastChangeTime=NULL;
}
iScrollPos = iScrollDir = 0;
}
// --------------------------------------------------
// MultilineLabel

View File

@ -929,7 +929,7 @@ void C4LandscapeRenderGL::BuildMatMap(GLfloat *pFMap, GLubyte *pIMap)
while(p = strchr(p, '-')) { p++; iPhases++; }
// Hard-coded hack. Fix me!
const int iPhaseLength = 300;
float phase = (iPhases == 1 ? 0 : float(GetTime() % (iPhases * iPhaseLength)) / iPhaseLength);
float phase = (iPhases == 1 ? 0 : float(GetTime().AsInt() % (iPhases * iPhaseLength)) / iPhaseLength);
// Find our transition
const char *pFrom = pEntry->GetTextureName();

View File

@ -71,7 +71,7 @@ public:
iStartCalled --;
if (!iStartCalled && iCount >= 100)
{
time_t tTime = GetTime() - tStartTime;
uint32_t tTime = GetTime() - tStartTime;
tTimeSum += tTime;
tTimeSumPart += tTime;
@ -89,7 +89,7 @@ protected:
C4Stat* pNext;
C4Stat* pPrev;
time_t tStartTime;
C4TimeMilliseconds tStartTime;
// start-call depth
unsigned int iStartCalled;

View File

@ -33,7 +33,7 @@
C4GameControlNetwork::C4GameControlNetwork(C4GameControl *pnParent)
: fEnabled(false), fRunning(false), iClientID(C4ClientIDUnknown),
fActivated(false), iTargetTick(-1),
iControlPreSend(1), tWaitStart(0), iAvgControlSendTime(0), iTargetFPS(38),
iControlPreSend(1), tWaitStart(NULL), iAvgControlSendTime(0), iTargetFPS(38),
iControlSent(0), iControlReady(0),
pCtrlStack(NULL),
tNextControlRequest(0),
@ -64,6 +64,11 @@ bool C4GameControlNetwork::Init(int32_t inClientID, bool fnHost, int32_t iStartT
fEnabled = true; fRunning = false;
iTargetFPS = 38;
tNextControlRequest = GetTime() + C4ControlRequestInterval;
if(tWaitStart)
{
delete tWaitStart;
tWaitStart = NULL;
}
return true;
}
@ -90,7 +95,7 @@ void C4GameControlNetwork::Execute() // by main thread
// Save time the control tick was reached
if (!tWaitStart)
tWaitStart = GetTime();
tWaitStart = new C4TimeMilliseconds(GetTime());
// Execute any queued sync control
ExecQueuedSyncCtrl();
@ -117,7 +122,11 @@ bool C4GameControlNetwork::GetControl(C4Control *pCtrl, int32_t iTick) // by mai
pCtrl->Append(pPkt->getControl());
// calc performance
CalcPerformance(iTick);
tWaitStart = 0;
if(tWaitStart)
{
delete tWaitStart;
tWaitStart = NULL;
}
// ok
return true;
}
@ -420,9 +429,9 @@ void C4GameControlNetwork::CalcPerformance(int32_t iCtrlTick)
// Performance statistics
// find control (may not be found, if we only got the complete ctrl)
C4GameControlPacket *pCtrl = getCtrl(pClient->getClientID(), iCtrlTick);
if (!pCtrl) continue;
if (!pCtrl || !tWaitStart) continue;
// calc stats
pClient->AddPerf(pCtrl->getTime() - tWaitStart);
pClient->AddPerf(pCtrl->getTime() - *tWaitStart);
}
// Now do PreSend-calcs based on ping times
int32_t iControlSendTime;
@ -765,7 +774,7 @@ C4GameControlPacket *C4GameControlNetwork::PackCompleteCtrl(int32_t iTick)
{
// async mode: wait n extra frames for slow clients
const int iMaxWait = (Config.Network.AsyncMaxWait * 1000) / iTargetFPS;
if (eMode != CNM_Async || !tWaitStart || GetTime() <= tWaitStart + iMaxWait)
if (eMode != CNM_Async || !tWaitStart || GetTime() <= *tWaitStart + iMaxWait)
return NULL;
}
@ -795,8 +804,8 @@ C4GameControlPacket *C4GameControlNetwork::PackCompleteCtrl(int32_t iTick)
if (eMode != CNM_Decentral)
::Network.Clients.BroadcastMsgToConnClients(MkC4NetIOPacket(PID_Control, *pComplete));
// advance control request time (note: this is buggy if time_t values overflow after ~1 month on 32Bit Windows)
tNextControlRequest = Max(tNextControlRequest, time_t(GetTime() + C4ControlRequestInterval));
// advance control request time
tNextControlRequest = Max(tNextControlRequest, GetTime() + C4ControlRequestInterval);
// return
return pComplete;

View File

@ -64,7 +64,10 @@ protected:
volatile int32_t iControlPreSend;
// statistics
time_t tWaitStart;
// time started to wait. NULL if not set yet
C4TimeMilliseconds *tWaitStart;
int32_t iAvgControlSendTime;
int32_t iTargetFPS; // used for PreSend-colculation
@ -85,7 +88,7 @@ protected:
C4GameControlPacket *pSyncCtrlQueue;
// control request timing
time_t tNextControlRequest;
C4TimeMilliseconds tNextControlRequest;
// links
C4GameControl *const pParent;
@ -182,7 +185,7 @@ public:
protected:
// header
int32_t iClientID, iCtrlTick;
time_t tTime;
C4TimeMilliseconds tTime;
// data
C4Control Ctrl;
@ -193,7 +196,7 @@ protected:
public:
int32_t getClientID() const { return iClientID; }
int32_t getCtrlTick() const { return iCtrlTick; }
time_t getTime() const { return tTime; }
C4TimeMilliseconds getTime() const { return tTime; }
const C4Control &getControl() const { return Ctrl; }
void Set(int32_t iClientID, int32_t iCtrlTick);

View File

@ -85,7 +85,7 @@ private:
C4InteractiveEventType Type;
void *Data;
#ifdef _DEBUG
time_t Time;
C4TimeMilliseconds Time;
#endif
Event *Next;
};

View File

@ -1795,7 +1795,7 @@ C4NetIOUDP::C4NetIOUDP()
pPeerList(NULL),
fSavePacket(false),
fDelayedLoopbackTest(false),
tNextCheck(0),
tNextCheck(NULL),
OPackets(iMaxOPacketBacklog),
iOPacketCounter(0),
iBroadcastRate(0)
@ -1805,6 +1805,7 @@ C4NetIOUDP::C4NetIOUDP()
C4NetIOUDP::~C4NetIOUDP()
{
delete tNextCheck;
Close();
}
@ -1829,7 +1830,9 @@ bool C4NetIOUDP::Init(uint16_t inPort)
// set flags
fInit = true;
fMultiCast = false;
tNextCheck = GetTime() + iCheckInterval;
if(!tNextCheck) tNextCheck = new C4TimeMilliseconds();
*tNextCheck = GetTime() + iCheckInterval;
// ok, that's all for now.
// call InitBroadcast for more initialization fun
@ -2001,17 +2004,18 @@ bool C4NetIOUDP::Execute(int iMaxTime, pollfd *) // (mt-safe)
ResetError();
// adjust maximum block time
time_t tNow = GetTime();
int iMaxBlock = GetNextTick(tNow) - tNow;
if (iMaxTime == TO_INF || iMaxTime > iMaxBlock) iMaxTime = iMaxBlock;
C4TimeMilliseconds tNow = GetTime();
uint32_t iMaxBlock = GetNextTick(tNow) - tNow;
if (iMaxTime == TO_INF || iMaxTime > (int) iMaxBlock) iMaxTime = iMaxBlock;
// execute subclass
if (!C4NetIOSimpleUDP::Execute(iMaxTime))
return false;
// connection check needed?
if (tNextCheck <= GetTime())
DoCheck();
if (tNextCheck)
if (*tNextCheck <= GetTime())
DoCheck();
// client timeout?
for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
if (!pPeer->Closed())
@ -2095,16 +2099,17 @@ bool C4NetIOUDP::SetBroadcast(const addr_t &addr, bool fSet) // (mt-safe)
return true;
}
time_t C4NetIOUDP::GetNextTick(time_t tNow) // (mt-safe)
C4TimeMilliseconds C4NetIOUDP::GetNextTick(C4TimeMilliseconds tNow) // (mt-safe)
{
// maximum time: check interval
time_t tTiming = Max(tNow, tNextCheck);
C4TimeMilliseconds tTiming = tNextCheck ? Max(tNow, *tNextCheck): tNow;
// client timeouts (e.g. connection timeout)
CStdShareLock PeerListLock(&PeerListCSec);
for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
if (!pPeer->Closed())
if (pPeer->GetTimeout() > 0)
tTiming = Min(tTiming, pPeer->GetTimeout());
if (pPeer->GetTimeout())
tTiming = Min(tTiming, *pPeer->GetTimeout());
// return timing value
return tTiming;
}
@ -2485,7 +2490,7 @@ C4NetIOUDP::Peer::Peer(const sockaddr_in &naddr, C4NetIOUDP *pnParent)
iIPacketCounter(0), iRIPacketCounter(0),
iIMCPacketCounter(0), iRIMCPacketCounter(0),
iMCAckPacketCounter(0),
tNextReCheck(0),
tNextReCheck(NULL),
iIRate(0), iORate(0), iLoss(0)
{
ZeroMem(&addr2, sizeof(addr2));
@ -2494,6 +2499,8 @@ C4NetIOUDP::Peer::Peer(const sockaddr_in &naddr, C4NetIOUDP *pnParent)
C4NetIOUDP::Peer::~Peer()
{
delete tNextReCheck;
delete tTimeout;
// send close-packet
Close("deleted");
}
@ -2533,7 +2540,7 @@ bool C4NetIOUDP::Peer::Check(bool fForceCheck)
if (eStatus != CS_Works) return true;
// prevent re-check (check floods)
// instead, ask for other packets that are missing until recheck is allowed
bool fNoReCheck = !!tNextReCheck && tNextReCheck > GetTime();
bool fNoReCheck = !!tNextReCheck && *tNextReCheck > GetTime();
if (!fNoReCheck) iLastPacketAsked = iLastMCPacketAsked = 0;
unsigned int iStartAt = fNoReCheck ? Max(iLastPacketAsked + 1, iIPacketCounter) : iIPacketCounter;
unsigned int iStartAtMC = fNoReCheck ? Max(iLastMCPacketAsked + 1, iIMCPacketCounter) : iIMCPacketCounter;
@ -2551,7 +2558,10 @@ bool C4NetIOUDP::Peer::Check(bool fForceCheck)
int iEAskCnt = iAskCnt + iMCAskCnt;
// no re-check limit? set it
if (!fNoReCheck)
tNextReCheck = iEAskCnt ? GetTime() + iReCheckInterval : 0;
{
if(!tNextReCheck) tNextReCheck = new C4TimeMilliseconds();
*tNextReCheck = iEAskCnt ? GetTime() + iReCheckInterval : 0;
}
// something to ask for? (or check forced?)
if (iEAskCnt || fForceCheck)
return DoCheck(iAskCnt, iMCAskCnt, iAskList);
@ -2616,7 +2626,15 @@ void C4NetIOUDP::Peer::OnRecv(const C4NetIOPacket &rPacket) // (mt-safe)
else
iRIPacketCounter = iIPacketCounter = pPkt->Nr;
// clear incoming packets
IPackets.Clear(); IMCPackets.Clear(); tNextReCheck = 0;
IPackets.Clear();
IMCPackets.Clear();
if(tNextReCheck)
{
delete tNextReCheck;
tNextReCheck = NULL;
}
iLastPacketAsked = iLastMCPacketAsked = 0;
// Activate Multicast?
if (!pParent->fMultiCast)
@ -2777,7 +2795,7 @@ void C4NetIOUDP::Peer::CheckTimeout()
// timeout set?
if (!tTimeout) return;
// check
if (GetTime() > tTimeout)
if (GetTime() > *tTimeout)
OnTimeout();
}
@ -2926,9 +2944,15 @@ void C4NetIOUDP::Peer::CheckCompleteIPackets()
void C4NetIOUDP::Peer::SetTimeout(int iLength, int iRetryCnt) // (mt-safe)
{
if (iLength != TO_INF)
tTimeout = GetTime() + iLength;
{
if(!tTimeout) tTimeout = new C4TimeMilliseconds();
*tTimeout = GetTime() + iLength;
}
else
tTimeout = 0;
{
delete tTimeout;
tTimeout = NULL;
}
iRetries = iRetryCnt;
}
@ -3144,8 +3168,10 @@ void C4NetIOUDP::DoCheck() // (mt-safe)
for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
if (pPeer->Open())
pPeer->Check();
// set time for next check
tNextCheck = GetTime() + iCheckInterval;
if(!tNextCheck) tNextCheck = new C4TimeMilliseconds();
*tNextCheck = GetTime() + iCheckInterval;
}
// debug
@ -3193,7 +3219,7 @@ void C4NetIOUDP::CloseDebugLog()
void C4NetIOUDP::DebugLogPkt(bool fOut, const C4NetIOPacket &Pkt)
{
StdStrBuf O;
time_t tTime = GetTime();
uint32_t tTime = GetTime().AsInt();
O.Format("%s %u:%02u:%02u:%03u %s:%d:", fOut ? "out" : "in ",
(tTime / 1000 / 60 / 60), (tTime / 1000 / 60) % 60, (tTime / 1000) % 60, tTime % 1000,
inet_ntoa(Pkt.getAddr().sin_addr), htons(Pkt.getAddr().sin_port));

View File

@ -458,7 +458,7 @@ public:
virtual bool Broadcast(const C4NetIOPacket &rPacket);
virtual bool SetBroadcast(const addr_t &addr, bool fSet = true);
virtual time_t GetNextTick(time_t tNow);
virtual C4TimeMilliseconds GetNextTick(C4TimeMilliseconds tNow);
virtual bool IsScheduledExecution() { return true; }
virtual bool GetStatistic(int *pBroadcastRate);
@ -620,12 +620,12 @@ protected:
// output critical section
CStdCSec OutCSec;
// connection check time limit
time_t tNextReCheck;
// connection check time limit. NULL if no recheck time yet
C4TimeMilliseconds *tNextReCheck;
unsigned int iLastPacketAsked, iLastMCPacketAsked;
// timeout
time_t tTimeout;
// timeout time. NULL if no timeout time set yet
C4TimeMilliseconds *tTimeout;
unsigned int iRetries;
// statistics
@ -661,7 +661,7 @@ protected:
unsigned int GetMCAckPacketCounter() const { return iMCAckPacketCounter; }
// timeout checking
time_t GetTimeout() { return tTimeout; }
C4TimeMilliseconds *GetTimeout() { return tTimeout; }
void CheckTimeout();
// selected for broadcast?
@ -726,8 +726,8 @@ protected:
addr_t MCLoopbackAddr;
bool fDelayedLoopbackTest;
// check timing
time_t tNextCheck;
// check timing. NULL if no next check yet
C4TimeMilliseconds *tNextCheck;
// outgoing packet list (for multicast)
PacketList OPackets;

View File

@ -146,7 +146,7 @@ C4Network2::C4Network2()
pLobby(NULL), fLobbyRunning(false), pLobbyCountdown(NULL),
iNextClientID(0),
iLastChaseTargetUpdate(0),
tLastActivateRequest(0),
tLastActivateRequest(NULL),
iLastReferenceUpdate(0),
iLastLeagueUpdate(0),
pLeagueClient(NULL),
@ -664,7 +664,12 @@ void C4Network2::Clear()
// stuff
fAllowJoin = false;
iDynamicTick = -1; fDynamicNeeded = false;
tLastActivateRequest = iLastChaseTargetUpdate = iLastReferenceUpdate = iLastLeagueUpdate = 0;
if(tLastActivateRequest)
{
delete tLastActivateRequest;
tLastActivateRequest = NULL;
}
iLastChaseTargetUpdate = iLastReferenceUpdate = iLastLeagueUpdate = 0;
fDelayedActivateReq = false;
delete pVoteDialog; pVoteDialog = NULL;
fPausedForVote = false;
@ -1503,7 +1508,7 @@ C4Network2Res::Ref C4Network2::RetrieveRes(const C4Network2ResCore &Core, int32_
C4GUI::ProgressDialog *pDlg = NULL;
bool fLog = false;
int32_t iProcess = -1;
time_t tTimeout = GetTime() + iTimeoutLen;
C4TimeMilliseconds tTimeout = GetTime() + iTimeoutLen;
// wait for resource
while (isEnabled())
{
@ -1511,6 +1516,7 @@ C4Network2Res::Ref C4Network2::RetrieveRes(const C4Network2ResCore &Core, int32_
C4Network2Res::Ref pRes = ResList.getRefRes(Core.getID());
// res not found?
if (!pRes)
{
if (Core.isNull())
{
// should wait for core?
@ -1521,6 +1527,7 @@ C4Network2Res::Ref C4Network2::RetrieveRes(const C4Network2ResCore &Core, int32_
// start loading
pRes = ResList.AddByCore(Core);
}
}
// res found and loaded completely
else if (!pRes->isLoading())
{
@ -1762,7 +1769,11 @@ void C4Network2::RequestActivate()
// neither observer nor activated?
if (Game.Clients.getLocal()->isObserver() || Game.Clients.getLocal()->isActivated())
{
tLastActivateRequest = 0;
if(tLastActivateRequest)
{
delete tLastActivateRequest;
tLastActivateRequest = NULL;
}
return;
}
// host? just do it
@ -1775,8 +1786,9 @@ void C4Network2::RequestActivate()
return;
}
// ensure interval
if (tLastActivateRequest && GetTime() < tLastActivateRequest + C4NetActivationReqInterval)
return;
if (tLastActivateRequest)
if(GetTime() < *tLastActivateRequest + C4NetActivationReqInterval)
return;
// status not reached yet? May be chasing, let's delay this.
if (!fStatusReached)
{
@ -1786,7 +1798,10 @@ void C4Network2::RequestActivate()
// request
Clients.SendMsgToHost(MkC4NetIOPacket(PID_ClientActReq, C4PacketActivateReq(Game.FrameCounter)));
// store time
tLastActivateRequest = GetTime();
if(!tLastActivateRequest)
tLastActivateRequest = new C4TimeMilliseconds(GetTime());
else
*tLastActivateRequest = GetTime();
}
void C4Network2::DeactivateInactiveClients()

View File

@ -166,8 +166,8 @@ protected:
// chase
uint32_t iLastChaseTargetUpdate;
// activation
time_t tLastActivateRequest;
// time of last activation request. NULL if no last request
C4TimeMilliseconds *tLastActivateRequest;
// reference
uint32_t iLastReferenceUpdate;

View File

@ -506,7 +506,7 @@ bool C4Network2IO::OnConn(const C4NetIO::addr_t &PeerAddr, const C4NetIO::addr_t
return false;
}
#if(C4NET2IO_DUMP_LEVEL > 1)
time_t tTime = GetTime();
uint32_t tTime = GetTime().AsInt();
ThreadLogS("OnConn: %u:%02u:%02u:%03u: %s",
(tTime / 1000 / 60 / 60), (tTime / 1000 / 60) % 60, (tTime / 1000) % 60, tTime % 1000,
getNetIOName(pNetIO));
@ -561,7 +561,7 @@ void C4Network2IO::OnDisconn(const C4NetIO::addr_t &addr, C4NetIO *pNetIO, const
return;
}
#if(C4NET2IO_DUMP_LEVEL > 1)
time_t tTime = GetTime();
uint32_t tTime = GetTime().AsInt();
ThreadLogS("OnDisconn: %u:%02u:%02u:%03u: %s",
(tTime / 1000 / 60 / 60), (tTime / 1000 / 60) % 60, (tTime / 1000) % 60, tTime % 1000,
getNetIOName(pNetIO));
@ -591,7 +591,7 @@ void C4Network2IO::OnDisconn(const C4NetIO::addr_t &addr, C4NetIO *pNetIO, const
void C4Network2IO::OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO)
{
#if(C4NET2IO_DUMP_LEVEL > 1)
time_t tTime = GetTime();
uint32_t tTime = GetTime().AsInt();
ThreadLogS("OnPacket: %u:%02u:%02u:%03u: status %02x %s",
(tTime / 1000 / 60 / 60), (tTime / 1000 / 60) % 60, (tTime / 1000) % 60, tTime % 1000,
rPacket.getStatus(), getNetIOName(pNetIO));
@ -629,14 +629,14 @@ bool C4Network2IO::Execute(int iTimeout, pollfd *)
CheckTimeout();
// ping all open connections
if (!Inside(tLastPing, GetTime() - C4NetPingFreq, GetTime()))
if (!Inside(tLastPing, tLastExecute - C4NetPingFreq, tLastExecute))
{
Ping();
tLastPing = tLastExecute;
}
// do statistics
if (!Inside(tLastStatistic, GetTime() - C4NetStatisticsFreq, GetTime()))
if (!Inside(tLastStatistic, tLastExecute - C4NetStatisticsFreq, tLastExecute))
{
GenerateStatistics(tLastExecute - tLastStatistic);
tLastStatistic = tLastExecute;
@ -649,7 +649,7 @@ bool C4Network2IO::Execute(int iTimeout, pollfd *)
return true;
}
time_t C4Network2IO::GetNextTick(time_t tNow)
C4TimeMilliseconds C4Network2IO::GetNextTick(C4TimeMilliseconds tNow)
{
return tLastExecute + C4NetTimer;
}
@ -845,7 +845,7 @@ bool C4Network2IO::HandlePacket(const C4NetIOPacket &rPacket, C4Network2IOConnec
#if(C4NET2IO_DUMP_LEVEL > 0)
if (fThread && Pkt.getPktType() != PID_Ping && Pkt.getPktType() != PID_Pong && Pkt.getPktType() != PID_NetResData)
{
time_t tTime = GetTime();
uint32_t tTime = GetTime().AsInt();
// StdStrBuf PacketDump = DecompileToBuf<StdCompilerINIWrite>(mkNamingAdaptrPacket);
StdStrBuf PacketHeader = FormatString("HandlePacket: %u:%02u:%02u:%03u by %s:%d (%lu bytes, counter %d)",
tTime / 1000 / 60 / 60, (tTime / 1000 / 60) % 60, (tTime / 1000) % 60, tTime % 1000,
@ -870,15 +870,18 @@ bool C4Network2IO::HandlePacket(const C4NetIOPacket &rPacket, C4Network2IOConnec
{
fHandled = true;
#if(C4NET2IO_DUMP_LEVEL > 2)
time_t tStart = GetTime();
C4TimeMilliseconds tStart = GetTime();
#endif
// call handler(s)
CallHandlers(pHData->HandlerID, &Pkt, pConn, fThread);
#if(C4NET2IO_DUMP_LEVEL > 2)
if (fThread && GetTime() - tStart > 100)
ThreadLogS("HandlePacket: ... blocked for %d ms!", GetTime() - tStart);
uint32_t iBlockedTime = GetTime() - tStart;
if (fThread && iBlockedTime > 100)
{
ThreadLogS("HandlePacket: ... blocked for %u ms!", iBlockedTime);
}
#endif
}
@ -1209,8 +1212,7 @@ void C4Network2IO::CheckTimeout()
void C4Network2IO::GenerateStatistics(int iInterval)
{
int iTCPIRateSum = 0, iTCPORateSum = 0,
iUDPIRateSum = 0, iUDPORateSum = 0;
int iTCPIRateSum = 0, iTCPORateSum = 0, iUDPIRateSum = 0, iUDPORateSum = 0;
// acquire lock, get connection statistics
CStdLock ConnListLock(&ConnListCSec);
@ -1303,7 +1305,7 @@ C4Network2IOConnection::C4Network2IOConnection()
fBroadcastTarget(false),
iTimestamp(0),
iPingTime(-1),
tLastPing(ULONG_MAX), tLastPong(ULONG_MAX),
tLastPing(NULL), tLastPong(NULL),
fConnSent(false),
fPostMortemSent(false),
iOutPacketCounter(0), iInPacketCounter(0),
@ -1320,17 +1322,23 @@ C4Network2IOConnection::~C4Network2IOConnection()
if (pNetClass && !isClosed()) Close();
// clear the packet log
ClearPacketLog();
delete tLastPing;
delete tLastPong;
}
int C4Network2IOConnection::getLag() const
{
// Last ping not answered yet?
if (iPingTime != -1 && tLastPing != ULONG_MAX && (tLastPong == ~0u || tLastPing > tLastPong))
if (iPingTime != -1)
{
int iPingLag = GetTime() - tLastPing;
// Use it for lag measurement once it's larger then the last ping time
// (the ping time won't be better than this anyway once the pong's here)
return Max(iPingLag, iPingTime);
// Last ping not answered yet?
if(tLastPing && (!tLastPong || *tLastPing > *tLastPong))
{
int iPingLag = GetTime() - *tLastPing;
// Use it for lag measurement once it's larger then the last ping time
// (the ping time won't be better than this anyway once the pong's here)
return Max(iPingLag, iPingTime);
}
}
// Last ping result
return iPingTime;
@ -1363,10 +1371,13 @@ void C4Network2IOConnection::SetPeerAddr(const C4NetIO::addr_t &nPeerAddr)
void C4Network2IOConnection::OnPing()
{
// Still no pong for the last ping?
if (tLastPong < tLastPing)
return;
if(tLastPing && tLastPong)
if (*tLastPong < *tLastPing)
return;
// Save time
tLastPing = GetTime();
if(!tLastPing) tLastPing = new C4TimeMilliseconds();
*tLastPing = GetTime();
}
void C4Network2IOConnection::SetPingTime(int inPingTime)
@ -1374,7 +1385,8 @@ void C4Network2IOConnection::SetPingTime(int inPingTime)
// save it
iPingTime = inPingTime;
// pong received - save timestamp
tLastPong = GetTime();
if(!tLastPong) tLastPong = new C4TimeMilliseconds();
*tLastPong = GetTime();
}
void C4Network2IOConnection::SetStatus(C4Network2IOConnStatus nStatus)

View File

@ -89,11 +89,11 @@ protected:
bool fExclusiveConn;
// timer & ping
time_t tLastExecute;
time_t tLastPing;
C4TimeMilliseconds tLastExecute;
C4TimeMilliseconds tLastPing;
// statistics
time_t tLastStatistic;
C4TimeMilliseconds tLastStatistic;
int iTCPIRate, iTCPORate, iTCPBCRate,
iUDPIRate, iUDPORate, iUDPBCRate;
@ -163,7 +163,7 @@ protected:
virtual void OnError(const char *strError, C4NetIO *pNetIO);
// StdSchedulerProc
virtual bool Execute(int iTimeout, pollfd *);
virtual time_t GetNextTick(time_t Now);
virtual C4TimeMilliseconds GetNextTick(C4TimeMilliseconds tNow);
virtual bool IsScheduledExecution() { return true; }
// Event callback by C4InteractiveThread
void OnThreadEvent(C4InteractiveEventType eEvent, void *pEventData); // by main thread
@ -231,8 +231,8 @@ protected:
bool fBroadcastTarget; // broadcast target?
time_t iTimestamp; // timestamp of last status change
int iPingTime; // ping
time_t tLastPing; // if > iLastPong, it's the first ping that hasn't been answered yet
time_t tLastPong; // last pong received
C4TimeMilliseconds *tLastPing; // if > iLastPong, it's the first ping that hasn't been answered yet, NULL if no ping received yet
C4TimeMilliseconds *tLastPong; // last pong received, NULL if no pong received yet
C4ClientCore CCore; // client core (>= CS_HalfAccepted)
CStdCSec CCoreCSec;
int iIRate, iORate; // input/output rates (by C4NetIO, in b/s)
@ -335,7 +335,7 @@ public:
C4PacketPing(uint32_t iPacketCounter = 0, uint32_t iRemotePacketCounter = 0);
protected:
time_t tTime;
C4TimeMilliseconds tTime;
uint32_t iPacketCounter;
public:

View File

@ -430,15 +430,15 @@ bool C4Network2HTTPClient::Execute(int iMaxTime)
return C4NetIOTCP::Execute(iMaxTime);
}
time_t C4Network2HTTPClient::GetNextTick(time_t tNow)
C4TimeMilliseconds C4Network2HTTPClient::GetNextTick(C4TimeMilliseconds tNow)
{
time_t iNetIOTCPTick = C4NetIOTCP::GetNextTick(tNow);
C4TimeMilliseconds tNetIOTCPTick = C4NetIOTCP::GetNextTick(tNow);
if (!fBusy)
return iNetIOTCPTick;
return tNetIOTCPTick;
time_t iHTTPClientTick = tNow + 1000 * Max<time_t>(iRequestTimeout - time(NULL), 0);
C4TimeMilliseconds tHTTPClientTick = tNow + 1000 * Max<time_t>(iRequestTimeout - time(NULL), 0);
return Max(iNetIOTCPTick, iHTTPClientTick);
return Max(tNetIOTCPTick, tHTTPClientTick);
}
bool C4Network2HTTPClient::IsScheduledExecution()

View File

@ -181,7 +181,7 @@ public:
// Overridden
virtual bool Execute(int iMaxTime, pollfd * readyfds) { return Execute(iMaxTime); }
virtual bool Execute(int iMaxTime = TO_INF);
virtual time_t GetNextTick(time_t tNow);
virtual C4TimeMilliseconds GetNextTick(C4TimeMilliseconds tNow);
virtual bool IsScheduledExecution();
private:

View File

@ -525,11 +525,9 @@ uint32_t C4PacketPing::getTravelTime() const
void C4PacketPing::CompileFunc(StdCompiler *pComp)
{
// FIXME: the compiler can't compile 64bit integers (yet), the ping will
// return wrong times if GetTime() returns integers too large for uint32
uint32_t time = tTime;
uint32_t time = tTime.AsInt();
pComp->Value(mkNamingAdapt(time, "Time", 0U));
tTime = time;
tTime = C4TimeMilliseconds(time);
pComp->Value(mkNamingAdapt(iPacketCounter, "PacketCounter", 0U));
}

View File

@ -90,7 +90,7 @@ public:
protected:
C4SoundEffect *pEffect;
int32_t iVolume, iPan, iChannel;
time_t tStarted;
C4TimeMilliseconds tStarted;
int32_t iNearInstanceMax;
bool fLooping;
C4Object *pObj;

View File

@ -0,0 +1,75 @@
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2013 Tobias Zwick
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* See isc_license.txt for full license and disclaimer.
*
* "Clonk" is a registered trademark of Matthes Bender.
* See clonk_trademark_license.txt for full license.
*/
#ifndef INC_C4TimeMilliseconds
#define INC_C4TimeMilliseconds
#include "PlatformAbstraction.h"
/* Class to store times in milliseconds for measurement purposes.
This class behaves for the most part like an unsigned integer, with the
difference that it handles an overflow correctly. For example:
C4TimeMilliseconds start = UINT32_MAX-10;
C4TimeMilliseconds stop = 10;
start < stop returns true. stop - start is 20.
A commonly used operation is to measure the time difference between two
C4TimeMilliseconds, that is why if two C4TimeMilliseconds are subtracted from another,
the return value is of the type uint32_t.
Otherwise, there should be no use case other than for printing, or packing/
unpacking for network to have a uint32_t representation of this. You can use
AsInt() for that. */
class C4TimeMilliseconds
{
private:
uint32_t time;
public:
C4TimeMilliseconds() : time(0) { }
C4TimeMilliseconds(uint32_t millis) : time(millis) { }
C4TimeMilliseconds(const C4TimeMilliseconds& rhs) : time(rhs.time) { }
~C4TimeMilliseconds() { }
uint32_t AsInt() const { return time; }
C4TimeMilliseconds& operator=(const C4TimeMilliseconds& rhs) { time = rhs.time; return *this; }
inline C4TimeMilliseconds& operator-=(const uint32_t& rhs) { time -= rhs; return *this; }
inline C4TimeMilliseconds& operator+=(const uint32_t& rhs) { time += rhs; return *this; }
};
inline bool operator==( const C4TimeMilliseconds& lhs, const C4TimeMilliseconds& rhs ) { return lhs.AsInt() == rhs.AsInt(); }
inline bool operator!=( const C4TimeMilliseconds& lhs, const C4TimeMilliseconds& rhs ) { return !(lhs == rhs); }
inline bool operator<( const C4TimeMilliseconds& lhs, const C4TimeMilliseconds& rhs ) { return int32_t(lhs.AsInt() - rhs.AsInt()) < 0; }
inline bool operator>( const C4TimeMilliseconds& lhs, const C4TimeMilliseconds& rhs ) { return rhs < lhs; }
inline bool operator<=( const C4TimeMilliseconds& lhs, const C4TimeMilliseconds& rhs ) { return !(lhs > rhs); }
inline bool operator>=( const C4TimeMilliseconds& lhs, const C4TimeMilliseconds& rhs ) { return !(lhs < rhs); }
inline uint32_t operator-(const C4TimeMilliseconds& lhs, const C4TimeMilliseconds& rhs) { return lhs.AsInt() - rhs.AsInt(); }
inline C4TimeMilliseconds operator+(C4TimeMilliseconds lhs, const uint32_t& rhs) { lhs += rhs; return lhs; }
inline C4TimeMilliseconds operator-(C4TimeMilliseconds lhs, const uint32_t& rhs) { lhs -= rhs; return lhs; }
/* the following operations make no sense and should rather be not defined to
throw a compiler error than being defined for the sake of it */
//inline uint32_t operator+(const C4TimeMilliseconds& lhs, const C4TimeMilliseconds& rhs) { return lhs.AsInt() + rhs.AsInt(); }
#endif

View File

@ -18,15 +18,16 @@
*/
#include "C4Include.h"
#include "C4TimeMilliseconds.h"
#ifdef _WIN32
#include <C4windowswrapper.h>
#include <mmsystem.h>
time_t GetTime()
C4TimeMilliseconds GetTime()
{
return timeGetTime();
return C4TimeMilliseconds(timeGetTime());
}
#else
@ -37,21 +38,20 @@ time_t GetTime()
#include <time.h>
#endif
time_t GetTime()
C4TimeMilliseconds GetTime()
{
#ifdef __APPLE__
static time_t sec_offset;
timeval tv;
gettimeofday(&tv, 0);
if (!sec_offset) sec_offset = tv.tv_sec;
return (tv.tv_sec - sec_offset) * 1000 + tv.tv_usec / 1000;
return C4TimeMilliseconds((tv.tv_sec - sec_offset) * 1000 + tv.tv_usec / 1000);
#else
timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
static time_t sec_offset = tv.tv_sec;
return (tv.tv_sec - sec_offset) * 1000 + tv.tv_nsec / 1000000;
return C4TimeMilliseconds((tv.tv_sec - sec_offset) * 1000 + tv.tv_nsec / 1000000);
#endif
}
#endif

View File

@ -230,8 +230,8 @@ bool IsGermanSystem();
bool OpenURL(const char* szURL);
// Get a monotonically increasing timestamp in milliseconds
#include <time.h>
time_t GetTime();
class C4TimeMilliseconds;
C4TimeMilliseconds GetTime();
#ifdef _WIN32
#include <io.h>

View File

@ -65,17 +65,17 @@ bool StdSchedulerProc::ExecuteUntil(int iTimeout)
if (!Execute())
return false;
// Calculate endpoint
time_t tStopTime = GetTime() + iTimeout;
C4TimeMilliseconds tStopTime = GetTime() + iTimeout;
for (;;)
{
// Call execute with given timeout
if (!Execute(Max(iTimeout, 0)))
return false;
// Calculate timeout
time_t tTime = GetTime();
C4TimeMilliseconds tTime = GetTime();
if (tTime >= tStopTime)
break;
iTimeout = int(tStopTime - tTime);
iTimeout = tStopTime - tTime;
}
// All ok.
return true;
@ -176,15 +176,17 @@ bool StdScheduler::ScheduleProcs(int iTimeout)
// Get timeout
int i;
time_t tProcTick;
time_t tNow = GetTime();
C4TimeMilliseconds tProcTick;
C4TimeMilliseconds tNow = GetTime();
for (i = 0; i < iProcCnt; i++)
{
if(ppProcs[i]->IsScheduledExecution())
{
tProcTick = ppProcs[i]->GetNextTick(tNow);
if (iTimeout == -1 || iTimeout + tNow > tProcTick)
iTimeout = Max<time_t>(tProcTick - tNow, 0);
if (iTimeout == -1 || tNow + iTimeout > tProcTick)
{
iTimeout = Max<uint32_t>(tProcTick - tNow, 0);
}
}
}

View File

@ -70,7 +70,7 @@ public:
#endif
// Call Execute() after this time has elapsed
virtual time_t GetNextTick(time_t tNow) { return 0; };
virtual C4TimeMilliseconds GetNextTick(C4TimeMilliseconds tNow) { return 0; };
virtual bool IsScheduledExecution() { return false; }
@ -86,30 +86,44 @@ public:
class CStdTimerProc : public StdSchedulerProc
{
public:
CStdTimerProc(uint32_t iDelay) : tLastTimer(0), iDelay(iDelay) { }
~CStdTimerProc() { }
CStdTimerProc(uint32_t iDelay) : tLastTimer(NULL), iDelay(iDelay) { }
~CStdTimerProc() { Set(); }
private:
time_t tLastTimer;
C4TimeMilliseconds *tLastTimer;
uint32_t iDelay;
public:
void Set() { tLastTimer = 0; }
void Set()
{
delete tLastTimer;
tLastTimer = NULL;
}
void SetDelay(uint32_t inDelay) { iDelay = inDelay; }
bool CheckAndReset()
{
if (GetTime() < tLastTimer + iDelay) return false;
C4TimeMilliseconds tTime = GetTime();
// first execution
if(!tLastTimer)
{
tLastTimer = new C4TimeMilliseconds(tTime - iDelay / 2);
return true;
}
// too early to execute
if (tTime < *tLastTimer + iDelay) return false;
// Compensate light drifting
time_t tTime = GetTime();
uint32_t iDrift = tTime - tLastTimer - iDelay; // >= 0 because of Check()
tLastTimer = tTime - Min(iDrift, iDelay / 2);
uint32_t iDrift = tTime - (*tLastTimer + iDelay); // a positive time difference because of above check
*tLastTimer = tTime - Min(iDrift, iDelay / 2);
return true;
}
// StdSchedulerProc override
virtual time_t GetNextTick(time_t tNow)
virtual C4TimeMilliseconds GetNextTick(C4TimeMilliseconds tNow)
{
return tLastTimer + iDelay;
// never executed yet? Execute now
if(!tLastTimer) return tNow;
// otherwise, last time executed plus specified delay
return *tLastTimer + iDelay;
}
virtual bool IsScheduledExecution() { return true; }

View File

@ -174,7 +174,7 @@ struct C4AulScriptContext
C4Value *Vars;
C4AulScriptFunc *Func;
C4AulBCC *CPos;
time_t tTime; // initialized only by profiler if active
C4TimeMilliseconds tTime; // initialized only by profiler if active
void dump(StdStrBuf Dump = StdStrBuf(""));
StdStrBuf ReturnDump(StdStrBuf Dump = StdStrBuf(""));
@ -227,7 +227,7 @@ public:
int GetLineOfCode(C4AulBCC * bcc);
C4AulBCC * GetCode();
time_t tProfileTime; // internally set by profiler
uint32_t tProfileTime; // internally set by profiler
friend class C4AulParse;
friend class C4ScriptHost;
@ -272,7 +272,7 @@ private:
struct Entry
{
C4AulScriptFunc *pFunc;
time_t tProfileTime;
uint32_t tProfileTime;
bool operator < (const Entry &e2) const { return tProfileTime < e2.tProfileTime ; }
};
@ -281,7 +281,7 @@ private:
std::vector<Entry> Times;
public:
void CollectEntry(C4AulScriptFunc *pFunc, time_t tProfileTime);
void CollectEntry(C4AulScriptFunc *pFunc, uint32_t tProfileTime);
void Show();
static void Abort();

View File

@ -941,7 +941,7 @@ void C4AulExec::StartProfiling(C4AulScript *pProfiledScript)
fProfiling = true;
// resets profling times and starts recording the times
this->pProfiledScript = pProfiledScript;
time_t tNow = GetTime();
C4TimeMilliseconds tNow = GetTime();
tDirectExecStart = tNow; // in case profiling is started from DirectExec
tDirectExecTotal = 0;
pProfiledScript->ResetProfilerTimes();
@ -984,8 +984,8 @@ void C4AulExec::PopContext()
// Profiler adding up times
if (fProfiling)
{
time_t dt = GetTime() - pCurCtx->tTime;
if (dt && pCurCtx->Func)
uint32_t dt = GetTime() - pCurCtx->tTime;
if (pCurCtx->Func)
pCurCtx->Func->tProfileTime += dt;
}
// Trace done?
@ -1014,7 +1014,7 @@ void C4AulProfiler::Abort()
AulExec.AbortProfiling();
}
void C4AulProfiler::CollectEntry(C4AulScriptFunc *pFunc, time_t tProfileTime)
void C4AulProfiler::CollectEntry(C4AulScriptFunc *pFunc, uint32_t tProfileTime)
{
// zero entries are not collected to have a cleaner list
if (!tProfileTime) return;
@ -1036,7 +1036,7 @@ void C4AulProfiler::Show()
for (EntryList::iterator i = Times.begin(); i!=Times.end(); ++i)
{
Entry &e = (*i);
LogF("%05dms\t%s", (int) e.tProfileTime, e.pFunc ? (e.pFunc->GetFullName().getData()) : "Direct exec");
LogF("%05ums\t%s", e.tProfileTime, e.pFunc ? (e.pFunc->GetFullName().getData()) : "Direct exec");
}
Log("==============================");
// done!

View File

@ -50,7 +50,8 @@ private:
int iTraceStart;
bool fProfiling;
time_t tDirectExecStart, tDirectExecTotal; // profiler time for DirectExec
C4TimeMilliseconds tDirectExecStart;
uint32_t tDirectExecTotal; // profiler time for DirectExec
C4AulScript *pProfiledScript;
C4AulScriptContext Contexts[MAX_CONTEXT_STACK];