Home | History | Annotate | Download | only in unix
      1 /*
      2  * Copyright (C) 2010 Apple Inc. All rights reserved.
      3  * Copyright (c) 2010 University of Szeged
      4  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     17  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     19  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     25  * THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "config.h"
     29 #include "SharedMemory.h"
     30 
     31 #include "ArgumentDecoder.h"
     32 #include "ArgumentEncoder.h"
     33 #include "WebCoreArgumentCoders.h"
     34 #include <errno.h>
     35 #include <fcntl.h>
     36 #include <stdlib.h>
     37 #include <sys/mman.h>
     38 #include <sys/stat.h>
     39 #include <sys/types.h>
     40 #include <unistd.h>
     41 #include <wtf/Assertions.h>
     42 #include <wtf/CurrentTime.h>
     43 
     44 #if PLATFORM(QT)
     45 #include <QDir>
     46 #elif PLATFORM(GTK)
     47 #include <wtf/gobject/GOwnPtr.h>
     48 #endif
     49 
     50 namespace WebKit {
     51 
     52 SharedMemory::Handle::Handle()
     53     : m_fileDescriptor(-1)
     54     , m_size(0)
     55 {
     56 }
     57 
     58 SharedMemory::Handle::~Handle()
     59 {
     60     if (!isNull())
     61         while (close(m_fileDescriptor) == -1 && errno == EINTR) { }
     62 }
     63 
     64 bool SharedMemory::Handle::isNull() const
     65 {
     66     return m_fileDescriptor == -1;
     67 }
     68 
     69 void SharedMemory::Handle::encode(CoreIPC::ArgumentEncoder* encoder) const
     70 {
     71     ASSERT(!isNull());
     72 
     73     encoder->encode(releaseToAttachment());
     74 }
     75 
     76 bool SharedMemory::Handle::decode(CoreIPC::ArgumentDecoder* decoder, Handle& handle)
     77 {
     78     ASSERT_ARG(handle, !handle.m_size);
     79     ASSERT_ARG(handle, handle.isNull());
     80 
     81     CoreIPC::Attachment attachment;
     82     if (!decoder->decode(attachment))
     83         return false;
     84 
     85     handle.adoptFromAttachment(attachment.releaseFileDescriptor(), attachment.size());
     86     return true;
     87 }
     88 
     89 CoreIPC::Attachment SharedMemory::Handle::releaseToAttachment() const
     90 {
     91     ASSERT(!isNull());
     92 
     93     int temp = m_fileDescriptor;
     94     m_fileDescriptor = -1;
     95     return CoreIPC::Attachment(temp, m_size);
     96 }
     97 
     98 void SharedMemory::Handle::adoptFromAttachment(int fileDescriptor, size_t size)
     99 {
    100     ASSERT(!m_size);
    101     ASSERT(isNull());
    102 
    103     m_fileDescriptor = fileDescriptor;
    104     m_size = size;
    105 }
    106 
    107 PassRefPtr<SharedMemory> SharedMemory::create(size_t size)
    108 {
    109 #if PLATFORM(QT)
    110     QString tempName = QDir::temp().filePath(QLatin1String("qwkshm.XXXXXX"));
    111     QByteArray tempNameCSTR = tempName.toLocal8Bit();
    112     char* tempNameC = tempNameCSTR.data();
    113 #elif PLATFORM(GTK)
    114     GOwnPtr<gchar> tempName(g_build_filename(g_get_tmp_dir(), "WK2SharedMemoryXXXXXX", NULL));
    115     gchar* tempNameC = tempName.get();
    116 #endif
    117 
    118     int fileDescriptor;
    119     while ((fileDescriptor = mkstemp(tempNameC)) == -1) {
    120         if (errno != EINTR)
    121             return 0;
    122     }
    123     while (fcntl(fileDescriptor, F_SETFD, FD_CLOEXEC) == -1) {
    124         if (errno != EINTR) {
    125             while (close(fileDescriptor) == -1 && errno == EINTR) { }
    126             unlink(tempNameC);
    127             return 0;
    128         }
    129     }
    130 
    131     while (ftruncate(fileDescriptor, size) == -1) {
    132         if (errno != EINTR) {
    133             while (close(fileDescriptor) == -1 && errno == EINTR) { }
    134             unlink(tempNameC);
    135             return 0;
    136         }
    137     }
    138 
    139     void* data = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileDescriptor, 0);
    140     if (data == MAP_FAILED) {
    141         while (close(fileDescriptor) == -1 && errno == EINTR) { }
    142         unlink(tempNameC);
    143         return 0;
    144     }
    145 
    146     unlink(tempNameC);
    147 
    148     RefPtr<SharedMemory> instance = adoptRef(new SharedMemory());
    149     instance->m_data = data;
    150     instance->m_fileDescriptor = fileDescriptor;
    151     instance->m_size = size;
    152     return instance.release();
    153 }
    154 
    155 static inline int accessModeMMap(SharedMemory::Protection protection)
    156 {
    157     switch (protection) {
    158     case SharedMemory::ReadOnly:
    159         return PROT_READ;
    160     case SharedMemory::ReadWrite:
    161         return PROT_READ | PROT_WRITE;
    162     }
    163 
    164     ASSERT_NOT_REACHED();
    165     return PROT_READ | PROT_WRITE;
    166 }
    167 
    168 PassRefPtr<SharedMemory> SharedMemory::create(const Handle& handle, Protection protection)
    169 {
    170     ASSERT(!handle.isNull());
    171 
    172     void* data = mmap(0, handle.m_size, accessModeMMap(protection), MAP_SHARED, handle.m_fileDescriptor, 0);
    173     if (data == MAP_FAILED)
    174         return 0;
    175 
    176     RefPtr<SharedMemory> instance = adoptRef(new SharedMemory());
    177     instance->m_data = data;
    178     instance->m_fileDescriptor = handle.m_fileDescriptor;
    179     instance->m_size = handle.m_size;
    180     handle.m_fileDescriptor = -1;
    181     return instance;
    182 }
    183 
    184 SharedMemory::~SharedMemory()
    185 {
    186     munmap(m_data, m_size);
    187     while (close(m_fileDescriptor) == -1 && errno == EINTR) { }
    188 }
    189 
    190 static inline int accessModeFile(SharedMemory::Protection protection)
    191 {
    192     switch (protection) {
    193     case SharedMemory::ReadOnly:
    194         return O_RDONLY;
    195     case SharedMemory::ReadWrite:
    196         return O_RDWR;
    197     }
    198 
    199     ASSERT_NOT_REACHED();
    200     return O_RDWR;
    201 }
    202 
    203 bool SharedMemory::createHandle(Handle& handle, Protection protection)
    204 {
    205     ASSERT_ARG(handle, !handle.m_size);
    206     ASSERT_ARG(handle, handle.isNull());
    207 
    208     int duplicatedHandle;
    209     while ((duplicatedHandle = dup(m_fileDescriptor)) == -1) {
    210         if (errno != EINTR) {
    211             ASSERT_NOT_REACHED();
    212             return false;
    213         }
    214     }
    215 
    216     while ((fcntl(duplicatedHandle, F_SETFD, FD_CLOEXEC | accessModeFile(protection)) == -1)) {
    217         if (errno != EINTR) {
    218             ASSERT_NOT_REACHED();
    219             while (close(duplicatedHandle) == -1 && errno == EINTR) { }
    220             return false;
    221         }
    222     }
    223     handle.m_fileDescriptor = duplicatedHandle;
    224     handle.m_size = m_size;
    225     return true;
    226 }
    227 
    228 unsigned SharedMemory::systemPageSize()
    229 {
    230     static unsigned pageSize = 0;
    231 
    232     if (!pageSize)
    233         pageSize = getpagesize();
    234 
    235     return pageSize;
    236 }
    237 
    238 } // namespace WebKit
    239