Wowy Wowy - 3 months ago 14
Linux Question

Keeping shared memory data in the case of reboot?

I am currently using shmget and shmat to create a shared memory between two process. When the process die the shared memory is still alive and restarting the process mean we can start where we were before. But if the machine is turned off then turned on we are losing the data.

I would like to know if there was an option in shmget/shmat or another method to make shared memory between process in order to keep the data alive even in the case of a reboot.

Right now i am doing this kind of thing :

const char *ZoneFile = "/home/Zone.dat";'
key_t sharedKeyZone;
int sharedSpaceIdZone;

int descriptor = open(ZoneFile, O_CREAT | O_RDWR, S_IRWXU);
close(descriptor);
sharedKeyZone = ftok(ZoneFile, 1);
sharedSpaceIdZone = shmget(sharedKeyZone, 1 * sizeof(Zone_t), IPC_CREAT);
ZoneArray = (Zone_t *) shmat(sharedSpaceIdZone, NULL, 0);


Zone_t being a structure type, i can access every data in ZoneArray[0] from my 2 process without problem.

Right now the only solution i can think of would be to periodicaly write a ini file with the data to "save" the state of the system and when restart it read this file but this would be not flexible at all if the structure must evolve later.

EDIT : following the idea of @Wumpus Q. Wumbley i tried to use mmap with msync this way :

#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>

//add rt to eclipse librairies

typedef struct count {

int counter;
} count;

int main()
{
count *memory;
int fd = shm_open("MYmemory.txt", O_CREAT | O_RDWR, S_IRWXU);

if(fd == -1)
{
perror("shm_open");
return 1;
}

ftruncate(fd, sizeof(count));
memory = mmap(NULL, sizeof(count), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
printf("before %d\n", memory->counter);
memory->counter = 5;
printf("after %d\n", memory->counter);
if(msync(memory, sizeof(count),MS_SYNC)<0)
{
printf("%s","msync ERROR.");
}
else { printf("%s","msync completed successfully.");}

return 0;
}


Same result as with shmget and shmat, after a reboot the data are 0. (the printf "before" show 0)

EDIT 2 :

This did it for me :

count *memory;
int fd = open(MYmemoryFile, O_CREAT | O_RDWR, S_IRWXU);

ftruncate(fd, sizeof(count));
memory = mmap(NULL, sizeof(count), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
printf("before %d\n", memory->counter);
memory->counter = 5;
printf("after %d\n", memory->counter);
if(msync(memory, sizeof(count),MS_SYNC)<0)
{
printf("%s","msync ERROR.");
}
else { printf("%s","msync completed successfully.\n");}


Still not perfect since everywhere in my former code i was using my memory without pointer form (Zone[0].param is now Zone[0]->param for example) but this is a step forward, thanks to @Wumpus Q. Wumbley.

Answer

If you mmap a regular file with MAP_SHARED, you effectively have a shm segment that is also a permanent file. The copy on disk will lag behind the copy in memory, but you can call msync to flush it periodically.