From ce9e8e47576e4bd9bbfb42722e6012ffab0cf640 Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Sat, 12 Dec 2020 16:40:16 +0500 Subject: [PATCH] Add raw examples --- .gitignore | 2 + Makefile.am | 13 +++- configure.ac | 3 + examples/raw.h | 35 +++++++++ examples/raw_receiver.c | 131 ++++++++++++++++++++++++++++++++++ examples/raw_sender.c | 153 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 examples/raw.h create mode 100644 examples/raw_receiver.c create mode 100644 examples/raw_sender.c diff --git a/.gitignore b/.gitignore index c9e0a7a..67db8a8 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,6 @@ /tests/test*.trs /examples/dummy +/examples/raw_receiver +/examples/raw_sender /tests/test_dummy diff --git a/Makefile.am b/Makefile.am index ac3bb57..4834913 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,7 +12,10 @@ TESTS = \ examples/dummy \ tests/test_dummy -noinst_PROGRAMS = $(TESTS) +noinst_PROGRAMS = \ + $(TESTS) \ + examples/raw_receiver \ + examples/raw_sender libshmemq_a_SOURCES = \ src/dummy.c @@ -21,6 +24,14 @@ examples_dummy_SOURCES = \ $(libshmemq_a_SOURCES) \ examples/dummy.c +examples_raw_receiver_SOURCES = \ + $(libshmemq_a_SOURCES) \ + examples/raw_receiver.c + +examples_raw_sender_SOURCES = \ + $(libshmemq_a_SOURCES) \ + examples/raw_sender.c + tests_test_dummy_SOURCES = \ $(libshmemq_a_SOURCES) \ tests/test_dummy.c diff --git a/configure.ac b/configure.ac index fc06c00..b1ae755 100644 --- a/configure.ac +++ b/configure.ac @@ -24,4 +24,7 @@ AC_PROG_CC AC_PROG_CC_C99 AC_PROG_RANLIB +AC_SEARCH_LIBS([shm_open], [rt]) +AC_SEARCH_LIBS([shm_unlink], [rt]) + AC_OUTPUT diff --git a/examples/raw.h b/examples/raw.h new file mode 100644 index 0000000..2476cf6 --- /dev/null +++ b/examples/raw.h @@ -0,0 +1,35 @@ +#ifndef _RAW_H +#define _RAW_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static const size_t BUFFER1_SIZE = 200; +static const long BUFFER1_MAGIC = 0xCAFEBABE; + +struct Indicator { + size_t buffer1_offset; +}; + +enum MessageType { + FINISH, + ONEBYTE, + NULLSTR, +}; + +struct Message { + long magic; + size_t size; + enum MessageType type; + + unsigned char data[]; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/raw_receiver.c b/examples/raw_receiver.c new file mode 100644 index 0000000..8aedd84 --- /dev/null +++ b/examples/raw_receiver.c @@ -0,0 +1,131 @@ +#include "raw.h" + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool running = true; + +static void signal_handler(const int signo) +{ + if (signo == SIGINT) { + running = false; + } +} + +int main() +{ + signal(SIGINT, signal_handler); + + printf("Open shared memory objects.\n"); + + int indicator_shm_id = shm_open( + "/indicator", + O_CREAT | O_EXCL | O_RDWR, + S_IRUSR | S_IWUSR + ); + + int buffer1_shm_id = shm_open( + "/buffer1", + O_CREAT | O_EXCL | O_RDWR, + S_IRUSR | S_IWUSR + ); + + assert(indicator_shm_id != -1); + assert(buffer1_shm_id != -1); + + printf("Truncate shared memory objects.\n"); + + assert(ftruncate(indicator_shm_id, sizeof(struct Indicator)) == 0); + assert(ftruncate(buffer1_shm_id, BUFFER1_SIZE) == 0); + + printf("Create memory mappings.\n"); + + struct Indicator *const indicator = mmap( + NULL, + sizeof(*indicator), + PROT_READ | PROT_WRITE, + MAP_SHARED, + indicator_shm_id, + 0 + ); + + void *const buffer1 = mmap( + NULL, + BUFFER1_SIZE, + PROT_READ, + MAP_SHARED, + buffer1_shm_id, + 0 + ); + + assert(indicator != MAP_FAILED); + assert(buffer1 != MAP_FAILED); + + printf("Initialize queues.\n"); + + indicator->buffer1_offset = 0; + + printf("Main loop.\n"); + + while (running) { + const struct Message *const message = buffer1 + indicator->buffer1_offset; + + if (message->magic != BUFFER1_MAGIC) { + printf("No messages.\n"); + sleep(1); + continue; + } + + if (message->size > BUFFER1_SIZE) { + printf("Message too big.\n"); + break; + } + + if (message->size > BUFFER1_SIZE - indicator->buffer1_offset) { + printf("Buffer return.\n"); + indicator->buffer1_offset = 0; + continue; + } + + indicator->buffer1_offset += message->size; + + switch (message->type) { + case FINISH: + printf("Message: finish.\n"); + running = false; + break; + case ONEBYTE: + printf("Message: 1 byte (%u)\n", *(unsigned char*)message->data); + break; + case NULLSTR: + printf("Message: null-terminated string (%s)\n", message->data); + break; + default: + printf("Invalid message.\n"); + running = false; + } + } + + printf("Destroy memory mappings.\n"); + + assert(munmap(indicator, sizeof(*indicator)) == 0); + assert(munmap(buffer1, BUFFER1_SIZE) == 0); + + printf("Unlink shared memory objects.\n"); + + assert(shm_unlink("/indicator") == 0); + assert(shm_unlink("/buffer1") == 0); + + return 0; +} diff --git a/examples/raw_sender.c b/examples/raw_sender.c new file mode 100644 index 0000000..739ec1d --- /dev/null +++ b/examples/raw_sender.c @@ -0,0 +1,153 @@ +#include "raw.h" + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char nullstr[] = "Hello, World!"; + +int main() +{ + printf("Open shared memory objects.\n"); + + int indicator_shm_id = shm_open( + "/indicator", + O_RDONLY, + S_IRUSR | S_IWUSR + ); + + int buffer1_shm_id = shm_open( + "/buffer1", + O_RDWR, + S_IRUSR | S_IWUSR + ); + + assert(indicator_shm_id != -1); + assert(buffer1_shm_id != -1); + + printf("Create memory mappings.\n"); + + struct Indicator *const indicator = mmap( + NULL, + sizeof(*indicator), + PROT_READ, + MAP_SHARED, + indicator_shm_id, + 0 + ); + + void *const buffer1 = mmap( + NULL, + BUFFER1_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + buffer1_shm_id, + 0 + ); + + assert(indicator != MAP_FAILED); + assert(buffer1 != MAP_FAILED); + + printf("Initialize queues.\n"); + + size_t buffer1_offset = indicator->buffer1_offset; + + for (;;) { + const struct Message *const message = buffer1 + buffer1_offset; + + if (message->magic != BUFFER1_MAGIC) break; + + if (message->size > BUFFER1_SIZE) { + printf("Message too big.\n"); + goto finalize; + } + + if (message->size > BUFFER1_SIZE - buffer1_offset) { + printf("Buffer return.\n"); + buffer1_offset = 0; + continue; + } + + buffer1_offset += message->size; + } + + printf( + "REPL commands:\n" + " x - exit\n" + " f - send finish message\n" + " 1 - send 1 byte\n" + " 0 - send null-terminated string\n" + ); + + printf("REPL.\n"); + + for (;;) { + const char chr = getchar(); + + if (chr == '\n') continue; + + if (chr == 'x') { + printf("Command: exit.\n"); + break; + } + + struct Message *message = buffer1 + buffer1_offset; + + switch (chr) { + case 'f': + { + const size_t size = sizeof(*message); + buffer1_offset += size; + message->type = FINISH; + message->size = size; + message->magic = BUFFER1_MAGIC; + } + break; + case '1': + { + const size_t size = sizeof(*message) + sizeof(unsigned char); + buffer1_offset += size; + *(unsigned char*)message->data = 123; + message->type = ONEBYTE; + message->size = size; + message->magic = BUFFER1_MAGIC; + } + break; + case '0': + { + const size_t size = sizeof(*message) + strlen(nullstr) + 1; + buffer1_offset += size; + strcpy((char*)message->data, nullstr); + message->type = NULLSTR; + message->size = size; + message->magic = BUFFER1_MAGIC; + } + break; + default: + printf("Unknown command: '%c'\n", chr); + } + } + +finalize: + printf("Destroy memory mappings.\n"); + + assert(munmap(indicator, sizeof(*indicator)) == 0); + assert(munmap(buffer1, BUFFER1_SIZE) == 0); + + printf("Close shared memory objects.\n"); + + assert(close(indicator_shm_id) == 0); + assert(close(buffer1_shm_id) == 0); + + return 0; +}