Changeset 203155 in webkit


Ignore:
Timestamp:
Jul 13, 2016 1:36:01 AM (8 years ago)
Author:
Carlos Garcia Campos
Message:

[GTK] WebKitGtk+ uses too many file descriptors
https://bugs.webkit.org/show_bug.cgi?id=152316

Reviewed by Michael Catanzaro.

Source/WebKit2:

The problem is that we are keeping file descriptors open in SharedMemory objects. Those objects can be kept
alive for a long time, for example in case of cached resources sent from the network process as shareable
resources. The thing is that we keep the file descriptor in the SharedMemory object only to be able to create a
Handle, duplicating the file descriptor. However, we are also assuming that we create handles for SharedMemory
objects created by another handle which is wrong. SharedMemory objects are created to map a file or data and
then a handle is created to send it to another process, or to map an existing file or data for a given handle
received from another process. They can also be created to wrap another map, but in that case we don't own the
file descritor nor the mapped data. So, after mapping from a handle, we no longer need the file descriptor, and
it can be closed to release it, while the mapped memory data will still be alive until munmap() is called. This
drastically reduces the amount of file descriptors used by WebKitGTK+.

  • Platform/IPC/unix/ConnectionUnix.cpp:

(IPC::readBytesFromSocket): Use setCloseOnExec().
(IPC::Connection::createPlatformConnection): Ditto.

  • Platform/SharedMemory.h:
  • Platform/unix/SharedMemoryUnix.cpp:

(WebKit::SharedMemory::map): Close the file descriptor right after mmap.
(WebKit::SharedMemory::~SharedMemory): Close the file descriptor only if it hasn't been closed yet.
(WebKit::SharedMemory::createHandle): Add an ASSERT to ensure we only try to create a handle for SharedMemory
objects having a valid file descriptor. Use dupCloseOnExec() to duplicate the handle and set the close on exec flag.

  • UIProcess/Launcher/gtk/ProcessLauncherGtk.cpp:

(WebKit::ProcessLauncher::launchProcess): Use setCloseOnExec().

Source/WTF:

Add helper functions to duplicate a file descriptor setting close on exec flag, and also to set close on exec
flag to an existing file descriptor.

  • wtf/UniStdExtras.h:
  • wtf/UniStdExtras.cpp

(WTF::setCloseOnExec):
(WTF::dupCloseOnExec):

