Inter process communication via shared memory - c

I am trying do an inter process communication using shared memory. Here is the structure definition.
#define SHM_SIZE (519430400)
test_ht *CommandLine_Buffer;
typedef struct
{
int a;
int testnum;
st_cl cli[3];
}test_ht;
typedef struct
{
tHT CliInfo;
} st_cl;
typedef struct
{
int x;
} tHT;
Shared memory is created as below
int fd;
int ret_v;
void* addr;
int i;
fd = shm_open("SharedBuf.shm", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
ret_v = ftruncate(fd, SHM_SIZE);
SharedBuffer = mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, SEEK_SET);
I access the structure members as below
CommandLine_Buffer->cli[i].CliInfo.x
Here I can read and write a and testnum across procesess. Shared memory is created successfully.
At the same time I can access
CommandLine_Buffer->cli[0].CliInfo.x and CommandLine_Buffer->cli[1].CliInfo.x
Am unable to get CommandLine_Buffer->cli[2].CliInfo.x.
Any tips to debug this or any idea why am unable to read the last location.

Related

Why is my string not showing after transfer via SHM?

I've created the following types to transfer a list of nodes from one process to the other one:
typedef struct {
char *from;
char *to;
} Edge;
typedef struct {
size_t numEdges;
Edge *fst;
} EdgeList;
typedef struct {
EdgeList buffer[BUFFER_SIZE];
...
} CircularBuffer; /**< used as shared memory. */
This is what the process that sends the EdgeList looks like:
// open shared memory -> shm_open()
int shm_fd = shm_open(SHM_PATH, O_RDWR, S_IRUSR | S_IWUSR);
...
// map shared memory into memory -> mmap()
CircularBuffer *shm = mmap(NULL, sizeof(CircularBuffer),
PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
...
while (true) {
shm->buffer[...] = getSolution(...);
...
}
...
This is what the process that receives the EdgeList looks like:
// create shared memory -> shm_open()
int shm_fd = shm_open(SHM_PATH, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
...
// set shared memory size -> ftruncate()
ftruncate(shm_fd, sizeof(CircularBuffer);
...
// map shared memory into memory -> mmap()
CircularBuffer *shm = mmap(NULL, sizeof(CircularBuffer),
PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
...
EdgeList bestSolution = {.numEdges = SIZE_MAX, .fst = NULL};
while (true) {
EdgeList solution = shm->buffer[...];
if (solution.numEdges < bestSolution.numEdges) {
bestSolution = solution;
// I can read 'bestSolution.numEdges' here just fine.
// But i can't read 'bestSolution.fst[i].from' and 'bestSolution.fst[i].to' for some reason.
}
...
}
...
Now here is where things behave unexpectedly: The receiving process is not showing me any strings from the shared memory but everything else works just as expected.
I have access to bestSolution.numEdges after it being read from the shared memory, but not to bestSolution.fst[i].from and bestSolution.fst[i].to (with i being a legal index from that array).
When I try to read these strings, I only see (null) instead of the strings. Can I fix this issue?

How to use struct in POSIX shared memory?

I want my POSIX shared memory segment to conform to a particular structure. I think this code creates the shared memory segment in the shape of the struct.
(File creating the shared memory segment)
typedef struct {
int cnt;
char buf[segsize];
} shmseg_t;
int shm_fd = shm_open(shm_name, O_CREAT | O_RDWR, 0666);
ftruncate(shm_fd, sizeof(shmseg_t);
void* addr = mmap(NULL, sizeof(shmseg_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
How do I write data from a file to the different fields of the struct in the shared memory?
(File writing to the shared memory segment)
int shm_fd = shm_open(shm_name, O_WRONLY, 0);
ftruncate(shm_fd, segsize);
void* addr = mmap(NULL, segsize, PROT_WRITE, MAP_SHARED, shm_fd, 0);
// How do I get shmp, which should be a shmseg_t struct?
shmp->cnt = read(fd, shmp->buf, segsize);
And how do I get out the data that was written to the struct in the shared memory?
(File reading from the shared memory segment)
int shm_fd = shm_open(shm_name, O_RDONLY, 0);
ftruncate(shm_fd, segsize);
void* addr = mmap(NULL, segsize, PROT_READ, MAP_SHARED, shm_fd, 0);
// How to get out shmp->cnt and shmp->buf?
It is unclear whether you want to share the entire structure or just buf.
Option 1: Make buf a pointer, and share what it points to.
typedef struct {
int cnt;
char *buf;
} shmseg_t;
ftruncate(shm_fd, segsize);
void* addr = mmap(NULL, segsize,
PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
assert(addr != MAP_FAILED);
shm_seg_t shmp = {
.cnt = ???, // Whatever value of cnt you want.
.buf = addr,
};
Option 2: Share the entire struct.
typedef struct {
int cnt;
char buf[segsize];
} shmseg_t;
ftruncate(shm_fd, sizeof(shmseg_t));
void* addr = mmap(NULL, sizeof(shmseg_t),
PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
assert(addr != MAP_FAILED);
shm_seg_t *shmp = addr;
If you share it this way, reading and writing are not really different (but you do need to use memory barriers or synchronization).

shm_open() fails while reopening with same name though O_CREAT is used again

According to the http://man7.org/linux/man-pages/man3/shm_open.3.html, it says that
After a successful shm_unlink(), attempts to shm_open() an object with the same name fail (unless O_CREAT was
specified, in which case a new, distinct object is created).
S, i tried this one. I am using the below example which creates new shared memory object after doing shm_unlink and as they said i use the O_CREAT.
But when i run this problem, it gives me error related bus error.
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
int main(void) {
// Open shared memory
int fd = shm_open("TEST", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
ftruncate(fd, sizeof(int));
// Map shared memory
int *shm = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd,0);
close(fd);
// Access shared memory
*shm = 0;
// Unmap shared memory
munmap(shm, sizeof(int));
if(shm_unlink("TEST")){
printf("************success****************");
}
fd = shm_open("TEST", O_CREAT |O_RDWR, S_IRUSR | S_IWUSR);
int *shm2 = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd,0);
*shm2 = 0;
return 0;
}
What is the right process of creating the shared memory with the same name again after doing shm_unlink.
You are accessing wrong shared memory in your second attempt (it should be shm2, not shm), and do not forget truncate.
Also not relevant but shm_unlink returns 0 on success.
#include <sys/mman.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(void) {
// Open shared memory
int fd = shm_open("TEST", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
ftruncate(fd, sizeof(int));
// Map shared memory
int *shm = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd,0);
close(fd);
// Access shared memory
*shm = 0;
// Unmap shared memory
munmap(shm, sizeof(int));
if(!shm_unlink("TEST")){
printf("************success****************");
}
fd = shm_open("TEST", O_CREAT |O_RDWR, S_IRUSR | S_IWUSR);
int *shm2 = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd,0);
ftruncate(fd, sizeof(int));
*shm2 = 0;
return 0;
}

ftruncate() invalid arguement error

I just started learned about shared memory and we are suppose to create an object of shared memory for my assignment, but I keep getting an error when I run my program.
The error comes from the ftruncate() function and it keeps telling me its an invalid argument, here's my code segment for the shared memory:
struct container* rPtr;
int fd;
/* Creates shared memory object and sets it size */
fd = shm_open("/collatzRegion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1)
{ perror("shm_open");
return 1;
}
if ((ftruncate(fd, sizeof(struct container))) == -1)
{ perror("ftruncate");
return 1;
}
/* Maps shared memory object */
rPtr = mmap(NULL, sizeof(struct container), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if ( rPtr == MAP_FAILED)
{ perror("mmap");
return 1;
}
and my structure, that is defined before my main(), is:
/* Defines "structure" of shared memory */
#define MAX_LEN 10000
struct container
{ int length;
int buf[MAX_LEN];
};

Sharing memory between processes on linux

I have server, that use multiple processes (fork()). There are large blocks of data, that can be created by one process and should be shared between other processes.
So, i use shm_open + mmap to create shared memory and map it to virtual memory.
struct SharedData {
const char *name;
int descriptor;
void *bytes;
size_t nbytes;
}
void shared_open(SharedData *data, const char *name, size_t nbytes) {
int d = shm_open(name, O_RDONLY, S_IRUSR | S_IWUSR);
if (d != -1) {
void *bytes = mmap(NULL, nbytes, PROT_READ, MAP_SHARED, d, 0 );
data->name = name;
data->descriptor = d;
data->bytes = bytes;
data->nbytes = nbytes;
} else {
data->descriptor = -1;
}
}
void shared_create(SharedData *data, const char *name, void *bytes, size_t nbytes) {
int d = shm_open(name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (d != -1) {
if (nbytes = write(d, bytes, nbytes)) {
shared_open(data, name, nbytes);
}
shm_unlink(name);
}
}
void shared_close(SharedData *data) {
if (data->descriptor != -1) {
munmap(data->bytes, data->nbytes);
shm_unlink(data->name);
}
}
Initial process create shared memory object with shared_create, other processes opens it with shared_open
Is this approach valid? Are there more effective or more simple methods?
Your design looks reasonable. To stay within the POSIX guidelines of the API to shared memory you should use ftruncate instead of write to extend the size, see
http://man7.org/linux/man-pages/man7/shm_overview.7.html
You can always do a memcpy to initialize the contents.
If you were using c++ you could use boost interprocess, if nothing else you can take a look at their interface.
http://www.boost.org/doc/libs/1_51_0/doc/html/interprocess/sharedmemorybetweenprocesses.html

Resources