• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <stdarg.h>
23 
24 #include <sys/mman.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/ioctl.h>
28 
29 #include <cutils/log.h>
30 #include <cutils/atomic.h>
31 
32 #include <hardware/hardware.h>
33 #include <hardware/gralloc.h>
34 
35 #include <linux/android_pmem.h>
36 
37 #include "gralloc_priv.h"
38 
39 
40 // we need this for now because pmem cannot mmap at an offset
41 #define PMEM_HACK   1
42 
43 /* desktop Linux needs a little help with gettid() */
44 #if defined(ARCH_X86) && !defined(HAVE_ANDROID_OS)
45 #define __KERNEL__
46 # include <linux/unistd.h>
gettid()47 pid_t gettid() { return syscall(__NR_gettid);}
48 #undef __KERNEL__
49 #endif
50 
51 /*****************************************************************************/
52 
gralloc_map(gralloc_module_t const * module,buffer_handle_t handle,void ** vaddr)53 static int gralloc_map(gralloc_module_t const* module,
54         buffer_handle_t handle,
55         void** vaddr)
56 {
57     private_handle_t* hnd = (private_handle_t*)handle;
58     if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
59         size_t size = hnd->size;
60 #if PMEM_HACK
61         size += hnd->offset;
62 #endif
63         void* mappedAddress = mmap(0, size,
64                 PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0);
65         if (mappedAddress == MAP_FAILED) {
66             ALOGE("Could not mmap handle %p, fd=%d (%s)",
67                     handle, hnd->fd, strerror(errno));
68             hnd->base = 0;
69             return -errno;
70         }
71         hnd->base = intptr_t(mappedAddress) + hnd->offset;
72         //ALOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",
73         //        hnd->fd, hnd->offset, hnd->size, mappedAddress);
74     }
75     *vaddr = (void*)hnd->base;
76     return 0;
77 }
78 
gralloc_unmap(gralloc_module_t const * module,buffer_handle_t handle)79 static int gralloc_unmap(gralloc_module_t const* module,
80         buffer_handle_t handle)
81 {
82     private_handle_t* hnd = (private_handle_t*)handle;
83     if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
84         void* base = (void*)hnd->base;
85         size_t size = hnd->size;
86 #if PMEM_HACK
87         base = (void*)(intptr_t(base) - hnd->offset);
88         size += hnd->offset;
89 #endif
90         //ALOGD("unmapping from %p, size=%d", base, size);
91         if (munmap(base, size) < 0) {
92             ALOGE("Could not unmap %s", strerror(errno));
93         }
94     }
95     hnd->base = 0;
96     return 0;
97 }
98 
99 /*****************************************************************************/
100 
101 static pthread_mutex_t sMapLock = PTHREAD_MUTEX_INITIALIZER;
102 
103 /*****************************************************************************/
104 
gralloc_register_buffer(gralloc_module_t const * module,buffer_handle_t handle)105 int gralloc_register_buffer(gralloc_module_t const* module,
106         buffer_handle_t handle)
107 {
108     if (private_handle_t::validate(handle) < 0)
109         return -EINVAL;
110 
111     // In this implementation, we don't need to do anything here
112 
113     /* NOTE: we need to initialize the buffer as not mapped/not locked
114      * because it shouldn't when this function is called the first time
115      * in a new process. Ideally these flags shouldn't be part of the
116      * handle, but instead maintained in the kernel or at least
117      * out-of-line
118      */
119 
120     // if this handle was created in this process, then we keep it as is.
121     private_handle_t* hnd = (private_handle_t*)handle;
122     if (hnd->pid != getpid()) {
123         hnd->base = 0;
124         hnd->lockState  = 0;
125         hnd->writeOwner = 0;
126     }
127     return 0;
128 }
129 
gralloc_unregister_buffer(gralloc_module_t const * module,buffer_handle_t handle)130 int gralloc_unregister_buffer(gralloc_module_t const* module,
131         buffer_handle_t handle)
132 {
133     if (private_handle_t::validate(handle) < 0)
134         return -EINVAL;
135 
136     /*
137      * If the buffer has been mapped during a lock operation, it's time
138      * to un-map it. It's an error to be here with a locked buffer.
139      * NOTE: the framebuffer is handled differently and is never unmapped.
140      */
141 
142     private_handle_t* hnd = (private_handle_t*)handle;
143 
144     ALOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK,
145             "[unregister] handle %p still locked (state=%08x)",
146             hnd, hnd->lockState);
147 
148     // never unmap buffers that were created in this process
149     if (hnd->pid != getpid()) {
150         if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) {
151             gralloc_unmap(module, handle);
152         }
153         hnd->base = 0;
154         hnd->lockState  = 0;
155         hnd->writeOwner = 0;
156     }
157     return 0;
158 }
159 
terminateBuffer(gralloc_module_t const * module,private_handle_t * hnd)160 int terminateBuffer(gralloc_module_t const* module,
161         private_handle_t* hnd)
162 {
163     /*
164      * If the buffer has been mapped during a lock operation, it's time
165      * to un-map it. It's an error to be here with a locked buffer.
166      */
167 
168     ALOGE_IF(hnd->lockState & private_handle_t::LOCK_STATE_READ_MASK,
169             "[terminate] handle %p still locked (state=%08x)",
170             hnd, hnd->lockState);
171 
172     if (hnd->lockState & private_handle_t::LOCK_STATE_MAPPED) {
173         // this buffer was mapped, unmap it now
174         if ((hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM) ||
175             (hnd->flags & private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP)) {
176             if (hnd->pid != getpid()) {
177                 // ... unless it's a "master" pmem buffer, that is a buffer
178                 // mapped in the process it's been allocated.
179                 // (see gralloc_alloc_buffer())
180                 gralloc_unmap(module, hnd);
181             }
182         } else {
183             gralloc_unmap(module, hnd);
184         }
185     }
186 
187     return 0;
188 }
189 
gralloc_lock(gralloc_module_t const * module,buffer_handle_t handle,int usage,int l,int t,int w,int h,void ** vaddr)190 int gralloc_lock(gralloc_module_t const* module,
191         buffer_handle_t handle, int usage,
192         int l, int t, int w, int h,
193         void** vaddr)
194 {
195     if (private_handle_t::validate(handle) < 0)
196         return -EINVAL;
197 
198     int err = 0;
199     private_handle_t* hnd = (private_handle_t*)handle;
200     int32_t current_value, new_value;
201     int retry;
202 
203     do {
204         current_value = hnd->lockState;
205         new_value = current_value;
206 
207         if (current_value & private_handle_t::LOCK_STATE_WRITE) {
208             // already locked for write
209             ALOGE("handle %p already locked for write", handle);
210             return -EBUSY;
211         } else if (current_value & private_handle_t::LOCK_STATE_READ_MASK) {
212             // already locked for read
213             if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
214                 ALOGE("handle %p already locked for read", handle);
215                 return -EBUSY;
216             } else {
217                 // this is not an error
218                 //ALOGD("%p already locked for read... count = %d",
219                 //        handle, (current_value & ~(1<<31)));
220             }
221         }
222 
223         // not currently locked
224         if (usage & (GRALLOC_USAGE_SW_WRITE_MASK | GRALLOC_USAGE_HW_RENDER)) {
225             // locking for write
226             new_value |= private_handle_t::LOCK_STATE_WRITE;
227         }
228         new_value++;
229 
230         retry = android_atomic_cmpxchg(current_value, new_value,
231                 (volatile int32_t*)&hnd->lockState);
232     } while (retry);
233 
234     if (new_value & private_handle_t::LOCK_STATE_WRITE) {
235         // locking for write, store the tid
236         hnd->writeOwner = gettid();
237     }
238 
239     // if requesting sw write for non-framebuffer handles, flag for
240     // flushing at unlock
241 
242     const uint32_t pmemMask =
243             private_handle_t::PRIV_FLAGS_USES_PMEM |
244             private_handle_t::PRIV_FLAGS_USES_PMEM_ADSP;
245 
246     if ((usage & GRALLOC_USAGE_SW_WRITE_MASK) &&
247             (hnd->flags & pmemMask) &&
248             !(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
249         hnd->flags |= private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
250     }
251 
252     if (usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
253         if (!(current_value & private_handle_t::LOCK_STATE_MAPPED)) {
254             // we need to map for real
255             pthread_mutex_t* const lock = &sMapLock;
256             pthread_mutex_lock(lock);
257             if (!(hnd->lockState & private_handle_t::LOCK_STATE_MAPPED)) {
258                 err = gralloc_map(module, handle, vaddr);
259                 if (err == 0) {
260                     android_atomic_or(private_handle_t::LOCK_STATE_MAPPED,
261                             (volatile int32_t*)&(hnd->lockState));
262                 }
263             }
264             pthread_mutex_unlock(lock);
265         }
266         *vaddr = (void*)hnd->base;
267     }
268 
269     return err;
270 }
271 
gralloc_unlock(gralloc_module_t const * module,buffer_handle_t handle)272 int gralloc_unlock(gralloc_module_t const* module,
273         buffer_handle_t handle)
274 {
275     if (private_handle_t::validate(handle) < 0)
276         return -EINVAL;
277 
278     private_handle_t* hnd = (private_handle_t*)handle;
279     int32_t current_value, new_value;
280 
281     if (hnd->flags & private_handle_t::PRIV_FLAGS_NEEDS_FLUSH) {
282         struct pmem_region region;
283         int err;
284 
285         region.offset = hnd->offset;
286         region.len = hnd->size;
287         err = ioctl(hnd->fd, PMEM_CACHE_FLUSH, &region);
288         ALOGE_IF(err < 0, "cannot flush handle %p (offs=%x len=%x)\n",
289                 hnd, hnd->offset, hnd->size);
290         hnd->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
291     }
292 
293     do {
294         current_value = hnd->lockState;
295         new_value = current_value;
296 
297         if (current_value & private_handle_t::LOCK_STATE_WRITE) {
298             // locked for write
299             if (hnd->writeOwner == gettid()) {
300                 hnd->writeOwner = 0;
301                 new_value &= ~private_handle_t::LOCK_STATE_WRITE;
302             }
303         }
304 
305         if ((new_value & private_handle_t::LOCK_STATE_READ_MASK) == 0) {
306             ALOGE("handle %p not locked", handle);
307             return -EINVAL;
308         }
309 
310         new_value--;
311 
312     } while (android_atomic_cmpxchg(current_value, new_value,
313             (volatile int32_t*)&hnd->lockState));
314 
315     return 0;
316 }
317 
318 /*****************************************************************************/
319 
gralloc_perform(struct gralloc_module_t const * module,int operation,...)320 int gralloc_perform(struct gralloc_module_t const* module,
321         int operation, ... )
322 {
323     int res = -EINVAL;
324     return res;
325 }
326