I have two pieces of code like this.
Sender:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>
//
//Globals
void *shmem = NULL;
int main()
{
shmem = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if(fork() == 0)
{
sleep(1);
printf("%s\n", (char*)shmem);
exit(0);
}
else
{
strcpy((char*)shmem, "Hello, world!");
strcpy((char*)shmem, "get putin!");
wait(NULL);
}
return 0;
}
Receiver/Reader :
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>
//
//Globals
void *shmem = NULL;
int main()
{
shmem = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
printf("%s\n", (char*)shmem);
return 0;
}
Requirement: 1. When i run the first program that writes to SHM created using mmap, i should be able to verify whether what i read is right using a forked process. 2. When i run second program its supposed to read what the first process wrote. Note that I SHOULD NOT BE USING FILES created using SHM_OPEN for this purpose. Without need of disk files/ file descriptors i should be able to create SHM to make both processes write/read to each other.
Problem:
- The first program will print correctly what the parent process wrote. But when you run the second program after the first finishes writing, the second process sees blank, looks so because both are different processes, so different shared memory locations.
How to ensure mmap returns same memory location to both processes, without using common fd or file?
CodePudding user response:
When i run second program its supposed to read what the first process wrote. Note that I SHOULD NOT BE USING FILES created using SHM_OPEN for this purpose. Without need of disk files/ file descriptors i should be able to create SHM to make both processes write/read to each other.
No, that is not correct.
You can only use MAP_ANONYMOUS
with a program and a process that it forks. It is a private mapping that disappears when the program terminates.
This works fine for the child you fork from your first program.
However, a separate program has no way to access that data without the use of a backing store (e.g. file created with open
or shm_open
).
And, per the comments in shm_open
, the creator has to use ftruncate
to enlarge the file to the correct size.
Perhaps, you may wish to consider using SysV shared memory (e.g. shmget
, shmat
, etc.).
Here is the corrected first program:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>
//
//Globals
void *shmem = NULL;
int
main()
{
#ifdef SHM
int fd = shm_open("/abc",O_RDWR | O_CREAT,0644);
#else
int fd = open("/tmp/abc",O_RDWR | O_CREAT,0644);
#endif
ftruncate(fd,4096);
shmem = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if (fork() == 0) {
sleep(1);
printf("%s\n", (char *) shmem);
exit(0);
}
else {
strcpy((char *) shmem, "Hello, world!");
strcpy((char *) shmem, "get putin!");
wait(NULL);
}
close(fd);
return 0;
}
Here is the corrected second program:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>
//
//Globals
void *shmem = NULL;
int
main()
{
#ifdef SHM
int fd = shm_open("/abc",O_RDWR,0644);
#else
int fd = open("/tmp/abc",O_RDWR,0644);
#endif
if (fd < 0) {
perror("abc");
exit(1);
}
shmem = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
printf("%s\n", (char *) shmem);
close(fd);
#ifdef SHM
shm_unlink("/abc");
#else
unlink("/tmp/abc");
#endif
return 0;
}
CodePudding user response:
By definition, every call to mmap with MAP_ANONYMOUS returns a different, indepedent memory block. So the only way to share this is to call mmap once, in one process, and then fork a child after the mmap (and not call exec, as that will clear all mappings).
If you want to have two calls to mmap (in two different processes, like you describe) refer to the same block of shared memroy they must have some sort of reference or handle to that shared thing. That "handle" is the fd argument to mmap -- that's the only way to do it. So you must have the two programs open a file descriptor on some memory-like object (might be a file, or a shared memory object, or a mappable device) that they can then pass to mmap.