libshmemq/src/main.c

113 lines
2.5 KiB
C
Raw Normal View History

2020-12-13 10:36:52 +00:00
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
2020-12-13 12:04:16 +00:00
#define _POSIX_C_SOURCE 200809L
#include <shmemq.h>
2020-12-13 11:32:17 +00:00
#include <fcntl.h>
#include <stdlib.h>
2020-12-13 11:25:53 +00:00
#include <string.h>
2020-12-13 11:32:17 +00:00
#include <sys/mman.h>
#include <sys/stat.h>
2020-12-13 12:04:16 +00:00
#include <unistd.h>
struct Shmemq *shmemq_new(
const char *const name,
const size_t size,
enum Shmemq_Error *const error_ptr
) {
struct Shmemq *const shmemq = malloc(sizeof(*shmemq));
if (!shmemq) {
2020-12-13 12:17:47 +00:00
if (error_ptr) *error_ptr = SHMEMQ_ERROR_FAILED_MALLOC;
return NULL;
}
const enum Shmemq_Error error = shmemq_init(shmemq, name, size);
if (error_ptr) *error_ptr = error;
if (error) {
free(shmemq);
return NULL;
}
return shmemq;
}
enum Shmemq_Error shmemq_init(
struct Shmemq *const shmemq,
const char *const name,
const size_t size
) {
2020-12-13 11:25:53 +00:00
if (strlen(name) > SHMEMQ_NAME_SLEN_MAX || name[0] != '/') {
2020-12-13 12:17:47 +00:00
return SHMEMQ_ERROR_INVALID_NAME;
2020-12-13 11:25:53 +00:00
}
for (const char *chr = &name[1]; *chr; ++chr) {
2020-12-13 12:17:47 +00:00
if (*chr == '/') return SHMEMQ_ERROR_INVALID_NAME;
2020-12-13 11:25:53 +00:00
}
strcpy(shmemq->name, name);
2020-12-13 12:19:46 +00:00
if (size != 0 && size < SHMEMQ_BUFFER_SIZE_MIN) {
return SHMEMQ_ERROR_INVALID_SIZE;
}
2020-12-13 11:25:53 +00:00
shmemq->is_consumer = size == 0;
2020-12-13 11:32:17 +00:00
shmemq->shm_id = shm_open(
shmemq->name,
O_CREAT | O_RDWR,
S_IRUSR | S_IWUSR
);
2020-12-13 12:27:23 +00:00
if (shmemq->shm_id == -1) return SHMEMQ_ERROR_FAILED_SHM_OPEN;
2020-12-13 11:32:17 +00:00
2020-12-13 12:04:16 +00:00
struct stat statbuf;
2020-12-13 12:13:38 +00:00
if (fstat(shmemq->shm_id, &statbuf) != 0) {
shm_unlink(shmemq->name);
2020-12-13 12:17:47 +00:00
return SHMEMQ_ERROR_FAILED_FSTAT;
2020-12-13 12:13:38 +00:00
}
2020-12-13 12:04:16 +00:00
2020-12-13 12:19:46 +00:00
const size_t min_size = size == 0 ? SHMEMQ_BUFFER_SIZE_MIN : size;
2020-12-13 12:04:16 +00:00
if ((size_t)statbuf.st_size < min_size) {
if (ftruncate(shmemq->shm_id, min_size) != 0) {
2020-12-13 12:13:38 +00:00
shm_unlink(shmemq->name);
2020-12-13 12:17:47 +00:00
return SHMEMQ_ERROR_FAILED_FTRUNCATE;
2020-12-13 12:04:16 +00:00
}
}
2020-12-13 12:13:38 +00:00
if (fstat(shmemq->shm_id, &statbuf) != 0) {
shm_unlink(shmemq->name);
2020-12-13 12:17:47 +00:00
return SHMEMQ_ERROR_FAILED_FSTAT;
2020-12-13 12:13:38 +00:00
}
2020-12-13 12:04:16 +00:00
if ((size_t)statbuf.st_size < size && !shmemq->is_consumer) {
2020-12-13 12:19:46 +00:00
if (ftruncate(shmemq->shm_id, min_size) != 0) {
2020-12-13 12:13:38 +00:00
shm_unlink(shmemq->name);
2020-12-13 12:17:47 +00:00
return SHMEMQ_ERROR_FAILED_FTRUNCATE;
2020-12-13 12:13:38 +00:00
}
2020-12-13 12:04:16 +00:00
}
2020-12-13 12:26:31 +00:00
shmemq->buffer = mmap(
NULL,
min_size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
shmemq->shm_id,
0
);
if (shmemq->buffer == MAP_FAILED) {
shm_unlink(shmemq->name);
return SHMEMQ_ERROR_FAILED_MMAP;
}
2020-12-13 11:25:53 +00:00
return SHMEMQ_ERROR_NONE;
}