I have a structure A of the form described below. My goal is to create the structure in one process and share it across to a different process. A->buffer depends upon user_size and value provided and hence I cannot have a pre-allocated buffer. Knowing that sharing pointers with shared memory is hard across processes since pointer value in one process will no longer be valid in the other process, I tried the following approach.
I wanted to allocate the buffer from shared memory, from the writing process so that other processes can map to the same shared memory and obtain a valid pointer address to the shared memory.
Conceptually, calling mmap on the same shared memory fd descriptor should point to the same location in shared memory, however on the reading process, I'm able to get a valid pointer and valid another_value.
Can someone clarify this? Parts of the code below.
struct A {
int another_variable;
void *buffer;
}
/* the size (in bytes) of shared memory object */
const int SIZE = 4096;
/* name of the shared memory object */
const char *name = "OS";
/* shared memory file descriptor */
int shm_fd;
/* create the shared memory object */
shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
/* configure the size of the shared memory object */
ftruncate(shm_fd, SIZE);
a_data = mmap(NULL, sizeof(*A), PROT_READ | PROT_WRITE, MAP_SHARED,
shm_fd, 0);
if (a_data == MAP_FAILED) {
printf("ERROR: mmap failed for a_data\n");
exit(EXIT_FAILURE);
}
a_data->buffer = mmap(NULL, user_size, PROT_WRITE,
MAP_SHARED , shm_fd, 0);
if (a_data->buffer == MAP_FAILED) {
printf("ERROR: mmap failed for a_data buffer\n");
exit(EXIT_FAILURE);
}
memcpy(a_data->buffer, "test", strlen("test"));
Related
I would like to do multi-process programming where I need to share data (reader/writer case).
My idea is to use shared memory to track read/write index.
And the index indicates the shared file index.
For example, if write index = 2, it means writer is writing shared file named
"temp_2.data". if read index = 1, it means reader is reading shared file named "temp_1.data".
My problem is:
Do I need the synchronization mechanism when, ex: accessing rptr below? or shm_open itself promises the synchronization? If so, how it makes the synchronization?
The hybrid design of shared memory and shared file makes sense? Or if there is any better way?
Thanks~
#include <unistd.h>
#include <sys/mman.h>
...
#define MAX_LEN 10000
struct region { /* Defines "structure" of shared memory */
int len;
char buf[MAX_LEN];
};
struct region *rptr;
int fd;
/* Create shared memory object and set its size */
fd = shm_open("/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1)
/* Handle error */;
if (ftruncate(fd, sizeof(struct region)) == -1)
/* Handle error */;
/* Map shared memory object */
rptr = mmap(NULL, sizeof(struct region),
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (rptr == MAP_FAILED)
/* Handle error */;
/* Now we can refer to mapped region using fields of rptr;
for example, rptr->len */
...
noob alert with C here.
I have a struct as such
typedef struct {
char* name
} info;
And storing an array (size 10) of this struct (in another struct called table) in a shared memory object using the shm_open call:
int fd = shm_open("someName", O_CREAT | O_EXCL | O_RDWR, S_IRWXU);
if (fd < 0) {
fd = shm_open("someName", O_CREAT | O_RDWR, S_IRWXU);
if (fd < 0) {
printf("ERROR: Could not open shared memory space\n");
return -1;
}
}
(*tables) = mmap(NULL, sizeof(table), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
ftruncate(fd, sizeof(table));
close(fd);
However, the issue that I have is that later through the code such a scenario happens:
If process B runs this and puts some text, say "foo" in the name field of an element of the table array, process A does not have access to that char*.
All it sees is a memory address, but not the actual content of the char* as opposed to if it wrote the content itself. However, I would also like to note that if I replace char* with a fixed size char[], say char name[20] instead of char *name, then this issue does not occur.
I would like to know whether there is any way around this, and if not, why is it so?
Thank you!
When using shared memory for IPC, all of the data to be shared, must be located in shared memory. It's that simple, there's no way around it. What you can do however for some larger, more variable chunks of data, is simply allocate a dedicated shared memory chunk for that data, and provide its name via the master table. Another option in your case is to arrange for the shared memory to be sufficiently larger than your info struct, such that name is just an offset from that address, to where the name data resides. Then address of data is `&name + *name'.
I am using shared memory for communication between two different process. I am creating shared memory of 16 MB size. I am trying to attach two different parts of the shared memory. One for writing and other for reading. Even though it maps to different memory address but when one is modified other also gets changed. I must be doing something wrong. Below is the code snippet where I am attaching to multiple shared memory location.
void createCommPool ()
{
CommSet set1;
int shmid1;
int fd1;
int r;
void * ptr;
void * ptr_res;
umask (0);
fd1 = open(SHARED_MEMORY0, O_CREAT | O_TRUNC | O_RDWR, 0777);
if (fd1 == -1)
error_and_die("open");
r = ftruncate(fd1, region_size);
if (r != 0)
error_and_die("ftruncate");
ptr = mmap(0, sizeof(struct operation_st), PROT_READ | PROT_WRITE,
,MAP_SHARED,fd1,sizeof(struct operation_st));
if (ptr == MAP_FAILED)
error_and_die("mmap");
close(fd1);
set1.shm_addr = ptr;
fd1 = open(SHARED_MEMORY0, O_RDWR, 0777);
if (fd1 == -1)
error_and_die("open");
fprintf(stderr,"The value of the file descriptor:%d\n",fd1);
if (lseek(fd1,sizeof(struct operation_st),SEEK_SET)<0)
{
fprintf(stderr,"could not perform lseek\n");
perror("lseek");
}
ptr_res = mmap(0,sizeof(struct operation_st), PROT_READ| PROT_WRITE,
MAP_SHARED,fd1,0);
if (ptr_res == MAP_FAILED)
error_and_die("mmap2");
close(fd1);
set1.shm_addr_res = ptr_res;
}
For data in shared memory, avoid the influence of bytes alignment with pack:
#pragma pack(1)
your shared memory code
#pragma unpack
lseek does not have any effect on the mapping of the shared memory. The offset parameter should be used in order to map to the different part of the shared memory. The offset should be in multiples of page size.
I've got this struct:
typedef struct ip_row {
sem_t row_lock;
char row_name[NAME_SIZE];
char row_address4[NAME_SIZE]; // IPv4 address name
char row_address6[NAME_SIZE]; // IPv6 address name
} ip_row_t;
I would like to use the struct multiple times in a shared memory file.I have verified that for exactly one use, it works.
int shmfd; //Shared memory file descriptor
struct ip_row *data;
/*...creating shared memory and map...*/
shmfd = shm_open(shared_memory, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP );
ftruncate(shmfd,FILESIZE);
data = (ip_row_t*)mmap(0, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd,0);
/*...getting to user inputs, this stuff is in a loop...*/
strcpy(data->row_name,ipstr1);
strcpy(data->row_address6,ipstr2);
strcpy(data->row_address4,ipstr3);
When I run the loop again, the writing starts at the beginning of the shared memory file, overwriting what was there before. How can I move the offset so I can support more entries into the shared memory? I've tried these two:
lseek(shmfd,sizeof(struct ip_row_t),SEEK_CUR); //segfault when we write agian
data = (ip_row_t*)mmap(0, FILESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd,sizeof(struct ip_row_t)); //also segfaults when we try to read
Any advice would be greatly appreciated.
`
You should use pointer arithmetic on struct ip_row *data; to reach "further" in your mmaped shared memory since mmap returns nothing but a pointer to a memory region of FILESIZE, which happens to be mirrored into shared memory.
For example use data[0] to access first copy, data[1] to access second etc.
lseek on shared memory object is unspecified and your second mmap causes segfault because you are trying to mmap FILESIZE bytes to a FILESIZE memory region that has been allocated to you but at an sizeof(struct ip_row_t) offset, thus effectively going outside the memory you are allowed to access, besides, offset has to be multiple of getpagesize(), which in this case it probably is not.
I have an issue attempting to access shared memory using mmap for complex types.
So I allocate my memory as so in my parent process:
/* Create mmap file */
fid = open(TMP_FILE_NAME, O_RDWR | O_CREAT | O_EXCL, (mode_t) 0755);
if (fid < 0)
{
printf("Bad Open of mmap file <%s>\n", TMP_FILE_NAME);
die(-1);
}
/* Make mmap file Buffer Size */
status = ftruncate(fid, INPUT_BUFFER_SIZE);
if (status)
{
printf("Failed to ftruncate the file <%s>, status = %d\n", TMP_FILE_NAME, status);
die(-1);
}
/* Initialize Shared Memory */
mmap_ptr = mmap((caddr_t) 0,
INPUT_BUFFER_SIZE, // Default Buffer Size
PROT_WRITE | PROT_READ, // R/W Permissions
MAP_SHARED, // No file backing
fid,
(off_t) 0);
if (mmap_ptr == MAP_FAILED)
{
printf("Failed to perform mmap, Exiting\n");
die(-1);
}
Now the Struct that I'm passing in memory to my child process is as follows:
/* Data structue for IPC */
typedef struct {
int current_active_id;
int consume_remaining;
Queue buffer;
} input_buffer;
where Queue is a data structure class from the following:
http://www.idevelopment.info/data/Programming/data_structures/c/Queue/Queue.shtml
In my child process it's okay when I do this, it returns the correct value:
printf("Got here... Shared Mem: %d\n", input_queue->consume_remaining);
but when I do something like:
IsEmpty(input_queue->buffer)
it crashes and in the code of the Queue it's only doing this:
return Q->Size == 0;
Any help would be appreciated, thanks!!
Queue is a pointer to struct QueueRecord, and should be allocated as such, presumably using the same shared memory segment. note that this should also be mapped at the same address in both parent and child, or you will not be able to dereference it.
The structure you are putting in the map contains pointers. The pointers are all relative to the address space of the process that created them.
If the other process doesn't mmap at the same address, or if it does but the allocations made for the queue aren't taken from inside that buffer, the pointers will be invalid in the other process.