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