mapper.cpp revision bd80b38f2945ac918f66fb336c149b28b9dd030e
1/* 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#include <unistd.h> 21#include <string.h> 22 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 35 36// we need this for now because pmem cannot mmap at an offset 37#define PMEM_HACK 1 38 39/* 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 47/*****************************************************************************/ 48 49static int gralloc_map(gralloc_module_t const* module, 50 buffer_handle_t handle, 51 void** vaddr) 52{ 53 private_handle_t* hnd = (private_handle_t*)handle; 54 if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { 55 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); 61 if (mappedAddress == MAP_FAILED) { 62 LOGE("Could not mmap %s", strerror(errno)); 63 return -errno; 64 } 65 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); 68 } 69 *vaddr = (void*)hnd->base; 70 return 0; 71} 72 73static int gralloc_unmap(gralloc_module_t const* module, 74 buffer_handle_t handle) 75{ 76 private_handle_t* hnd = (private_handle_t*)handle; 77 if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) { 78 void* base = (void*)hnd->base; 79 size_t size = hnd->size; 80#if PMEM_HACK 81 base = (void*)(intptr_t(base) - hnd->offset); 82 size += hnd->offset; 83#endif 84 //LOGD("unmapping from %p, size=%d", base, size); 85 if (munmap(base, size) < 0) { 86 LOGE("Could not unmap %s", strerror(errno)); 87 } 88 } 89 hnd->base = 0; 90 return 0; 91} 92 93/*****************************************************************************/ 94 95static pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER; 96 97/*****************************************************************************/ 98 99int gralloc_register_buffer(gralloc_module_t const* module, 100 buffer_handle_t handle) 101{ 102 if (private_handle_t::validate(handle) < 0) 103 return -EINVAL; 104 105 // In this implementation, we don't need to do anything here 106 107 /* NOTE: we need to initialize the buffer as not mapped/not locked 108 * because it shouldn't when this function is called the first time 109 * in a new process. Ideally these flags shouldn't be part of the 110 * handle, but instead maintained in the kernel or at least 111 * out-of-line 112 */ 113 114 // if this handle was created in this process, then we keep it as is. 115 private_handle_t* hnd = (private_handle_t*)handle; 116 if (hnd->pid != getpid()) { 117 hnd->base = 0; 118 hnd->lockState = 0; 119 hnd->writeOwner = 0; 120 } 121 return 0; 122} 123 124int gralloc_unregister_buffer(gralloc_module_t const* module, 125 buffer_handle_t handle) 126{ 127 if (private_handle_t::validate(handle) < 0) 128 return -EINVAL; 129 130 /* 131 * If the buffer has been mapped during a lock operation, it's time 132 * to un-map it. It's an error to be here with a locked buffer. 133 * NOTE: the framebuffer is handled differently and is never unmapped. 134 */ 135 136 private_handle_t* hnd = (private_handle_t*)handle; 137 138 LOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK, 139 "handle %p still locked (state=%08x)", 140 hnd, hnd->lockState); 141 142 // never unmap buffers that were created in this process 143 if (hnd->pid != getpid()) { 144 if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) { 145 gralloc_unmap(module, handle); 146 } 147 hnd->base = 0; 148 hnd->lockState = 0; 149 hnd->writeOwner = 0; 150 } 151 return 0; 152} 153 154int terminateBuffer(gralloc_module_t const* module, 155 private_handle_t* hnd) 156{ 157 /* 158 * If the buffer has been mapped during a lock operation, it's time 159 * to un-map it. It's an error to be here with a locked buffer. 160 */ 161 162 LOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK, 163 "handle %p still locked (state=%08x)", 164 hnd, hnd->lockState); 165 166 if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) { 167 // this buffer was mapped, unmap it now 168 if ((hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) && 169 (hnd->pid == getpid())) { 170 // ... unless it's a "master" pmem buffer, that is a buffer 171 // mapped in the process it's been allocated. 172 // (see gralloc_alloc_buffer()) 173 } else { 174 gralloc_unmap(module, hnd); 175 } 176 } 177 178 return 0; 179} 180 181int gralloc_lock(gralloc_module_t const* module, 182 buffer_handle_t handle, int usage, 183 int l, int t, int w, int h, 184 void** vaddr) 185{ 186 if (private_handle_t::validate(handle) < 0) 187 return -EINVAL; 188 189 int err = 0; 190 private_handle_t* hnd = (private_handle_t*)handle; 191 int32_t current_value, new_value; 192 int retry; 193 194 do { 195 current_value = hnd->lockState; 196 new_value = current_value; 197 198 if (current_value & private_handle_t::LOCK_STATE_WRITE) { 199 // already locked for write 200 LOGE("handle %p already locked for write", handle); 201 return -EBUSY; 202 } else if (current_value & private_handle_t::LOCK_STATE_READ_MASK) { 203 // already locked for read 204 if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) { 205 LOGE("handle %p already locked for read", handle); 206 return -EBUSY; 207 } else { 208 // this is not an error 209 //LOGD("%p already locked for read... count = %d", 210 // handle, (current_value & ~(1<<31))); 211 } 212 } 213 214 // not currently locked 215 if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) { 216 // locking for write 217 new_value |= private_handle_t::LOCK_STATE_WRITE; 218 } 219 new_value++; 220 221 retry = android_atomic_cmpxchg(current_value, new_value, 222 (volatile int32_t*)&hnd->lockState); 223 } while (retry); 224 225 if (new_value & private_handle_t::LOCK_STATE_WRITE) { 226 // locking for write, store the tid 227 hnd->writeOwner = gettid(); 228 } 229 230 if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) { 231 if (!(current_value & private_handle_t::LOCK_STATE_MAPPED)) { 232 // we need to map for real 233 pthread_mutex_t* const lock = &sMapLock; 234 pthread_mutex_lock(lock); 235 if (!(hnd->lockState & private_handle_t::LOCK_STATE_MAPPED)) { 236 err = gralloc_map(module, handle, vaddr); 237 if (err == 0) { 238 android_atomic_or(private_handle_t::LOCK_STATE_MAPPED, 239 (volatile int32_t*)&(hnd->lockState)); 240 } 241 } 242 pthread_mutex_unlock(lock); 243 } 244 *vaddr = (void*)hnd->base; 245 } 246 247 return err; 248} 249 250int gralloc_unlock(gralloc_module_t const* module, 251 buffer_handle_t handle) 252{ 253 if (private_handle_t::validate(handle) < 0) 254 return -EINVAL; 255 256 private_handle_t* hnd = (private_handle_t*)handle; 257 int32_t current_value, new_value; 258 259 do { 260 current_value = hnd->lockState; 261 new_value = current_value; 262 263 if (current_value & private_handle_t::LOCK_STATE_WRITE) { 264 // locked for write 265 if (hnd->writeOwner == gettid()) { 266 hnd->writeOwner = 0; 267 new_value &= ~private_handle_t::LOCK_STATE_WRITE; 268 } 269 } 270 271 if ((new_value & private_handle_t::LOCK_STATE_READ_MASK) == 0) { 272 LOGE("handle %p not locked", handle); 273 return -EINVAL; 274 } 275 276 new_value--; 277 278 } while (android_atomic_cmpxchg(current_value, new_value, 279 (volatile int32_t*)&hnd->lockState)); 280 281 return 0; 282} 283