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;
}