Changeset 213030 in webkit
- Timestamp:
- Feb 26, 2017 11:50:31 PM (7 years ago)
- Location:
- trunk/Source/WebKit2
- Files:
-
- 1 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebKit2/ChangeLog
r213025 r213030 1 2017-02-26 Carlos Garcia Campos <cgarcia@igalia.com> 2 3 [GTK] Hangs when showing Google search results 4 https://bugs.webkit.org/show_bug.cgi?id=168699 5 6 Reviewed by Žan Doberšek. 7 8 Connection::sendOutgoingMessage() can poll forever if sendmsg fails with EAGAIN or EWOULDBLOCK. For example if 9 socket read buffers are full, poll will be blocked until we read the pending data, but we can't read because 10 the thread is blocked in the poll. In case of EAGAIN/EWOULDBLOCK we should poll using the run loop, to allow 11 reads to happen in thread while we wait for the socket to be writable again. In the GTK+ port we use 12 GSocketMonitor to poll socket file descriptor without blocking, using the run loop. This patch renames the 13 socket monitor as readSocketMonitor and adds another one for polling output. When sendmsg fails with 14 EAGAIN/EWOULDBLOCK, the pending message is saved and the write monitor starts polling. Once the socket is 15 writable again we send the pending message. Helper class MessageInfo and a new one UnixMessage have been moved 16 to its own header file to be able to use std::unique_ptr member to save the pending message. 17 18 * Platform/IPC/Connection.cpp: Include UnixMessage.h as required by std::unique_ptr. 19 * Platform/IPC/Connection.h: Add write socket monitor and also keep the GSocket as a member to reuse it. 20 * Platform/IPC/glib/GSocketMonitor.cpp: Use Function instead of std::function. 21 (IPC::GSocketMonitor::start): 22 * Platform/IPC/glib/GSocketMonitor.h: 23 * Platform/IPC/unix/ConnectionUnix.cpp: 24 (IPC::Connection::platformInitialize): Initialize the GSocket here since we rely on it to take the ownership of 25 the descriptor. We were leaking it if the connection was invalidated without being opened. 26 (IPC::Connection::platformInvalidate): Destroy the GSocket even when not connected. Also stop the write monitor. 27 (IPC::Connection::processMessage): 28 (IPC::Connection::open): 29 (IPC::Connection::platformCanSendOutgoingMessages): Return false if we have a pending message to ensure 30 Connection doesn't try to send more messages until the pending message is dispatched. We don't need to check 31 m_isConnected because the caller already checks that. 32 (IPC::Connection::sendOutgoingMessage): Split it in two. This creates and prepares a UnixMessage and then calls 33 sendOutputMessage() to do the rest. 34 (IPC::Connection::sendOutputMessage): Send the message, or save it if sendmsg fails with EAGAIN or EWOULDBLOCK 35 to be sent later when the socket is writable. 36 * Platform/IPC/unix/UnixMessage.h: Added. 37 (IPC::MessageInfo::MessageInfo): 38 (IPC::MessageInfo::setMessageBodyIsOutOfLine): 39 (IPC::MessageInfo::isMessageBodyIsOutOfLine): 40 (IPC::MessageInfo::bodySize): 41 (IPC::MessageInfo::attachmentCount): 42 (IPC::UnixMessage::UnixMessage): 43 (IPC::UnixMessage::~UnixMessage): 44 (IPC::UnixMessage::attachments): 45 (IPC::UnixMessage::messageInfo): 46 (IPC::UnixMessage::body): 47 (IPC::UnixMessage::bodySize): 48 (IPC::UnixMessage::appendAttachment): 49 * PlatformGTK.cmake: 50 1 51 2017-02-26 Devin Rousso <dcrousso+webkit@gmail.com> 2 52 -
trunk/Source/WebKit2/Platform/IPC/Connection.cpp
r211482 r213030 40 40 #endif 41 41 42 #if USE(UNIX_DOMAIN_SOCKETS) 43 #include "UnixMessage.h" 44 #endif 45 42 46 namespace IPC { 43 47 -
trunk/Source/WebKit2/Platform/IPC/Connection.h
r209575 r213030 80 80 81 81 class MachMessage; 82 class UnixMessage; 82 83 83 84 class Connection : public ThreadSafeRefCounted<Connection> { … … 309 310 void readyReadHandler(); 310 311 bool processMessage(); 312 bool sendOutputMessage(UnixMessage&); 311 313 312 314 Vector<uint8_t> m_readBuffer; 313 315 Vector<int> m_fileDescriptors; 314 316 int m_socketDescriptor; 317 std::unique_ptr<UnixMessage> m_pendingOutputMessage; 315 318 #if PLATFORM(GTK) 316 GSocketMonitor m_socketMonitor; 319 GRefPtr<GSocket> m_socket; 320 GSocketMonitor m_readSocketMonitor; 321 GSocketMonitor m_writeSocketMonitor; 317 322 #endif 318 323 #elif OS(DARWIN) -
trunk/Source/WebKit2/Platform/IPC/glib/GSocketMonitor.cpp
r194496 r213030 43 43 } 44 44 45 void GSocketMonitor::start(GSocket* socket, GIOCondition condition, RunLoop& runLoop, std::function<gboolean (GIOCondition)>&& callback)45 void GSocketMonitor::start(GSocket* socket, GIOCondition condition, RunLoop& runLoop, Function<gboolean (GIOCondition)>&& callback) 46 46 { 47 47 stop(); -
trunk/Source/WebKit2/Platform/IPC/glib/GSocketMonitor.h
r191881 r213030 44 44 ~GSocketMonitor(); 45 45 46 void start(GSocket*, GIOCondition, RunLoop&, std::function<gboolean (GIOCondition)>&&);46 void start(GSocket*, GIOCondition, RunLoop&, Function<gboolean (GIOCondition)>&&); 47 47 void stop(); 48 48 … … 52 52 GRefPtr<GSource> m_source; 53 53 GRefPtr<GCancellable> m_cancellable; 54 std::function<gboolean (GIOCondition)> m_callback;54 Function<gboolean (GIOCondition)> m_callback; 55 55 }; 56 56 -
trunk/Source/WebKit2/Platform/IPC/unix/ConnectionUnix.cpp
r212557 r213030 31 31 #include "DataReference.h" 32 32 #include "SharedMemory.h" 33 #include "UnixMessage.h" 33 34 #include <sys/socket.h> 34 35 #include <unistd.h> … … 61 62 static const size_t attachmentMaxAmount = 255; 62 63 63 enum {64 MessageBodyIsOutOfLine = 1U << 3165 };66 67 class MessageInfo {68 public:69 MessageInfo() { }70 71 MessageInfo(size_t bodySize, size_t initialAttachmentCount)72 : m_bodySize(bodySize)73 , m_attachmentCount(initialAttachmentCount)74 , m_isMessageBodyOutOfLine(false)75 {76 }77 78 void setMessageBodyIsOutOfLine()79 {80 ASSERT(!isMessageBodyIsOutOfLine());81 82 m_isMessageBodyOutOfLine = true;83 m_attachmentCount++;84 }85 86 bool isMessageBodyIsOutOfLine() const { return m_isMessageBodyOutOfLine; }87 88 size_t bodySize() const { return m_bodySize; }89 90 size_t attachmentCount() const { return m_attachmentCount; }91 92 private:93 size_t m_bodySize;94 size_t m_attachmentCount;95 bool m_isMessageBodyOutOfLine;96 };97 98 64 class AttachmentInfo { 99 65 WTF_MAKE_FAST_ALLOCATED; 100 66 public: 101 AttachmentInfo() 102 : m_type(Attachment::Uninitialized) 103 , m_size(0) 104 , m_isNull(false) 105 { 106 } 67 AttachmentInfo() = default; 107 68 108 69 void setType(Attachment::Type type) { m_type = type; } 109 Attachment::Type getType(){ return m_type; }70 Attachment::Type type() const { return m_type; } 110 71 void setSize(size_t size) 111 72 { … … 114 75 } 115 76 116 size_t getSize()77 size_t size() const 117 78 { 118 79 ASSERT(m_type == Attachment::MappedMemoryType); … … 122 83 // The attachment is not null unless explicitly set. 123 84 void setNull() { m_isNull = true; } 124 bool isNull() { return m_isNull; }85 bool isNull() const { return m_isNull; } 125 86 126 87 private: 127 Attachment::Type m_type ;128 size_t m_size ;129 bool m_isNull ;88 Attachment::Type m_type { Attachment::Uninitialized }; 89 size_t m_size { 0 }; 90 bool m_isNull { false }; 130 91 }; 131 92 … … 133 94 { 134 95 m_socketDescriptor = identifier; 96 #if PLATFORM(GTK) 97 m_socket = adoptGRef(g_socket_new_from_fd(m_socketDescriptor, nullptr)); 98 #endif 135 99 m_readBuffer.reserveInitialCapacity(messageMaxSize); 136 100 m_fileDescriptors.reserveInitialCapacity(attachmentMaxAmount); … … 139 103 void Connection::platformInvalidate() 140 104 { 141 // In GTK+ platform the socket is closed by the work queue. 142 #if !PLATFORM(GTK) 105 #if PLATFORM(GTK) 106 // In GTK+ platform the socket descriptor is owned by GSocket. 107 m_socket = nullptr; 108 #else 143 109 if (m_socketDescriptor != -1) 144 110 closeWithRetry(m_socketDescriptor); … … 149 115 150 116 #if PLATFORM(GTK) 151 m_socketMonitor.stop(); 117 m_readSocketMonitor.stop(); 118 m_writeSocketMonitor.stop(); 152 119 #endif 153 120 … … 166 133 messageData += sizeof(messageInfo); 167 134 168 size_t messageLength = sizeof(MessageInfo) + messageInfo.attachmentCount() * sizeof(AttachmentInfo) + (messageInfo.is MessageBodyIsOutOfLine() ? 0 : messageInfo.bodySize());135 size_t messageLength = sizeof(MessageInfo) + messageInfo.attachmentCount() * sizeof(AttachmentInfo) + (messageInfo.isBodyOutOfLine() ? 0 : messageInfo.bodySize()); 169 136 if (m_readBuffer.size() < messageLength) 170 137 return false; … … 180 147 181 148 for (size_t i = 0; i < attachmentCount; ++i) { 182 switch (attachmentInfo[i]. getType()) {149 switch (attachmentInfo[i].type()) { 183 150 case Attachment::MappedMemoryType: 184 151 case Attachment::SocketType: … … 192 159 } 193 160 194 if (messageInfo.is MessageBodyIsOutOfLine())161 if (messageInfo.isBodyOutOfLine()) 195 162 attachmentCount--; 196 163 } … … 202 169 for (size_t i = 0; i < attachmentCount; ++i) { 203 170 int fd = -1; 204 switch (attachmentInfo[i]. getType()) {171 switch (attachmentInfo[i].type()) { 205 172 case Attachment::MappedMemoryType: 206 173 if (!attachmentInfo[i].isNull()) 207 174 fd = m_fileDescriptors[fdIndex++]; 208 attachments[attachmentCount - i - 1] = Attachment(fd, attachmentInfo[i]. getSize());175 attachments[attachmentCount - i - 1] = Attachment(fd, attachmentInfo[i].size()); 209 176 break; 210 177 case Attachment::SocketType: … … 220 187 } 221 188 222 if (messageInfo.is MessageBodyIsOutOfLine()) {189 if (messageInfo.isBodyOutOfLine()) { 223 190 ASSERT(messageInfo.bodySize()); 224 191 … … 229 196 230 197 WebKit::SharedMemory::Handle handle; 231 handle.adoptAttachment(IPC::Attachment(m_fileDescriptors[attachmentFileDescriptorCount - 1], attachmentInfo[attachmentCount]. getSize()));198 handle.adoptAttachment(IPC::Attachment(m_fileDescriptors[attachmentFileDescriptorCount - 1], attachmentInfo[attachmentCount].size())); 232 199 233 200 oolMessageBody = WebKit::SharedMemory::map(handle, WebKit::SharedMemory::Protection::ReadOnly); … … 238 205 } 239 206 240 ASSERT(attachments.size() == (messageInfo.is MessageBodyIsOutOfLine() ? messageInfo.attachmentCount() - 1 : messageInfo.attachmentCount()));207 ASSERT(attachments.size() == (messageInfo.isBodyOutOfLine() ? messageInfo.attachmentCount() - 1 : messageInfo.attachmentCount())); 241 208 242 209 uint8_t* messageBody = messageData; 243 if (messageInfo.is MessageBodyIsOutOfLine())210 if (messageInfo.isBodyOutOfLine()) 244 211 messageBody = reinterpret_cast<uint8_t*>(oolMessageBody->data()); 245 212 … … 366 333 m_isConnected = true; 367 334 #if PLATFORM(GTK) 368 GRefPtr<GSocket> socket = adoptGRef(g_socket_new_from_fd(m_socketDescriptor, nullptr)); 369 m_socketMonitor.start(socket.get(), G_IO_IN, m_connectionQueue->runLoop(), [protectedThis] (GIOCondition condition) -> gboolean { 335 m_readSocketMonitor.start(m_socket.get(), G_IO_IN, m_connectionQueue->runLoop(), [protectedThis] (GIOCondition condition) -> gboolean { 370 336 if (condition & G_IO_HUP || condition & G_IO_ERR || condition & G_IO_NVAL) { 371 337 protectedThis->connectionDidClose(); … … 393 359 bool Connection::platformCanSendOutgoingMessages() const 394 360 { 395 return m_isConnected;361 return !m_pendingOutputMessage; 396 362 } 397 363 … … 400 366 COMPILE_ASSERT(sizeof(MessageInfo) + attachmentMaxAmount * sizeof(size_t) <= messageMaxSize, AttachmentsFitToMessageInline); 401 367 402 Vector<Attachment> attachments = encoder->releaseAttachments();403 if ( attachments.size() > (attachmentMaxAmount - 1)) {368 UnixMessage outputMessage(*encoder); 369 if (outputMessage.attachments().size() > (attachmentMaxAmount - 1)) { 404 370 ASSERT_NOT_REACHED(); 405 371 return false; 406 372 } 407 373 408 MessageInfo messageInfo(encoder->bufferSize(), attachments.size()); 409 size_t messageSizeWithBodyInline = sizeof(messageInfo) + (attachments.size() * sizeof(AttachmentInfo)) + encoder->bufferSize(); 410 if (messageSizeWithBodyInline > messageMaxSize && encoder->bufferSize()) { 374 size_t messageSizeWithBodyInline = sizeof(MessageInfo) + (outputMessage.attachments().size() * sizeof(AttachmentInfo)) + outputMessage.bodySize(); 375 if (messageSizeWithBodyInline > messageMaxSize && outputMessage.bodySize()) { 411 376 RefPtr<WebKit::SharedMemory> oolMessageBody = WebKit::SharedMemory::allocate(encoder->bufferSize()); 412 377 if (!oolMessageBody) … … 417 382 return false; 418 383 419 messageInfo.setMessageBodyIsOutOfLine(); 420 421 memcpy(oolMessageBody->data(), encoder->buffer(), encoder->bufferSize()); 422 423 attachments.append(handle.releaseAttachment()); 424 } 425 384 outputMessage.messageInfo().setBodyOutOfLine(); 385 386 memcpy(oolMessageBody->data(), outputMessage.body(), outputMessage.bodySize()); 387 388 outputMessage.appendAttachment(handle.releaseAttachment()); 389 } 390 391 return sendOutputMessage(outputMessage); 392 } 393 394 bool Connection::sendOutputMessage(UnixMessage& outputMessage) 395 { 396 ASSERT(!m_pendingOutputMessage); 397 398 auto& messageInfo = outputMessage.messageInfo(); 426 399 struct msghdr message; 427 400 memset(&message, 0, sizeof(message)); … … 439 412 MallocPtr<char> attachmentFDBuffer; 440 413 414 auto& attachments = outputMessage.attachments(); 441 415 if (!attachments.isEmpty()) { 442 416 int* fdPtr = 0; … … 489 463 } 490 464 491 if (!messageInfo.is MessageBodyIsOutOfLine() && encoder->bufferSize()) {492 iov[iovLength].iov_base = reinterpret_cast<void*>( encoder->buffer());493 iov[iovLength].iov_len = encoder->bufferSize();465 if (!messageInfo.isBodyOutOfLine() && outputMessage.bodySize()) { 466 iov[iovLength].iov_base = reinterpret_cast<void*>(outputMessage.body()); 467 iov[iovLength].iov_len = outputMessage.bodySize(); 494 468 ++iovLength; 495 469 } … … 501 475 continue; 502 476 if (errno == EAGAIN || errno == EWOULDBLOCK) { 477 #if PLATFORM(GTK) 478 m_pendingOutputMessage = std::make_unique<UnixMessage>(WTFMove(outputMessage)); 479 m_writeSocketMonitor.start(m_socket.get(), G_IO_OUT, m_connectionQueue->runLoop(), [this, protectedThis = makeRef(*this)] (GIOCondition condition) -> gboolean { 480 if (condition & G_IO_OUT) { 481 ASSERT(m_pendingOutputMessage); 482 // We can't stop the monitor from this lambda, because stop destroys the lambda. 483 m_connectionQueue->dispatch([this, protectedThis = makeRef(*this)] { 484 m_writeSocketMonitor.stop(); 485 auto message = WTFMove(m_pendingOutputMessage); 486 if (m_isConnected) { 487 sendOutputMessage(*message); 488 sendOutgoingMessages(); 489 } 490 }); 491 } 492 return G_SOURCE_REMOVE; 493 }); 494 return false; 495 #else 503 496 struct pollfd pollfd; 504 497 … … 508 501 poll(&pollfd, 1, -1); 509 502 continue; 503 #endif 510 504 } 511 505 -
trunk/Source/WebKit2/PlatformGTK.cmake
r212949 r213030 868 868 "${WEBKIT2_DIR}/NetworkProcess/unix" 869 869 "${WEBKIT2_DIR}/Platform/IPC/glib" 870 "${WEBKIT2_DIR}/Platform/IPC/unix" 870 871 "${WEBKIT2_DIR}/Platform/classifier" 871 872 "${WEBKIT2_DIR}/Shared/API/c/gtk"
Note: See TracChangeset
for help on using the changeset viewer.