Location:
trunk/Source
Files:
9 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r203147 r203155  
     12016-07-13  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GTK] WebKitGtk+ uses too many file descriptors
     4        https://bugs.webkit.org/show_bug.cgi?id=152316
     5
     6        Reviewed by Michael Catanzaro.
     7
     8        Add helper functions to duplicate a file descriptor setting close on exec flag, and also to set close on exec
     9        flag to an existing file descriptor.
     10
     11        * wtf/UniStdExtras.h:
     12        * wtf/UniStdExtras.cpp
     13        (WTF::setCloseOnExec):
     14        (WTF::dupCloseOnExec):
     15
    1162016-07-12  Benjamin Poulain  <bpoulain@apple.com>
    217
  • trunk/Source/WTF/wtf/PlatformEfl.cmake

    r203038 r203155  
    11list(APPEND WTF_SOURCES
    22    PlatformUserPreferredLanguagesUnix.cpp
     3    UniStdExtras.cpp
    34
    45    text/efl/TextBreakIteratorInternalICUEfl.cpp
  • trunk/Source/WTF/wtf/PlatformGTK.cmake

    r203038 r203155  
    99    glib/RunLoopGLib.cpp
    1010    PlatformUserPreferredLanguagesUnix.cpp
     11    UniStdExtras.cpp
    1112
    1213    text/gtk/TextBreakIteratorInternalICUGtk.cpp
  • trunk/Source/WTF/wtf/UniStdExtras.cpp

    r203154 r203155  
    11/*
    2  * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
     2 * Copyright (C) 2016 Igalia S.L.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2424 */
    2525
    26 #ifndef UniStdExtras_h
    27 #define UniStdExtras_h
     26#include "config.h"
     27#include "UniStdExtras.h"
    2828
    29 #include <errno.h>
    30 #include <unistd.h>
     29#include <fcntl.h>
    3130
    3231namespace WTF {
    3332
    34 inline int closeWithRetry(int fileDescriptor)
     33bool setCloseOnExec(int fileDescriptor)
    3534{
    36     int ret;
    37 #if OS(LINUX)
    38     // Workaround for the Linux behavior of closing the descriptor
    39     // unconditionally, even if the close() call is interrupted.
    40     // See https://bugs.webkit.org/show_bug.cgi?id=117266 for more
    41     // details.
    42     if ((ret = close(fileDescriptor)) == -1 && errno == EINTR)
    43         return 0;
    44 #else
    45     while ((ret = close(fileDescriptor)) == -1 && errno == EINTR) { }
     35    int returnValue = -1;
     36    do {
     37        int flags = fcntl(fileDescriptor, F_GETFD);
     38        if (flags != -1)
     39            returnValue = fcntl(fileDescriptor, F_SETFD, flags | FD_CLOEXEC);
     40    } while (returnValue == -1 && errno == EINTR);
     41
     42    return returnValue != -1;
     43}
     44
     45int dupCloseOnExec(int fileDescriptor)
     46{
     47    int duplicatedFileDescriptor = -1;
     48#ifdef F_DUPFD_CLOEXEC
     49    while ((duplicatedFileDescriptor = fcntl(fileDescriptor, F_DUPFD_CLOEXEC, 0)) == -1 && errno == EINTR) { }
     50    if (duplicatedFileDescriptor != -1)
     51        return duplicatedFileDescriptor;
     52
    4653#endif
    47     return ret;
     54
     55    while ((duplicatedFileDescriptor = dup(fileDescriptor)) == -1 && errno == EINTR) { }
     56    if (duplicatedFileDescriptor == -1)
     57        return -1;
     58
     59    if (!setCloseOnExec(duplicatedFileDescriptor)) {
     60        closeWithRetry(duplicatedFileDescriptor);
     61        return -1;
     62    }
     63
     64    return duplicatedFileDescriptor;
    4865}
    4966
    5067} // namespace WTF
    51 
    52 using WTF::closeWithRetry;
    53 
    54 #endif // UniStdExtras_h
  • trunk/Source/WTF/wtf/UniStdExtras.h

    r151825 r203155  
    3232namespace WTF {
    3333
     34bool setCloseOnExec(int fileDescriptor);
     35int dupCloseOnExec(int fileDescriptor);
     36
    3437inline int closeWithRetry(int fileDescriptor)
    3538{
     
    5154
    5255using WTF::closeWithRetry;
     56using WTF::setCloseOnExec;
     57using WTF::dupCloseOnExec;
    5358
    5459#endif // UniStdExtras_h
  • trunk/Source/WebKit2/ChangeLog

    r203145 r203155  
     12016-07-13  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GTK] WebKitGtk+ uses too many file descriptors
     4        https://bugs.webkit.org/show_bug.cgi?id=152316
     5
     6        Reviewed by Michael Catanzaro.
     7
     8        The problem is that we are keeping file descriptors open in SharedMemory objects. Those objects can be kept
     9        alive for a long time, for example in case of cached resources sent from the network process as shareable
     10        resources. The thing is that we keep the file descriptor in the SharedMemory object only to be able to create a
     11        Handle, duplicating the file descriptor. However, we are also assuming that we create handles for SharedMemory
     12        objects created by another handle which is wrong. SharedMemory objects are created to map a file or data and
     13        then a handle is created to send it to another process, or to map an existing file or data for a given handle
     14        received from another process. They can also be created to wrap another map, but in that case we don't own the
     15        file descritor nor the mapped data. So, after mapping from a handle, we no longer need the file descriptor, and
     16        it can be closed to release it, while the mapped memory data will still be alive until munmap() is called. This
     17        drastically reduces the amount of file descriptors used by WebKitGTK+.
     18
     19        * Platform/IPC/unix/ConnectionUnix.cpp:
     20        (IPC::readBytesFromSocket): Use setCloseOnExec().
     21        (IPC::Connection::createPlatformConnection): Ditto.
     22        * Platform/SharedMemory.h:
     23        * Platform/unix/SharedMemoryUnix.cpp:
     24        (WebKit::SharedMemory::map): Close the file descriptor right after mmap.
     25        (WebKit::SharedMemory::~SharedMemory): Close the file descriptor only if it hasn't been closed yet.
     26        (WebKit::SharedMemory::createHandle): Add an ASSERT to ensure we only try to create a handle for SharedMemory
     27        objects having a valid file descriptor. Use dupCloseOnExec() to duplicate the handle and set the close on exec flag.
     28        * UIProcess/Launcher/gtk/ProcessLauncherGtk.cpp:
     29        (WebKit::ProcessLauncher::launchProcess): Use setCloseOnExec().
     30
    1312016-07-12  Simon Fraser  <simon.fraser@apple.com>
    232
  • trunk/Source/WebKit2/Platform/IPC/unix/ConnectionUnix.cpp

    r201381 r203155  
    309309
    310310                for (size_t i = 0; i < fileDescriptorsCount; ++i) {
    311                     while (fcntl(fileDescriptors[previousFileDescriptorsSize + i], F_SETFD, FD_CLOEXEC) == -1) {
    312                         if (errno != EINTR) {
    313                             ASSERT_NOT_REACHED();
    314                             break;
    315                         }
     311                    if (!setCloseOnExec(fileDescriptors[previousFileDescriptorsSize + i])) {
     312                        ASSERT_NOT_REACHED();
     313                        break;
    316314                    }
    317315                }
     
    533531    if (options & SetCloexecOnServer) {
    534532        // Don't expose the child socket to the parent process.
    535         while (fcntl(sockets[1], F_SETFD, FD_CLOEXEC)  == -1)
    536             RELEASE_ASSERT(errno != EINTR);
     533        if (!setCloseOnExec(sockets[1]))
     534            RELEASE_ASSERT_NOT_REACHED();
    537535    }
    538536
    539537    if (options & SetCloexecOnClient) {
    540538        // Don't expose the parent socket to potential future children.
    541         while (fcntl(sockets[0], F_SETFD, FD_CLOEXEC) == -1)
    542             RELEASE_ASSERT(errno != EINTR);
     539        if (!setCloseOnExec(sockets[0]))
     540            RELEASE_ASSERT_NOT_REACHED();
    543541    }
    544542
  • trunk/Source/WebKit2/Platform/SharedMemory.h

    r191856 r203155  
    114114
    115115#if USE(UNIX_DOMAIN_SOCKETS)
    116     int m_fileDescriptor;
     116    Optional<int> m_fileDescriptor;
    117117    bool m_isWrappingMap { false };
    118118#elif OS(DARWIN)
  • trunk/Source/WebKit2/Platform/unix/SharedMemoryUnix.cpp

    r194496 r203155  
    153153    ASSERT(!handle.isNull());
    154154
    155     void* data = mmap(0, handle.m_attachment.size(), accessModeMMap(protection), MAP_SHARED, handle.m_attachment.fileDescriptor(), 0);
     155    int fd = handle.m_attachment.releaseFileDescriptor();
     156    void* data = mmap(0, handle.m_attachment.size(), accessModeMMap(protection), MAP_SHARED, fd, 0);
     157    closeWithRetry(fd);
    156158    if (data == MAP_FAILED)
    157159        return nullptr;
    158160
    159     RefPtr<SharedMemory> instance = wrapMap(data, handle.m_attachment.size(), handle.m_attachment.releaseFileDescriptor());
     161    RefPtr<SharedMemory> instance = wrapMap(data, handle.m_attachment.size(), -1);
     162    instance->m_fileDescriptor = Nullopt;
    160163    instance->m_isWrappingMap = false;
    161164    return instance;
     
    174177SharedMemory::~SharedMemory()
    175178{
    176     if (!m_isWrappingMap) {
    177         munmap(m_data, m_size);
    178         closeWithRetry(m_fileDescriptor);
    179     }
     179    if (m_isWrappingMap)
     180        return;
     181
     182    munmap(m_data, m_size);
     183    if (m_fileDescriptor)
     184        closeWithRetry(m_fileDescriptor.value());
    180185}
    181186
     
    183188{
    184189    ASSERT_ARG(handle, handle.isNull());
     190    ASSERT(m_fileDescriptor);
    185191
    186192    // FIXME: Handle the case where the passed Protection is ReadOnly.
    187193    // See https://bugs.webkit.org/show_bug.cgi?id=131542.
    188194
    189     int duplicatedHandle;
    190     while ((duplicatedHandle = dup(m_fileDescriptor)) == -1) {
    191         if (errno != EINTR) {
    192             ASSERT_NOT_REACHED();
    193             return false;
    194         }
    195     }
    196 
    197     while (fcntl(duplicatedHandle, F_SETFD, FD_CLOEXEC) == -1) {
    198         if (errno != EINTR) {
    199             ASSERT_NOT_REACHED();
    200             closeWithRetry(duplicatedHandle);
    201             return false;
    202         }
     195    int duplicatedHandle = dupCloseOnExec(m_fileDescriptor.value());
     196    if (duplicatedHandle == -1) {
     197        ASSERT_NOT_REACHED();
     198        return false;
    203199    }
    204200    handle.m_attachment = IPC::Attachment(duplicatedHandle, m_size);
  • trunk/Source/WebKit2/UIProcess/Launcher/gtk/ProcessLauncherGtk.cpp

    r196548 r203155  
    3939#include <locale.h>
    4040#include <wtf/RunLoop.h>
     41#include <wtf/UniStdExtras.h>
    4142#include <wtf/glib/GLibUtilities.h>
    4243#include <wtf/glib/GUniquePtr.h>
     
    126127
    127128    // Don't expose the parent socket to potential future children.
    128     while (fcntl(socketPair.client, F_SETFD, FD_CLOEXEC) == -1)
    129         RELEASE_ASSERT(errno != EINTR);
     129    if (!setCloseOnExec(socketPair.client))
     130        RELEASE_ASSERT_NOT_REACHED();
    130131
    131132    close(socketPair.client);
Note: See TracChangeset for help on using the changeset viewer.