Instantly share code, notes, and snippets.
Created
March 29, 2018 21:37
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save hedenface/0f6b59aeca8cedd0f2939f0cc46bada6 to your computer and use it in GitHub Desktop.
Shared memory buffer between two processes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/***************************** | |
* | |
* 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