Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing struct to mapped memory file (mmap)

Tags:

c

file

io

mmap

I have a problem to write struct into a mapped memory file.

I have two file namely mmap.write.c and mmap.read.c, and in these files, I'm writing an integer to a file and reading it from file.

When I want to write struct and read it, I could not think about that since in line 32 of mmap.write.c

sprintf((char*) file_memory, "%d\n", i);

and in line 25 of mmap.read.c

sscanf (file_memory, "%d", &integer);

There is no difference to write and read integer/double/float/char etc. since I can put pattern as second argument "%d" for integer. But what I will write here to indicate struct? That is my main problem.

The struct that I want to write and read:

#define CHANNELS 20
typedef dataholder struct {
    int value[CHANNELS];
    time_t time;
    int hash;
}dataholder;

mmap.read.c

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mmap.h"
#define FILE_LENGTH 0x10000
int main (int argc, char* const argv[])
{
    int fd;
    void* file_memory;
    int integer;
    /* Open the file. */
    fd = open (argv[1], O_RDWR, S_IRUSR | S_IWUSR);
    printf("file opened\n");
    /* Create the memory mapping. */
    file_memory = mmap (0, FILE_LENGTH, PROT_READ | PROT_WRITE,
    MAP_SHARED, fd, 0);
    printf("memfile opened\n");
    close (fd);
    printf("file closed\n");
    /* Read the integer, print it out, and double it. */
    while(1) {
        sscanf (file_memory, "%d", &integer);
        printf ("value: %d\n", integer);
        usleep(100000);
    }
    //sprintf ((char*) file_memory, "%d\n", 2 * integer);
    /* Release the memory (unnecessary because the program exits). */
    munmap (file_memory, FILE_LENGTH);
    return 0;
}

mmap.write.c

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "mmap.h"
#define FILE_LENGTH 0x10000
/* Return a uniformly random number in the range [low,high]. */
int random_range (unsigned const low, unsigned const high)
{
    unsigned const range = high - low + 1;
    return low + (int) (((double) range) * rand () / (RAND_MAX + 1.0));
}
int main (int argc, char* const argv[])
{
    int fd, i;
    void* file_memory;
    /* Seed the random number generator. */
    srand (time (NULL));
    /* Prepare a file large enough to hold an unsigned integer. */
    fd = open (argv[1], O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
    //lseek (fd, FILE_LENGTH+1, SEEK_SET);
    write (fd, "", 1);
    //lseek (fd, 0, SEEK_SET);
    /* Create the memory mapping. */
    file_memory = mmap (0, FILE_LENGTH, PROT_WRITE, MAP_SHARED, fd, 0);
    close (fd);
    /* Write a random integer to memory-mapped area. */
    for(i=0; i<10000; i++) {
        sprintf((char*) file_memory, "%d\n", i);
        //goto a;
        usleep(100000);
    }
    a:
    /* Release the memory (unnecessary because the program exits). */
    munmap (file_memory, FILE_LENGTH);
    return 0;
}

Thanks a lot in advance.

like image 552
totten Avatar asked Jan 15 '13 12:01

totten


People also ask

Does mmap load file into memory?

Yes, mmap creates a mapping. It does not normally read the entire content of whatever you have mapped into memory. If you wish to do that you can use the mlock/mlockall system call to force the kernel to read into RAM the content of the mapping, if applicable.

How does mmap work for files?

mmap works by manipulating your process's page table, a data structure your CPU uses to map address spaces. The CPU will translate "virtual" addresses to "physical" ones, and does so according to the page table set up by your kernel. When you access the mapped memory for the first time, your CPU generates a page fault.

What is mmap offset?

The mmap function creates a new mapping, connected to bytes ( offset ) to ( offset + length - 1) in the file open on filedes . A new reference for the file specified by filedes is created, which is not removed by closing the file. address gives a preferred starting address for the mapping. NULL expresses no preference.


2 Answers

First of all you have to keep track of where in the memory you want to write, second you have to remember that the mapped memory is just like any other pointer to memory. The last bit is important, as this means you can use normal array indexing to access the memory, or use functions such as memcpy to copy into the memory.

To write a structure, you have three choices:

  1. Write the structure as-is, like in a binary file. This will mean you have to memcpy the structure to a specified position.

  2. Write the structure, field-by-field, as text using e.g. sprintf to the correct position.

  3. Treat the memory as one large string, and do e.g. sprintf of each field into a temporary buffer, then strcat to add it to the memory.

like image 179
Some programmer dude Avatar answered Oct 26 '22 20:10

Some programmer dude


The simplest way is to just use a pointer:

dataholder *dh = file_memory;
/* now you can access dh->value, dh->time, dh->hash */

Since this struct doesn't contain any pointers, if you need to copy it in or out, you can just assign it, like:

dataholder dh_other = *dh;

or

*dh = dh_other;
like image 33
FatalError Avatar answered Oct 26 '22 20:10

FatalError