tags:

views:

1018

answers:

3

I'm trying to allow two different processes to communicate by using memory mapping the same file. However, I'm having some problems with this. I have a feeling this has to do with the way I'm using the open() call and passing my file descriptor to mmap.

Here is my code, can you see anything wrong with it?

Object 1's code:

 16     FILE* temp = fopen(theSharedFileName, "w");
 17     fseek(temp, fileSize-1, SEEK_SET);
 18     fprintf(temp, "0"); // make the file a certain size
 19     fseek(temp, 0, SEEK_CUR);
 20 
 21     int sharedFileName = fileno(temp);
 ...
 31     sharedArea = (MyStruct*)mmap(0, fileSize,
 32         PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, sharedFileName, 0);

I use the "w" file mode since Object 1 will only ever be made once and I want it to reset any previously existing data.

Object 2's Code:

 130     FILE* tempFile = fopen(sharedFileName, "a");
 131     int theFile = fileno(tempFile);
 ...
 135     sharedArea = (MyStruct*)mmap(NULL, fileSize,
 136         PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, theFile, 0);
+14  A: 

A few issues:

  1. Avoid mixing high-level I/O (fopen(), fseek()) and some low-level operation like mmap(). Although you can get the low-level file descriptor using fileno(), that is like taking the longest route to get to the same place. Also, just using mmap() breaks compatibility beyond BSD and POSIX, so you get nothing by using standard C I/O functions. Just use open() and lseek() directly.
  2. It doesn't make sense to use stream formatted I/O (fprintf()) on the same file you are memory-mapping. When you memory-map a file, you are implicitly telling the system you are going to use it as random-access (direct indexing) data. fprintf() is for stream output, you usually use it for sequential access. In fact, although possible, it is unusual to see fprintf() and fseek() in the same descriptor (this is not even portable, but due to the previous item, I'm not considering portability).
  3. The protection must match the open file protection. Since you are passing "w" to fopen(), and PROT_READ | PROT_WRITE | PROT_EXEC to mmap(), you are violating this restriction. This also highlights why you shouldn't mix high-level I/O with memory-mapping: how do you guarantee that fopen(...,"w") will open the file with the correct flags? This is supposed to be "implementation-detail" for the C library. If you want to memory-map a file with read and write permissions, you should use the low-level open(theSharedFileName, O_RDWR) to open the file.
  4. Do not use PROT_WRITE and PROT_EXEC together. It is not portable and it is a security risk. Read about W^X and executable space protection.
Juliano
Very complete answer.
Tony k
+1  A: 

As others have said, don't use fopen() and friends for this.

Part of the problem you are experiencing may be due to the fact that fprintf() can have stream buffers, so it may not actually change the file, and hence be visible to the other process when expected. You could add an fflush(), but read() and write() don't do any application level buffering, which is part of why they are more suitable.

Don Neufeld
+1  A: 

If you can use C++ and libraries like ACE or Boost that shield you from the low level details and provide easier abstraction for IPC.

lothar