OLD | NEW |
| (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 | |
17 #include "omaha/base/reactor.h" | |
18 | |
19 #include <vector> | |
20 #include "base/scoped_ptr.h" | |
21 #include "omaha/base/debug.h" | |
22 #include "omaha/base/error.h" | |
23 #include "omaha/base/logging.h" | |
24 #include "omaha/base/event_handler.h" | |
25 | |
26 namespace omaha { | |
27 | |
28 Reactor::Reactor() { | |
29 CORE_LOG(L4, (_T("[Reactor::Reactor]"))); | |
30 ::InitializeCriticalSection(&cs_); | |
31 } | |
32 | |
33 Reactor::~Reactor() { | |
34 CORE_LOG(L4, (_T("[Reactor::~Reactor]"))); | |
35 | |
36 // Each handle must be unregistered before destroying the reactor. | |
37 ASSERT1(handlers_.empty()); | |
38 ::DeleteCriticalSection(&cs_); | |
39 } | |
40 | |
41 // The reactor loop is just an efficient wait, as the demultiplexing of the | |
42 // events is actually done by the OS thread pool. | |
43 // TODO(omaha): replace the alertable wait with waiting on an event and provide | |
44 // a method for the reactor to stop handling events. | |
45 HRESULT Reactor::HandleEvents() { | |
46 CORE_LOG(L1, (_T("[Reactor::HandleEvents]"))); | |
47 VERIFY1(::SleepEx(INFINITE, true) == WAIT_IO_COMPLETION); | |
48 CORE_LOG(L1, (_T("[Reactor::HandleEvents exit]"))); | |
49 return S_OK; | |
50 } | |
51 | |
52 void __stdcall Reactor::Callback(void* param, BOOLEAN timer_or_wait) { | |
53 ASSERT1(param); | |
54 | |
55 // Since we wait an INFINITE the wait handle is always signaled. | |
56 VERIFY1(!timer_or_wait); | |
57 RegistrationState* state = static_cast<RegistrationState*>(param); | |
58 ASSERT1(state->reactor); | |
59 state->reactor->DoCallback(state); | |
60 } | |
61 | |
62 // Method does not check to see if the same handle is registered twice. | |
63 HRESULT Reactor::RegisterHandle(HANDLE handle, | |
64 EventHandler* event_handler, | |
65 uint32 flags) { | |
66 ASSERT1(handle); | |
67 ASSERT1(event_handler); | |
68 | |
69 if (!handle || !event_handler) { | |
70 return E_INVALIDARG; | |
71 } | |
72 | |
73 scoped_ptr<RegistrationState> state(new RegistrationState); | |
74 state->event_handler = event_handler; | |
75 state->handle = handle; | |
76 state->reactor = this; | |
77 state->flags = flags | WT_EXECUTEONLYONCE; | |
78 | |
79 // The reactor only calls the handler once. | |
80 ASSERT1(WT_EXECUTEDEFAULT == 0); | |
81 | |
82 // As soon as the handle is registered, the thread pool can queue up a | |
83 // callback and reenter the reactor on a different thread. | |
84 // Acquire the critical section before registering the handle. | |
85 ::EnterCriticalSection(&cs_); | |
86 #if DEBUG | |
87 // The same handle should not be registered multiple times. | |
88 std::vector<RegistrationState*>::iterator it = handlers_.begin(); | |
89 for (; it != handlers_.end(); ++it) { | |
90 ASSERT((*it)->handle != handle, (_T("[already registered %d]"), handle)); | |
91 } | |
92 #endif | |
93 bool res = !!::RegisterWaitForSingleObject(&state->wait_handle, | |
94 state->handle, | |
95 &Reactor::Callback, | |
96 state.get(), | |
97 INFINITE, | |
98 state->flags); | |
99 HRESULT hr = res ? S_OK : HRESULTFromLastError(); | |
100 if (SUCCEEDED(hr)) { | |
101 handlers_.push_back(state.release()); | |
102 } | |
103 ::LeaveCriticalSection(&cs_); | |
104 | |
105 return hr; | |
106 } | |
107 | |
108 HRESULT Reactor::RegisterHandle(HANDLE handle) { | |
109 ::EnterCriticalSection(&cs_); | |
110 HRESULT hr = DoRegisterHandle(handle); | |
111 ::LeaveCriticalSection(&cs_); | |
112 return hr; | |
113 } | |
114 | |
115 HRESULT Reactor::DoRegisterHandle(HANDLE handle) { | |
116 ASSERT1(handle); | |
117 std::vector<RegistrationState*>::iterator it = handlers_.begin(); | |
118 for (; it != handlers_.end(); ++it) { | |
119 if ((*it)->handle == handle) { | |
120 break; | |
121 } | |
122 } | |
123 if (it == handlers_.end()) { | |
124 // The handle is not registered with the reactor anymore. Registering the | |
125 // the handle again is not possible. | |
126 return E_FAIL; | |
127 } | |
128 | |
129 // Unregister and register the handle again. Unregistering is an non blocking | |
130 // call. | |
131 RegistrationState* state = *it; | |
132 bool res = !!::UnregisterWaitEx(state->wait_handle, NULL); | |
133 if (!res && ::GetLastError() != ERROR_IO_PENDING) { | |
134 return HRESULTFromLastError(); | |
135 } | |
136 if (!::RegisterWaitForSingleObject(&state->wait_handle, | |
137 state->handle, | |
138 &Reactor::Callback, | |
139 state, | |
140 INFINITE, | |
141 state->flags)) { | |
142 return HRESULTFromLastError(); | |
143 } | |
144 return S_OK; | |
145 } | |
146 | |
147 HRESULT Reactor::UnregisterHandle(HANDLE handle) { | |
148 ASSERT1(handle); | |
149 if (!handle) { | |
150 return E_INVALIDARG; | |
151 } | |
152 | |
153 // Attempts to take the ownership of the registration state for the handle. | |
154 // If taking the ownership does not succeed, it means the handle has already | |
155 // been unregistered. | |
156 scoped_ptr<RegistrationState> state(ReleaseHandlerState(handle)); | |
157 if (!state.get()) { | |
158 return E_UNEXPECTED; | |
159 } | |
160 | |
161 // Unregisters the wait handle from the thread pool. The call blocks waiting | |
162 // for any pending callbacks to finish. No lock is being held while waiting | |
163 // here. If there is no callback pending, the call will succeed right away. | |
164 // Otherwise, if a callback has already started, the call waits for the | |
165 // callback to complete. | |
166 bool res = !!::UnregisterWaitEx(state->wait_handle, INVALID_HANDLE_VALUE); | |
167 | |
168 // Clear the registration state, as a defensive programming measure and | |
169 // for debugging purposes. | |
170 state->reactor = NULL; | |
171 state->handle = NULL; | |
172 state->wait_handle = NULL; | |
173 state->event_handler = NULL; | |
174 | |
175 return res ? S_OK : HRESULTFromLastError(); | |
176 } | |
177 | |
178 void Reactor::DoCallback(RegistrationState* state) { | |
179 ASSERT1(state); | |
180 ASSERT1(state->event_handler); | |
181 ASSERT1(state->handle); | |
182 state->event_handler->HandleEvent(state->handle); | |
183 } | |
184 | |
185 // Looks up the registration state for a handle and releases the ownership | |
186 // of it to the caller. As the clean up of the state can happen from multiple | |
187 // places, the transfer of ownership ensures the clean up happens once and | |
188 // only once. | |
189 Reactor::RegistrationState* Reactor::ReleaseHandlerState(HANDLE handle) { | |
190 RegistrationState* registration_state = NULL; | |
191 ::EnterCriticalSection(&cs_); | |
192 std::vector<RegistrationState*>::iterator it = handlers_.begin(); | |
193 for (; it != handlers_.end(); ++it) { | |
194 if ((*it)->handle == handle) { | |
195 registration_state = *it; | |
196 handlers_.erase(it); | |
197 break; | |
198 } | |
199 } | |
200 ::LeaveCriticalSection(&cs_); | |
201 return registration_state; | |
202 } | |
203 | |
204 } // namespace omaha | |
205 | |
OLD | NEW |