1/* 2 * Copyright (C) 2005 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stdlib.h> 18#include <string.h> 19 20#include <log/log.h> 21 22#include "SharedBuffer.h" 23 24// --------------------------------------------------------------------------- 25 26namespace android { 27 28SharedBuffer* SharedBuffer::alloc(size_t size) 29{ 30 // Don't overflow if the combined size of the buffer / header is larger than 31 // size_max. 32 LOG_ALWAYS_FATAL_IF((size >= (SIZE_MAX - sizeof(SharedBuffer))), 33 "Invalid buffer size %zu", size); 34 35 SharedBuffer* sb = static_cast<SharedBuffer *>(malloc(sizeof(SharedBuffer) + size)); 36 if (sb) { 37 // Should be std::atomic_init(&sb->mRefs, 1); 38 // But that generates a warning with some compilers. 39 // The following is OK on Android-supported platforms. 40 sb->mRefs.store(1, std::memory_order_relaxed); 41 sb->mSize = size; 42 } 43 return sb; 44} 45 46 47void SharedBuffer::dealloc(const SharedBuffer* released) 48{ 49 free(const_cast<SharedBuffer*>(released)); 50} 51 52SharedBuffer* SharedBuffer::edit() const 53{ 54 if (onlyOwner()) { 55 return const_cast<SharedBuffer*>(this); 56 } 57 SharedBuffer* sb = alloc(mSize); 58 if (sb) { 59 memcpy(sb->data(), data(), size()); 60 release(); 61 } 62 return sb; 63} 64 65SharedBuffer* SharedBuffer::editResize(size_t newSize) const 66{ 67 if (onlyOwner()) { 68 SharedBuffer* buf = const_cast<SharedBuffer*>(this); 69 if (buf->mSize == newSize) return buf; 70 // Don't overflow if the combined size of the new buffer / header is larger than 71 // size_max. 72 LOG_ALWAYS_FATAL_IF((newSize >= (SIZE_MAX - sizeof(SharedBuffer))), 73 "Invalid buffer size %zu", newSize); 74 75 buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize); 76 if (buf != NULL) { 77 buf->mSize = newSize; 78 return buf; 79 } 80 } 81 SharedBuffer* sb = alloc(newSize); 82 if (sb) { 83 const size_t mySize = mSize; 84 memcpy(sb->data(), data(), newSize < mySize ? newSize : mySize); 85 release(); 86 } 87 return sb; 88} 89 90SharedBuffer* SharedBuffer::attemptEdit() const 91{ 92 if (onlyOwner()) { 93 return const_cast<SharedBuffer*>(this); 94 } 95 return 0; 96} 97 98SharedBuffer* SharedBuffer::reset(size_t new_size) const 99{ 100 // cheap-o-reset. 101 SharedBuffer* sb = alloc(new_size); 102 if (sb) { 103 release(); 104 } 105 return sb; 106} 107 108void SharedBuffer::acquire() const { 109 mRefs.fetch_add(1, std::memory_order_relaxed); 110} 111 112int32_t SharedBuffer::release(uint32_t flags) const 113{ 114 int32_t prev = 1; 115 if (onlyOwner() || ((prev = mRefs.fetch_sub(1, std::memory_order_release) == 1) 116 && (atomic_thread_fence(std::memory_order_acquire), true))) { 117 mRefs.store(0, std::memory_order_relaxed); 118 if ((flags & eKeepStorage) == 0) { 119 free(const_cast<SharedBuffer*>(this)); 120 } 121 } 122 return prev; 123} 124 125 126}; // namespace android 127