Home | History | Annotate | Download | only in libutils
      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 #define LOG_TAG "sharedbuffer"
     18 
     19 #include "SharedBuffer.h"
     20 
     21 #include <stdlib.h>
     22 #include <string.h>
     23 
     24 #include <log/log.h>
     25 
     26 // ---------------------------------------------------------------------------
     27 
     28 namespace android {
     29 
     30 SharedBuffer* SharedBuffer::alloc(size_t size)
     31 {
     32     // Don't overflow if the combined size of the buffer / header is larger than
     33     // size_max.
     34     LOG_ALWAYS_FATAL_IF((size >= (SIZE_MAX - sizeof(SharedBuffer))),
     35                         "Invalid buffer size %zu", size);
     36 
     37     SharedBuffer* sb = static_cast<SharedBuffer *>(malloc(sizeof(SharedBuffer) + size));
     38     if (sb) {
     39         // Should be std::atomic_init(&sb->mRefs, 1);
     40         // But that generates a warning with some compilers.
     41         // The following is OK on Android-supported platforms.
     42         sb->mRefs.store(1, std::memory_order_relaxed);
     43         sb->mSize = size;
     44     }
     45     return sb;
     46 }
     47 
     48 
     49 void SharedBuffer::dealloc(const SharedBuffer* released)
     50 {
     51     free(const_cast<SharedBuffer*>(released));
     52 }
     53 
     54 SharedBuffer* SharedBuffer::edit() const
     55 {
     56     if (onlyOwner()) {
     57         return const_cast<SharedBuffer*>(this);
     58     }
     59     SharedBuffer* sb = alloc(mSize);
     60     if (sb) {
     61         memcpy(sb->data(), data(), size());
     62         release();
     63     }
     64     return sb;
     65 }
     66 
     67 SharedBuffer* SharedBuffer::editResize(size_t newSize) const
     68 {
     69     if (onlyOwner()) {
     70         SharedBuffer* buf = const_cast<SharedBuffer*>(this);
     71         if (buf->mSize == newSize) return buf;
     72         // Don't overflow if the combined size of the new buffer / header is larger than
     73         // size_max.
     74         LOG_ALWAYS_FATAL_IF((newSize >= (SIZE_MAX - sizeof(SharedBuffer))),
     75                             "Invalid buffer size %zu", newSize);
     76 
     77         buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize);
     78         if (buf != NULL) {
     79             buf->mSize = newSize;
     80             return buf;
     81         }
     82     }
     83     SharedBuffer* sb = alloc(newSize);
     84     if (sb) {
     85         const size_t mySize = mSize;
     86         memcpy(sb->data(), data(), newSize < mySize ? newSize : mySize);
     87         release();
     88     }
     89     return sb;
     90 }
     91 
     92 SharedBuffer* SharedBuffer::attemptEdit() const
     93 {
     94     if (onlyOwner()) {
     95         return const_cast<SharedBuffer*>(this);
     96     }
     97     return 0;
     98 }
     99 
    100 SharedBuffer* SharedBuffer::reset(size_t new_size) const
    101 {
    102     // cheap-o-reset.
    103     SharedBuffer* sb = alloc(new_size);
    104     if (sb) {
    105         release();
    106     }
    107     return sb;
    108 }
    109 
    110 void SharedBuffer::acquire() const {
    111     mRefs.fetch_add(1, std::memory_order_relaxed);
    112 }
    113 
    114 int32_t SharedBuffer::release(uint32_t flags) const
    115 {
    116     const bool useDealloc = ((flags & eKeepStorage) == 0);
    117     if (onlyOwner()) {
    118         // Since we're the only owner, our reference count goes to zero.
    119         mRefs.store(0, std::memory_order_relaxed);
    120         if (useDealloc) {
    121             dealloc(this);
    122         }
    123         // As the only owner, our previous reference count was 1.
    124         return 1;
    125     }
    126     // There's multiple owners, we need to use an atomic decrement.
    127     int32_t prevRefCount = mRefs.fetch_sub(1, std::memory_order_release);
    128     if (prevRefCount == 1) {
    129         // We're the last reference, we need the acquire fence.
    130         atomic_thread_fence(std::memory_order_acquire);
    131         if (useDealloc) {
    132             dealloc(this);
    133         }
    134     }
    135     return prevRefCount;
    136 }
    137 
    138 
    139 }; // namespace android
    140