From c49253824a46a45dac86d2a0404b9d5c6e1a92a4 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 19 Dec 2004 18:08:09 +0100 Subject: [PATCH] Replaced time_ms() with a threadsafe and non-overflowing cTimeMs --- CONTRIBUTORS | 1 + HISTORY | 2 ++ lirc.c | 17 ++++++++--------- menu.c | 28 ++++++++++++++-------------- menu.h | 6 +++--- rcu.c | 9 ++++----- tools.c | 44 +++++++++++++++++++++++++++++++------------- tools.h | 14 ++++++++++++-- 8 files changed, 75 insertions(+), 46 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index b62f8a32..38d3bfd9 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -350,6 +350,7 @@ Rainer Zocholl for reporting a possible race condition in generating the DVB device names for pointing out that non-threadsafe functions should be replaced with their threadsafe versions + for pointing out a threadsafe and overflow problem with time_ms() Oleg Assovski for adding EPG scanning for another 4 days diff --git a/HISTORY b/HISTORY index 0813fbf9..9fd32246 100644 --- a/HISTORY +++ b/HISTORY @@ -3222,3 +3222,5 @@ Video Disk Recorder Revision History WeekDayName() -> cWeekDayName DayDateTime() -> cDayDateTime - Removed delay_ms(), using cCondWait::SleepMs() instead. +- Replaced time_ms() with a threadsafe and non-overflowing cTimeMs (thanks to Rainer + Zocholl for pointing out this problem). diff --git a/lirc.c b/lirc.c index ae905fdc..8fe585ab 100644 --- a/lirc.c +++ b/lirc.c @@ -6,7 +6,7 @@ * * LIRC support added by Carsten Koch 2000-06-16. * - * $Id: lirc.c 1.8 2004/12/18 13:25:11 kls Exp $ + * $Id: lirc.c 1.9 2004/12/19 18:05:13 kls Exp $ */ #include "lirc.h" @@ -52,8 +52,8 @@ bool cLircRemote::Ready(void) void cLircRemote::Action(void) { - int FirstTime = 0; - int LastTime = 0; + cTimeMs FirstTime; + cTimeMs LastTime; char buf[LIRC_BUFFER_SIZE]; char LastKeyName[LIRC_KEY_BUF] = ""; bool repeat = false; @@ -75,28 +75,27 @@ void cLircRemote::Action(void) int count; char KeyName[LIRC_KEY_BUF]; sscanf(buf, "%*x %x %29s", &count, KeyName); // '29' in '%29s' is LIRC_KEY_BUF-1! - int Now = time_ms(); if (count == 0) { - if (strcmp(KeyName, LastKeyName) == 0 && Now - FirstTime < KEYPRESSDELAY) + if (strcmp(KeyName, LastKeyName) == 0 && FirstTime.Elapsed() < KEYPRESSDELAY) continue; // skip keys coming in too fast if (repeat) Put(LastKeyName, false, true); strcpy(LastKeyName, KeyName); repeat = false; - FirstTime = Now; + FirstTime.Set(); timeout = -1; } else { - if (Now - FirstTime < REPEATDELAY) + if (FirstTime.Elapsed() < REPEATDELAY) continue; // repeat function kicks in after a short delay repeat = true; timeout = REPEATDELAY; } - LastTime = Now; + LastTime.Set(); Put(KeyName, repeat); } else if (repeat) { // the last one was a repeat, so let's generate a release - if (time_ms() - LastTime >= REPEATDELAY) { + if (LastTime.Elapsed() >= REPEATDELAY) { Put(LastKeyName, false, true); repeat = false; *LastKeyName = 0; diff --git a/menu.c b/menu.c index b5d57e5c..e1629a31 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.321 2004/12/12 16:07:05 kls Exp $ + * $Id: menu.c 1.322 2004/12/19 17:59:47 kls Exp $ */ #include "menu.h" @@ -2516,7 +2516,7 @@ cDisplayChannel::cDisplayChannel(int Number, bool Switched) DisplayInfo(); displayChannel->Flush(); } - lastTime = time_ms(); + lastTime.Set(); } cDisplayChannel::cDisplayChannel(eKeys FirstKey) @@ -2525,7 +2525,7 @@ cDisplayChannel::cDisplayChannel(eKeys FirstKey) group = -1; number = 0; lastPresent = lastFollowing = NULL; - lastTime = time_ms(); + lastTime.Set(); withInfo = Setup.ShowInfoOnChSwitch; displayChannel = Skins.Current()->DisplayChannel(withInfo); ProcessKey(FirstKey); @@ -2570,7 +2570,7 @@ void cDisplayChannel::Refresh(void) channel = Channels.GetByNumber(cDevice::CurrentChannel()); DisplayChannel(); displayChannel->SetEvents(NULL, NULL); - lastTime = time_ms(); + lastTime.Set(); } eOSState cDisplayChannel::ProcessKey(eKeys Key) @@ -2590,7 +2590,7 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key) displayChannel->SetEvents(NULL, NULL); withInfo = false; DisplayChannel(); - lastTime = time_ms(); + lastTime.Set(); // Lets see if there can be any useful further input: int n = channel ? number * 10 : 0; cChannel *ch = channel; @@ -2639,7 +2639,7 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key) group = -1; } } - lastTime = time_ms(); + lastTime.Set(); break; case kUp|k_Repeat: case kUp: @@ -2656,14 +2656,14 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key) Refresh(); break; case kNone: - if (number && time_ms() - lastTime > DIRECTCHANNELTIMEOUT) { + if (number && lastTime.Elapsed() > DIRECTCHANNELTIMEOUT) { if (Channels.GetByNumber(number)) Channels.SwitchTo(number); else { number = 0; channel = NULL; DisplayChannel(); - lastTime = time_ms(); + lastTime.Set(); return osContinue; } return osEnd; @@ -2687,7 +2687,7 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key) return osEnd; } }; - if (time_ms() - lastTime < INFOTIMEOUT) { + if (lastTime.Elapsed() < INFOTIMEOUT) { if (!number && group < 0 && channel && channel->Number() != cDevice::CurrentChannel()) Refresh(); // makes sure a channel switch through the SVDRP CHAN command is displayed DisplayInfo(); @@ -2708,7 +2708,7 @@ cDisplayVolume::cDisplayVolume(void) :cOsdObject(true) { currentDisplayVolume = this; - timeout = time_ms() + (cDevice::PrimaryDevice()->IsMute() ? MUTETIMEOUT : VOLUMETIMEOUT); + timeout.Set(cDevice::PrimaryDevice()->IsMute() ? MUTETIMEOUT : VOLUMETIMEOUT); displayVolume = Skins.Current()->DisplayVolume(); Show(); } @@ -2745,15 +2745,15 @@ eOSState cDisplayVolume::ProcessKey(eKeys Key) case kVolDn|k_Repeat: case kVolDn: Show(); - timeout = time_ms() + VOLUMETIMEOUT; + timeout.Set(VOLUMETIMEOUT); break; case kMute: if (cDevice::PrimaryDevice()->IsMute()) { Show(); - timeout = time_ms() + MUTETIMEOUT; + timeout.Set(MUTETIMEOUT); } else - timeout = 0; + timeout.Set(); break; case kNone: break; default: if ((Key & k_Release) == 0) { @@ -2761,7 +2761,7 @@ eOSState cDisplayVolume::ProcessKey(eKeys Key) return osEnd; } } - return time_ms() < timeout ? osContinue : osEnd; + return timeout.TimedOut() ? osEnd : osContinue; } // --- cRecordControl -------------------------------------------------------- diff --git a/menu.h b/menu.h index 5990a2ea..3b841363 100644 --- a/menu.h +++ b/menu.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.64 2004/06/13 11:46:03 kls Exp $ + * $Id: menu.h 1.65 2004/12/19 17:59:47 kls Exp $ */ #ifndef __MENU_H @@ -46,7 +46,7 @@ private: cSkinDisplayChannel *displayChannel; int group; bool withInfo; - int lastTime; + cTimeMs lastTime; int number; cChannel *channel; const cEvent *lastPresent; @@ -64,7 +64,7 @@ public: class cDisplayVolume : public cOsdObject { private: cSkinDisplayVolume *displayVolume; - int timeout; + cTimeMs timeout; static cDisplayVolume *currentDisplayVolume; virtual void Show(void); cDisplayVolume(void); diff --git a/rcu.c b/rcu.c index 71a3220e..4ea80d9e 100644 --- a/rcu.c +++ b/rcu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: rcu.c 1.7 2004/12/19 17:19:34 kls Exp $ + * $Id: rcu.c 1.8 2004/12/19 18:06:00 kls Exp $ */ #include "rcu.h" @@ -94,7 +94,7 @@ void cRcuRemote::Action(void) #pragma pack() time_t LastCodeRefresh = 0; - int FirstTime = 0; + cTimeMs FirstTime; uint64 LastCommand = 0; bool repeat = false; @@ -116,15 +116,14 @@ void cRcuRemote::Action(void) // This remote control sends the above command before and after // each keypress - let's just drop this: break; - int Now = time_ms(); Command |= uint64(Address) << 32; if (Command != LastCommand) { LastCommand = Command; repeat = false; - FirstTime = Now; + FirstTime.Set(); } else { - if (Now - FirstTime < REPEATDELAY) + if (FirstTime.Elapsed() < REPEATDELAY) break; // repeat function kicks in after a short delay repeat = true; } diff --git a/tools.c b/tools.c index 3776e6b9..fb95e7df 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.84 2004/12/19 17:19:46 kls Exp $ + * $Id: tools.c 1.85 2004/12/19 18:06:16 kls Exp $ */ #include "tools.h" @@ -187,18 +187,6 @@ int numdigits(int n) return strlen(buf); } -int time_ms(void) -{ - static time_t t0 = 0; - struct timeval t; - if (gettimeofday(&t, NULL) == 0) { - if (t0 == 0) - t0 = t.tv_sec; // this avoids an overflow (we only work with deltas) - return (t.tv_sec - t0) * 1000 + t.tv_usec / 1000; - } - return 0; -} - bool isnumber(const char *s) { if (!*s) @@ -432,6 +420,36 @@ time_t LastModifiedTime(const char *FileName) return 0; } +// --- cTimeMs --------------------------------------------------------------- + +cTimeMs::cTimeMs(void) +{ + Set(); +} + +void cTimeMs::Set(int Ms) +{ + begin = Now() + Ms; +} + +bool cTimeMs::TimedOut(void) +{ + return Now() >= begin; +} + +uint64 cTimeMs::Now(void) +{ + struct timeval t; + if (gettimeofday(&t, NULL) == 0) + return (uint64(t.tv_sec)) * 1000 + t.tv_usec / 1000; + return 0; +} + +uint64 cTimeMs::Elapsed(void) +{ + return Now() - begin; +} + // --- cBufferedStringFunction ----------------------------------------------- cBufferedStringFunction::cBufferedStringFunction(void) diff --git a/tools.h b/tools.h index 71e7d884..2c90ff75 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.60 2004/12/19 17:20:05 kls Exp $ + * $Id: tools.h 1.61 2004/12/19 18:06:10 kls Exp $ */ #ifndef __TOOLS_H @@ -71,7 +71,6 @@ bool startswith(const char *s, const char *p); bool endswith(const char *s, const char *p); bool isempty(const char *s); int numdigits(int n); -int time_ms(void); bool isnumber(const char *s); int FreeDiskSpaceMB(const char *Directory, int *UsedMB = NULL); bool DirectoryOk(const char *DirName, bool LogErrors = false); @@ -82,6 +81,17 @@ char *ReadLink(const char *FileName); bool SpinUpDisk(const char *FileName); time_t LastModifiedTime(const char *FileName); +class cTimeMs { +private: + uint64 begin; +public: + cTimeMs(void); + void Set(int Ms = 0); + bool TimedOut(void); + uint64 Now(void); + uint64 Elapsed(void); + }; + class cBufferedStringFunction { protected: char *buffer;