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.
SatCommAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

SatCommAuthor Commented:
I meant to say that my environment was Solaris 2.5
0
mlevCommented:
The optional start address you specify as a parameter to mmap() call, is only a "hint". If you want mmap() to use the exact address, pass MAP_FIXED in the flags parameter.
On the other hand, you can pass NULL for start address and MAP_SHARED for flags. mmap() will then allocate memory on its own. You won't need to use either shmget() or shmat(). The memory
will be shared in the sense that if several processes call mmap() with start=NULL and flags=MAP_SHARED for the same file, they will all map to the same memory address. It will be different from the shared memory segments you create with shmget() in the sense that you cannot access it with a key or id.
Hope this helps.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
SatCommAuthor Commented:
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!
0
OWASP: Forgery and Phishing

Learn the techniques to avoid forgery and phishing attacks and the types of attacks an application or network may face.

mlevCommented:
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.)

0
SatCommAuthor Commented:
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?
0
mlevCommented:
You have to use mmap() in both processes.
0
SatCommAuthor Commented:
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.
0
SatCommAuthor Commented:
Any further suggestions???
0
mlevCommented:
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?
0
SatCommAuthor Commented:
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...
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.