blob: 2c42f57cedc7a3befa55a3d0c1a162e066dabdad [file] [log] [blame]
Cody Schuffelen134ff032019-11-22 00:25:32 -08001/*
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
25using vsoc::gralloc::GrallocRegionView;
26using vsoc::layout::gralloc::BufferEntry;
27using vsoc::layout::gralloc::GrallocBufferLayout;
28using vsoc::layout::gralloc::GrallocManagerLayout;
29
30namespace {
31template <typename T>
32inline 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.
37inline uint32_t gralloc_owned_value() {
38 return gettid();
39}
40
41} // namespace
42
43bool 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
63int 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}