blob: 57ea5d8ff54ff142e41533585053a66d5f48f04a [file] [log] [blame]
Mathias Agopiana8a75162009-04-10 14:24:31 -07001/*
2 * Copyright (C) 2008 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 <limits.h>
18#include <errno.h>
19#include <pthread.h>
20
21#include <sys/mman.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24
25#include <cutils/log.h>
26#include <cutils/atomic.h>
27
28#include <hardware/hardware.h>
29#include <hardware/gralloc.h>
30
31#include "gralloc_priv.h"
32
33/*****************************************************************************/
34
35struct mapped_buffer_t {
36 intptr_t key;
37 int size;
38 int base;
39 int refCount;
40
Mathias Agopian988b8bd2009-05-04 14:26:56 -070041 mapped_buffer_t() { /* no init */ };
42 mapped_buffer_t(private_handle_t* hnd)
43 : key(intptr_t(hnd)), size(hnd->size), base(0), refCount(0) {
Mathias Agopiana8a75162009-04-10 14:24:31 -070044 }
45};
46
47static int compare(const mapped_buffer_t& a, const mapped_buffer_t& b) {
48 if (a.key < b.key) {
49 return -1;
50 }
51 if (a.key > b.key) {
52 return 1;
53 }
54 return 0;
55}
56
57struct mapped_buffers_t {
58 pthread_mutex_t mutex;
59 growable_sorted_array_t<mapped_buffer_t> records;
60
61 int map(gralloc_module_t const* module,
62 buffer_handle_t handle,
63 void** vaddr)
64 {
65 private_handle_t* hnd = (private_handle_t*)(handle);
Mathias Agopian988b8bd2009-05-04 14:26:56 -070066 mapped_buffer_t key(hnd);
Mathias Agopiana8a75162009-04-10 14:24:31 -070067 //printRecord(ANDROID_LOG_DEBUG, "map", &key);
Mathias Agopian988b8bd2009-05-04 14:26:56 -070068 int result = 0;
Mathias Agopiana8a75162009-04-10 14:24:31 -070069 mapped_buffer_t* record = 0;
70 pthread_mutex_lock(&mutex);
71 // From here to the end of the function we return by jumping to "exit"
72 // so that we always unlock the mutex.
73
74 int index = -1;
75 if (!records.find(key, index)) {
76 //LOGD("New item at %d", index);
77 void* mappedAddress = mmap(0, hnd->size,
78 PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0);
79 if (mappedAddress == MAP_FAILED) {
80 result = -errno;
81 //LOGE("map failed %d", result);
82 goto exit;
83 }
84 key.base = intptr_t(mappedAddress);
85 records.insert(index, key);
86 record = records.at(index);
87 } else {
88 //LOGD("Found existing mapping at index %d", index);
89 record = records.at(index);
90 if (record->size != key.size) {
91 LOGE("Requested a new mapping at the same offset"
92 "but with a different size");
93 printRecord(ANDROID_LOG_ERROR, "old", record);
94 printRecord(ANDROID_LOG_ERROR, "new", &key);
95 result = -EINVAL;
96 goto exit;
97 }
98 }
99 record->refCount += 1;
100 hnd->base = record->base;
101 *vaddr = (void*) record->base;
102 exit:
103 //print();
104 pthread_mutex_unlock(&mutex);
105 return result;
106 }
107
108 int unmap(gralloc_module_t const* module,
109 buffer_handle_t handle)
110 {
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700111 mapped_buffer_t key((private_handle_t*) handle);
Mathias Agopiana8a75162009-04-10 14:24:31 -0700112 //printRecord(ANDROID_LOG_DEBUG, "unmap", &key);
113 int index = -1;
Mathias Agopiana8a75162009-04-10 14:24:31 -0700114 int result = 0;
115 mapped_buffer_t* record = 0;
116 pthread_mutex_lock(&mutex);
117 // From here to the end of the function we return by jumping to "exit"
118 // so that we always unlock the mutex.
119
120 if (!records.find(key, index)) {
121 // This handle is not currently locked.
122 //LOGE("Could not find existing mapping near %d", index);
123 result = -ENOENT;
124 goto exit;
125 }
126 record = records.at(index);
127 //printRecord(ANDROID_LOG_DEBUG, "record", record);
128 record->refCount -= 1;
129 if (record->refCount == 0) {
130 //LOGD("Unmapping...");
131 if (munmap((void*)record->base, record->size) < 0) {
132 result = -errno;
133 //LOGE("Could not unmap %d", result);
134 }
135 records.remove(index);
136 ((private_handle_t*)handle)->base = 0;
137 }
138
139 exit:
140 //print();
141 pthread_mutex_unlock(&mutex);
142 return result;
143 }
144
145 void print() {
146 char prefix[16];
147 LOGD("Dumping records: count=%d size=%d", records.count, records.size);
148 for(int i=0; i<records.count ; i++) {
149 sprintf(prefix, "%3d", i);
150 printRecord(ANDROID_LOG_DEBUG, prefix, records.at(i));
151 }
152 }
153
154 void printRecord(int level, const char* what, mapped_buffer_t* record) {
155 LOG_PRI(level, LOG_TAG,
156 "%s: key=0x%08x, size=0x%08x, base=0x%08x refCount=%d",
157 what, int(record->key), record->size,
158 record->base, record->refCount);
159 }
160};
161
162static mapped_buffers_t sMappedBuffers = {
163 mutex: PTHREAD_MUTEX_INITIALIZER
164};
165
166/*****************************************************************************/
167
168int gralloc_map(gralloc_module_t const* module,
169 buffer_handle_t handle,
170 void** vaddr)
171{
172 if (private_handle_t::validate(handle) < 0)
173 return -EINVAL;
174
175 private_handle_t* hnd = (private_handle_t*)(handle);
176 if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
177 const private_module_t* m =
178 reinterpret_cast<const private_module_t*>(module);
179 handle = m->framebuffer;
180 }
181
182 int err = sMappedBuffers.map(module, handle, vaddr);
183
184 if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
185 *vaddr = (void*)hnd->base;
186 }
187
188 return err;
189}
190
191int gralloc_unmap(gralloc_module_t const* module,
192 buffer_handle_t handle)
193{
194 if (private_handle_t::validate(handle) < 0)
195 return -EINVAL;
196
197 private_handle_t* hnd = (private_handle_t*)(handle);
198 if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
199 const private_module_t* m =
200 reinterpret_cast<const private_module_t*>(module);
201 handle = m->framebuffer;
202 }
203
204 return sMappedBuffers.unmap(module, handle);
205}
206
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700207int gralloc_register_buffer(gralloc_module_t const* module,
208 buffer_handle_t handle)
209{
210 if (private_handle_t::validate(handle) < 0)
211 return -EINVAL;
212
213 // In this implementation, we don't need to do anything here
214
215 /* FIXME: we need to initialize the buffer as not mapped/not locked
216 * because it shouldn't when this function is called the first time
217 * in a new process. ideally these flags shouldn't be part of the
218 * handle, but instead maintained in the kernel or at least
219 * out-of-line
220 */
221 private_handle_t* hnd = (private_handle_t*)(handle);
222 hnd->base = 0;
Mathias Agopian485e6982009-05-05 20:21:57 -0700223 hnd->flags &= ~private_handle_t::PRIV_FLAGS_MAPPED;
224 hnd->lockState = 0;
225 hnd->writeOwner = 0;
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700226
227 return 0;
228}
229
230int gralloc_unregister_buffer(gralloc_module_t const* module,
231 buffer_handle_t handle)
232{
233 if (private_handle_t::validate(handle) < 0)
234 return -EINVAL;
235
236 /*
237 * If the buffer has been mapped during a lock operation, it's time
238 * to unmap it. It's an error to be here with a locked buffer.
239 * NOTE: the framebuffer is handled differently and is never unmapped.
240 */
241
242 private_handle_t* hnd = (private_handle_t*)(handle);
243
Mathias Agopian485e6982009-05-05 20:21:57 -0700244 LOGE_IF(hnd->lockState, "handle %p still locked (state=%08x)",
245 hnd, hnd->lockState);
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700246
247 if (hnd->flags & private_handle_t::PRIV_FLAGS_MAPPED) {
248 if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
249 gralloc_unmap(module, handle);
250 LOGE_IF(hnd->base,
251 "handle %p still mapped at %p",
252 hnd, (void*)hnd->base);
253 }
254 }
255
256 return 0;
257}
Mathias Agopiana8a75162009-04-10 14:24:31 -0700258
259int gralloc_lock(gralloc_module_t const* module,
260 buffer_handle_t handle, int usage,
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700261 int l, int t, int w, int h,
262 void** vaddr)
Mathias Agopiana8a75162009-04-10 14:24:31 -0700263{
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700264 if (private_handle_t::validate(handle) < 0)
265 return -EINVAL;
266
267 int err = 0;
268 private_handle_t* hnd = (private_handle_t*)(handle);
Mathias Agopian485e6982009-05-05 20:21:57 -0700269 int32_t current_value, new_value;
270 int retry;
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700271
Mathias Agopian485e6982009-05-05 20:21:57 -0700272 do {
273 current_value = hnd->lockState;
274 new_value = current_value;
275
276 if (current_value>>31) {
277 // already locked for write
278 LOGE("handle %p already locked for write", handle);
279 return -EBUSY;
280 } else if (current_value<<1) {
281 // already locked for read
282 if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
283 LOGE("handle %p already locked for read", handle);
284 return -EBUSY;
285 } else {
Mathias Agopian82f7c042009-06-03 19:03:26 -0700286 // this is not an error
287 //LOGD("%p already locked for read... count = %d",
288 // handle, (current_value & ~(1<<31)));
Mathias Agopian485e6982009-05-05 20:21:57 -0700289 }
290 }
291
292 // not currently locked
293 if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
294 // locking for write
295 new_value |= (1<<31);
296 }
297 new_value++;
298
299 retry = android_atomic_cmpxchg(current_value, new_value,
300 (volatile int32_t*)&hnd->lockState);
301 } while (retry);
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700302
Mathias Agopian485e6982009-05-05 20:21:57 -0700303 if (new_value>>31) {
304 // locking for write, store the tid
305 hnd->writeOwner = gettid();
306 }
307
308 if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700309 if (hnd->flags & private_handle_t::PRIV_FLAGS_MAPPED) {
310 *vaddr = (void*)hnd->base;
311 } else {
312 hnd->flags |= private_handle_t::PRIV_FLAGS_MAPPED;
313 err = gralloc_map(module, handle, vaddr);
314 }
315 }
Mathias Agopian485e6982009-05-05 20:21:57 -0700316
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700317 return err;
Mathias Agopiana8a75162009-04-10 14:24:31 -0700318}
319
320int gralloc_unlock(gralloc_module_t const* module,
321 buffer_handle_t handle)
322{
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700323 if (private_handle_t::validate(handle) < 0)
324 return -EINVAL;
325
326 private_handle_t* hnd = (private_handle_t*)(handle);
Mathias Agopian485e6982009-05-05 20:21:57 -0700327 int32_t current_value, new_value;
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700328
Mathias Agopian485e6982009-05-05 20:21:57 -0700329 do {
330 current_value = hnd->lockState;
331 new_value = current_value;
332
333 if (current_value>>31) {
334 // locked for write
335 if (hnd->writeOwner == gettid()) {
336 hnd->writeOwner = 0;
337 new_value &= ~(1<<31);
338 }
339 }
340
341 if ((new_value<<1) == 0) {
342 LOGE("handle %p not locked", handle);
343 return -EINVAL;
344 }
345
346 new_value--;
347
348 } while (android_atomic_cmpxchg(current_value, new_value,
349 (volatile int32_t*)&hnd->lockState));
350
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700351
352 /* FOR DEBUGGING
353 if (hnd->flags & private_handle_t::PRIV_FLAGS_MAPPED) {
354 if (gralloc_unmap(module, handle) == 0) {
355 hnd->flags &= ~private_handle_t::PRIV_FLAGS_MAPPED;
356 }
357 }
Mathias Agopian485e6982009-05-05 20:21:57 -0700358 */
359
Mathias Agopiana8a75162009-04-10 14:24:31 -0700360 return 0;
361}