LCOV - code coverage report
Current view: directory - xpcom/threads - TimerThread.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 209 192 91.9 %
Date: 2012-06-02 Functions: 26 25 96.2 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is mozilla.org code.
      18                 :  *
      19                 :  * The Initial Developer of the Original Code is
      20                 :  * Netscape Communications Corporation.
      21                 :  * Portions created by the Initial Developer are Copyright (C) 2001
      22                 :  * the Initial Developer. All Rights Reserved.
      23                 :  *
      24                 :  * Contributor(s):
      25                 :  *   Stuart Parmenter <pavlov@netscape.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #include "nsTimerImpl.h"
      42                 : #include "TimerThread.h"
      43                 : 
      44                 : #include "nsThreadUtils.h"
      45                 : #include "pratom.h"
      46                 : 
      47                 : #include "nsIObserverService.h"
      48                 : #include "nsIServiceManager.h"
      49                 : #include "mozilla/Services.h"
      50                 : 
      51                 : #include <math.h>
      52                 : 
      53                 : using namespace mozilla;
      54                 : 
      55           18587 : NS_IMPL_THREADSAFE_ISUPPORTS2(TimerThread, nsIRunnable, nsIObserver)
      56                 : 
      57            1419 : TimerThread::TimerThread() :
      58                 :   mInitInProgress(0),
      59                 :   mInitialized(false),
      60                 :   mMonitor("TimerThread.mMonitor"),
      61                 :   mShutdown(false),
      62                 :   mWaiting(false),
      63                 :   mSleeping(false),
      64                 :   mDelayLineCounter(0),
      65            1419 :   mMinTimerPeriod(0)
      66                 : {
      67            1419 : }
      68                 : 
      69            2838 : TimerThread::~TimerThread()
      70                 : {
      71            1419 :   mThread = nsnull;
      72                 : 
      73            1419 :   NS_ASSERTION(mTimers.IsEmpty(), "Timers remain in TimerThread::~TimerThread");
      74            1419 : }
      75                 : 
      76                 : nsresult
      77            1419 : TimerThread::InitLocks()
      78                 : {
      79            1419 :   return NS_OK;
      80                 : }
      81                 : 
      82                 : namespace {
      83                 : 
      84                 : class TimerObserverRunnable : public nsRunnable
      85            4092 : {
      86                 : public:
      87            1023 :   TimerObserverRunnable(nsIObserver* observer)
      88            1023 :     : mObserver(observer)
      89            1023 :   { }
      90                 : 
      91                 :   NS_DECL_NSIRUNNABLE
      92                 : 
      93                 : private:
      94                 :   nsCOMPtr<nsIObserver> mObserver;
      95                 : };
      96                 : 
      97                 : NS_IMETHODIMP
      98            1023 : TimerObserverRunnable::Run()
      99                 : {
     100                 :   nsCOMPtr<nsIObserverService> observerService =
     101            2046 :     mozilla::services::GetObserverService();
     102            1023 :   if (observerService) {
     103            1023 :     observerService->AddObserver(mObserver, "sleep_notification", PR_FALSE);
     104            1023 :     observerService->AddObserver(mObserver, "wake_notification", PR_FALSE);
     105                 :   }
     106            1023 :   return NS_OK;
     107                 : }
     108                 : 
     109                 : } // anonymous namespace
     110                 : 
     111           21292 : nsresult TimerThread::Init()
     112                 : {
     113           21292 :   PR_LOG(gTimerLog, PR_LOG_DEBUG, ("TimerThread::Init [%d]\n", mInitialized));
     114                 : 
     115           21292 :   if (mInitialized) {
     116           20269 :     if (!mThread)
     117               0 :       return NS_ERROR_FAILURE;
     118                 : 
     119           20269 :     return NS_OK;
     120                 :   }
     121                 : 
     122            1023 :   if (PR_ATOMIC_SET(&mInitInProgress, 1) == 0) {
     123                 :     // We hold on to mThread to keep the thread alive.
     124            1023 :     nsresult rv = NS_NewThread(getter_AddRefs(mThread), this);
     125            1023 :     if (NS_FAILED(rv)) {
     126               0 :       mThread = nsnull;
     127                 :     }
     128                 :     else {
     129            2046 :       nsRefPtr<TimerObserverRunnable> r = new TimerObserverRunnable(this);
     130            1023 :       if (NS_IsMainThread()) {
     131            1020 :         r->Run();
     132                 :       }
     133                 :       else {
     134               3 :         NS_DispatchToMainThread(r);
     135                 :       }
     136                 :     }
     137                 : 
     138                 :     {
     139            2046 :       MonitorAutoLock lock(mMonitor);
     140            1023 :       mInitialized = true;
     141            1023 :       mMonitor.NotifyAll();
     142                 :     }
     143                 :   }
     144                 :   else {
     145               0 :     MonitorAutoLock lock(mMonitor);
     146               0 :     while (!mInitialized) {
     147               0 :       mMonitor.Wait();
     148                 :     }
     149                 :   }
     150                 : 
     151            1023 :   if (!mThread)
     152               0 :     return NS_ERROR_FAILURE;
     153                 : 
     154            1023 :   return NS_OK;
     155                 : }
     156                 : 
     157            1419 : nsresult TimerThread::Shutdown()
     158                 : {
     159            1419 :   PR_LOG(gTimerLog, PR_LOG_DEBUG, ("TimerThread::Shutdown begin\n"));
     160                 : 
     161            1419 :   if (!mThread)
     162             396 :     return NS_ERROR_NOT_INITIALIZED;
     163                 : 
     164            2046 :   nsTArray<nsTimerImpl*> timers;
     165                 :   {   // lock scope
     166            2046 :     MonitorAutoLock lock(mMonitor);
     167                 : 
     168            1023 :     mShutdown = true;
     169                 : 
     170                 :     // notify the cond var so that Run() can return
     171            1023 :     if (mWaiting)
     172            1023 :       mMonitor.Notify();
     173                 : 
     174                 :     // Need to copy content of mTimers array to a local array
     175                 :     // because call to timers' ReleaseCallback() (and release its self)
     176                 :     // must not be done under the lock. Destructor of a callback
     177                 :     // might potentially call some code reentering the same lock
     178                 :     // that leads to unexpected behavior or deadlock.
     179                 :     // See bug 422472.
     180            1023 :     timers.AppendElements(mTimers);
     181            1023 :     mTimers.Clear();
     182                 :   }
     183                 : 
     184            1023 :   PRUint32 timersCount = timers.Length();
     185            1425 :   for (PRUint32 i = 0; i < timersCount; i++) {
     186             402 :     nsTimerImpl *timer = timers[i];
     187             402 :     timer->ReleaseCallback();
     188             402 :     ReleaseTimerInternal(timer);
     189                 :   }
     190                 : 
     191            1023 :   mThread->Shutdown();    // wait for the thread to die
     192                 : 
     193            1023 :   PR_LOG(gTimerLog, PR_LOG_DEBUG, ("TimerThread::Shutdown end\n"));
     194            1023 :   return NS_OK;
     195                 : }
     196                 : 
     197                 : // Keep track of how early (positive slack) or late (negative slack) timers
     198                 : // are running, and use the filtered slack number to adaptively estimate how
     199                 : // early timers should fire to be "on time".
     200            4243 : void TimerThread::UpdateFilter(PRUint32 aDelay, TimeStamp aTimeout,
     201                 :                                TimeStamp aNow)
     202                 : {
     203            4243 :   TimeDuration slack = aTimeout - aNow;
     204            4243 :   double smoothSlack = 0;
     205                 :   PRUint32 i, filterLength;
     206                 :   static TimeDuration kFilterFeedbackMaxTicks =
     207            4243 :     TimeDuration::FromMilliseconds(FILTER_FEEDBACK_MAX);
     208                 :   static TimeDuration kFilterFeedbackMinTicks =
     209            4243 :     TimeDuration::FromMilliseconds(-FILTER_FEEDBACK_MAX);
     210                 : 
     211            4243 :   if (slack > kFilterFeedbackMaxTicks)
     212               2 :     slack = kFilterFeedbackMaxTicks;
     213            4241 :   else if (slack < kFilterFeedbackMinTicks)
     214             348 :     slack = kFilterFeedbackMinTicks;
     215                 : 
     216            4243 :   mDelayLine[mDelayLineCounter & DELAY_LINE_LENGTH_MASK] =
     217            4243 :     slack.ToMilliseconds();
     218            4243 :   if (++mDelayLineCounter < DELAY_LINE_LENGTH) {
     219                 :     // Startup mode: accumulate a full delay line before filtering.
     220            2506 :     PR_ASSERT(mTimeoutAdjustment.ToSeconds() == 0);
     221            2506 :     filterLength = 0;
     222                 :   } else {
     223                 :     // Past startup: compute number of filter taps based on mMinTimerPeriod.
     224            1737 :     if (mMinTimerPeriod == 0) {
     225              18 :       mMinTimerPeriod = (aDelay != 0) ? aDelay : 1;
     226            1719 :     } else if (aDelay != 0 && aDelay < mMinTimerPeriod) {
     227               3 :       mMinTimerPeriod = aDelay;
     228                 :     }
     229                 : 
     230            1737 :     filterLength = (PRUint32) (FILTER_DURATION / mMinTimerPeriod);
     231            1737 :     if (filterLength > DELAY_LINE_LENGTH)
     232             505 :       filterLength = DELAY_LINE_LENGTH;
     233            1232 :     else if (filterLength < 4)
     234            1204 :       filterLength = 4;
     235                 : 
     236           23239 :     for (i = 1; i <= filterLength; i++)
     237           21502 :       smoothSlack += mDelayLine[(mDelayLineCounter-i) & DELAY_LINE_LENGTH_MASK];
     238            1737 :     smoothSlack /= filterLength;
     239                 : 
     240                 :     // XXXbe do we need amplification?  hacking a fudge factor, need testing...
     241            1737 :     mTimeoutAdjustment = TimeDuration::FromMilliseconds(smoothSlack * 1.5);
     242                 :   }
     243                 : 
     244                 : #ifdef DEBUG_TIMERS
     245            4243 :   PR_LOG(gTimerLog, PR_LOG_DEBUG,
     246                 :          ("UpdateFilter: smoothSlack = %g, filterLength = %u\n",
     247                 :           smoothSlack, filterLength));
     248                 : #endif
     249            4243 : }
     250                 : 
     251                 : /* void Run(); */
     252            1023 : NS_IMETHODIMP TimerThread::Run()
     253                 : {
     254            2046 :   MonitorAutoLock lock(mMonitor);
     255                 : 
     256                 :   // We need to know how many microseconds give a positive PRIntervalTime. This
     257                 :   // is platform-dependent, we calculate it at runtime now.
     258                 :   // First we find a value such that PR_MicrosecondsToInterval(high) = 1
     259            1023 :   PRInt32 low = 0, high = 1;
     260           11253 :   while (PR_MicrosecondsToInterval(high) == 0)
     261            9207 :     high <<= 1;
     262                 :   // We now have
     263                 :   //    PR_MicrosecondsToInterval(low)  = 0
     264                 :   //    PR_MicrosecondsToInterval(high) = 1
     265                 :   // and we can proceed to find the critical value using binary search
     266           11253 :   while (high-low > 1) {
     267            9207 :     PRInt32 mid = (high+low) >> 1;
     268            9207 :     if (PR_MicrosecondsToInterval(mid) == 0)
     269            7161 :       low = mid;
     270                 :     else
     271            2046 :       high = mid;
     272                 :   }
     273                 : 
     274                 :   // Half of the amount of microseconds needed to get positive PRIntervalTime.
     275                 :   // We use this to decide how to round our wait times later
     276            1023 :   PRInt32 halfMicrosecondsIntervalResolution = high >> 1;
     277                 : 
     278           34770 :   while (!mShutdown) {
     279                 :     // Have to use PRIntervalTime here, since PR_WaitCondVar takes it
     280                 :     PRIntervalTime waitFor;
     281                 : 
     282           32724 :     if (mSleeping) {
     283                 :       // Sleep for 0.1 seconds while not firing timers.
     284               1 :       waitFor = PR_MillisecondsToInterval(100);
     285                 :     } else {
     286           32723 :       waitFor = PR_INTERVAL_NO_TIMEOUT;
     287           32723 :       TimeStamp now = TimeStamp::Now();
     288           32723 :       nsTimerImpl *timer = nsnull;
     289                 : 
     290           32723 :       if (!mTimers.IsEmpty()) {
     291           28181 :         timer = mTimers[0];
     292                 : 
     293           28181 :         if (now >= timer->mTimeout + mTimeoutAdjustment) {
     294                 :     next:
     295                 :           // NB: AddRef before the Release under RemoveTimerInternal to avoid
     296                 :           // mRefCnt passing through zero, in case all other refs than the one
     297                 :           // from mTimers have gone away (the last non-mTimers[i]-ref's Release
     298                 :           // must be racing with us, blocked in gThread->RemoveTimer waiting
     299                 :           // for TimerThread::mMonitor, under nsTimerImpl::Release.
     300                 : 
     301            4298 :           NS_ADDREF(timer);
     302            4298 :           RemoveTimerInternal(timer);
     303                 : 
     304                 :           {
     305                 :             // We release mMonitor around the Fire call to avoid deadlock.
     306            8596 :             MonitorAutoUnlock unlock(mMonitor);
     307                 : 
     308                 : #ifdef DEBUG_TIMERS
     309            4298 :             if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
     310               0 :               PR_LOG(gTimerLog, PR_LOG_DEBUG,
     311                 :                      ("Timer thread woke up %fms from when it was supposed to\n",
     312                 :                       fabs((now - timer->mTimeout).ToMilliseconds())));
     313                 :             }
     314                 : #endif
     315                 : 
     316                 :             // We are going to let the call to PostTimerEvent here handle the
     317                 :             // release of the timer so that we don't end up releasing the timer
     318                 :             // on the TimerThread instead of on the thread it targets.
     319            4298 :             if (NS_FAILED(timer->PostTimerEvent())) {
     320                 :               nsrefcnt rc;
     321               0 :               NS_RELEASE2(timer, rc);
     322                 :             
     323                 :               // The nsITimer interface requires that its users keep a reference
     324                 :               // to the timers they use while those timers are initialized but
     325                 :               // have not yet fired.  If this ever happens, it is a bug in the
     326                 :               // code that created and used the timer.
     327                 :               //
     328                 :               // Further, note that this should never happen even with a
     329                 :               // misbehaving user, because nsTimerImpl::Release checks for a
     330                 :               // refcount of 1 with an armed timer (a timer whose only reference
     331                 :               // is from the timer thread) and when it hits this will remove the
     332                 :               // timer from the timer thread and thus destroy the last reference,
     333                 :               // preventing this situation from occurring.
     334               0 :               NS_ASSERTION(rc != 0, "destroyed timer off its target thread!");
     335                 :             }
     336            4298 :             timer = nsnull;
     337                 :           }
     338                 : 
     339            4298 :           if (mShutdown)
     340               0 :             break;
     341                 : 
     342                 :           // Update now, as PostTimerEvent plus the locking may have taken a
     343                 :           // tick or two, and we may goto next below.
     344            4298 :           now = TimeStamp::Now();
     345                 :         }
     346                 :       }
     347                 : 
     348           32740 :       if (!mTimers.IsEmpty()) {
     349           28049 :         timer = mTimers[0];
     350                 : 
     351           28049 :         TimeStamp timeout = timer->mTimeout + mTimeoutAdjustment;
     352                 : 
     353                 :         // Don't wait at all (even for PR_INTERVAL_NO_WAIT) if the next timer
     354                 :         // is due now or overdue.
     355                 :         //
     356                 :         // Note that we can only sleep for integer values of a certain
     357                 :         // resolution. We use halfMicrosecondsIntervalResolution, calculated
     358                 :         // before, to do the optimal rounding (i.e., of how to decide what
     359                 :         // interval is so small we should not wait at all).
     360           28049 :         double microseconds = (timeout - now).ToMilliseconds()*1000;
     361           28049 :         if (microseconds < halfMicrosecondsIntervalResolution)
     362              17 :           goto next; // round down; execute event now
     363           28032 :         waitFor = PR_MicrosecondsToInterval(microseconds);
     364           28032 :         if (waitFor == 0)
     365               6 :           waitFor = 1; // round up, wait the minimum time we can wait
     366                 :       }
     367                 : 
     368                 : #ifdef DEBUG_TIMERS
     369           32723 :       if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
     370               0 :         if (waitFor == PR_INTERVAL_NO_TIMEOUT)
     371               0 :           PR_LOG(gTimerLog, PR_LOG_DEBUG,
     372                 :                  ("waiting for PR_INTERVAL_NO_TIMEOUT\n"));
     373                 :         else
     374               0 :           PR_LOG(gTimerLog, PR_LOG_DEBUG,
     375                 :                  ("waiting for %u\n", PR_IntervalToMilliseconds(waitFor)));
     376                 :       }
     377                 : #endif
     378                 :     }
     379                 : 
     380           32724 :     mWaiting = true;
     381           32724 :     mMonitor.Wait(waitFor);
     382           32724 :     mWaiting = false;
     383                 :   }
     384                 : 
     385            1023 :   return NS_OK;
     386                 : }
     387                 : 
     388           23043 : nsresult TimerThread::AddTimer(nsTimerImpl *aTimer)
     389                 : {
     390           46086 :   MonitorAutoLock lock(mMonitor);
     391                 : 
     392                 :   // Add the timer to our list.
     393           23043 :   PRInt32 i = AddTimerInternal(aTimer);
     394           23043 :   if (i < 0)
     395               0 :     return NS_ERROR_OUT_OF_MEMORY;
     396                 : 
     397                 :   // Awaken the timer thread.
     398           23043 :   if (mWaiting && i == 0)
     399           13950 :     mMonitor.Notify();
     400                 : 
     401           23043 :   return NS_OK;
     402                 : }
     403                 : 
     404            3658 : nsresult TimerThread::TimerDelayChanged(nsTimerImpl *aTimer)
     405                 : {
     406            7316 :   MonitorAutoLock lock(mMonitor);
     407                 : 
     408                 :   // Our caller has a strong ref to aTimer, so it can't go away here under
     409                 :   // ReleaseTimerInternal.
     410            3658 :   RemoveTimerInternal(aTimer);
     411                 : 
     412            3658 :   PRInt32 i = AddTimerInternal(aTimer);
     413            3658 :   if (i < 0)
     414               0 :     return NS_ERROR_OUT_OF_MEMORY;
     415                 : 
     416                 :   // Awaken the timer thread.
     417            3658 :   if (mWaiting && i == 0)
     418             360 :     mMonitor.Notify();
     419                 : 
     420            3658 :   return NS_OK;
     421                 : }
     422                 : 
     423           19936 : nsresult TimerThread::RemoveTimer(nsTimerImpl *aTimer)
     424                 : {
     425           39872 :   MonitorAutoLock lock(mMonitor);
     426                 : 
     427                 :   // Remove the timer from our array.  Tell callers that aTimer was not found
     428                 :   // by returning NS_ERROR_NOT_AVAILABLE.  Unlike the TimerDelayChanged case
     429                 :   // immediately above, our caller may be passing a (now-)weak ref in via the
     430                 :   // aTimer param, specifically when nsTimerImpl::Release loses a race with
     431                 :   // TimerThread::Run, must wait for the mMonitor auto-lock here, and during the
     432                 :   // wait Run drops the only remaining ref to aTimer via RemoveTimerInternal.
     433                 : 
     434           19936 :   if (!RemoveTimerInternal(aTimer))
     435            1578 :     return NS_ERROR_NOT_AVAILABLE;
     436                 : 
     437                 :   // Awaken the timer thread.
     438           18358 :   if (mWaiting)
     439           18311 :     mMonitor.Notify();
     440                 : 
     441           18358 :   return NS_OK;
     442                 : }
     443                 : 
     444                 : // This function must be called from within a lock
     445           26701 : PRInt32 TimerThread::AddTimerInternal(nsTimerImpl *aTimer)
     446                 : {
     447           26701 :   if (mShutdown)
     448               0 :     return -1;
     449                 : 
     450           26701 :   TimeStamp now = TimeStamp::Now();
     451           26701 :   PRUint32 count = mTimers.Length();
     452           26701 :   PRUint32 i = 0;
     453           50107 :   for (; i < count; i++) {
     454           37070 :     nsTimerImpl *timer = mTimers[i];
     455                 : 
     456                 :     // Don't break till we have skipped any overdue timers.
     457                 : 
     458                 :     // XXXbz why?  Given our definition of overdue in terms of
     459                 :     // mTimeoutAdjustment, aTimer might be overdue already!  Why not
     460                 :     // just fire timers in order?
     461                 : 
     462                 :     // XXX does this hold for TYPE_REPEATING_PRECISE?  /be
     463                 : 
     464           74105 :     if (now < timer->mTimeout + mTimeoutAdjustment &&
     465           37035 :         aTimer->mTimeout < timer->mTimeout) {
     466           13664 :       break;
     467                 :     }
     468                 :   }
     469                 : 
     470           26701 :   if (!mTimers.InsertElementAt(i, aTimer))
     471               0 :     return -1;
     472                 : 
     473           26701 :   aTimer->mArmed = true;
     474           26701 :   NS_ADDREF(aTimer);
     475           26701 :   return i;
     476                 : }
     477                 : 
     478           27892 : bool TimerThread::RemoveTimerInternal(nsTimerImpl *aTimer)
     479                 : {
     480           27892 :   if (!mTimers.RemoveElement(aTimer))
     481            1593 :     return false;
     482                 : 
     483           26299 :   ReleaseTimerInternal(aTimer);
     484           26299 :   return true;
     485                 : }
     486                 : 
     487           26701 : void TimerThread::ReleaseTimerInternal(nsTimerImpl *aTimer)
     488                 : {
     489                 :   // Order is crucial here -- see nsTimerImpl::Release.
     490           26701 :   aTimer->mArmed = false;
     491           26701 :   NS_RELEASE(aTimer);
     492           26701 : }
     493                 : 
     494               1 : void TimerThread::DoBeforeSleep()
     495                 : {
     496               1 :   mSleeping = true;
     497               1 : }
     498                 : 
     499               1 : void TimerThread::DoAfterSleep()
     500                 : {
     501               1 :   mSleeping = true; // wake may be notified without preceding sleep notification
     502               5 :   for (PRUint32 i = 0; i < mTimers.Length(); i ++) {
     503               4 :     nsTimerImpl *timer = mTimers[i];
     504                 :     // get and set the delay to cause its timeout to be recomputed
     505                 :     PRUint32 delay;
     506               4 :     timer->GetDelay(&delay);
     507               4 :     timer->SetDelay(delay);
     508                 :   }
     509                 : 
     510                 :   // nuke the stored adjustments, so they get recalibrated
     511               1 :   mTimeoutAdjustment = TimeDuration(0);
     512               1 :   mDelayLineCounter = 0;
     513               1 :   mSleeping = false;
     514               1 : }
     515                 : 
     516                 : 
     517                 : /* void observe (in nsISupports aSubject, in string aTopic, in wstring aData); */
     518                 : NS_IMETHODIMP
     519               2 : TimerThread::Observe(nsISupports* /* aSubject */, const char *aTopic, const PRUnichar* /* aData */)
     520                 : {
     521               2 :   if (strcmp(aTopic, "sleep_notification") == 0)
     522               1 :     DoBeforeSleep();
     523               1 :   else if (strcmp(aTopic, "wake_notification") == 0)
     524               1 :     DoAfterSleep();
     525                 : 
     526               2 :   return NS_OK;
     527            4392 : }

Generated by: LCOV version 1.7