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 #ifndef BUILDING_ON_TIGER
     29 
     30 #include "PurgeableBuffer.h"
     31 
     32 #include <mach/mach.h>
     33 #include <wtf/Assertions.h>
     34 
     35 namespace WebCore {
     36 
     37 static const size_t minPurgeableBufferSize = 4096; // one page
     38 
     39 PurgeableBuffer::PurgeableBuffer(char* data, size_t size)
     40     : m_data(data)
     41     , m_size(size)
     42     , m_purgePriority(PurgeDefault)
     43     , m_state(NonVolatile)
     44 {
     45 }
     46 
     47 PurgeableBuffer::~PurgeableBuffer()
     48 {
     49     vm_deallocate(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), m_size);
     50 }
     51 
     52 PurgeableBuffer* PurgeableBuffer::create(const char* data, size_t size)
     53 {
     54     if (size < minPurgeableBufferSize)
     55         return 0;
     56 
     57     vm_address_t buffer = 0;
     58     kern_return_t ret = vm_allocate(mach_task_self(), &buffer, size, VM_FLAGS_PURGABLE | VM_FLAGS_ANYWHERE);
     59 
     60     ASSERT(ret == KERN_SUCCESS);
     61     if (ret != KERN_SUCCESS)
     62         return 0;
     63 
     64     ret = vm_copy(mach_task_self(), reinterpret_cast<vm_address_t>(data), size, buffer);
     65 
     66     ASSERT(ret == KERN_SUCCESS);
     67     if (ret != KERN_SUCCESS) {
     68         vm_deallocate(mach_task_self(), buffer, size);
     69         return 0;
     70     }
     71 
     72     return new PurgeableBuffer(reinterpret_cast<char*>(buffer), size);
     73 }
     74 
     75 bool PurgeableBuffer::makePurgeable(bool purgeable)
     76 {
     77     if (purgeable) {
     78         if (m_state != NonVolatile)
     79             return true;
     80 
     81         int volatileGroup;
     82         if (m_purgePriority == PurgeFirst)
     83             volatileGroup = VM_VOLATILE_GROUP_0;
     84         else if (m_purgePriority == PurgeMiddle)
     85             volatileGroup = VM_VOLATILE_GROUP_4;
     86         else
     87             volatileGroup = VM_VOLATILE_GROUP_7;
     88 
     89         int state = VM_PURGABLE_VOLATILE | volatileGroup;
     90         // So apparently "purgeable" is the correct spelling and the API here is misspelled.
     91         kern_return_t ret = vm_purgable_control(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), VM_PURGABLE_SET_STATE, &state);
     92 
     93         if (ret != KERN_SUCCESS) {
     94             // If that failed we have no clue what state we are in so assume purged.
     95             m_state = Purged;
     96             return true;
     97         }
     98 
     99         m_state = Volatile;
    100         return true;
    101     }
    102 
    103     if (m_state == NonVolatile)
    104         return true;
    105     if (m_state == Purged)
    106         return false;
    107 
    108     int state = VM_PURGABLE_NONVOLATILE;
    109     kern_return_t ret = vm_purgable_control(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), VM_PURGABLE_SET_STATE, &state);
    110 
    111     if (ret != KERN_SUCCESS) {
    112         // If that failed we have no clue what state we are in so assume purged.
    113         m_state = Purged;
    114         return false;
    115     }
    116 
    117     m_state = state & VM_PURGABLE_EMPTY ? Purged : NonVolatile;
    118     return m_state == NonVolatile;
    119 }
    120 
    121 bool PurgeableBuffer::wasPurged() const
    122 {
    123     if (m_state == NonVolatile)
    124         return false;
    125     if (m_state == Purged)
    126         return true;
    127 
    128     int state;
    129     kern_return_t ret = vm_purgable_control(mach_task_self(), reinterpret_cast<vm_address_t>(m_data), VM_PURGABLE_GET_STATE, &state);
    130 
    131     if (ret != KERN_SUCCESS) {
    132         // If that failed we have no clue what state we are in so assume purged.
    133         m_state = Purged;
    134         return true;
    135     }
    136 
    137     if (state & VM_PURGABLE_EMPTY) {
    138         m_state = Purged;
    139         return true;
    140     }
    141 
    142     return false;
    143 }
    144 
    145 void PurgeableBuffer::setPurgePriority(PurgePriority priority)
    146 {
    147     if (priority == m_purgePriority)
    148         return;
    149     m_purgePriority = priority;
    150     if (m_state != Volatile)
    151         return;
    152     m_state = NonVolatile;
    153     makePurgeable(true);
    154 }
    155 
    156 const char* PurgeableBuffer::data() const
    157 {
    158     ASSERT(m_state == NonVolatile);
    159     return m_data;
    160 }
    161 
    162 }
    163 
    164 #endif // BUILDING_ON_TIGER
    165