1 /* 2 * Copyright (C) 2017 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 "guest/vsoc/lib/gralloc_region_view.h" 18 19 #include <common/vsoc/lib/lock_guard.h> 20 #include <log/log.h> 21 #include <sys/types.h> 22 #include <uapi/vsoc_shm.h> 23 #include <atomic> 24 25 using vsoc::gralloc::GrallocRegionView; 26 using vsoc::layout::gralloc::BufferEntry; 27 using vsoc::layout::gralloc::GrallocBufferLayout; 28 using vsoc::layout::gralloc::GrallocManagerLayout; 29 30 namespace { 31 template <typename T> 32 inline T gralloc_align(T val) { 33 return (val + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); 34 } 35 36 // Use the thread id to identify the original creator of a buffer. 37 inline uint32_t gralloc_owned_value() { 38 return gettid(); 39 } 40 41 } // namespace 42 43 bool GrallocRegionView::Open() { 44 if (!vsoc::ManagerRegionView<GrallocRegionView, GrallocManagerLayout>::Open()) { 45 return false; 46 } 47 std::shared_ptr<vsoc::RegionControl> managed_region = 48 vsoc::RegionControl::Open( 49 GrallocManagerLayout::ManagedRegion::region_name); 50 if (!managed_region) { 51 LOG_FATAL("Unable to open managed region"); 52 return false; 53 } 54 offset_of_buffer_memory_ = gralloc_align<uint32_t>( 55 managed_region->region_desc().offset_of_region_data); 56 total_buffer_memory_ = 57 managed_region->region_size() - offset_of_buffer_memory_; 58 59 // TODO(jemoreira): Handle the case of unexpected values in the region. 60 return true; 61 } 62 63 int GrallocRegionView::AllocateBuffer(size_t size, uint32_t* begin_offset) { 64 size = gralloc_align<size_t>(size); 65 // Cache the value of buffer_count in shared memory. 66 uint32_t buffer_count_local = 0; 67 { 68 vsoc::LockGuard<vsoc::layout::GuestLock>(&data()->new_buffer_lock); 69 buffer_count_local = data()->buffer_count; 70 } 71 // Find a free buffer entry of the appropriate size. 72 for (uint32_t idx = 0; idx < buffer_count_local; ++idx) { 73 BufferEntry& entry = data()->buffers_table[idx]; 74 if (entry.owned_by == VSOC_REGION_FREE && entry.buffer_size() == size) { 75 int fd = control_->CreateFdScopedPermission( 76 GrallocManagerLayout::ManagedRegion::region_name, 77 pointer_to_region_offset(&entry.owned_by), 78 gralloc_owned_value(), 79 entry.buffer_begin, 80 entry.buffer_end); 81 if (fd >= 0) { 82 if (begin_offset) { 83 *begin_offset = entry.buffer_begin; 84 } 85 return fd; 86 } 87 } 88 } 89 90 // We couldn't find any suitable buffer, create one 91 { 92 vsoc::LockGuard<vsoc::layout::GuestLock>(&data()->new_buffer_lock); 93 // don't use the cached value here!!! 94 uint32_t idx = data()->buffer_count; 95 if (pointer_to_region_offset(&data()->buffers_table[idx + 1]) > 96 control_->region_size()) { 97 ALOGE( 98 "Out of memory in gralloc_manager (total: %d, used: %d, " 99 "requested: %d)", 100 static_cast<int>(control_->region_size()), 101 static_cast<int>( 102 pointer_to_region_offset(&data()->buffers_table[idx])), 103 static_cast<int>(sizeof(data()->buffers_table[idx]))); 104 return -ENOMEM; 105 } 106 if (total_buffer_memory_ - data()->allocated_buffer_memory < size) { 107 ALOGE( 108 "Out of memory in gralloc_memory (total: %d, used: %d, requested: %d)", 109 static_cast<int>(total_buffer_memory_), 110 static_cast<int>(data()->allocated_buffer_memory), 111 static_cast<int>(size)); 112 return -ENOMEM; 113 } 114 // Initialize the buffer entry and acquire ownership 115 // Do it before increasing buffer_count so that another thread looking for 116 // free entries doesn't find this one 117 BufferEntry& new_entry = data()->buffers_table[idx]; 118 new_entry.buffer_begin = 119 offset_of_buffer_memory_ + data()->allocated_buffer_memory; 120 data()->allocated_buffer_memory += size; 121 new_entry.buffer_end = new_entry.buffer_begin + size; 122 int fd = control_->CreateFdScopedPermission( 123 GrallocManagerLayout::ManagedRegion::region_name, 124 pointer_to_region_offset(&new_entry.owned_by), 125 gralloc_owned_value(), 126 new_entry.buffer_begin, 127 new_entry.buffer_end); 128 if (fd < 0) { 129 LOG_FATAL( 130 "Unexpected error while creating fd scoped permission over " 131 "uncontested memory: %s", 132 strerror(-fd)); 133 return fd; 134 } 135 // Increment buffer_count now that the entry can't be taken from us 136 data()->buffer_count++; 137 if (begin_offset) { 138 *begin_offset = new_entry.buffer_begin; 139 } 140 return fd; 141 } 142 } 143