| Index: base/queue_timer.cc
|
| diff --git a/base/queue_timer.cc b/base/queue_timer.cc
|
| deleted file mode 100644
|
| index 255fd2b00d8b9b09da80319a6788caa3588cb3e2..0000000000000000000000000000000000000000
|
| --- a/base/queue_timer.cc
|
| +++ /dev/null
|
| @@ -1,185 +0,0 @@
|
| -// Copyright 2007-2009 Google Inc.
|
| -//
|
| -// Licensed under the Apache License, Version 2.0 (the "License");
|
| -// you may not use this file except in compliance with the License.
|
| -// You may obtain a copy of the License at
|
| -//
|
| -// http://www.apache.org/licenses/LICENSE-2.0
|
| -//
|
| -// Unless required by applicable law or agreed to in writing, software
|
| -// distributed under the License is distributed on an "AS IS" BASIS,
|
| -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| -// See the License for the specific language governing permissions and
|
| -// limitations under the License.
|
| -// ========================================================================
|
| -//
|
| -// The implementation is straightforward except the destruction of the
|
| -// QueueTimer which needs some clarification.
|
| -// If there is no callback running, then the destructor gets the critical
|
| -// section and then it blocks on the DeleteTimerQueueTimer call, waiting for
|
| -// the kernel to clean up the timer handle. The callback never fires in this
|
| -// case.
|
| -// If a callback is running, then there are two possibilities:
|
| -// 1. The callback gets the critical section. The callback runs as usual and
|
| -// then the destructor gets the critical section. This is also easy.
|
| -// 2. The destructor gets the critical section. In this case, the callback
|
| -// tries the critical section then it returns right away.
|
| -//
|
| -// Alarm timers are started and restarted every time they fire. The usage
|
| -// patterns for alarms is usually Start, Callback, Start, Callback, etc...
|
| -// The cleanup of an alarm timer handle usually happens in the callback, unless
|
| -// the destructor of the QueueTimer is called, in which case the logic
|
| -// above applies.
|
| -//
|
| -// Periodic timers are only started once: Start, Callback, Callback, etc...
|
| -// In this case, the destructor does all the necessary cleanup.
|
| -// Periodic timers must fire at intervals that are reasonable long so that
|
| -// the callbacks do not queue up.
|
| -
|
| -#include "omaha/base/queue_timer.h"
|
| -
|
| -#include "omaha/base/debug.h"
|
| -#include "omaha/base/error.h"
|
| -#include "omaha/base/logging.h"
|
| -
|
| -namespace omaha {
|
| -
|
| -QueueTimer::QueueTimer(HANDLE timer_queue, Callback callback, void* ctx)
|
| - : callback_tid_(0),
|
| - ctx_(ctx),
|
| - due_time_(0),
|
| - period_(0),
|
| - flags_(0),
|
| - timer_handle_(NULL),
|
| - timer_queue_(timer_queue),
|
| - callback_(callback) {
|
| - UTIL_LOG(L3, (_T("[QueueTimer::QueueTimer][0x%p]"), this));
|
| - ASSERT1(timer_queue);
|
| - ASSERT1(callback);
|
| - ::InitializeCriticalSection(&dtor_cs_);
|
| - ::InitializeCriticalSection(&cs_);
|
| -}
|
| -
|
| -// The destructor blocks on waiting for the timer kernel object to be deleted.
|
| -// We can't call the destructor of QueueTimer while we are handling a callback.
|
| -// This will result is a deadlock.
|
| -QueueTimer::~QueueTimer() {
|
| - UTIL_LOG(L3, (_T("[QueueTimer::~QueueTimer][0x%p]"), this));
|
| -
|
| - ::EnterCriticalSection(&dtor_cs_);
|
| - if (timer_handle_) {
|
| - ASSERT1(callback_tid_ != ::GetCurrentThreadId());
|
| -
|
| - // This is a blocking call waiting for all callbacks to clear up.
|
| - bool res = !!::DeleteTimerQueueTimer(timer_queue_,
|
| - timer_handle_,
|
| - INVALID_HANDLE_VALUE);
|
| - ASSERT1(res);
|
| - timer_handle_ = NULL;
|
| - }
|
| - callback_ = NULL;
|
| - timer_queue_ = NULL;
|
| - flags_ = 0;
|
| - period_ = 0;
|
| - due_time_ = 0;
|
| - ctx_ = 0;
|
| - callback_tid_ = 0;
|
| - ::LeaveCriticalSection(&dtor_cs_);
|
| -
|
| - ::DeleteCriticalSection(&cs_);
|
| - ::DeleteCriticalSection(&dtor_cs_);
|
| -}
|
| -
|
| -// Thread safe.
|
| -HRESULT QueueTimer::Start(int due_time, int period, uint32 flags) {
|
| - // Since Start creates the timer there could be a race condition where
|
| - // the timer could fire while we are still executing Start. We protect
|
| - // the start with a critical section so the Start completes before the
|
| - // timer can be entered by the callback.
|
| -
|
| - ::EnterCriticalSection(&cs_);
|
| - HRESULT hr = DoStart(due_time, period, flags);
|
| - ::LeaveCriticalSection(&cs_);
|
| - return hr;
|
| -}
|
| -
|
| -// Thread-safe.
|
| -void QueueTimer::TimerCallback(void* param, BOOLEAN timer_or_wait) {
|
| - ASSERT1(param);
|
| - VERIFY1(timer_or_wait);
|
| -
|
| - QueueTimer* timer = static_cast<QueueTimer*>(param);
|
| -
|
| - if (!::TryEnterCriticalSection(&timer->dtor_cs_)) {
|
| - return;
|
| - }
|
| -
|
| - ::EnterCriticalSection(&timer->cs_);
|
| - timer->DoCallback();
|
| - ::LeaveCriticalSection(&timer->cs_);
|
| -
|
| - ::LeaveCriticalSection(&timer->dtor_cs_);
|
| -}
|
| -
|
| -
|
| -HRESULT QueueTimer::DoStart(int due_time, int period, uint32 flags) {
|
| - UTIL_LOG(L2, (_T("[QueueTimer::DoStart][0x%p][%d][%d][0x%08u]"),
|
| - this, due_time, period, flags));
|
| - due_time_ = due_time;
|
| - period_ = period;
|
| - flags_ = flags;
|
| -
|
| - // Application Verifier says period must be 0 for WT_EXECUTEONLYONCE timers.
|
| - if ((flags & WT_EXECUTEONLYONCE) && period != 0) {
|
| - return E_INVALIDARG;
|
| - }
|
| -
|
| - // Periodic timers can't be started more than one time.
|
| - if (timer_handle_) {
|
| - return E_UNEXPECTED;
|
| - }
|
| -
|
| - bool res = !!::CreateTimerQueueTimer(&timer_handle_,
|
| - timer_queue_,
|
| - &QueueTimer::TimerCallback,
|
| - this,
|
| - due_time,
|
| - period,
|
| - flags_);
|
| - if (!res) {
|
| - HRESULT hr = HRESULTFromLastError();
|
| - UTIL_LOG(LE, (_T("[QueueTimer::Start failed][0x%p][0x%08x]"), this, hr));
|
| - return hr;
|
| - }
|
| -
|
| - ASSERT1(timer_handle_);
|
| - UTIL_LOG(L3, (_T("[QueueTimer::Start timer created][0x%p]"), this));
|
| - return S_OK;
|
| -}
|
| -
|
| -void QueueTimer::DoCallback() {
|
| - UTIL_LOG(L2, (_T("[QueueTimer::OnCallback][0x%p]"), this));
|
| -
|
| - ASSERT1(timer_queue_);
|
| - ASSERT1(timer_handle_);
|
| - ASSERT1(callback_);
|
| -
|
| - if (!period_) {
|
| - // Non-periodic aka alarm timers fire only once. We delete the timer
|
| - // handle so that the timer object can be restarted later on.
|
| - // The call below is non-blocking. The deletion of the kernel object can
|
| - // succeed right away, for example if the timer runs in the timer thread
|
| - // itself. Otherwise, if the last error is ERROR_IO_PENDING the kernel
|
| - // cleans up the object once the callback returns.
|
| - bool res = !!::DeleteTimerQueueTimer(timer_queue_, timer_handle_, NULL);
|
| - ASSERT1(res || (!res && ::GetLastError() == ERROR_IO_PENDING));
|
| - timer_handle_ = NULL;
|
| - }
|
| -
|
| - callback_tid_ = ::GetCurrentThreadId();
|
| - callback_(this);
|
| - callback_tid_ = 0;
|
| -}
|
| -
|
| -} // namespace omaha
|
| -
|
|
|