celix_status_t shmPool_create()

in bundles/remote_services/remote_service_admin_shm_v2/shm_pool/src/shm_pool.c [46:128]


celix_status_t shmPool_create(size_t size, shm_pool_t **pool) {
    celix_status_t status = CELIX_SUCCESS;
    size_t normalizedSharedInfoSize = (sizeof(struct shm_pool_shared_info) % sizeof(void *) == 0) ?
            sizeof(struct shm_pool_shared_info) : (sizeof(struct shm_pool_shared_info)+sizeof(void *))/sizeof(void *) * sizeof(void *);
    if (size <= tlsf_size() + normalizedSharedInfoSize || pool == NULL) {
        celix_err_pushf("Shm pool: Shm size should be greater than %zu.\n", tlsf_size());
        status = CELIX_ILLEGAL_ARGUMENT;
        goto shm_size_invalid;
    }

    shm_pool_t *shmPool = (shm_pool_t *)malloc(sizeof(*shmPool));
    if (shmPool == NULL) {
        status = CELIX_ENOMEM;
        goto alloc_failed;
    }

    status = celixThreadMutex_create(&shmPool->mutex, NULL);
    if(status != CELIX_SUCCESS) {
        goto shm_pool_mutex_err;
    }
    /* Specify the IPC_PRIVATE constant as the key value to the `shmget` when creating the
     * IPC object, which always results in the creation of a new IPC object that is guaranteed to have a unique key.
     * And other process can use 'shmat' to attach relevant shared memory.
     */
    shmPool->shmId = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
    if (shmPool->shmId  == -1) {
        celix_err_pushf("Shm pool: Error getting shm. %d.\n",errno);
        status = CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,errno);
        goto err_getting_shm;
    }
    shmPool->shmStartAddr = shmat(shmPool->shmId, NULL, 0);
    if (shmPool->shmStartAddr == NULL) {
        celix_err_pushf("Shm pool: Error attaching shm, %d.\n",errno);
        status = CELIX_ERROR_MAKE(CELIX_FACILITY_CERRNO,errno);
        goto err_attaching_shm;
    }

    shmPool->sharedInfo = (struct shm_pool_shared_info *)shmPool->shmStartAddr;
    shmPool->sharedInfo->heartbeatCnt = 1;
    shmPool->sharedInfo->size = sizeof(struct shm_pool_shared_info);

    void *poolMem = shmPool->shmStartAddr + normalizedSharedInfoSize;
    shmPool->allocator = tlsf_create_with_pool(poolMem, size - normalizedSharedInfoSize);
    if (shmPool->allocator == NULL) {
        celix_err_pushf("Shm pool: Error creating shm pool allocator.\n");
        status = CELIX_ILLEGAL_STATE;
        goto allocator_err;
    }

    status = celixThreadCondition_init(&shmPool->heartbeatThreadStoped, NULL);
    if (status != CELIX_SUCCESS) {
        celix_err_pushf("Shm pool: Error creating stoped condition for heartbeat thread. %d.\n", status);
        goto stopped_cond_err;
    }
    shmPool->heartbeatThreadActive = true;
    status = celixThread_create(&shmPool->shmHeartbeatThread, NULL,
            shmPool_heartbeatThread, shmPool);
    if (status != CELIX_SUCCESS) {
        celix_err_pushf("Shm pool: Error creating heartbeat thread. %d.\n", status);
        goto heartbeat_thread_err;
    }

    (void)shmctl(shmPool->shmId, IPC_RMID, NULL);
    *pool = shmPool;

    return CELIX_SUCCESS;

heartbeat_thread_err:
    (void)celixThreadCondition_destroy(&shmPool->heartbeatThreadStoped);
stopped_cond_err:
    tlsf_destroy(shmPool->allocator);
allocator_err:
    (void)shmdt(shmPool->shmStartAddr);
err_attaching_shm:
    (void)shmctl(shmPool->shmId, IPC_RMID, NULL);
err_getting_shm:
    (void)celixThreadMutex_destroy(&shmPool->mutex);
shm_pool_mutex_err:
    free(shmPool);
alloc_failed:
shm_size_invalid:
    return status;
}