DFBResult dfb_clipboard_set( DFBClipboardCore *core, const char *mime_type, const void *data, unsigned int size, struct timeval *timestamp ) { DFBClipboardCoreShared *shared; char *new_mime; void *new_data; D_MAGIC_ASSERT( core, DFBClipboardCore ); D_ASSERT( mime_type != NULL ); D_ASSERT( data != NULL ); D_ASSERT( size > 0 ); shared = core->shared; D_MAGIC_ASSERT( shared, DFBClipboardCoreShared ); new_mime = SHSTRDUP( shared->shmpool, mime_type ); if (!new_mime) return D_OOSHM(); new_data = SHMALLOC( shared->shmpool, size ); if (!new_data) { SHFREE( shared->shmpool, new_mime ); return D_OOSHM(); } direct_memcpy( new_data, data, size ); if (fusion_skirmish_prevail( &shared->lock )) { SHFREE( shared->shmpool, new_data ); SHFREE( shared->shmpool, new_mime ); return DFB_FUSION; } if (shared->data) SHFREE( shared->shmpool, shared->data ); if (shared->mime_type) SHFREE( shared->shmpool, shared->mime_type ); shared->mime_type = new_mime; shared->data = new_data; shared->size = size; gettimeofday( &shared->timestamp, NULL ); if (timestamp) *timestamp = shared->timestamp; fusion_skirmish_dismiss( &shared->lock ); return DFB_OK; }
static DirectResult init_pool( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared, const char *name, unsigned int max_size, bool debug ) { DirectResult ret; int size; long page_size; int pool_id; unsigned int pool_max_size; void *pool_addr_base = NULL; FusionWorld *world; char buf[FUSION_SHM_TMPFS_PATH_NAME_LEN + 32]; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p, '%s', %d, %sdebug )\n", __FUNCTION__, shm, pool, shared, name, max_size, debug ? "" : "non-" ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); D_ASSERT( name != NULL ); D_ASSERT( max_size > sizeof(shmalloc_heap) ); world = shm->world; D_MAGIC_ASSERT( world, FusionWorld ); D_ASSERT( pool != NULL ); D_ASSERT( shared != NULL ); page_size = direct_pagesize(); pool_id = ++world->shared->pool_ids; pool_max_size = max_size + BLOCKALIGN(sizeof(shmalloc_heap)) + BLOCKALIGN( (max_size + BLOCKSIZE-1) / BLOCKSIZE * sizeof(shmalloc_info) ); pool_addr_base = world->shared->pool_base; world->shared->pool_base += ((pool_max_size + page_size - 1) & ~(page_size - 1)) + page_size; /* Exceeded limit? */ if (world->shared->pool_base > world->shared->pool_max) return DR_NOSHAREDMEMORY; /* Generate filename. */ snprintf( buf, sizeof(buf), "%s/fusion.%d.%d", shm->shared->tmpfs, fusion_world_index( world ), pool_id ); /* Initialize the heap. */ ret = __shmalloc_init_heap( shm, buf, pool_addr_base, max_size, &size ); if (ret) return ret; /* initialize local data. */ pool->attached = true; pool->shm = shm; pool->shared = shared; pool->pool_id = pool_id; pool->filename = D_STRDUP( buf ); /* Initialize shared data. */ shared->active = true; shared->debug = debug; shared->shm = shm->shared; shared->max_size = pool_max_size; shared->pool_id = pool_id; shared->addr_base = pool_addr_base; shared->heap = pool_addr_base; shared->heap->pool = shared; fusion_skirmish_init( &shared->lock, name, world ); D_MAGIC_SET( pool, FusionSHMPool ); D_MAGIC_SET( shared, FusionSHMPoolShared ); shared->name = SHSTRDUP( shared, name ); return DR_OK; }
static DirectResult init_pool( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared, const char *name, unsigned int max_size, bool debug ) { DirectResult ret; int size; FusionWorld *world; FusionSHMPoolNew pool_new = { .pool_id = 0 }; FusionSHMPoolAttach pool_attach = { .pool_id = 0 }; FusionEntryInfo info; char buf[FUSION_SHM_TMPFS_PATH_NAME_LEN + 32]; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p, '%s', %d, %sdebug )\n", __FUNCTION__, shm, pool, shared, name, max_size, debug ? "" : "non-" ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); D_ASSERT( name != NULL ); D_ASSERT( max_size > sizeof(shmalloc_heap) ); world = shm->world; D_MAGIC_ASSERT( world, FusionWorld ); D_ASSERT( pool != NULL ); D_ASSERT( shared != NULL ); /* Fill out information for new pool. */ pool_new.max_size = max_size; pool_new.max_size += BLOCKALIGN(sizeof(shmalloc_heap)) + BLOCKALIGN( (max_size + BLOCKSIZE-1) / BLOCKSIZE * sizeof(shmalloc_info) ); /* Create the new pool. */ while (ioctl( world->fusion_fd, FUSION_SHMPOOL_NEW, &pool_new )) { if (errno == EINTR) continue; D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_NEW failed!\n" ); return DR_FUSION; } /* Set the pool info. */ info.type = FT_SHMPOOL; info.id = pool_new.pool_id; snprintf( info.name, sizeof(info.name), "%s", name ); ioctl( world->fusion_fd, FUSION_ENTRY_SET_INFO, &info ); fusion_entry_add_permissions( world, FT_SHMPOOL, pool_new.pool_id, 0, FUSION_SHMPOOL_ATTACH, FUSION_SHMPOOL_DETACH, 0 ); /* Set pool to attach to. */ pool_attach.pool_id = pool_new.pool_id; /* Attach to the pool. */ while (ioctl( world->fusion_fd, FUSION_SHMPOOL_ATTACH, &pool_attach )) { if (errno == EINTR) continue; D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_ATTACH failed!\n" ); while (ioctl( world->fusion_fd, FUSION_SHMPOOL_DESTROY, &shared->pool_id )) { if (errno != EINTR) { D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_DESTROY failed!\n" ); break; } } return DR_FUSION; } /* Generate filename. */ snprintf( buf, sizeof(buf), "%s/fusion.%d.%d", shm->shared->tmpfs, fusion_world_index( shm->world ), pool_new.pool_id ); /* Initialize the heap. */ ret = __shmalloc_init_heap( shm, buf, pool_new.addr_base, max_size, &size ); if (ret) { while (ioctl( world->fusion_fd, FUSION_SHMPOOL_DESTROY, &shared->pool_id )) { if (errno != EINTR) { D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_DESTROY failed!\n" ); break; } } return ret; } /* Initialize local data. */ pool->attached = true; pool->shm = shm; pool->shared = shared; pool->pool_id = pool_new.pool_id; pool->filename = D_STRDUP( buf ); /* Initialize shared data. */ shared->active = true; shared->debug = debug; shared->shm = shm->shared; shared->max_size = pool_new.max_size; shared->pool_id = pool_new.pool_id; shared->addr_base = pool_new.addr_base; shared->heap = pool_new.addr_base; shared->heap->pool = shared; fusion_skirmish_init2( &shared->lock, name, world, fusion_config->secure_fusion ); D_MAGIC_SET( pool, FusionSHMPool ); D_MAGIC_SET( shared, FusionSHMPoolShared ); shared->name = SHSTRDUP( shared, name ); return DR_OK; } static DirectResult join_pool( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared ) { DirectResult ret; FusionWorld *world; FusionSHMPoolAttach pool_attach = { .pool_id = 0 }; char buf[FUSION_SHM_TMPFS_PATH_NAME_LEN + 32]; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p )\n", __FUNCTION__, shm, pool, shared ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( shm->shared, FusionSHMShared ); D_MAGIC_ASSERT( shared, FusionSHMPoolShared ); #if !DIRECT_BUILD_DEBUGS if (shared->debug) { D_ERROR( "Fusion/SHM: Can't join debug enabled pool with pure-release library!\n" ); return DR_UNSUPPORTED; } #endif world = shm->world; D_MAGIC_ASSERT( world, FusionWorld ); /* Set pool to attach to. */ pool_attach.pool_id = shared->pool_id; /* Attach to the pool. */ while (ioctl( world->fusion_fd, FUSION_SHMPOOL_ATTACH, &pool_attach )) { if (errno == EINTR) continue; D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_ATTACH failed!\n" ); return DR_FUSION; } /* Generate filename. */ snprintf( buf, sizeof(buf), "%s/fusion.%d.%d", shm->shared->tmpfs, fusion_world_index( shm->world ), shared->pool_id ); /* Join the heap. */ ret = __shmalloc_join_heap( shm, buf, pool_attach.addr_base, shared->max_size, !fusion_config->secure_fusion ); if (ret) { while (ioctl( world->fusion_fd, FUSION_SHMPOOL_DETACH, &shared->pool_id )) { if (errno != EINTR) { D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_DETACH failed!\n" ); break; } } return ret; } /* Initialize local data. */ pool->attached = true; pool->shm = shm; pool->shared = shared; pool->pool_id = shared->pool_id; pool->filename = D_STRDUP( buf ); D_MAGIC_SET( pool, FusionSHMPool ); return DR_OK; } static void leave_pool( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared ) { FusionWorld *world; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p )\n", __FUNCTION__, shm, pool, shared ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( pool, FusionSHMPool ); D_MAGIC_ASSERT( shared, FusionSHMPoolShared ); world = shm->world; D_MAGIC_ASSERT( world, FusionWorld ); while (ioctl( world->fusion_fd, FUSION_SHMPOOL_DETACH, &shared->pool_id )) { if (errno != EINTR) { D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_DETACH failed!\n" ); break; } } if (munmap( shared->addr_base, shared->max_size )) D_PERROR( "Fusion/SHM: Could not munmap shared memory file '%s'!\n", pool->filename ); pool->attached = false; D_FREE( pool->filename ); D_MAGIC_CLEAR( pool ); } static void shutdown_pool( FusionSHM *shm, FusionSHMPool *pool, FusionSHMPoolShared *shared ) { FusionWorld *world; D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p )\n", __FUNCTION__, shm, pool, shared ); D_MAGIC_ASSERT( shm, FusionSHM ); D_MAGIC_ASSERT( pool, FusionSHMPool ); D_MAGIC_ASSERT( shared, FusionSHMPoolShared ); world = shm->world; D_MAGIC_ASSERT( world, FusionWorld ); SHFREE( shared, shared->name ); fusion_dbg_print_memleaks( shared ); while (ioctl( world->fusion_fd, FUSION_SHMPOOL_DESTROY, &shared->pool_id )) { if (errno != EINTR) { D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_DESTROY failed!\n" ); break; } } if (munmap( shared->addr_base, shared->max_size )) D_PERROR( "Fusion/SHM: Could not munmap shared memory file '%s'!\n", pool->filename ); if (unlink( pool->filename )) D_PERROR( "Fusion/SHM: Could not unlink shared memory file '%s'!\n", pool->filename ); shared->active = false; pool->attached = false; D_FREE( pool->filename ); D_MAGIC_CLEAR( pool ); fusion_skirmish_destroy( &shared->lock ); D_MAGIC_CLEAR( shared ); }