forked from Mirrors/openclonk
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
parent
c03effd104
commit
94c618d153
|
@ -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
|
||||
|
|
|
@ -108,4 +108,6 @@ inline void operator delete(void *p, const char *, long)
|
|||
|
||||
#include "C4Game.h"
|
||||
|
||||
#include "C4TimeMilliseconds.h"
|
||||
|
||||
#endif // INC_C4Include
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -85,7 +85,7 @@ private:
|
|||
C4InteractiveEventType Type;
|
||||
void *Data;
|
||||
#ifdef _DEBUG
|
||||
time_t Time;
|
||||
C4TimeMilliseconds Time;
|
||||
#endif
|
||||
Event *Next;
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in New Issue