mirror of
https://github.com/OpenSolo/OpenSolo.git
synced 2025-05-01 15:14:35 +02:00
197 lines
4.5 KiB
C
197 lines
4.5 KiB
C
|
|
#include <fcntl.h>
|
|
#include <semaphore.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include "rc_pkt.h"
|
|
#include "rc_ipc.h"
|
|
|
|
/* these must start with slash then contain no more slashes */
|
|
#define RC_IPC_SHM_NAME "/rc_shm"
|
|
#define RC_IPC_SEM_NAME "/rc_sem"
|
|
|
|
/*
|
|
* Information about an instance of the RC IPC. One of these is allocated and
|
|
* returned from create or attach, and passed back to the other functions. An
|
|
* application must eventually give it to detach/delete to free it.
|
|
*/
|
|
struct rc_ipc_info {
|
|
uint32_t magic;
|
|
struct rc_pkt *pkt;
|
|
sem_t *sem;
|
|
};
|
|
|
|
#define RC_IPC_INFO_MAGIC 0x21436587
|
|
|
|
/* return rc_ipc_id pointer on success, NULL on error */
|
|
void *rc_ipc_attach(int verbosity)
|
|
{
|
|
struct rc_ipc_info *info;
|
|
int fd;
|
|
|
|
info = (struct rc_ipc_info *)malloc(sizeof(struct rc_ipc_info));
|
|
if (info == NULL) {
|
|
if (verbosity > 0)
|
|
perror("malloc");
|
|
return NULL;
|
|
}
|
|
|
|
memset(info, 0, sizeof(struct rc_ipc_info));
|
|
|
|
/* create or attach shared memory */
|
|
|
|
fd = shm_open(RC_IPC_SHM_NAME, O_RDWR | O_CREAT, 0666);
|
|
if (fd < 0) {
|
|
if (verbosity > 0)
|
|
perror("shm_open");
|
|
free(info);
|
|
return NULL;
|
|
}
|
|
|
|
if (ftruncate(fd, sizeof(struct rc_pkt)) != 0) {
|
|
if (verbosity > 0)
|
|
perror("ftruncate");
|
|
close(fd); /* instead of shm_unlink() */
|
|
free(info);
|
|
return NULL;
|
|
}
|
|
|
|
info->pkt = mmap(NULL, sizeof(struct rc_pkt), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
|
if (info->pkt == MAP_FAILED) {
|
|
if (verbosity > 0)
|
|
perror("mmap");
|
|
close(fd);
|
|
free(info);
|
|
return NULL;
|
|
}
|
|
|
|
/* after mapping, the fd is no longer needed */
|
|
close(fd);
|
|
|
|
/* create semaphore */
|
|
|
|
info->sem = sem_open(RC_IPC_SEM_NAME, O_CREAT, 0666, 1);
|
|
if (info->sem == SEM_FAILED) {
|
|
if (verbosity > 0)
|
|
perror("sem_open");
|
|
munmap(info->pkt, sizeof(struct rc_pkt));
|
|
free(info);
|
|
return NULL;
|
|
}
|
|
|
|
info->magic = RC_IPC_INFO_MAGIC;
|
|
|
|
if (verbosity > 1)
|
|
printf("%s: shared memory and semaphore created\n", __FUNCTION__);
|
|
|
|
return (void *)info;
|
|
|
|
} /* rc_ipc_attach */
|
|
|
|
/* return 0 on success, nonzero on error */
|
|
int rc_ipc_put(void *rc_ipc_id, const struct rc_pkt *pkt, int verbosity)
|
|
{
|
|
struct rc_ipc_info *info = (struct rc_ipc_info *)rc_ipc_id;
|
|
|
|
/* sanity check */
|
|
if (info->magic != RC_IPC_INFO_MAGIC) {
|
|
printf("%s: ERROR: bad magic\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
/* lock */
|
|
if (sem_wait(info->sem) != 0) {
|
|
if (verbosity > 0)
|
|
perror("sem_wait");
|
|
return -1;
|
|
}
|
|
|
|
/* write packet */
|
|
memcpy(info->pkt, pkt, sizeof(struct rc_pkt));
|
|
|
|
/* unlock */
|
|
if (sem_post(info->sem) != 0) {
|
|
if (verbosity > 0)
|
|
perror("sem_post");
|
|
return -1;
|
|
}
|
|
|
|
if (verbosity > 1)
|
|
printf("%s: packet written to shared memory\n", __FUNCTION__);
|
|
|
|
return 0;
|
|
|
|
} /* rc_ipc_put */
|
|
|
|
/* return 0 on success, nonzero on error */
|
|
int rc_ipc_get(void *rc_ipc_id, struct rc_pkt *pkt, int verbosity)
|
|
{
|
|
struct rc_ipc_info *info = (struct rc_ipc_info *)rc_ipc_id;
|
|
|
|
/* sanity check */
|
|
if (info->magic != RC_IPC_INFO_MAGIC) {
|
|
printf("%s: ERROR: bad magic\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
/* lock */
|
|
if (sem_wait(info->sem) != 0) {
|
|
if (verbosity > 0)
|
|
perror("sem_wait");
|
|
return -1;
|
|
}
|
|
|
|
/* read packet */
|
|
memcpy(pkt, info->pkt, sizeof(struct rc_pkt));
|
|
|
|
/* unlock */
|
|
if (sem_post(info->sem) != 0) {
|
|
if (verbosity > 0)
|
|
perror("sem_post");
|
|
return -1;
|
|
}
|
|
|
|
if (verbosity > 1)
|
|
printf("%s: packet read from shared memory\n", __FUNCTION__);
|
|
|
|
return 0;
|
|
|
|
} /* rc_ipc_get */
|
|
|
|
/* return 0 on success, nonzero on error */
|
|
int rc_ipc_detach(void *rc_ipc_id, int verbosity)
|
|
{
|
|
struct rc_ipc_info *info = (struct rc_ipc_info *)rc_ipc_id;
|
|
int status = 0;
|
|
|
|
/* sanity check */
|
|
if (info->magic != RC_IPC_INFO_MAGIC) {
|
|
printf("%s: ERROR: bad magic\n", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
|
|
info->magic = 0;
|
|
|
|
if (munmap(info->pkt, sizeof(struct rc_pkt)) != 0) {
|
|
perror("munmap");
|
|
status = -1;
|
|
}
|
|
info->pkt = NULL;
|
|
|
|
if (sem_close(info->sem) != 0) {
|
|
perror("sem_close");
|
|
status = -1;
|
|
}
|
|
info->sem = NULL;
|
|
|
|
free(info);
|
|
|
|
return status;
|
|
|
|
} /* rc_ipc_detach */
|