blob: 75a9bb6ff143ca5d89c46ef79fdae4cde7e3c335 [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>
Mathias Agopian8c4ab1f2009-06-11 16:32:05 -070020#include <unistd.h>
Marco Nelissena4b587c2009-07-07 09:29:00 -070021#include <string.h>
Mathias Agopiana8a75162009-04-10 14:24:31 -070022
23#include <sys/mman.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26
27#include <cutils/log.h>
28#include <cutils/atomic.h>
29
30#include <hardware/hardware.h>
31#include <hardware/gralloc.h>
32
33#include "gralloc_priv.h"
34
Mathias Agopian8c4ab1f2009-06-11 16:32:05 -070035
36// we need this for now because pmem cannot mmap at an offset
37#define PMEM_HACK 1
38
Marco Nelissena4b587c2009-07-07 09:29:00 -070039/* desktop Linux needs a little help with gettid() */
40#if defined(ARCH_X86) && !defined(HAVE_ANDROID_OS)
41#define __KERNEL__
42# include <linux/unistd.h>
43pid_t gettid() { return syscall(__NR_gettid);}
44#undef __KERNEL__
45#endif
46
Mathias Agopiana8a75162009-04-10 14:24:31 -070047/*****************************************************************************/
48
Mathias Agopian51156652009-06-09 18:55:49 -070049static int gralloc_map(gralloc_module_t const* module,
Mathias Agopiana8a75162009-04-10 14:24:31 -070050 buffer_handle_t handle,
51 void** vaddr)
52{
Mathias Agopian51156652009-06-09 18:55:49 -070053 private_handle_t* hnd = (private_handle_t*)handle;
54 if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
Mathias Agopian8c4ab1f2009-06-11 16:32:05 -070055 size_t size = hnd->size;
56#if PMEM_HACK
57 size += hnd->offset;
58#endif
59 void* mappedAddress = mmap(0, size,
60 PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0);
Mathias Agopian51156652009-06-09 18:55:49 -070061 if (mappedAddress == MAP_FAILED) {
Mathias Agopian8c4ab1f2009-06-11 16:32:05 -070062 LOGE("Could not mmap %s", strerror(errno));
Mathias Agopian51156652009-06-09 18:55:49 -070063 return -errno;
64 }
Mathias Agopian8c4ab1f2009-06-11 16:32:05 -070065 hnd->base = intptr_t(mappedAddress) + hnd->offset;
66 //LOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",
67 // hnd->fd, hnd->offset, hnd->size, mappedAddress);
Mathias Agopiana8a75162009-04-10 14:24:31 -070068 }
Mathias Agopian51156652009-06-09 18:55:49 -070069 *vaddr = (void*)hnd->base;
70 return 0;
Mathias Agopiana8a75162009-04-10 14:24:31 -070071}
72
Mathias Agopian51156652009-06-09 18:55:49 -070073static int gralloc_unmap(gralloc_module_t const* module,
Mathias Agopiana8a75162009-04-10 14:24:31 -070074 buffer_handle_t handle)
75{
Mathias Agopian51156652009-06-09 18:55:49 -070076 private_handle_t* hnd = (private_handle_t*)handle;
77 if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
78 if (munmap((void*)hnd->base, hnd->size) < 0) {
Mathias Agopian8c4ab1f2009-06-11 16:32:05 -070079 LOGE("Could not unmap %s", strerror(errno));
Mathias Agopian51156652009-06-09 18:55:49 -070080 }
Mathias Agopiana8a75162009-04-10 14:24:31 -070081 }
Mathias Agopian51156652009-06-09 18:55:49 -070082 hnd->base = 0;
83 return 0;
Mathias Agopiana8a75162009-04-10 14:24:31 -070084}
85
Mathias Agopian51156652009-06-09 18:55:49 -070086/*****************************************************************************/
87
88static pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER;
89
90/*****************************************************************************/
91
Mathias Agopian988b8bd2009-05-04 14:26:56 -070092int gralloc_register_buffer(gralloc_module_t const* module,
93 buffer_handle_t handle)
94{
95 if (private_handle_t::validate(handle) < 0)
96 return -EINVAL;
Mathias Agopian51156652009-06-09 18:55:49 -070097
Mathias Agopian988b8bd2009-05-04 14:26:56 -070098 // In this implementation, we don't need to do anything here
99
Mathias Agopian51156652009-06-09 18:55:49 -0700100 /* NOTE: we need to initialize the buffer as not mapped/not locked
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700101 * because it shouldn't when this function is called the first time
Mathias Agopian51156652009-06-09 18:55:49 -0700102 * in a new process. Ideally these flags shouldn't be part of the
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700103 * handle, but instead maintained in the kernel or at least
104 * out-of-line
105 */
Mathias Agopian8c4ab1f2009-06-11 16:32:05 -0700106
107 // if this handle was created in this process, then we keep it as is.
Mathias Agopian51156652009-06-09 18:55:49 -0700108 private_handle_t* hnd = (private_handle_t*)handle;
Mathias Agopian8c4ab1f2009-06-11 16:32:05 -0700109 if (hnd->pid != getpid()) {
110 hnd->base = 0;
111 hnd->lockState = 0;
112 hnd->writeOwner = 0;
113 }
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700114 return 0;
115}
116
117int gralloc_unregister_buffer(gralloc_module_t const* module,
118 buffer_handle_t handle)
119{
120 if (private_handle_t::validate(handle) < 0)
121 return -EINVAL;
122
123 /*
124 * If the buffer has been mapped during a lock operation, it's time
Mathias Agopian51156652009-06-09 18:55:49 -0700125 * to un-map it. It's an error to be here with a locked buffer.
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700126 * NOTE: the framebuffer is handled differently and is never unmapped.
127 */
128
Mathias Agopian51156652009-06-09 18:55:49 -0700129 private_handle_t* hnd = (private_handle_t*)handle;
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700130
Mathias Agopian51156652009-06-09 18:55:49 -0700131 LOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK,
132 "handle %p still locked (state=%08x)",
Mathias Agopian485e6982009-05-05 20:21:57 -0700133 hnd, hnd->lockState);
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700134
Mathias Agopian8c4ab1f2009-06-11 16:32:05 -0700135 // never unmap buffers that were created in this process
136 if (hnd->pid != getpid()) {
137 if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) {
138 gralloc_unmap(module, handle);
139 }
140 hnd->base = 0;
141 hnd->lockState = 0;
142 hnd->writeOwner = 0;
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700143 }
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700144 return 0;
145}
Mathias Agopiana8a75162009-04-10 14:24:31 -0700146
147int gralloc_lock(gralloc_module_t const* module,
148 buffer_handle_t handle, int usage,
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700149 int l, int t, int w, int h,
150 void** vaddr)
Mathias Agopiana8a75162009-04-10 14:24:31 -0700151{
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700152 if (private_handle_t::validate(handle) < 0)
153 return -EINVAL;
154
155 int err = 0;
Mathias Agopian51156652009-06-09 18:55:49 -0700156 private_handle_t* hnd = (private_handle_t*)handle;
Mathias Agopian485e6982009-05-05 20:21:57 -0700157 int32_t current_value, new_value;
158 int retry;
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700159
Mathias Agopian485e6982009-05-05 20:21:57 -0700160 do {
161 current_value = hnd->lockState;
162 new_value = current_value;
Mathias Agopian51156652009-06-09 18:55:49 -0700163
164 if (current_value & private_handle_t::LOCK_STATE_WRITE) {
Mathias Agopian485e6982009-05-05 20:21:57 -0700165 // already locked for write
166 LOGE("handle %p already locked for write", handle);
167 return -EBUSY;
Mathias Agopian51156652009-06-09 18:55:49 -0700168 } else if (current_value & private_handle_t::LOCK_STATE_READ_MASK) {
Mathias Agopian485e6982009-05-05 20:21:57 -0700169 // already locked for read
170 if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
171 LOGE("handle %p already locked for read", handle);
172 return -EBUSY;
173 } else {
Mathias Agopian82f7c042009-06-03 19:03:26 -0700174 // this is not an error
175 //LOGD("%p already locked for read... count = %d",
176 // handle, (current_value & ~(1<<31)));
Mathias Agopian485e6982009-05-05 20:21:57 -0700177 }
178 }
179
180 // not currently locked
181 if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
182 // locking for write
Mathias Agopian51156652009-06-09 18:55:49 -0700183 new_value |= private_handle_t::LOCK_STATE_WRITE;
Mathias Agopian485e6982009-05-05 20:21:57 -0700184 }
185 new_value++;
186
187 retry = android_atomic_cmpxchg(current_value, new_value,
188 (volatile int32_t*)&hnd->lockState);
189 } while (retry);
Mathias Agopian51156652009-06-09 18:55:49 -0700190
191 if (new_value & private_handle_t::LOCK_STATE_WRITE) {
Mathias Agopian485e6982009-05-05 20:21:57 -0700192 // locking for write, store the tid
193 hnd->writeOwner = gettid();
194 }
195
196 if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
Mathias Agopian51156652009-06-09 18:55:49 -0700197 if (!(current_value & private_handle_t::LOCK_STATE_MAPPED)) {
198 // we need to map for real
199 pthread_mutex_t* const lock = &sMapLock;
200 pthread_mutex_lock(lock);
201 if (!(hnd->lockState & private_handle_t::LOCK_STATE_MAPPED)) {
202 err = gralloc_map(module, handle, vaddr);
203 if (err == 0) {
204 android_atomic_or(private_handle_t::LOCK_STATE_MAPPED,
205 (volatile int32_t*)&(hnd->lockState));
206 }
207 }
208 pthread_mutex_unlock(lock);
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700209 }
Mathias Agopian51156652009-06-09 18:55:49 -0700210 *vaddr = (void*)hnd->base;
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700211 }
Mathias Agopian485e6982009-05-05 20:21:57 -0700212
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700213 return err;
Mathias Agopiana8a75162009-04-10 14:24:31 -0700214}
215
216int gralloc_unlock(gralloc_module_t const* module,
217 buffer_handle_t handle)
218{
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700219 if (private_handle_t::validate(handle) < 0)
220 return -EINVAL;
221
Mathias Agopian51156652009-06-09 18:55:49 -0700222 private_handle_t* hnd = (private_handle_t*)handle;
Mathias Agopian485e6982009-05-05 20:21:57 -0700223 int32_t current_value, new_value;
Mathias Agopian988b8bd2009-05-04 14:26:56 -0700224
Mathias Agopian485e6982009-05-05 20:21:57 -0700225 do {
226 current_value = hnd->lockState;
227 new_value = current_value;
228
Mathias Agopian51156652009-06-09 18:55:49 -0700229 if (current_value & private_handle_t::LOCK_STATE_WRITE) {
Mathias Agopian485e6982009-05-05 20:21:57 -0700230 // locked for write
231 if (hnd->writeOwner == gettid()) {
232 hnd->writeOwner = 0;
Mathias Agopian51156652009-06-09 18:55:49 -0700233 new_value &= ~private_handle_t::LOCK_STATE_WRITE;
Mathias Agopian485e6982009-05-05 20:21:57 -0700234 }
235 }
236
Mathias Agopian51156652009-06-09 18:55:49 -0700237 if ((new_value & private_handle_t::LOCK_STATE_READ_MASK) == 0) {
Mathias Agopian485e6982009-05-05 20:21:57 -0700238 LOGE("handle %p not locked", handle);
239 return -EINVAL;
240 }
241
242 new_value--;
243
244 } while (android_atomic_cmpxchg(current_value, new_value,
245 (volatile int32_t*)&hnd->lockState));
246
Mathias Agopiana8a75162009-04-10 14:24:31 -0700247 return 0;
248}