Link to home
Start Free TrialLog in
Avatar of SatComm
SatComm

asked on

mmap() disk file to shared memory

I am trying to do the following in the Solaris environment.

Problem Statement
-----------------
My basic problem is that I would like to mmap() a disk file into *shared* memory. Or does this not make any sense at all?

Background
----------
I have been able to mmap() a disk file into memory.
I have been able to create a shared memory segment and attached/detached to it.
Now, what I would like is to mmap() the disk file into the shared memory segment I create in the previous step. I tried this by passing the address returned by the creation of the shared memory segment, to the mmap() call. But all mmap() did was to map the file in a memory location "close to" the shared memory segment.

Thanks in advance.
Avatar of SatComm
SatComm

ASKER

I meant to say that my environment was Solaris 2.5
ASKER CERTIFIED SOLUTION
Avatar of mlev
mlev

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of SatComm

ASKER

I liked the second approach and have gotten it to work.
Thanks for providing the missing link in my understanding of mmap()!

Unfortunately, I need to also use the first approach. When I changed the flags parameter to MAP_FIXED, and passed the address returned by shmat() to mmap() as the start address, mmap() fails with errno set to EINVAL. My offset parameter is still 0. Any hints on what could be going wrong? Could it be a page alignment problem? If you have some sample code handy, could you please provide that.

Thanks!
In principle, page alignment could be a problem, but your
address comes from shmat() and is thus always page-aligned.
Your problem comes from invalid flags parameter.
Either MAP_PRIVATE or MAP_SHARED always has to be specified.
MAP_FIXED is an "add-on". That is, you have to use MAP_SHARED|MAP_FIXED.

Here is a sample program that works for me (Linux 2.0.18)

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/fcntl.h>
#include <sys/mman.h>

main()
{
        key_t key;
        int shmid;
        char *shmaddr;
        int fd;

        if ((key = ftok("/bin/cat", 'A')) == -1) { perror("ftok"); exit(1); }
        if ((shmid = shmget(key, 100000, IPC_CREAT|0600)) == -1) { perror("smget"); exit(1); }
        if ((shmaddr = shmat(shmid, NULL, 0)) == NULL) { perror("shmat"); exit(1); }

        if ((fd = open("shm.c", O_RDONLY)) == -1) { perror("open"); exit(1); }
        if (mmap(shmaddr, 500, PROT_READ, MAP_SHARED|MAP_FIXED, fd, 0) == -1) { perror("mmap"); exit(1); }
}

(I checked return values with strace.)

Avatar of SatComm

ASKER

Well, I got the "writer" side of things to work, i.e. if I can call the process that creates the shared memory and maps a file to that location as the writer, as you have indicated in your example above.

But now, another process, the "reader", needs to read that file in the shared memory created by the writer. I did an shmget() to get the shmId from the key (used by the writer); and then did an shmat(), using the  id. shmat() returns the same address as the start of the shared memory, but then I dont see the contents of the mapped file in the reader process! Am I missing something here?
You have to use mmap() in both processes.
Avatar of SatComm

ASKER

If we use mmap() of the same file in the reader process also, then we are, in essence, back to the second option you had originally suggested, and I dont really need to use shmget() and shmat().
To use mmap() to map the *shared memory* to the specific location in the reader process, requires the shared memory file descriptor. shmget(), etc. dont return file descriptors, but rather IDs. Solaris 2.5 does not support the POSIX interface yet, i.e., shm_open() etc. that work with file descriptors...

I guess, at this point, I'm stuck.
Avatar of SatComm

ASKER

Any further suggestions???
I don't think there is any way to use mmap() without opening the file in both processes.
You are right - there is no need to use shmget() and shmat() when you use mmap(). And shm_open() wouldn't help you, either. Below is the closest possible, to my understanding, analogy between shared memory segments and memory-mapped files:
shared memory segment <---> file
shmget()              <---> open()
shmid                 <---> fd
shmat()               <---> mmap()
shmdt()               <---> munmap()
N/A                   <---> close()
shmctl()              <---> fcntl()

You cannot map a file to a shared memory segment, same as you cannot map one file to another. The best you can do is make them share a common logical memory address in a process' paging space (which you did, with MAP_FIXED), but that doesn't help much.

Is there any special reason why you are reluctant to open the file in the second process?
Avatar of SatComm

ASKER

Thanks for your input.

The reason is that, I didn't want the second process to have to deal with files and filenames, but just memory and shared memory.  In our system, the files arrive on disk via FTP from a different location, and the files names might contain some type of timestamp for identification purposes. I wanted the first process to be the front end that opens the file, maps it to shared memory, makes some changes in memory, and then sends a notification to the second process to pick up the info from shared memory, and not worry about dynamically changing filenames, etc. Now, I could do other things to get around the name changes, I suppose, but I wanted to see if I could avoid that.

As a first step workaround, in my first process, after mapping the file to some other location in memory, I am doing a memcpy() into shared memory for the second process to be able to see the file...