+struct gralloc_memregions_t {
+ MemRegionSet ashmemRegions;
+};
+
+#define INITIAL_DMA_REGION_SIZE 4096
+struct gralloc_dmaregion_t {
+ goldfish_dma_context goldfish_dma;
+ uint32_t sz;
+ uint32_t refcount;
+ pthread_mutex_t lock;
+};
+
+// global device instance
+static gralloc_memregions_t* s_grdev = NULL;
+static gralloc_dmaregion_t* s_grdma = NULL;
+
+void init_gralloc_memregions() {
+ if (s_grdev) return;
+ s_grdev = new gralloc_memregions_t;
+}
+
+void init_gralloc_dmaregion() {
+ D("%s: call\n", __FUNCTION__);
+ if (s_grdma) return;
+
+ s_grdma = new gralloc_dmaregion_t;
+ s_grdma->sz = INITIAL_DMA_REGION_SIZE;
+ s_grdma->refcount = 0;
+
+ pthread_mutex_init(&s_grdma->lock, NULL);
+ pthread_mutex_lock(&s_grdma->lock);
+ goldfish_dma_create_region(s_grdma->sz, &s_grdma->goldfish_dma);
+ pthread_mutex_unlock(&s_grdma->lock);
+}
+
+void get_gralloc_dmaregion() {
+ if (!s_grdma) return;
+ pthread_mutex_lock(&s_grdma->lock);
+ s_grdma->refcount++;
+ D("%s: call. refcount: %u\n", __FUNCTION__, s_grdma->refcount);
+ pthread_mutex_unlock(&s_grdma->lock);
+}
+
+static void resize_gralloc_dmaregion_locked(uint32_t new_sz) {
+ if (!s_grdma) return;
+ if (s_grdma->goldfish_dma.mapped) {
+ goldfish_dma_unmap(&s_grdma->goldfish_dma);
+ }
+ close(s_grdma->goldfish_dma.fd);
+ goldfish_dma_create_region(new_sz, &s_grdma->goldfish_dma);
+ s_grdma->sz = new_sz;
+}
+
+bool put_gralloc_dmaregion() {
+ if (!s_grdma) return false;
+ pthread_mutex_lock(&s_grdma->lock);
+ D("%s: call. refcount before: %u\n", __FUNCTION__, s_grdma->refcount);
+ s_grdma->refcount--;
+ bool shouldDelete = !s_grdma->refcount;
+ if (shouldDelete) {
+ D("%s: should delete!\n", __FUNCTION__);
+ resize_gralloc_dmaregion_locked(INITIAL_DMA_REGION_SIZE);
+ D("%s: done\n", __FUNCTION__);
+ }
+ pthread_mutex_unlock(&s_grdma->lock);
+ D("%s: exit\n", __FUNCTION__);
+ return shouldDelete;
+}
+
+void gralloc_dmaregion_register_ashmem(uint32_t sz) {
+ if (!s_grdma) return;
+ pthread_mutex_lock(&s_grdma->lock);
+ D("%s: for sz %u, refcount %u", __FUNCTION__, sz, s_grdma->refcount);
+ uint32_t new_sz = std::max(s_grdma->sz, sz);
+ if (new_sz != s_grdma->sz) {
+ D("%s: change sz from %u to %u", __FUNCTION__, s_grdma->sz, sz);
+ resize_gralloc_dmaregion_locked(new_sz);
+ }
+ if (!s_grdma->goldfish_dma.mapped) {
+ goldfish_dma_map(&s_grdma->goldfish_dma);
+ }
+ pthread_mutex_unlock(&s_grdma->lock);
+}
+
+void get_mem_region(void* ashmemBase) {
+ init_gralloc_memregions();
+ D("%s: call for %p", __FUNCTION__, ashmemBase);
+ MemRegionInfo lookup;
+ lookup.ashmemBase = ashmemBase;
+ mem_region_handle_t handle = s_grdev->ashmemRegions.find(lookup);
+ if (handle == s_grdev->ashmemRegions.end()) {
+ MemRegionInfo newRegion;
+ newRegion.ashmemBase = ashmemBase;
+ newRegion.refCount = 1;
+ s_grdev->ashmemRegions.insert(newRegion);
+ } else {
+ handle->refCount++;
+ }
+}
+
+bool put_mem_region(void* ashmemBase) {
+ init_gralloc_memregions();
+ D("%s: call for %p", __FUNCTION__, ashmemBase);
+ MemRegionInfo lookup;
+ lookup.ashmemBase = ashmemBase;
+ mem_region_handle_t handle = s_grdev->ashmemRegions.find(lookup);
+ if (handle == s_grdev->ashmemRegions.end()) {
+ ALOGE("%s: error: tried to put nonexistent mem region!", __FUNCTION__);
+ return true;
+ } else {
+ handle->refCount--;
+ bool shouldRemove = !handle->refCount;
+ if (shouldRemove) {
+ s_grdev->ashmemRegions.erase(lookup);
+ }
+ return shouldRemove;
+ }
+}
+
+void dump_regions() {
+ init_gralloc_memregions();
+ mem_region_handle_t curr = s_grdev->ashmemRegions.begin();
+ std::stringstream res;
+ for (; curr != s_grdev->ashmemRegions.end(); curr++) {
+ res << "\tashmem base " << curr->ashmemBase << " refcount " << curr->refCount << "\n";
+ }
+ ALOGD("ashmem region dump [\n%s]", res.str().c_str());
+}
+
+#if DEBUG
+
+#define GET_ASHMEM_REGION(cb) \
+ dump_regions(); \
+ get_mem_region((void*)cb->ashmemBase); \
+ dump_regions(); \
+
+#define PUT_ASHMEM_REGION(cb) \
+ dump_regions(); \
+ bool SHOULD_UNMAP = put_mem_region((void*)cb->ashmemBase); \
+ dump_regions(); \
+
+#else
+
+#define GET_ASHMEM_REGION(cb) \
+ get_mem_region((void*)cb->ashmemBase); \
+
+#define PUT_ASHMEM_REGION(cb) \
+ bool SHOULD_UNMAP = put_mem_region((void*)cb->ashmemBase); \
+
+#endif
+