Index: base/message_pump_win.cc |
diff --git a/base/message_pump_win.cc b/base/message_pump_win.cc |
index 2b2a10e07534afcf7c7dd8de14567bd4c794d5cd..5f670676043b7324efa035ac32958470a175941b 100644 |
--- a/base/message_pump_win.cc |
+++ b/base/message_pump_win.cc |
@@ -475,11 +475,26 @@ void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { |
void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle, |
IOHandler* handler) { |
- ULONG_PTR key = reinterpret_cast<ULONG_PTR>(handler); |
+ ULONG_PTR key = HandlerToKey(handler, true); |
HANDLE port = CreateIoCompletionPort(file_handle, port_, key, 1); |
DPCHECK(port); |
} |
+bool MessagePumpForIO::RegisterJobObject(HANDLE job_handle, |
+ IOHandler* handler) { |
+ // Job object notifications use the OVERLAPPED pointer to carry the message |
+ // data. Mark the completion key correspondingly, so we will not try to |
+ // convert OVERLAPPED* to IOContext*. |
+ ULONG_PTR key = HandlerToKey(handler, false); |
+ JOBOBJECT_ASSOCIATE_COMPLETION_PORT info; |
+ info.CompletionKey = reinterpret_cast<void*>(key); |
+ info.CompletionPort = port_; |
+ return SetInformationJobObject(job_handle, |
+ JobObjectAssociateCompletionPortInformation, |
+ &info, |
+ sizeof(info)) != FALSE; |
+} |
+ |
//----------------------------------------------------------------------------- |
// MessagePumpForIO private: |
@@ -546,12 +561,17 @@ bool MessagePumpForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) { |
return true; |
} |
- if (item.context->handler) { |
+ // Avoid dereferencing |item.context| if the context hasn't been allocated by |
+ // operator new(), i.e. when |item.has_valid_io_context| is false. |
+ // |item.context| is not a valid pointer in this case, though it can be |
+ // a valid non-pointer value. |
Wez
2012/08/15 23:22:20
Suggest rewording: "If |item.has_valid_io_context|
alexeypa (please no reviews)
2012/08/15 23:55:50
Done.
|
+ if (!item.has_valid_io_context || item.context->handler) { |
if (filter && item.handler != filter) { |
// Save this item for later |
completed_io_.push_back(item); |
} else { |
- DCHECK_EQ(item.context->handler, item.handler); |
+ DCHECK(!item.has_valid_io_context || |
+ (item.context->handler == item.handler)); |
WillProcessIOEvent(); |
item.handler->OnIOCompleted(item.context, item.bytes_transfered, |
item.error); |
@@ -577,7 +597,7 @@ bool MessagePumpForIO::GetIOItem(DWORD timeout, IOItem* item) { |
item->bytes_transfered = 0; |
} |
- item->handler = reinterpret_cast<IOHandler*>(key); |
+ item->handler = KeyToHandler(key, &item->has_valid_io_context); |
item->context = reinterpret_cast<IOContext*>(overlapped); |
return true; |
} |
@@ -623,4 +643,28 @@ void MessagePumpForIO::DidProcessIOEvent() { |
FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent()); |
} |
+// static |
+ULONG_PTR MessagePumpForIO::HandlerToKey(IOHandler* handler, |
+ bool has_valid_io_context) { |
+ ULONG_PTR key = reinterpret_cast<ULONG_PTR>(handler); |
+ |
+ // |IOHandler| is at least pointer-size aligned, so the lowest two bits are |
+ // always cleared. We use the lowest bit to distinguish completion keys with |
+ // and without the associated |IOContext|. |
+ DCHECK((key & 1) == 0); |
+ |
+ // Mark the completion key as context-less. |
+ if (!has_valid_io_context) |
+ key = key | 1; |
+ return key; |
+} |
+ |
+// static |
+MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( |
+ ULONG_PTR key, |
+ bool* has_valid_io_context) { |
+ *has_valid_io_context = ((key & 1) == 0); |
+ return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); |
+} |
+ |
} // namespace base |