Home | History | Annotate | Download | only in mac
      1 /*
      2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 
     28 #if ENABLE(PURGEABLE_MEMORY)
     29 
     30 #include "PurgeableBuffer.h"
     31 
     32 #include <mach/mach.h>
     33 #include <wtf/Assertions.h>
     34 #include <wtf/VMTags.h>
     35 
     36 namespace WebCore {
     37 
     38 // Purgeable buffers are allocated in multiples of the page size (4KB in common CPUs) so
     39 // it does not make sense for very small buffers. Set our minimum size to 16KB.
     40 static const size_t minPurgeableBufferSize = 4 * 4096;
     41 
     42 PurgeableBuffer::PurgeableBuffer(char* data, size_t size)
     43     : m_data(data)
     44     , m_size(size)
     45     , m_purgePriority(PurgeDefault)
     46     , m_state(NonVolatile)
     47 {
     48 }
     49 
     50 PurgeableBuffer::~PurgeableBuffer()
     51 {
     52     vm_deallocate(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), m_size);
     53 }
     54 
     55 PassOwnPtr<PurgeableBuffer> PurgeableBuffer::create(const char* data, size_t size)
     56 {
     57     if (size < minPurgeableBufferSize)
     58         return PassOwnPtr<PurgeableBuffer>();
     59 
     60     vm_address_t buffer = 0;
     61     kern_return_t ret = vm_allocate(mach_task_self(), &buffer, size, VM_FLAGS_PURGABLE | VM_FLAGS_ANYWHERE | VM_TAG_FOR_WEBCORE_PURGEABLE_MEMORY);
     62 
     63     ASSERT(ret == KERN_SUCCESS);
     64     if (ret != KERN_SUCCESS)
     65         return PassOwnPtr<PurgeableBuffer>();
     66 
     67     ret = vm_copy(mach_task_self(), reinterpret_cast<vm_address_t>(data), size, buffer);
     68 
     69     ASSERT(ret == KERN_SUCCESS);
     70     if (ret != KERN_SUCCESS) {
     71         vm_deallocate(mach_task_self(), buffer, size);
     72         return PassOwnPtr<PurgeableBuffer>();
     73     }
     74 
     75     return adoptPtr(new PurgeableBuffer(reinterpret_cast<char*>(buffer), size));
     76 }
     77 
     78 bool PurgeableBuffer::makePurgeable(bool purgeable)
     79 {
     80     if (purgeable) {
     81         if (m_state != NonVolatile)
     82             return true;
     83 
     84         int volatileGroup;
     85         if (m_purgePriority == PurgeFirst)
     86             volatileGroup = VM_VOLATILE_GROUP_0;
     87         else if (m_purgePriority == PurgeMiddle)
     88             volatileGroup = VM_VOLATILE_GROUP_4;
     89         else
     90             volatileGroup = VM_VOLATILE_GROUP_7;
     91 
     92         int state = VM_PURGABLE_VOLATILE | volatileGroup;
     93         // So apparently "purgeable" is the correct spelling and the API here is misspelled.
     94         kern_return_t ret = vm_purgable_control(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), VM_PURGABLE_SET_STATE, &state);
     95 
     96         if (ret != KERN_SUCCESS) {
     97             // If that failed we have no clue what state we are in so assume purged.
     98             m_state = Purged;
     99             return true;
    100         }
    101 
    102         m_state = Volatile;
    103         return true;
    104     }
    105 
    106     if (m_state == NonVolatile)
    107         return true;
    108     if (m_state == Purged)
    109         return false;
    110 
    111     int state = VM_PURGABLE_NONVOLATILE;
    112     kern_return_t ret = vm_purgable_control(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), VM_PURGABLE_SET_STATE, &state);
    113 
    114     if (ret != KERN_SUCCESS) {
    115         // If that failed we have no clue what state we are in so assume purged.
    116         m_state = Purged;
    117         return false;
    118     }
    119 
    120     m_state = state & VM_PURGABLE_EMPTY ? Purged : NonVolatile;
    121     return m_state == NonVolatile;
    122 }
    123 
    124 bool PurgeableBuffer::wasPurged() const
    125 {
    126     if (m_state == NonVolatile)
    127         return false;
    128     if (m_state == Purged)
    129         return true;
    130 
    131     int state;
    132     kern_return_t ret = vm_purgable_control(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), VM_PURGABLE_GET_STATE, &state);
    133 
    134     if (ret != KERN_SUCCESS) {
    135         // If that failed we have no clue what state we are in so assume purged.
    136         m_state = Purged;
    137         return true;
    138     }
    139 
    140     if (state & VM_PURGABLE_EMPTY) {
    141         m_state = Purged;
    142         return true;
    143     }
    144 
    145     return false;
    146 }
    147 
    148 const char* PurgeableBuffer::data() const
    149 {
    150     ASSERT(m_state == NonVolatile);
    151     return m_data;
    152 }
    153 
    154 }
    155 
    156 #endif // BUILDING_ON_TIGER
    157