Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: base/queue_timer.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/queue_timer.h ('k') | base/queue_timer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2007-2009 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15 //
16 // The implementation is straightforward except the destruction of the
17 // QueueTimer which needs some clarification.
18 // If there is no callback running, then the destructor gets the critical
19 // section and then it blocks on the DeleteTimerQueueTimer call, waiting for
20 // the kernel to clean up the timer handle. The callback never fires in this
21 // case.
22 // If a callback is running, then there are two possibilities:
23 // 1. The callback gets the critical section. The callback runs as usual and
24 // then the destructor gets the critical section. This is also easy.
25 // 2. The destructor gets the critical section. In this case, the callback
26 // tries the critical section then it returns right away.
27 //
28 // Alarm timers are started and restarted every time they fire. The usage
29 // patterns for alarms is usually Start, Callback, Start, Callback, etc...
30 // The cleanup of an alarm timer handle usually happens in the callback, unless
31 // the destructor of the QueueTimer is called, in which case the logic
32 // above applies.
33 //
34 // Periodic timers are only started once: Start, Callback, Callback, etc...
35 // In this case, the destructor does all the necessary cleanup.
36 // Periodic timers must fire at intervals that are reasonable long so that
37 // the callbacks do not queue up.
38
39 #include "omaha/base/queue_timer.h"
40
41 #include "omaha/base/debug.h"
42 #include "omaha/base/error.h"
43 #include "omaha/base/logging.h"
44
45 namespace omaha {
46
47 QueueTimer::QueueTimer(HANDLE timer_queue, Callback callback, void* ctx)
48 : callback_tid_(0),
49 ctx_(ctx),
50 due_time_(0),
51 period_(0),
52 flags_(0),
53 timer_handle_(NULL),
54 timer_queue_(timer_queue),
55 callback_(callback) {
56 UTIL_LOG(L3, (_T("[QueueTimer::QueueTimer][0x%p]"), this));
57 ASSERT1(timer_queue);
58 ASSERT1(callback);
59 ::InitializeCriticalSection(&dtor_cs_);
60 ::InitializeCriticalSection(&cs_);
61 }
62
63 // The destructor blocks on waiting for the timer kernel object to be deleted.
64 // We can't call the destructor of QueueTimer while we are handling a callback.
65 // This will result is a deadlock.
66 QueueTimer::~QueueTimer() {
67 UTIL_LOG(L3, (_T("[QueueTimer::~QueueTimer][0x%p]"), this));
68
69 ::EnterCriticalSection(&dtor_cs_);
70 if (timer_handle_) {
71 ASSERT1(callback_tid_ != ::GetCurrentThreadId());
72
73 // This is a blocking call waiting for all callbacks to clear up.
74 bool res = !!::DeleteTimerQueueTimer(timer_queue_,
75 timer_handle_,
76 INVALID_HANDLE_VALUE);
77 ASSERT1(res);
78 timer_handle_ = NULL;
79 }
80 callback_ = NULL;
81 timer_queue_ = NULL;
82 flags_ = 0;
83 period_ = 0;
84 due_time_ = 0;
85 ctx_ = 0;
86 callback_tid_ = 0;
87 ::LeaveCriticalSection(&dtor_cs_);
88
89 ::DeleteCriticalSection(&cs_);
90 ::DeleteCriticalSection(&dtor_cs_);
91 }
92
93 // Thread safe.
94 HRESULT QueueTimer::Start(int due_time, int period, uint32 flags) {
95 // Since Start creates the timer there could be a race condition where
96 // the timer could fire while we are still executing Start. We protect
97 // the start with a critical section so the Start completes before the
98 // timer can be entered by the callback.
99
100 ::EnterCriticalSection(&cs_);
101 HRESULT hr = DoStart(due_time, period, flags);
102 ::LeaveCriticalSection(&cs_);
103 return hr;
104 }
105
106 // Thread-safe.
107 void QueueTimer::TimerCallback(void* param, BOOLEAN timer_or_wait) {
108 ASSERT1(param);
109 VERIFY1(timer_or_wait);
110
111 QueueTimer* timer = static_cast<QueueTimer*>(param);
112
113 if (!::TryEnterCriticalSection(&timer->dtor_cs_)) {
114 return;
115 }
116
117 ::EnterCriticalSection(&timer->cs_);
118 timer->DoCallback();
119 ::LeaveCriticalSection(&timer->cs_);
120
121 ::LeaveCriticalSection(&timer->dtor_cs_);
122 }
123
124
125 HRESULT QueueTimer::DoStart(int due_time, int period, uint32 flags) {
126 UTIL_LOG(L2, (_T("[QueueTimer::DoStart][0x%p][%d][%d][0x%08u]"),
127 this, due_time, period, flags));
128 due_time_ = due_time;
129 period_ = period;
130 flags_ = flags;
131
132 // Application Verifier says period must be 0 for WT_EXECUTEONLYONCE timers.
133 if ((flags & WT_EXECUTEONLYONCE) && period != 0) {
134 return E_INVALIDARG;
135 }
136
137 // Periodic timers can't be started more than one time.
138 if (timer_handle_) {
139 return E_UNEXPECTED;
140 }
141
142 bool res = !!::CreateTimerQueueTimer(&timer_handle_,
143 timer_queue_,
144 &QueueTimer::TimerCallback,
145 this,
146 due_time,
147 period,
148 flags_);
149 if (!res) {
150 HRESULT hr = HRESULTFromLastError();
151 UTIL_LOG(LE, (_T("[QueueTimer::Start failed][0x%p][0x%08x]"), this, hr));
152 return hr;
153 }
154
155 ASSERT1(timer_handle_);
156 UTIL_LOG(L3, (_T("[QueueTimer::Start timer created][0x%p]"), this));
157 return S_OK;
158 }
159
160 void QueueTimer::DoCallback() {
161 UTIL_LOG(L2, (_T("[QueueTimer::OnCallback][0x%p]"), this));
162
163 ASSERT1(timer_queue_);
164 ASSERT1(timer_handle_);
165 ASSERT1(callback_);
166
167 if (!period_) {
168 // Non-periodic aka alarm timers fire only once. We delete the timer
169 // handle so that the timer object can be restarted later on.
170 // The call below is non-blocking. The deletion of the kernel object can
171 // succeed right away, for example if the timer runs in the timer thread
172 // itself. Otherwise, if the last error is ERROR_IO_PENDING the kernel
173 // cleans up the object once the callback returns.
174 bool res = !!::DeleteTimerQueueTimer(timer_queue_, timer_handle_, NULL);
175 ASSERT1(res || (!res && ::GetLastError() == ERROR_IO_PENDING));
176 timer_handle_ = NULL;
177 }
178
179 callback_tid_ = ::GetCurrentThreadId();
180 callback_(this);
181 callback_tid_ = 0;
182 }
183
184 } // namespace omaha
185
OLDNEW
« no previous file with comments | « base/queue_timer.h ('k') | base/queue_timer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698