Skip to content

Instantly share code, notes, and snippets.

@hedenface
Created March 29, 2018 21:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hedenface/0f6b59aeca8cedd0f2939f0cc46bada6 to your computer and use it in GitHub Desktop.
Save hedenface/0f6b59aeca8cedd0f2939f0cc46bada6 to your computer and use it in GitHub Desktop.
Shared memory buffer between two processes
/*****************************
*
* shared_mem_buffer.c
*
* Compile:
* gcc shared_mem_buffer.c -lpthread -lrt -o shared_mem_buffer
*
* Execute:
* ./shared_mem_buffer
*
* Why:
* In the process of looking into
* kernel message queue alternatives
* for NDOUtils. Wanted a fast
* way of atomic communication.
* This was one of the research
* avenues for that.
*
* One process injects data into
* a queue, with each data message
* separated with some advanced
* token. Then a child (or children)
* process(es) read the first message
* and adjust the remaining string.
*
* https://github.com/NagiosEnterprises/ndoutils
*
*****************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>
#define RANDOM_STR_SIZE 104
#define SHARED_STR_SIZE 104 * 10
#define END_TOKEN ";|;|;|;"
#define END_TOKEN_FIRST_CHAR ';'
#define END_TOKEN_LEN 7
/* just a magic function to get a character
in the range of: 0-9A-Za-z */
char get_random_char()
{
register unsigned int tmp = rand() % 62;
if (tmp < 10) {
return tmp + 48;
}
if (tmp < 36) {
return tmp + 55;
}
return tmp + 61;
}
int main (int argc, char **argv)
{
int i, j;
sem_t *sem;
pid_t pid;
int sh_desc = -1;
char * sh_str = NULL;
char * random_str[5] = { NULL };
/* generate several large strings */
for (i = 0; i < 5; i++) {
random_str[i] = malloc(RANDOM_STR_SIZE + 2 + 1);
for (j = 1; j < RANDOM_STR_SIZE - 2; j++) {
random_str[i][j] = get_random_char();
}
random_str[i][0] = '[';
random_str[i][RANDOM_STR_SIZE - 2] = ']';
random_str[i][RANDOM_STR_SIZE - 1] = '\0';
printf("random_str[%d] = %s\n", i, random_str[i]);
}
printf("random_strs setup\n");
/* create a semaphore */
sem = sem_open("/my_sem", O_CREAT | O_EXCL, 0644, 1);
printf("sem opened\n");
/* create some shared memory buffer */
sh_desc = shm_open("/my_shm", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
ftruncate(sh_desc, SHARED_STR_SIZE);
sh_str = mmap(NULL, SHARED_STR_SIZE, PROT_WRITE | PROT_READ, MAP_SHARED, sh_desc, 0);
memset(sh_str, 0, sizeof(char) * SHARED_STR_SIZE);
printf("sh_str setup\n");
/* spawn */
pid = fork();
/* parent */
if (pid != 0) {
printf("parent: adding random_strs to sh_str\n");
for (i = 0; i < 5; i++) {
/* grab the semaphore */
sem_wait(sem);
/* append our random_str and token to the shared string */
printf("parent: adding random_str[%d]...\n%s\n\n", i, random_str[i]);
strcat(sh_str, random_str[i]);
strcat(sh_str, END_TOKEN);
/* release the semaphore */
sem_post(sem);
/* let the child do some work */
sleep(1);
}
/* this stops the cli from returning too fast */
sleep(2);
}
/* child */
else {
printf("child: reading random_strs from sh_str\n");
char * this_random_str = NULL;
char * token = NULL;
unsigned int offset = 0;
for (i = 0; i < 5; i++) {
/* wait for the parent to have added some things */
sleep(1);
/* grab the semaphore */
sem_wait(sem);
/* keep looking until we find one */
while (this_random_str == NULL) {
/* search for the first character of our token in sh_str */
token = memchr(sh_str + offset, END_TOKEN_FIRST_CHAR, SHARED_STR_SIZE - offset - 1);
/* if we didn't find one of our chars from
the terminating token, we just stop
trying - we'll catch it next time */
if (token == NULL) {
break;
}
/* we need this data no matter what */
offset = token - sh_str;
/* check if we really have our token
or just found a character in a sea
of characters */
if (strstr(token, END_TOKEN) != token) {
continue;
}
/* now we populate our this_random_str
with the data from before the token */
this_random_str = malloc(offset+1);
memcpy(this_random_str, sh_str, offset);
this_random_str[offset] = '\0';
}
/* now that we have our data, we need to
push sh_str forward by offset + a few
characters */
memmove(sh_str, sh_str + offset + END_TOKEN_LEN, strlen(sh_str));
/* HOORAY! we got the message */
printf("child: got msg: %s\n\n", this_random_str);
/* free our intermediary resource */
free(this_random_str);
this_random_str = NULL;
/* release the semaphore */
sem_post(sem);
}
}
/* free up what we've used */
for (i = 0; i < 5; i++) {
free(random_str[i]);
}
/* unmap our shared space */
munmap(sh_str, SHARED_STR_SIZE);
/* close semaphore */
sem_close(sem);
/* delete our shared resources */
if (pid != 0) {
shm_unlink("/my_shm");
sem_unlink("/my_sem");
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment