/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "guest/vsoc/lib/gralloc_region_view.h" #include <common/vsoc/lib/lock_guard.h> #include <log/log.h> #include <sys/types.h> #include <uapi/vsoc_shm.h> #include <atomic> using vsoc::gralloc::GrallocRegionView; using vsoc::layout::gralloc::BufferEntry; using vsoc::layout::gralloc::GrallocBufferLayout; using vsoc::layout::gralloc::GrallocManagerLayout; namespace { template <typename T> inline T gralloc_align(T val) { return (val + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); } // Use the thread id to identify the original creator of a buffer. inline uint32_t gralloc_owned_value() { return gettid(); } } // namespace bool GrallocRegionView::Open() { if (!vsoc::ManagerRegionView<GrallocRegionView, GrallocManagerLayout>::Open()) { return false; } std::shared_ptr<vsoc::RegionControl> managed_region = vsoc::RegionControl::Open( GrallocManagerLayout::ManagedRegion::region_name); if (!managed_region) { LOG_FATAL("Unable to open managed region"); return false; } offset_of_buffer_memory_ = gralloc_align<uint32_t>( managed_region->region_desc().offset_of_region_data); total_buffer_memory_ = managed_region->region_size() - offset_of_buffer_memory_; // TODO(jemoreira): Handle the case of unexpected values in the region. return true; } int GrallocRegionView::AllocateBuffer(size_t size, uint32_t* begin_offset) { size = gralloc_align<size_t>(size); // Cache the value of buffer_count in shared memory. uint32_t buffer_count_local = 0; { vsoc::LockGuard<vsoc::layout::GuestLock>(&data()->new_buffer_lock); buffer_count_local = data()->buffer_count; } // Find a free buffer entry of the appropriate size. for (uint32_t idx = 0; idx < buffer_count_local; ++idx) { BufferEntry& entry = data()->buffers_table[idx]; if (entry.owned_by == VSOC_REGION_FREE && entry.buffer_size() == size) { int fd = control_->CreateFdScopedPermission( GrallocManagerLayout::ManagedRegion::region_name, pointer_to_region_offset(&entry.owned_by), gralloc_owned_value(), entry.buffer_begin, entry.buffer_end); if (fd >= 0) { if (begin_offset) { *begin_offset = entry.buffer_begin; } return fd; } } } // We couldn't find any suitable buffer, create one { vsoc::LockGuard<vsoc::layout::GuestLock>(&data()->new_buffer_lock); // don't use the cached value here!!! uint32_t idx = data()->buffer_count; if (pointer_to_region_offset(&data()->buffers_table[idx + 1]) > control_->region_size()) { ALOGE( "Out of memory in gralloc_manager (total: %d, used: %d, " "requested: %d)", static_cast<int>(control_->region_size()), static_cast<int>( pointer_to_region_offset(&data()->buffers_table[idx])), static_cast<int>(sizeof(data()->buffers_table[idx]))); return -ENOMEM; } if (total_buffer_memory_ - data()->allocated_buffer_memory < size) { ALOGE( "Out of memory in gralloc_memory (total: %d, used: %d, requested: %d)", static_cast<int>(total_buffer_memory_), static_cast<int>(data()->allocated_buffer_memory), static_cast<int>(size)); return -ENOMEM; } // Initialize the buffer entry and acquire ownership // Do it before increasing buffer_count so that another thread looking for // free entries doesn't find this one BufferEntry& new_entry = data()->buffers_table[idx]; new_entry.buffer_begin = offset_of_buffer_memory_ + data()->allocated_buffer_memory; data()->allocated_buffer_memory += size; new_entry.buffer_end = new_entry.buffer_begin + size; int fd = control_->CreateFdScopedPermission( GrallocManagerLayout::ManagedRegion::region_name, pointer_to_region_offset(&new_entry.owned_by), gralloc_owned_value(), new_entry.buffer_begin, new_entry.buffer_end); if (fd < 0) { LOG_FATAL( "Unexpected error while creating fd scoped permission over " "uncontested memory: %s", strerror(-fd)); return fd; } // Increment buffer_count now that the entry can't be taken from us data()->buffer_count++; if (begin_offset) { *begin_offset = new_entry.buffer_begin; } return fd; } }