Changeset 67013 in webkit
- Timestamp:
- Sep 8, 2010, 2:16:45 PM (15 years ago)
- Location:
- trunk/WebKit2
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebKit2/ChangeLog
r67005 r67013 1 2010-09-08 Adam Roben <aroben@apple.com> 2 3 Teach WorkQueue how to stop waiting on objects on Windows 4 5 WorkQueue now uses a subclass of WorkItemWin, HandleWorkItem, to hold 6 the waited-upon HANDLE and its corresponding wait handle. When a 7 HANDLE is unregistered, we use the HandleWorkItem to cancel the wait 8 and destroy the HANDLE. 9 10 Fixes <http://webkit.org/b/42826> <rdar://problem/8222253> Crash in 11 thread pool because WorkQueue keeps waiting on closed HANDLEs 12 13 Reviewed by Anders Carlsson. 14 15 * Platform/CoreIPC/win/ConnectionWin.cpp: 16 (CoreIPC::Connection::platformInvalidate): Changed to call 17 WorkQueue::unregisterAndCloseHandle instead of closing our handles 18 manually. 19 20 (CoreIPC::Connection::readEventHandler): 21 (CoreIPC::Connection::writeEventHandler): 22 Handle cases where the pipe has already closed by just bailing out. 23 This can happen if a WorkItem to call one of these functions has 24 already been scheduled before platformInvalidate is called. 25 26 * Platform/WorkQueue.h: Gave WorkItemWin a virtual destructor, added 27 HandleWorkItem, changed m_handles to hold HandleWorkItems, and added 28 functions for unregistering waits. 29 30 * Platform/win/WorkQueueWin.cpp: 31 (WorkQueue::WorkItemWin::~WorkItemWin): Added. This virtual destructor 32 ensures that HandleWorkItem's destructor gets called. 33 34 (WorkQueue::HandleWorkItem::HandleWorkItem): 35 (WorkQueue::HandleWorkItem::createByAdoptingHandle): 36 Added simple constructor/creator. 37 38 (WorkQueue::HandleWorkItem::~HandleWorkItem): Closes the handle we 39 adopted. 40 (WorkQueue::registerHandle): Changed to create a HandleWorkItemWin and 41 to store the wait handle in it. 42 (WorkQueue::unregisterAndCloseHandle): Added. Removes the 43 HandleWorkItem for this HANDLE from m_handles and then schedules its 44 wait to be unregistered and the item to be destroyed. 45 (WorkQueue::platformInvalidate): Added an assertion and removed an 46 obsolete FIXME. 47 (WorkQueue::unregisterWaitAndDestroyItemSoon): Added. Calls 48 unregisterWaitAndDestroyItemCallback on a worker thread, passing it 49 ownership of the HandleWorkItem. 50 (WorkQueue::unregisterWaitAndDestroyItemCallback): Added. Adopts the 51 passed-in HandleWorkItem, then unregisters the handle's wait, then 52 destroys the HandleWorkItem when the RefPtr holding it goes out of 53 scope. Destroying the HandleWorkItem closes the handle. 54 1 55 2010-09-08 Adam Roben <aroben@apple.com> 2 56 -
trunk/WebKit2/Platform/CoreIPC/win/ConnectionWin.cpp
r66231 r67013 99 99 return; 100 100 101 // FIXME: Unregister the handles. 102 103 ::CloseHandle(m_readState.hEvent); 101 m_connectionQueue.unregisterAndCloseHandle(m_readState.hEvent); 104 102 m_readState.hEvent = 0; 105 103 106 ::CloseHandle(m_writeState.hEvent);104 m_connectionQueue.unregisterAndCloseHandle(m_writeState.hEvent); 107 105 m_writeState.hEvent = 0; 108 106 … … 113 111 void Connection::readEventHandler() 114 112 { 113 if (m_connectionPipe == INVALID_HANDLE_VALUE) 114 return; 115 115 116 while (true) { 116 117 // Check if we got some data. … … 232 233 void Connection::writeEventHandler() 233 234 { 235 if (m_connectionPipe == INVALID_HANDLE_VALUE) 236 return; 237 234 238 DWORD numberOfBytesWritten = 0; 235 239 if (!::GetOverlappedResult(m_connectionPipe, &m_writeState, &numberOfBytesWritten, FALSE)) { -
trunk/WebKit2/Platform/WorkQueue.h
r66999 r67013 69 69 #elif PLATFORM(WIN) 70 70 void registerHandle(HANDLE, PassOwnPtr<WorkItem>); 71 void unregister Handle(HANDLE);71 void unregisterAndCloseHandle(HANDLE); 72 72 #elif PLATFORM(QT) 73 73 void connectSignal(QObject*, const char* signal, PassOwnPtr<WorkItem>); … … 97 97 public: 98 98 static PassRefPtr<WorkItemWin> create(PassOwnPtr<WorkItem>, WorkQueue*); 99 virtual ~WorkItemWin(); 99 100 100 101 WorkItem* item() const { return m_item.get(); } 101 102 WorkQueue* queue() const { return m_queue; } 102 103 103 pr ivate:104 protected: 104 105 WorkItemWin(PassOwnPtr<WorkItem>, WorkQueue*); 105 106 107 private: 106 108 OwnPtr<WorkItem> m_item; 107 109 WorkQueue* m_queue; 110 }; 111 112 class HandleWorkItem : public WorkItemWin { 113 public: 114 static PassRefPtr<HandleWorkItem> createByAdoptingHandle(HANDLE, PassOwnPtr<WorkItem>, WorkQueue*); 115 virtual ~HandleWorkItem(); 116 117 void setWaitHandle(HANDLE waitHandle) { m_waitHandle = waitHandle; } 118 HANDLE waitHandle() const { return m_waitHandle; } 119 120 private: 121 HandleWorkItem(HANDLE, PassOwnPtr<WorkItem>, WorkQueue*); 122 123 HANDLE m_handle; 124 HANDLE m_waitHandle; 108 125 }; 109 126 … … 115 132 void performWorkOnRegisteredWorkThread(); 116 133 134 static void unregisterWaitAndDestroyItemSoon(PassRefPtr<HandleWorkItem>); 135 static DWORD WINAPI unregisterWaitAndDestroyItemCallback(void* context); 136 117 137 volatile LONG m_isWorkThreadRegistered; 118 138 … … 121 141 122 142 Mutex m_handlesLock; 123 HashMap<HANDLE, RefPtr< WorkItemWin> > m_handles;143 HashMap<HANDLE, RefPtr<HandleWorkItem> > m_handles; 124 144 #elif PLATFORM(QT) 125 145 class WorkItemQt; -
trunk/WebKit2/Platform/win/WorkQueueWin.cpp
r66999 r67013 39 39 } 40 40 41 WorkQueue::WorkItemWin::~WorkItemWin() 42 { 43 } 44 45 inline WorkQueue::HandleWorkItem::HandleWorkItem(HANDLE handle, PassOwnPtr<WorkItem> item, WorkQueue* queue) 46 : WorkItemWin(item, queue) 47 , m_handle(handle) 48 , m_waitHandle(0) 49 { 50 ASSERT_ARG(handle, handle); 51 } 52 53 PassRefPtr<WorkQueue::HandleWorkItem> WorkQueue::HandleWorkItem::createByAdoptingHandle(HANDLE handle, PassOwnPtr<WorkItem> item, WorkQueue* queue) 54 { 55 return adoptRef(new HandleWorkItem(handle, item, queue)); 56 } 57 58 WorkQueue::HandleWorkItem::~HandleWorkItem() 59 { 60 ::CloseHandle(m_handle); 61 } 62 41 63 void WorkQueue::handleCallback(void* context, BOOLEAN timerOrWaitFired) 42 64 { … … 66 88 void WorkQueue::registerHandle(HANDLE handle, PassOwnPtr<WorkItem> item) 67 89 { 68 RefPtr<WorkItemWin> itemWin = WorkItemWin::create(item, this); 69 70 // Add the item. 90 RefPtr<HandleWorkItem> handleItem = HandleWorkItem::createByAdoptingHandle(handle, item, this); 91 92 { 93 MutexLocker lock(m_handlesLock); 94 ASSERT_ARG(handle, !m_handles.contains(handle)); 95 m_handles.set(handle, handleItem); 96 } 97 98 HANDLE waitHandle; 99 if (!::RegisterWaitForSingleObject(&waitHandle, handle, handleCallback, handleItem.get(), INFINITE, WT_EXECUTEDEFAULT)) { 100 DWORD error = ::GetLastError(); 101 ASSERT_NOT_REACHED(); 102 } 103 handleItem->setWaitHandle(waitHandle); 104 } 105 106 void WorkQueue::unregisterAndCloseHandle(HANDLE handle) 107 { 108 RefPtr<HandleWorkItem> item; 71 109 { 72 110 MutexLocker locker(m_handlesLock); 73 m_handles.set(handle, itemWin); 74 } 75 76 // FIXME: We need to hold onto waitHandle so that we can unregister the wait later. 77 HANDLE waitHandle; 78 if (!::RegisterWaitForSingleObject(&waitHandle, handle, handleCallback, itemWin.get(), INFINITE, WT_EXECUTEDEFAULT)) { 79 DWORD error = ::GetLastError(); 80 ASSERT_NOT_REACHED(); 81 } 111 ASSERT_ARG(handle, m_handles.contains(handle)); 112 item = m_handles.take(handle); 113 } 114 115 unregisterWaitAndDestroyItemSoon(item.release()); 82 116 } 83 117 … … 147 181 void WorkQueue::platformInvalidate() 148 182 { 149 // FIXME: Stop the thread and do other cleanup. 183 #if !ASSERT_DISABLED 184 MutexLocker lock(m_handlesLock); 185 ASSERT(m_handles.isEmpty()); 186 #endif 150 187 } 151 188 … … 165 202 ::QueueUserWorkItem(workThreadCallback, this, WT_EXECUTEDEFAULT); 166 203 } 204 205 void WorkQueue::unregisterWaitAndDestroyItemSoon(PassRefPtr<HandleWorkItem> item) 206 { 207 // We're going to make a blocking call to ::UnregisterWaitEx before closing the handle. (The 208 // blocking version of ::UnregisterWaitEx is much simpler than the non-blocking version.) If we 209 // do this on the current thread, we'll deadlock if we're currently in a callback function for 210 // the wait we're unregistering. So instead we do it asynchronously on some other worker thread. 211 212 ::QueueUserWorkItem(unregisterWaitAndDestroyItemCallback, item.leakRef(), WT_EXECUTEDEFAULT); 213 } 214 215 DWORD WINAPI WorkQueue::unregisterWaitAndDestroyItemCallback(void* context) 216 { 217 ASSERT_ARG(context, context); 218 RefPtr<HandleWorkItem> item = adoptRef(static_cast<HandleWorkItem*>(context)); 219 220 // Now that we know we're not in a callback function for the wait we're unregistering, we can 221 // make a blocking call to ::UnregisterWaitEx. 222 if (!::UnregisterWaitEx(item->waitHandle(), INVALID_HANDLE_VALUE)) { 223 DWORD error = ::GetLastError(); 224 ASSERT_NOT_REACHED(); 225 } 226 227 return 0; 228 }
Note:
See TracChangeset
for help on using the changeset viewer.