| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_ | 5 #ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_ |
| 6 #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_ | 6 #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_ |
| 7 | 7 |
| 8 #include <windows.h> | 8 #include <windows.h> |
| 9 | 9 |
| 10 #include <list> | 10 #include <list> |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 }; | 141 }; |
| 142 | 142 |
| 143 //----------------------------------------------------------------------------- | 143 //----------------------------------------------------------------------------- |
| 144 // MessagePumpForIO extends MessagePumpWin with methods that are particular to a | 144 // MessagePumpForIO extends MessagePumpWin with methods that are particular to a |
| 145 // MessageLoop instantiated with TYPE_IO. This version of MessagePump does not | 145 // MessageLoop instantiated with TYPE_IO. This version of MessagePump does not |
| 146 // deal with Windows mesagges, and instead has a Run loop based on Completion | 146 // deal with Windows mesagges, and instead has a Run loop based on Completion |
| 147 // Ports so it is better suited for IO operations. | 147 // Ports so it is better suited for IO operations. |
| 148 // | 148 // |
| 149 class BASE_EXPORT MessagePumpForIO : public MessagePumpWin { | 149 class BASE_EXPORT MessagePumpForIO : public MessagePumpWin { |
| 150 public: | 150 public: |
| 151 struct IOContext; | 151 struct BASE_EXPORT IOContext { |
| 152 IOContext(); |
| 153 OVERLAPPED overlapped; |
| 154 }; |
| 152 | 155 |
| 153 // Clients interested in receiving OS notifications when asynchronous IO | 156 // Clients interested in receiving OS notifications when asynchronous IO |
| 154 // operations complete should implement this interface and register themselves | 157 // operations complete should implement this interface and register themselves |
| 155 // with the message pump. | 158 // with the message pump. |
| 156 // | 159 // |
| 157 // Typical use #1: | 160 // Typical use #1: |
| 158 // // Use only when there are no user's buffers involved on the actual IO, | |
| 159 // // so that all the cleanup can be done by the message pump. | |
| 160 // class MyFile : public IOHandler { | 161 // class MyFile : public IOHandler { |
| 161 // MyFile() { | 162 // MyFile() { |
| 162 // ... | 163 // ... |
| 163 // context_ = new IOContext; | |
| 164 // context_->handler = this; | |
| 165 // message_pump->RegisterIOHandler(file_, this); | |
| 166 // } | |
| 167 // ~MyFile() { | |
| 168 // if (pending_) { | |
| 169 // // By setting the handler to NULL, we're asking for this context | |
| 170 // // to be deleted when received, without calling back to us. | |
| 171 // context_->handler = NULL; | |
| 172 // } else { | |
| 173 // delete context_; | |
| 174 // } | |
| 175 // } | |
| 176 // virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered, | |
| 177 // DWORD error) { | |
| 178 // pending_ = false; | |
| 179 // } | |
| 180 // void DoSomeIo() { | |
| 181 // ... | |
| 182 // // The only buffer required for this operation is the overlapped | |
| 183 // // structure. | |
| 184 // ConnectNamedPipe(file_, &context_->overlapped); | |
| 185 // pending_ = true; | |
| 186 // } | |
| 187 // bool pending_; | |
| 188 // IOContext* context_; | |
| 189 // HANDLE file_; | |
| 190 // }; | |
| 191 // | |
| 192 // Typical use #2: | |
| 193 // class MyFile : public IOHandler { | |
| 194 // MyFile() { | |
| 195 // ... | |
| 196 // message_pump->RegisterIOHandler(file_, this); | 164 // message_pump->RegisterIOHandler(file_, this); |
| 197 // } | 165 // } |
| 198 // // Plus some code to make sure that this destructor is not called | 166 // // Plus some code to make sure that this destructor is not called |
| 199 // // while there are pending IO operations. | 167 // // while there are pending IO operations. |
| 200 // ~MyFile() { | 168 // ~MyFile() { |
| 201 // } | 169 // } |
| 202 // virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered, | 170 // virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered, |
| 203 // DWORD error) { | 171 // DWORD error) { |
| 204 // ... | 172 // ... |
| 205 // delete context; | 173 // delete context; |
| 206 // } | 174 // } |
| 207 // void DoSomeIo() { | 175 // void DoSomeIo() { |
| 208 // ... | 176 // ... |
| 209 // IOContext* context = new IOContext; | 177 // IOContext* context = new IOContext; |
| 210 // // This is not used for anything. It just prevents the context from | 178 // ReadFile(file_, buffer, num_bytes, &read, &context); |
| 211 // // being considered "abandoned". | |
| 212 // context->handler = this; | |
| 213 // ReadFile(file_, buffer, num_bytes, &read, &context->overlapped); | |
| 214 // } | 179 // } |
| 215 // HANDLE file_; | 180 // HANDLE file_; |
| 216 // }; | 181 // }; |
| 217 // | 182 // |
| 218 // Typical use #3: | 183 // Typical use #2: |
| 219 // Same as the previous example, except that in order to deal with the | 184 // Same as the previous example, except that in order to deal with the |
| 220 // requirement stated for the destructor, the class calls WaitForIOCompletion | 185 // requirement stated for the destructor, the class calls WaitForIOCompletion |
| 221 // from the destructor to block until all IO finishes. | 186 // from the destructor to block until all IO finishes. |
| 222 // ~MyFile() { | 187 // ~MyFile() { |
| 223 // while(pending_) | 188 // while(pending_) |
| 224 // message_pump->WaitForIOCompletion(INFINITE, this); | 189 // message_pump->WaitForIOCompletion(INFINITE, this); |
| 225 // } | 190 // } |
| 226 // | 191 // |
| 227 class IOHandler { | 192 class IOHandler { |
| 228 public: | 193 public: |
| 229 virtual ~IOHandler() {} | 194 virtual ~IOHandler() {} |
| 230 // This will be called once the pending IO operation associated with | 195 // This will be called once the pending IO operation associated with |
| 231 // |context| completes. |error| is the Win32 error code of the IO operation | 196 // |context| completes. |error| is the Win32 error code of the IO operation |
| 232 // (ERROR_SUCCESS if there was no error). |bytes_transfered| will be zero | 197 // (ERROR_SUCCESS if there was no error). |bytes_transfered| will be zero |
| 233 // on error. | 198 // on error. |
| 234 virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered, | 199 virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered, |
| 235 DWORD error) = 0; | 200 DWORD error) = 0; |
| 236 }; | 201 }; |
| 237 | 202 |
| 238 // The extended context that should be used as the base structure on every | |
| 239 // overlapped IO operation. |handler| must be set to the registered IOHandler | |
| 240 // for the given file when the operation is started, and it can be set to NULL | |
| 241 // before the operation completes to indicate that the handler should not be | |
| 242 // called anymore, and instead, the IOContext should be deleted when the OS | |
| 243 // notifies the completion of this operation. Please remember that any buffers | |
| 244 // involved with an IO operation should be around until the callback is | |
| 245 // received, so this technique can only be used for IO that do not involve | |
| 246 // additional buffers (other than the overlapped structure itself). | |
| 247 struct IOContext { | |
| 248 OVERLAPPED overlapped; | |
| 249 IOHandler* handler; | |
| 250 }; | |
| 251 | |
| 252 MessagePumpForIO(); | 203 MessagePumpForIO(); |
| 253 ~MessagePumpForIO() override; | 204 ~MessagePumpForIO() override; |
| 254 | 205 |
| 255 // MessagePump methods: | 206 // MessagePump methods: |
| 256 void ScheduleWork() override; | 207 void ScheduleWork() override; |
| 257 void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override; | 208 void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override; |
| 258 | 209 |
| 259 // Register the handler to be used when asynchronous IO for the given file | 210 // Register the handler to be used when asynchronous IO for the given file |
| 260 // completes. The registration persists as long as |file_handle| is valid, so | 211 // completes. The registration persists as long as |file_handle| is valid, so |
| 261 // |handler| must be valid as long as there is pending IO for the given file. | 212 // |handler| must be valid as long as there is pending IO for the given file. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 277 // External use of this method should be reserved for the rare case when the | 228 // External use of this method should be reserved for the rare case when the |
| 278 // caller is willing to allow pausing regular task dispatching on this thread. | 229 // caller is willing to allow pausing regular task dispatching on this thread. |
| 279 bool WaitForIOCompletion(DWORD timeout, IOHandler* filter); | 230 bool WaitForIOCompletion(DWORD timeout, IOHandler* filter); |
| 280 | 231 |
| 281 private: | 232 private: |
| 282 struct IOItem { | 233 struct IOItem { |
| 283 IOHandler* handler; | 234 IOHandler* handler; |
| 284 IOContext* context; | 235 IOContext* context; |
| 285 DWORD bytes_transfered; | 236 DWORD bytes_transfered; |
| 286 DWORD error; | 237 DWORD error; |
| 287 | |
| 288 // In some cases |context| can be a non-pointer value casted to a pointer. | |
| 289 // |has_valid_io_context| is true if |context| is a valid IOContext | |
| 290 // pointer, and false otherwise. | |
| 291 bool has_valid_io_context; | |
| 292 }; | 238 }; |
| 293 | 239 |
| 294 void DoRunLoop() override; | 240 void DoRunLoop() override; |
| 295 void WaitForWork(); | 241 void WaitForWork(); |
| 296 bool MatchCompletedIOItem(IOHandler* filter, IOItem* item); | 242 bool MatchCompletedIOItem(IOHandler* filter, IOItem* item); |
| 297 bool GetIOItem(DWORD timeout, IOItem* item); | 243 bool GetIOItem(DWORD timeout, IOItem* item); |
| 298 bool ProcessInternalIOItem(const IOItem& item); | 244 bool ProcessInternalIOItem(const IOItem& item); |
| 299 | 245 |
| 300 // Converts an IOHandler pointer to a completion port key. | |
| 301 // |has_valid_io_context| specifies whether completion packets posted to | |
| 302 // |handler| will have valid OVERLAPPED pointers. | |
| 303 static ULONG_PTR HandlerToKey(IOHandler* handler, bool has_valid_io_context); | |
| 304 | |
| 305 // Converts a completion port key to an IOHandler pointer. | |
| 306 static IOHandler* KeyToHandler(ULONG_PTR key, bool* has_valid_io_context); | |
| 307 | |
| 308 // The completion port associated with this thread. | 246 // The completion port associated with this thread. |
| 309 win::ScopedHandle port_; | 247 win::ScopedHandle port_; |
| 310 // This list will be empty almost always. It stores IO completions that have | 248 // This list will be empty almost always. It stores IO completions that have |
| 311 // not been delivered yet because somebody was doing cleanup. | 249 // not been delivered yet because somebody was doing cleanup. |
| 312 std::list<IOItem> completed_io_; | 250 std::list<IOItem> completed_io_; |
| 313 }; | 251 }; |
| 314 | 252 |
| 315 } // namespace base | 253 } // namespace base |
| 316 | 254 |
| 317 #endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_ | 255 #endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_ |
| OLD | NEW |