I create a shared memory in program A with the following codes:
shm = shm_open("/mfs_hash_pool_container", O_CREAT|O_RDWR, 0666);
size = sizeof(struct mfs_hash_pool_container);
ftruncate(shm, size);
mfs_hash_pool_stat_p = (struct mfs_hash_pool_container *)mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shm, 0);
I use that to store a hash table.
The other program B, will receives the addr (mfs_hash_pool_stat_p+offset) send from program A, but I can not write it in B.
Does this means I must also open this shared memory in B? Is there any other way to solve that? Because I create this memory automatically.
Thanks you guys.
You can't just use that address in the other program. B has to:
Obtain the file descriptor: shm_open("/mfs_hash_pool_container", O_RDWR, 0)
Map memory for the file descriptor: mmap just like A does
Notes:
You need to check the return value of mmap (it could return MAP_FAILED)
You need not cast the return value of mmap
Separate processes do not share memory, so the address being passed to B from A will not point to the shared memory segment. Each process must call shm_open() and mmap() the segment individually.
If you have information about the segment that every process needs to be aware of, pack it at the beginning of the segment in an order that each process is aware of.
I am not sure about how your program A and program B are related, but if you manage to spawn 'B' from 'A', using fork() + execve() combination, then you need not worry about passing the memory pointer as both processes will have the same copy.
For your reference I am pasting a nice code example present at IBM developerworks here-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/wait.h>
void error_and_die(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
int r;
const char *memname = "sample";
const size_t region_size = sysconf(_SC_PAGE_SIZE);
int fd = shm_open(memname, O_CREAT | O_TRUNC | O_RDWR, 0666);
if (fd == -1)
error_and_die("shm_open");
r = ftruncate(fd, region_size);
if (r != 0)
error_and_die("ftruncate");
void *ptr = mmap(0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
error_and_die("mmap");
close(fd);
pid_t pid = fork();
if (pid == 0)
{
u_long *d = (u_long *)ptr;
*d = 0xdbeebee;
exit(0);
}
else
{
int status;
waitpid(pid, &status, 0);
printf("child wrote %#lx\n", *(u_long *)ptr);
}
r = munmap(ptr, region_size);
if (r != 0)
error_and_die("munmap");
r = shm_unlink(memname);
if (r != 0)
error_and_die("shm_unlink");
return 0;
}
Read the full article in the above link to gain a better understanding of shared memory!
Process do not share memory by default. If you want this 2 processes to communicate or share memory, you'll have to make that happen. Check this question.
Another solution is to use threads, which share code and memory alike.
Related
In the child process the mapping is giving me issue. the parent is creating a shared memory and child is using it for writing a message to parent but when the mmap executes, it gives an error of permission denied. kindly help me to get rid of this issue. everything else is running file. when I try to create shared memory in child process the issue is resolved but the requirement is creating shared memory in parent process, that is why it is taking time to solve it.
/**
* Simple program demonstrating shared memory in POSIX systems.
*
* This is the consumer process
*
* Figure 3.18
*
* To compile, enter
* gcc shm-posix-consumer.c -lrt
*
* #author Gagne, Galvin, Silberschatz
* Operating System Concepts - Tenth Edition
* Copyright John Wiley & Sons - 2018
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/mman.h>
int main()
{
const int SIZE = 4096;
const char *name = "OS";
//shm_unlink(name);
int shm_fd;
void *ptr;
pid_t pid;
pid=fork();
if(pid==-1) {
printf("Error in creating a child process\n");
return -1;
}
else if(pid==0) {
sleep(2);
printf("child process is executing\n");
/* open the shared memory segment */
shm_fd = shm_open(name, O_RDWR, S_IRWXU);
if (shm_fd == -1) {
printf("opening of shared memory failed\n");
exit(-1);
}
if(ftruncate(shm_fd,SIZE)==-1){
printf("Error in configuring the size of shared memory");
exit(1);
}
/* now map the shared memory segment in the address space of the process */
ptr = mmap(0,SIZE,PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (ptr == MAP_FAILED) {
perror("Map failed in child process\n");
printf("error:%s %d",strerror(errno),errno);
return -1;
}
char *message0;
strcpy(message0,"Greeting to parent");
printf("Message to parent from child:%s\n",message0);
sprintf(ptr,"%s",message0);
ptr += strlen(message0);
if(munmap(ptr,SIZE)==-1){
printf("munmap error:\n");
exit(1);
}
close(shm_fd);
}
else {
printf("parent process is executing\n");
/* create the shared memory segment */
shm_fd = shm_open(name, O_CREAT | O_RDWR, S_IRWXU);
/* configure the size of the shared memory segment */
if(ftruncate(shm_fd,SIZE)==-1){
printf("Error in configuring the size of shared memory");
exit(1);
}
printf("parent process wait after creating shared memory\n");
wait(NULL);
printf("back to parent process after child termination\n");
/* now map the shared memory segment in the address space of the process */
ptr = mmap(0,SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
if (ptr == MAP_FAILED) {
printf("Map failed in parent\n");
return -1;
}
printf("%s\n",(char *)ptr);
if (shm_unlink(name) == -1) {
printf("Error removing %s\n",name);
exit(-1);
}
}
return 0;
}
At least three problems:
char *message0;
strcpy(message0,"Greeting to parent");
You are using message0 uninitialized, switch to something like
char message0[64];
strcpy(message0,"Greeting to parent");
or simply:
char *message0 = "Greeting to parent";
Here:
void *ptr;
...
ptr += strlen(message0);
You can't use pointer arithmetic with void *, switch to char *ptr;
And here:
ptr += strlen(message0);
if(munmap(ptr,SIZE)==-1){
you need to rewind ptr to the original position returned by mmap before calling munmap, it seems that you can remove this line:
ptr += strlen(message0);
Now it works for me adding #define _XOPEN_SOURCE 500 at the very beginning (for ftruncate).
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/mman.h>
int main()
{
const int SIZE = 500;
const char *name = "name";
int fd;
char *ptr = NULL;
pid_t pid;
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0) {
fd = shm_open(name,O_CREAT | O_RDWR,0666);
ftruncate(fd, SIZE);
ptr = (char *)mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
sprintf(ptr, "%s", "Hello, World!\n");
return 0;
}
else {
wait(NULL);
fd = shm_open(name, O_RDONLY, 0666);
ptr = (char *)mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
printf("%s\n", (char *)ptr);
}
return 0;
}
I am basically looking to create some shared memory in the child process and access it from the parent.
In the child process, the mmap works fine. When I print using the pointer returned by mmap it does in fact print Hello, World!, but the same print gives a seg fault from the parent.
In the parent (pid != 0) you opened the object O_RDONLY, but mmapped it with PROT_WRITE, MAP_SHARED. Remove the | PROT_WRITE and you are fine.
You might want to check the return values for errors the odd time.
The crash is due to this excerpt from man:
O_RDONLY Open the object for read access. A shared memory object
opened in this way can be mmap(2)ed only for read
(PROT_READ) access.
You've attempted to:
fd = shm_open(name, O_RDONLY, 0666);
// ^^^^^^^^
ptr = (char *)mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// ^^^^^^^^^^^^ incorrect!
Another remark: your name should follow the man recommendation for portability:
For portable use, a shared memory object should be identified by a name
of the form /somename; that is, a null-terminated string of up to
NAME_MAX (i.e., 255) characters consisting of an initial slash,
followed by one or more characters, none of which are slashes.
Lastly, you have some unnecessary (char *) casts and always error check your return values.
I am creating an "One Process per Client" server using the TCP protocol for academic purpose.
I use a global struct like the one bellow:
struct keyvalue
{
char a[4096];
char b[4096];
}data[1000];
I use fork() to create a child for each client.
I know that each child sees this struct as an exact copy of the parent process however if a child makes a change it is not visible to the other children and this is my goal.
I searched in google for hours and the only proper solution i found is mmap()
Bellow I present how i tried to solve this task:
int main ( int argc, char *argv[])
{
for(int c = 0; c < 1000 ; c++)
{
data[c] = mmap(NULL, sizeof(data[c]), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
}
.
.
.
return 0;
}
However I think that I haven't understand properly the use of this function and the documentation didn't help for this project.
It would be great if someone explained to me the exact way to use this function for my project.
EDIT:
This global struct is used by two global function:
void put(char *key, char *value)
{
.
.
.
strcpy(data[lp].keys,key);
strcpy(data[lp].values,value);
.
.
.
}
Thank you in behave and sorry for my bad English.
You can use the following piece of code to create an array of structs that is shared across multiple forked processes.
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define MAX_LEN 10000
struct region {
int len;
char buf[MAX_LEN];
};
int fd;
int main(void){
//Create shared memory
fd = shm_open("/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1)
printf("Error: shm_open\n");
//Expand to meet the desirable size
if (ftruncate(fd, MAX_LEN*sizeof(struct region)) == -1)
printf("Error: ftruncate\n");
pid_t pid = fork();
if (pid == 0){
struct region * ptr = mmap(NULL, MAX_LEN*sizeof(struct region), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
printf("Error\n");
memset(ptr, 0, 50*sizeof(struct region));
usleep(1500000);
ptr[33].len = 42;
}else if (pid > 0){
struct region * ptr = mmap(NULL, MAX_LEN*sizeof(struct region), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED)
printf("Error\n");
usleep(1000000);
printf("Value before: %d\n", ptr[33].len);
usleep(1000000);
printf("Value after: %d\n", ptr[33].len);
}else{
printf("Error: fork\n");
}
shm_unlink("/myregion");
return 0;
}
Compilation: gcc -o shmem_test shmem_test.c -lrt
EDIT: If you can't use shm_open, alternatively you can do the following in your main function:
int main(void){
struct region * ptr = mmap(NULL, MAX_LEN*sizeof(struct region), PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED,-1,0);
pid_t pid = fork();
if (pid == 0){
usleep(1500000);
ptr[33].len = 42;
}else if (pid > 0){
usleep(1000000);
printf("Value before: %d\n", ptr[33].len);
usleep(1000000);
printf("Value after: %d\n", ptr[33].len);
}else{
printf("Error: fork\n");
}
return 0;
}
The difference between the two, is that shm_open creates a named shared memory, which means that different processes in different executables can map this memory, given that they have the struct region definition. In the second case this cannot be done, i.e the shared memory is anonymous.
I have the following main.c:
#include <unistd.h> //has thread calls for fork()
#include <stdio.h>
struct globalInfo{
int x;
};
int do this()
{
info.x++;
printf("%d\n",info.x);
return 0;
}
int main{
struct globalInfo info = { .x = 2};
for(int i = 0 ; i < 5 ; i++)
{
if(fork() = 0)
{
dothis();
}
}
}
This isn't my exact code, but my question is more easily demonstrated here.
Now the output for the above function is:
3
3
3
3
3
What I want is:
3
4
5
6
7
How do share this struct between threads? It seems like every thread is just creating its own copy of the struct and manipulating its own copy. I've tried to pass a pointer to the info struct as a parameter to dothis(), but that doesn't fix it either. I've also tried placing the info initialization out of the main; that didn't work either..
Help would be greatly appreciated.
fork() doesnot create a thread it creates processes, processess will have different address spaces altogether hence data wil not be shared even if it is global data.
in case you are thinking of threads use pthreads
incase you are looking for processes you need to use IPC mechanisms
Use any IPC to share data b/w processes. In threads the data can be shared by following methods:
return value of thread passed to pthread_exit and catch in pthread_join
shared/global resource of process accessed by synchronizing methods
As people have already noted you are creating processes not threads. Sharing data among processes is harder. Every process has its own memory address space which means that they may share same code, but their data is private.
There are several techniques if you want to have shared data among processes. One of them is shared memory with memory map
#include <unistd.h> //has thread calls for fork()
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
struct globalInfo{
int x;
};
char *shm = "/asd8"; // change this before every run to avoid error 22
int dothis()
{
// sleep(1); // helps to simulate race condition
int len = sizeof(struct globalInfo);
int fd = shm_open(shm, O_RDWR, 0);
void *addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FAILED){
perror(""); // error handling
}
struct globalInfo *info = (struct globalInfo *)addr;
info->x++;
printf("%d %d\n", info->x, getpid());
return 0;
}
int main(){
struct globalInfo info = { .x = 2};
int len = sizeof(struct globalInfo);
int fd = shm_open(shm, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1)
perror(""); // error handling
if(ftruncate(fd, len) == -1){
printf("%d\n", errno); // osx produces error 22 don't know why
perror("");
}
void *addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
memcpy(addr, &info, len);
for(int i = 0 ; i < 5 ; i++)
{
if(fork() == 0)
{
dothis();
break;
}
}
}
sample output
3 30588
4 30589
6 30590
6 30591
7 30592
Also it would be great if you read chapters from The Linux Programming Interface: A Linux and UNIX System Programming Handbook
24 Process Creation
49 Memory Mapping
53 POSIX Semaphores (you have to solve synchronisation problem after the data is shared)
54 POSIX Shared Memory
I was trying to figure out shared memory and tried to write a simple program involving a consumer and a producer. I didnt make it to the consumer part and found this weird little problem: The parent will return at the *spool=3; with no rhyme or reason on why. Nothing on dmesg.
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define PRODUCER_ERROR(msg) \
do {perror("Producer Error: " msg "\n"); exit(1); }while(0)
#define SHM_NAME "/my_sharedmem"
void producer();
int main(int argc, char *argv[])
{
pid_t pID = fork();
if (pID == 0) {
// Code only executed by child process
printf ("Son here\n");
return 0;
} else if (pID < 0) {
perror("Unable to fork\n");
exit(1);
} else {
// Code only executed by parent process
printf ("Parent here\n");
producer();
return 0;
}
return 0;
}
void producer()
{
int fd, d;
unsigned* spool;
printf("<<Producer>> started\n");
fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO ); // FIXED
printf ("<<Producer>> memory file opened\n");
spool = mmap(NULL, sizeof(unsigned), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, fd, 0);
printf ("<<Producer>> mmaped to %p\n\tGonna write.\n", spool);
perror(NULL);
*spool = 3;
// msync(spool, sizeof(unsigned), MS_SYNC | MS_INVALIDATE);
printf("<<Producer>> ended\n");
}
EDIT: fixed shm_open mode argument
The object you get with shm_open is zero size. You need to allocate some space for it. mmap will allow you to map things beyond their size (both shm objects and files), but you'll crash when you access that memory.
Something like this after shm_open is what you want to do:
ftruncate(fd, <the size you want>);
You can do it after mmap too, if that floats your boat.
You have the mode argument to shm_open wrong. This is supposed to be a mode specification as for open. Probably your version here by conincidence forbids writing to the address, so the process then crashes when you try to write to it.
BTW: you should always check the return of library calls such as shm_open and mmap.
Edit: As I also observed in a comment below, you are also missing to scale the segment to an appropriate size with ftruncate.