From boxbackup-dev at fluffy.co.uk Tue Jul 1 00:04:15 2008 From: boxbackup-dev at fluffy.co.uk (boxbackup-dev at fluffy.co.uk) Date: Tue, 1 Jul 2008 00:04:15 +0100 (BST) Subject: [Box Backup-commit] COMMIT r2196 - box/trunk/lib/common Message-ID: <20080630230415.0CB4732503E@www.boxbackup.org> Author: chris Date: 2008-07-01 00:04:14 +0100 (Tue, 01 Jul 2008) New Revision: 2196 Modified: box/trunk/lib/common/Logging.cpp Log: Compile fix for strerror() on RedHat 9, thanks to Alex Howansky. Modified: box/trunk/lib/common/Logging.cpp =================================================================== --- box/trunk/lib/common/Logging.cpp 2008-06-27 23:12:39 UTC (rev 2195) +++ box/trunk/lib/common/Logging.cpp 2008-06-30 23:04:14 UTC (rev 2196) @@ -10,6 +10,7 @@ #include "Box.h" #include +#include #include #ifdef HAVE_SYSLOG_H From boxbackup-dev at fluffy.co.uk Wed Jul 2 18:50:48 2008 From: boxbackup-dev at fluffy.co.uk (boxbackup-dev at fluffy.co.uk) Date: Wed, 2 Jul 2008 18:50:48 +0100 (BST) Subject: [Box Backup-commit] COMMIT r2197 - box/trunk/bin/bbackupd Message-ID: <20080702175048.0583232503E@www.boxbackup.org> Author: chris Date: 2008-07-02 18:50:46 +0100 (Wed, 02 Jul 2008) New Revision: 2197 Modified: box/trunk/bin/bbackupd/BackupDaemon.cpp Log: Add missing #include, thanks to Alex Howansky. Reset notification state for backup-error after a successful backup, thanks to Wolfgang Trexler. Modified: box/trunk/bin/bbackupd/BackupDaemon.cpp =================================================================== --- box/trunk/bin/bbackupd/BackupDaemon.cpp 2008-06-30 23:04:14 UTC (rev 2196) +++ box/trunk/bin/bbackupd/BackupDaemon.cpp 2008-07-02 17:50:46 UTC (rev 2197) @@ -10,6 +10,7 @@ #include "Box.h" #include +#include #include #ifdef HAVE_UNISTD_H @@ -888,7 +889,8 @@ } else { - // Unset the read error flag, so the // error is reported again if it + // Unset the read error flag, so the + // error is reported again if it // happens again mNotificationsSent[NotifyEvent_ReadError] = false; } @@ -1014,6 +1016,13 @@ doSyncForcedByPreviousSyncError = true; } } + else + { + // Unset the read error flag, so the + // error is reported again if it + // happens again + mNotificationsSent[NotifyEvent_BackupError] = false; + } // Log the stats BOX_NOTICE("File statistics: total file size uploaded " From boxbackup-dev at fluffy.co.uk Thu Jul 3 21:31:22 2008 From: boxbackup-dev at fluffy.co.uk (boxbackup-dev at fluffy.co.uk) Date: Thu, 3 Jul 2008 21:31:22 +0100 (BST) Subject: [Box Backup-commit] COMMIT r2198 - box/trunk/bin/bbackupd Message-ID: <20080703203122.5E61B32503E@www.boxbackup.org> Author: chris Date: 2008-07-03 21:31:21 +0100 (Thu, 03 Jul 2008) New Revision: 2198 Modified: box/trunk/bin/bbackupd/BackupClientDirectoryRecord.cpp Log: Don't warn about ignoring sockets and FIFOs during backup, thanks to Tollef Fog Heen (http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=479145) Modified: box/trunk/bin/bbackupd/BackupClientDirectoryRecord.cpp =================================================================== --- box/trunk/bin/bbackupd/BackupClientDirectoryRecord.cpp 2008-07-02 17:50:46 UTC (rev 2197) +++ box/trunk/bin/bbackupd/BackupClientDirectoryRecord.cpp 2008-07-03 20:31:21 UTC (rev 2198) @@ -357,6 +357,11 @@ // Store on list dirs.push_back(std::string(en->d_name)); } + else if (type == S_IFSOCK || type == S_IFIFO) + { + // removed notification for these types + // see Debian bug 479145, no objections + } else { if(rParams.mrContext.ExcludeFile(filename)) From boxbackup-dev at fluffy.co.uk Sun Jul 6 15:30:19 2008 From: boxbackup-dev at fluffy.co.uk (boxbackup-dev at fluffy.co.uk) Date: Sun, 6 Jul 2008 15:30:19 +0100 (BST) Subject: [Box Backup-commit] COMMIT r2199 - box/trunk/lib/common Message-ID: <20080706143019.BA5DF325019@www.boxbackup.org> Author: chris Date: 2008-07-06 15:30:18 +0100 (Sun, 06 Jul 2008) New Revision: 2199 Modified: box/trunk/lib/common/Logging.h Log: Remove comma from last item in enum, to silence warnings from solaris cc. Modified: box/trunk/lib/common/Logging.h =================================================================== --- box/trunk/lib/common/Logging.h 2008-07-03 20:31:21 UTC (rev 2198) +++ box/trunk/lib/common/Logging.h 2008-07-06 14:30:18 UTC (rev 2199) @@ -95,7 +95,7 @@ INFO, TRACE, EVERYTHING, - INVALID = -1, + INVALID = -1 }; } From boxbackup-dev at fluffy.co.uk Sun Jul 6 15:31:48 2008 From: boxbackup-dev at fluffy.co.uk (boxbackup-dev at fluffy.co.uk) Date: Sun, 6 Jul 2008 15:31:48 +0100 (BST) Subject: [Box Backup-commit] COMMIT r2200 - box/trunk/lib/common Message-ID: <20080706143148.B1257325019@www.boxbackup.org> Author: chris Date: 2008-07-06 15:31:48 +0100 (Sun, 06 Jul 2008) New Revision: 2200 Modified: box/trunk/lib/common/Logging.cpp Log: Fix includes to get getpid() on Solaris and to make them easier to read. Modified: box/trunk/lib/common/Logging.cpp =================================================================== --- box/trunk/lib/common/Logging.cpp 2008-07-06 14:30:18 UTC (rev 2199) +++ box/trunk/lib/common/Logging.cpp 2008-07-06 14:31:48 UTC (rev 2200) @@ -16,12 +16,14 @@ #ifdef HAVE_SYSLOG_H #include #endif +#ifdef HAVE_UNISTD_H + #include +#endif -#include "Logging.h" - #include #include "BoxTime.h" +#include "Logging.h" bool Logging::sLogToSyslog = false; bool Logging::sLogToConsole = false; From boxbackup-dev at fluffy.co.uk Sat Jul 26 16:02:51 2008 From: boxbackup-dev at fluffy.co.uk (boxbackup-dev at fluffy.co.uk) Date: Sat, 26 Jul 2008 16:02:51 +0100 (BST) Subject: [Box Backup-commit] COMMIT r2201 - box/trunk Message-ID: <20080726150251.B011032686E@www.boxbackup.org> Author: chris Date: 2008-07-26 16:02:50 +0100 (Sat, 26 Jul 2008) New Revision: 2201 Modified: box/trunk/configure.ac Log: Remove -rdynamic flag from mingw gcc which doesn't support it. Modified: box/trunk/configure.ac =================================================================== --- box/trunk/configure.ac 2008-07-06 14:31:48 UTC (rev 2200) +++ box/trunk/configure.ac 2008-07-26 15:02:50 UTC (rev 2201) @@ -20,11 +20,16 @@ test "x$ac_cv_cxx_namespaces" != "xyes"; then AC_MSG_ERROR([[basic compile checks failed, the C++ compiler is broken]]) fi + if test "x$GXX" = "xyes"; then # Use -Wall if we have gcc. This gives better warnings AC_SUBST([CXXFLAGS_STRICT], ['-Wall -Wundef']) - # Use -rdynamic if we have gcc. This is needed for backtrace - AC_SUBST([LDADD_RDYNAMIC], ['-rdynamic']) + + # Use -rdynamic if we have gcc, but not mingw. This is needed for backtrace + case $target_os in + mingw*) ;; + *) AC_SUBST([LDADD_RDYNAMIC], ['-rdynamic']) ;; + esac fi AC_PATH_PROG([PERL], [perl], [AC_MSG_ERROR([[perl executable was not found]])]) From boxbackup-dev at fluffy.co.uk Sat Jul 26 16:03:28 2008 From: boxbackup-dev at fluffy.co.uk (boxbackup-dev at fluffy.co.uk) Date: Sat, 26 Jul 2008 16:03:28 +0100 (BST) Subject: [Box Backup-commit] COMMIT r2202 - box/trunk/infrastructure Message-ID: <20080726150328.5B1D432686E@www.boxbackup.org> Author: chris Date: 2008-07-26 16:03:27 +0100 (Sat, 26 Jul 2008) New Revision: 2202 Modified: box/trunk/infrastructure/makebuildenv.pl.in Log: Add spaces before Make progress output lines to visually separate them better from error messages. Modified: box/trunk/infrastructure/makebuildenv.pl.in =================================================================== --- box/trunk/infrastructure/makebuildenv.pl.in 2008-07-26 15:02:50 UTC (rev 2201) +++ box/trunk/infrastructure/makebuildenv.pl.in 2008-07-26 15:03:27 UTC (rev 2202) @@ -569,11 +569,11 @@ _RANLIB = \$(RANLIB) .else HIDE = @ -_CXX = @ echo "[CXX] " \$(*F) && \$(CXX) -_LINK = @ echo "[LINK] " \$(*F) && \$(CXX) -_WINDRES = @ echo "[WINDRES]" \$(*F) && \$(WINDRES) -_AR = @ echo "[AR] " \$(*F) && \$(AR) -_RANLIB = @ echo "[RANLIB] " \$(*F) && \$(RANLIB) +_CXX = @ echo " [CXX] " \$(*F) && \$(CXX) +_LINK = @ echo " [LINK] " \$(*F) && \$(CXX) +_WINDRES = @ echo " [WINDRES]" \$(*F) && \$(WINDRES) +_AR = @ echo " [AR] " \$(*F) && \$(AR) +_RANLIB = @ echo " [RANLIB] " \$(*F) && \$(RANLIB) .endif __E @@ -582,11 +582,11 @@ { print MAKE <<__E; HIDE = \$(if \$(V),,@) -_CXX = \$(if \$(V),\$(CXX), @ echo "[CXX] \$<" && \$(CXX)) -_LINK = \$(if \$(V),\$(CXX), @ echo "[LINK] \$@" && \$(CXX)) -_WINDRES = \$(if \$(V),\$(WINDRES), @ echo "[WINDRES] \$<" && \$(WINDRES)) -_AR = \$(if \$(V),\$(AR), @ echo "[AR] \$@" && \$(AR)) -_RANLIB = \$(if \$(V),\$(RANLIB), @ echo "[RANLIB] \$@" && \$(RANLIB)) +_CXX = \$(if \$(V),\$(CXX), @ echo " [CXX] \$<" && \$(CXX)) +_LINK = \$(if \$(V),\$(CXX), @ echo " [LINK] \$@" && \$(CXX)) +_WINDRES = \$(if \$(V),\$(WINDRES), @ echo " [WINDRES] \$<" && \$(WINDRES)) +_AR = \$(if \$(V),\$(AR), @ echo " [AR] \$@" && \$(AR)) +_RANLIB = \$(if \$(V),\$(RANLIB), @ echo " [RANLIB] \$@" && \$(RANLIB)) __E } From boxbackup-dev at fluffy.co.uk Sun Jul 27 21:09:01 2008 From: boxbackup-dev at fluffy.co.uk (boxbackup-dev at fluffy.co.uk) Date: Sun, 27 Jul 2008 21:09:01 +0100 (BST) Subject: [Box Backup-commit] COMMIT r2203 - box/trunk/lib/common Message-ID: <20080727200901.B9A2432508D@www.boxbackup.org> Author: chris Date: 2008-07-27 21:09:00 +0100 (Sun, 27 Jul 2008) New Revision: 2203 Modified: box/trunk/lib/common/BoxTime.cpp box/trunk/lib/common/BoxTime.h Log: Add a function to format a BoxTime as a human-readable time only (for use in logging). Modified: box/trunk/lib/common/BoxTime.cpp =================================================================== --- box/trunk/lib/common/BoxTime.cpp 2008-07-26 15:03:27 UTC (rev 2202) +++ box/trunk/lib/common/BoxTime.cpp 2008-07-27 20:09:00 UTC (rev 2203) @@ -52,3 +52,37 @@ return SecondsToBoxTime(time(0)); } + +std::string FormatTime(box_time_t time, bool showMicros) +{ + std::ostringstream buf; + + time_t seconds = BoxTimeToSeconds(time); + int micros = BoxTimeToMicroSeconds(time) % MICRO_SEC_IN_SEC; + + struct tm tm_now, *tm_ptr = &tm_now; + + #ifdef WIN32 + if ((tm_ptr = localtime(&seconds)) != NULL) + #else + if (localtime_r(&seconds, &tm_now) != NULL) + #endif + { + buf << std::setfill('0') << + std::setw(2) << tm_ptr->tm_hour << ":" << + std::setw(2) << tm_ptr->tm_min << ":" << + std::setw(2) << tm_ptr->tm_sec; + + if (showMicros) + { + buf << "." << std::setw(6) << micros; + } + } + else + { + buf << strerror(errno); + } + + return buf.str(); +} + Modified: box/trunk/lib/common/BoxTime.h =================================================================== --- box/trunk/lib/common/BoxTime.h 2008-07-26 15:03:27 UTC (rev 2202) +++ box/trunk/lib/common/BoxTime.h 2008-07-27 20:09:00 UTC (rev 2203) @@ -40,4 +40,6 @@ return Time; } +std::string FormatTime(box_time_t time, bool showMicros = false); + #endif // BOXTIME__H From boxbackup-dev at fluffy.co.uk Sun Jul 27 21:10:13 2008 From: boxbackup-dev at fluffy.co.uk (boxbackup-dev at fluffy.co.uk) Date: Sun, 27 Jul 2008 21:10:13 +0100 (BST) Subject: [Box Backup-commit] COMMIT r2204 - box/trunk/lib/common Message-ID: <20080727201013.D88D632508D@www.boxbackup.org> Author: chris Date: 2008-07-27 21:10:13 +0100 (Sun, 27 Jul 2008) New Revision: 2204 Modified: box/trunk/lib/common/Logging.cpp Log: Use the new time function when generating console log messages. Modified: box/trunk/lib/common/Logging.cpp =================================================================== --- box/trunk/lib/common/Logging.cpp 2008-07-27 20:09:00 UTC (rev 2203) +++ box/trunk/lib/common/Logging.cpp 2008-07-27 20:10:13 UTC (rev 2204) @@ -274,35 +274,8 @@ if (sShowTime) { - box_time_t time_now = GetCurrentBoxTime(); - time_t seconds = BoxTimeToSeconds(time_now); - int micros = BoxTimeToMicroSeconds(time_now) % MICRO_SEC_IN_SEC; - - struct tm tm_now, *tm_ptr = &tm_now; - - #ifdef WIN32 - if ((tm_ptr = localtime(&seconds)) != NULL) - #else - if (localtime_r(&seconds, &tm_now) != NULL) - #endif - { - buf << std::setfill('0') << - std::setw(2) << tm_ptr->tm_hour << ":" << - std::setw(2) << tm_ptr->tm_min << ":" << - std::setw(2) << tm_ptr->tm_sec; - - if (sShowTimeMicros) - { - buf << "." << std::setw(6) << micros; - } - - buf << " "; - } - else - { - buf << strerror(errno); - buf << " "; - } + buf << FormatTime(GetCurrentBoxTime(), sShowTimeMicros); + buf << " "; } if (sShowTag) From boxbackup-dev at fluffy.co.uk Sun Jul 27 21:11:25 2008 From: boxbackup-dev at fluffy.co.uk (boxbackup-dev at fluffy.co.uk) Date: Sun, 27 Jul 2008 21:11:25 +0100 (BST) Subject: [Box Backup-commit] COMMIT r2205 - box/trunk/lib/common Message-ID: <20080727201125.EDC2A32508D@www.boxbackup.org> Author: chris Date: 2008-07-27 21:11:25 +0100 (Sun, 27 Jul 2008) New Revision: 2205 Modified: box/trunk/lib/common/Test.cpp Log: On Windows XP, you can open a process even after it's terminated, to retrieve the exit code, so the check for process liveness has to be modified to make the basicserver test pass. Modified: box/trunk/lib/common/Test.cpp =================================================================== --- box/trunk/lib/common/Test.cpp 2008-07-27 20:10:13 UTC (rev 2204) +++ box/trunk/lib/common/Test.cpp 2008-07-27 20:11:25 UTC (rev 2205) @@ -88,23 +88,46 @@ bool ServerIsAlive(int pid) { -#ifdef WIN32 - HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, false, pid); - if (hProcess == NULL) - { - if (GetLastError() != ERROR_INVALID_PARAMETER) + #ifdef WIN32 + + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, + false, pid); + if (hProcess == NULL) { - printf("Failed to open process %d: error %d\n", - pid, (int)GetLastError()); + if (GetLastError() != ERROR_INVALID_PARAMETER) + { + BOX_ERROR("Failed to open process " << pid << + ": " << + GetErrorMessage(GetLastError())); + } + return false; } + + DWORD exitCode; + BOOL result = GetExitCodeProcess(hProcess, &exitCode); + CloseHandle(hProcess); + + if (result == 0) + { + BOX_ERROR("Failed to get exit code for process " << + pid << ": " << + GetErrorMessage(GetLastError())) + return false; + } + + if (exitCode == STILL_ACTIVE) + { + return true; + } + return false; - } - CloseHandle(hProcess); - return true; -#else // !WIN32 - if(pid == 0) return false; - return ::kill(pid, 0) != -1; -#endif // WIN32 + + #else // !WIN32 + + if(pid == 0) return false; + return ::kill(pid, 0) != -1; + + #endif // WIN32 } int ReadPidFile(const char *pidFile) From boxbackup-dev at fluffy.co.uk Sun Jul 27 21:36:14 2008 From: boxbackup-dev at fluffy.co.uk (boxbackup-dev at fluffy.co.uk) Date: Sun, 27 Jul 2008 21:36:14 +0100 (BST) Subject: [Box Backup-commit] COMMIT r2206 - box/trunk/lib/common Message-ID: <20080727203614.62FC832508D@www.boxbackup.org> Author: chris Date: 2008-07-27 21:36:14 +0100 (Sun, 27 Jul 2008) New Revision: 2206 Modified: box/trunk/lib/common/Timer.cpp box/trunk/lib/common/Timer.h Log: New timer implementation using TimerQueue on Windows to avoid the need to create and manage a separate thread ourselves. Modified: box/trunk/lib/common/Timer.cpp =================================================================== --- box/trunk/lib/common/Timer.cpp 2008-07-27 20:11:25 UTC (rev 2205) +++ box/trunk/lib/common/Timer.cpp 2008-07-27 20:36:14 UTC (rev 2206) @@ -8,6 +8,10 @@ // // -------------------------------------------------------------------------- +#ifdef WIN32 + #define _WIN32_WINNT 0x0500 +#endif + #include "Box.h" #include @@ -20,6 +24,9 @@ std::vector* Timers::spTimers = NULL; bool Timers::sRescheduleNeeded = false; +#define TIMER_ID "timer " << mName << " (" << this << ") " +#define TIMER_ID_OF(t) "timer " << (t).GetName() << " (" << &(t) << ") " + typedef void (*sighandler_t)(int); // -------------------------------------------------------------------------- @@ -35,9 +42,7 @@ ASSERT(!spTimers); #if defined WIN32 && ! defined PLATFORM_CYGWIN - // no support for signals at all - InitTimer(); - SetTimerHandler(Timers::SignalHandler); + // no init needed #else struct sigaction newact, oldact; newact.sa_handler = Timers::SignalHandler; @@ -72,9 +77,7 @@ } #if defined WIN32 && ! defined PLATFORM_CYGWIN - // no support for signals at all - FiniTimer(); - SetTimerHandler(NULL); + // no cleanup needed #else struct itimerval timeout; memset(&timeout, 0, sizeof(timeout)); @@ -149,9 +152,22 @@ Reschedule(); } +void Timers::RequestReschedule() +{ + sRescheduleNeeded = true; +} + +void Timers::RescheduleIfNeeded() +{ + if (sRescheduleNeeded) + { + Reschedule(); + } +} + #define FORMAT_MICROSECONDS(t) \ (int)(t / 1000000) << "." << \ - (int)(t % 1000000) + (int)(t % 1000000) << " seconds" // -------------------------------------------------------------------------- // @@ -195,6 +211,9 @@ // we will do it anyway. sRescheduleNeeded = false; +#ifdef WIN32 + // win32 timers need no management +#else box_time_t timeNow = GetCurrentBoxTime(); // scan for, trigger and remove expired timers. Removal requires @@ -212,8 +231,14 @@ if (timeToExpiry <= 0) { + /* BOX_TRACE("timer " << *i << " has expired, " "triggering it"); + */ + BOX_TRACE(TIMER_ID_OF(**i) "has expired, " + "triggering " << + FORMAT_MICROSECONDS(-timeToExpiry) << + " late"); rTimer.OnExpire(); spTimers->erase(i); restart = true; @@ -221,10 +246,12 @@ } else { + /* BOX_TRACE("timer " << *i << " has not " "expired, triggering in " << FORMAT_MICROSECONDS(timeToExpiry) << " seconds"); + */ } } } @@ -233,6 +260,7 @@ // Scan to find the next one to fire (earliest deadline). int64_t timeToNextEvent = 0; + std::string nameOfNextEvent; for (std::vector::iterator i = spTimers->begin(); i != spTimers->end(); i++) @@ -240,6 +268,7 @@ Timer& rTimer = **i; int64_t timeToExpiry = rTimer.GetExpiryTime() - timeNow; + ASSERT(timeToExpiry > 0) if (timeToExpiry <= 0) { timeToExpiry = 1; @@ -248,23 +277,36 @@ if (timeToNextEvent == 0 || timeToNextEvent > timeToExpiry) { timeToNextEvent = timeToExpiry; + nameOfNextEvent = rTimer.GetName(); } } ASSERT(timeToNextEvent >= 0); - + + if (timeToNextEvent == 0) + { + BOX_TRACE("timer: no more events, going to sleep."); + } + else + { + BOX_TRACE("timer: next event: " << nameOfNextEvent << + " expires in " << FORMAT_MICROSECONDS(timeToNextEvent)); + } + struct itimerval timeout; memset(&timeout, 0, sizeof(timeout)); timeout.it_value.tv_sec = BoxTimeToSeconds(timeToNextEvent); timeout.it_value.tv_usec = (int) - (BoxTimeToMicroSeconds(timeToNextEvent) % MICRO_SEC_IN_SEC); + (BoxTimeToMicroSeconds(timeToNextEvent) + % MICRO_SEC_IN_SEC); if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0) { - BOX_ERROR("Failed to initialise timer\n"); + BOX_ERROR("Failed to initialise system timer\n"); THROW_EXCEPTION(CommonException, Internal) } +#endif } // -------------------------------------------------------------------------- @@ -279,27 +321,42 @@ // Created: 5/11/2006 // // -------------------------------------------------------------------------- -void Timers::SignalHandler(int iUnused) +void Timers::SignalHandler(int unused) { // ASSERT(spTimers); Timers::RequestReschedule(); } -Timer::Timer(size_t timeoutSecs) +// -------------------------------------------------------------------------- +// +// Function +// Name: Timer::Timer(size_t timeoutSecs, +// const std::string& rName) +// Purpose: Standard timer constructor, takes a timeout in +// seconds from now, and an optional name for +// logging purposes. +// Created: 27/07/2008 +// +// -------------------------------------------------------------------------- + +Timer::Timer(size_t timeoutSecs, const std::string& rName) : mExpires(GetCurrentBoxTime() + SecondsToBoxTime(timeoutSecs)), - mExpired(false) + mExpired(false), + mName(rName) +#ifdef WIN32 +, mTimerHandle(INVALID_HANDLE_VALUE) +#endif { #ifndef NDEBUG if (timeoutSecs == 0) { - BOX_TRACE("timer " << this << " initialised for " << - timeoutSecs << " secs, will not fire"); + BOX_TRACE(TIMER_ID "initialised for " << timeoutSecs << + " secs, will not fire"); } else { - BOX_TRACE("timer " << this << " initialised for " << - timeoutSecs << " secs, to fire at " << - FORMAT_MICROSECONDS(mExpires)); + BOX_TRACE(TIMER_ID "initialised for " << timeoutSecs << + " secs, to fire at " << FormatTime(mExpires, true)); } #endif @@ -310,37 +367,157 @@ else { Timers::Add(*this); + Start(timeoutSecs * MICRO_SEC_IN_SEC_LL); } } +// -------------------------------------------------------------------------- +// +// Function +// Name: Timer::Start() +// Purpose: This internal function initialises an OS TimerQueue +// timer on Windows, while on Unixes there is only a +// single global timer, managed by the Timers class, +// so this method does nothing. +// Created: 27/07/2008 +// +// -------------------------------------------------------------------------- + +void Timer::Start() +{ +#ifdef WIN32 + box_time_t timeNow = GetCurrentBoxTime(); + int64_t timeToExpiry = mExpires - timeNow; + + if (timeToExpiry <= 0) + { + BOX_WARNING(TIMER_ID << "fudging expiry from -" << + FORMAT_MICROSECONDS(-timeToExpiry)) + timeToExpiry = 1; + } + + Start(timeToExpiry); +#endif +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: Timer::Start(int64_t delayInMicros) +// Purpose: This internal function initialises an OS TimerQueue +// timer on Windows, with a specified delay already +// calculated to save us doing it again. Like +// Timer::Start(), on Unixes it does nothing. +// Created: 27/07/2008 +// +// -------------------------------------------------------------------------- + +void Timer::Start(int64_t delayInMicros) +{ +#ifdef WIN32 + // only call me once! + ASSERT(mTimerHandle == INVALID_HANDLE_VALUE); + + int64_t delayInMillis = delayInMicros / 1000; + + // Windows XP always seems to fire timers up to 20 ms late, + // at least on my test laptop. Not critical in practice, but our + // tests are precise enough that they will fail if we don't + // correct for it. + delayInMillis -= 20; + + // Set a system timer to call our timer routine + if (CreateTimerQueueTimer(&mTimerHandle, NULL, TimerRoutine, + (PVOID)this, delayInMillis, 0, WT_EXECUTEINTIMERTHREAD) + == FALSE) + { + BOX_ERROR(TIMER_ID "failed to create timer: " << + GetErrorMessage(GetLastError())); + mTimerHandle = INVALID_HANDLE_VALUE; + } +#endif +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: Timer::Stop() +// Purpose: This internal function deletes the associated OS +// TimerQueue timer on Windows, and on Unixes does +// nothing. +// Created: 27/07/2008 +// +// -------------------------------------------------------------------------- + +void Timer::Stop() +{ +#ifdef WIN32 + if (mTimerHandle != INVALID_HANDLE_VALUE) + { + if (DeleteTimerQueueTimer(NULL, mTimerHandle, + INVALID_HANDLE_VALUE) == FALSE) + { + BOX_ERROR(TIMER_ID "failed to delete timer: " << + GetErrorMessage(GetLastError())); + } + mTimerHandle = INVALID_HANDLE_VALUE; + } +#endif +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: Timer::~Timer() +// Purpose: Destructor for Timer objects. +// Created: 27/07/2008 +// +// -------------------------------------------------------------------------- + Timer::~Timer() { #ifndef NDEBUG - BOX_TRACE("timer " << this << " destroyed"); + BOX_TRACE(TIMER_ID "destroyed"); #endif Timers::Remove(*this); + Stop(); } +// -------------------------------------------------------------------------- +// +// Function +// Name: Timer::Timer(Timer& rToCopy) +// Purpose: Copy constructor for Timer objects. Creates a new +// timer that will trigger at the same time as the +// original. The original will usually be discarded. +// Created: 27/07/2008 +// +// -------------------------------------------------------------------------- + Timer::Timer(const Timer& rToCopy) : mExpires(rToCopy.mExpires), - mExpired(rToCopy.mExpired) + mExpired(rToCopy.mExpired), + mName(rToCopy.mName) +#ifdef WIN32 +, mTimerHandle(INVALID_HANDLE_VALUE) +#endif { #ifndef NDEBUG if (mExpired) { - BOX_TRACE("timer " << this << " initialised from timer " << - &rToCopy << ", already expired, will not fire"); + BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", " + "already expired, will not fire"); } else if (mExpires == 0) { - BOX_TRACE("timer " << this << " initialised from timer " << - &rToCopy << ", no expiry, will not fire"); + BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", " + "no expiry, will not fire"); } else { - BOX_TRACE("timer " << this << " initialised from timer " << - &rToCopy << " to fire at " << + BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", " + "to fire at " << (int)(mExpires / 1000000) << "." << (int)(mExpires % 1000000)); } @@ -349,46 +526,99 @@ if (!mExpired && mExpires != 0) { Timers::Add(*this); + Start(); } } +// -------------------------------------------------------------------------- +// +// Function +// Name: Timer::operator=(const Timer& rToCopy) +// Purpose: Assignment operator for Timer objects. Works +// exactly the same as the copy constructor, except +// that if the receiving timer is already running, +// it is stopped first. +// Created: 27/07/2008 +// +// -------------------------------------------------------------------------- + Timer& Timer::operator=(const Timer& rToCopy) { #ifndef NDEBUG if (rToCopy.mExpired) { - BOX_TRACE("timer " << this << " initialised from timer " << - &rToCopy << ", already expired, will not fire"); + BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", " + "already expired, will not fire"); } else if (rToCopy.mExpires == 0) { - BOX_TRACE("timer " << this << " initialised from timer " << - &rToCopy << ", no expiry, will not fire"); + BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", " + "no expiry, will not fire"); } else { - BOX_TRACE("timer " << this << " initialised from timer " << - &rToCopy << " to fire at " << + BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", " + "to fire at " << (int)(rToCopy.mExpires / 1000000) << "." << (int)(rToCopy.mExpires % 1000000)); } #endif Timers::Remove(*this); + Stop(); + mExpires = rToCopy.mExpires; mExpired = rToCopy.mExpired; + if (!mExpired && mExpires != 0) { Timers::Add(*this); + Start(); } + return *this; } +// -------------------------------------------------------------------------- +// +// Function +// Name: Timer::OnExpire() +// Purpose: Method called by Timers::Reschedule (on Unixes) +// on next poll after timer expires, or from +// Timer::TimerRoutine (on Windows) from a separate +// thread managed by the OS. Marks the timer as +// expired for future reference. +// Created: 27/07/2008 +// +// -------------------------------------------------------------------------- + void Timer::OnExpire() { #ifndef NDEBUG - BOX_TRACE("timer " << this << " fired"); + BOX_TRACE(TIMER_ID "fired"); #endif mExpired = true; } + +// -------------------------------------------------------------------------- +// +// Function +// Name: Timer::TimerRoutine(PVOID lpParam, +// BOOLEAN TimerOrWaitFired) +// Purpose: Static method called by the Windows OS when a +// TimerQueue timer expires. +// Created: 27/07/2008 +// +// -------------------------------------------------------------------------- + +#ifdef WIN32 +VOID CALLBACK Timer::TimerRoutine(PVOID lpParam, + BOOLEAN TimerOrWaitFired) +{ + Timer* pTimer = (Timer*)lpParam; + pTimer->OnExpire(); + // is it safe to write to write debug output from a timer? + // e.g. to write to the Event Log? +} +#endif Modified: box/trunk/lib/common/Timer.h =================================================================== --- box/trunk/lib/common/Timer.h 2008-07-27 20:11:25 UTC (rev 2205) +++ box/trunk/lib/common/Timer.h 2008-07-27 20:36:14 UTC (rev 2206) @@ -40,35 +40,24 @@ static bool sRescheduleNeeded; static void SignalHandler(int iUnused); - + public: static void Init(); static void Cleanup(); static void Add (Timer& rTimer); static void Remove(Timer& rTimer); - static void RequestReschedule() - { - sRescheduleNeeded = true; - } - - static void RescheduleIfNeeded() - { - if (sRescheduleNeeded) - { - Reschedule(); - } - } + static void RequestReschedule(); + static void RescheduleIfNeeded(); }; class Timer { public: - Timer(size_t timeoutSecs); + Timer(size_t timeoutSecs, const std::string& rName = ""); virtual ~Timer(); Timer(const Timer &); Timer &operator=(const Timer &); -public: box_time_t GetExpiryTime() { return mExpires; } virtual void OnExpire(); bool HasExpired() @@ -76,10 +65,23 @@ Timers::RescheduleIfNeeded(); return mExpired; } + + const std::string& GetName() const { return mName; } private: - box_time_t mExpires; - bool mExpired; + box_time_t mExpires; + bool mExpired; + std::string mName; + + void Start(); + void Start(int64_t delayInMicros); + void Stop(); + + #ifdef WIN32 + HANDLE mTimerHandle; + static VOID CALLBACK TimerRoutine(PVOID lpParam, + BOOLEAN TimerOrWaitFired); + #endif }; #include "MemLeakFindOff.h"