mmap()--Memory Map a File


  Syntax
 #include <sys/types.h>
 #include <sys/mman.h>

 void *mmap( void *addr,    
             size_t len,
             int protection,
             int flags,
             int fildes,
             off_t off);   
  Service Program Name: QP0LLIB1   

  Default Public Authority: *USE

  Threadsafe: Yes

The mmap() function establishes a mapping between a process' address space and a stream file.

The address space of the process from the address returned to the caller, for a length of len, is mapped onto a stream file starting at offset off.

The portion of the stream file being mapped is from starting offset off for a length of len bytes. The actual address returned from the function is derived from the values of flags and the value specified for address.

The mmap() function causes a reference to be associated with the file represented by fildes. This reference is not removed by subsequent close operations. The file remains referenced as long as a mapping exists over the file.

If a mapping already exists for the portion of the processes address space that is to be mapped and the value MAP_FIXED was specified for flags, then the previous mappings for the affected pages are implicitly unmapped. If one or more files affected by the implicit unmap no longer have active mappings, these files will be unreferenced as a result of mmap().

The use of the mmap() function is restricted by the QSHRMEMCTL System Value. When this system value is 0, the mmap() function may not create a shared mapping having with PROT_WRITE capability. Essentially, this prevents the creation of a memory map that could alter the contents of the stream file being mapped. If the flags parameter indicated MAP_SHARED, the prot parameter specifies PROT_WRITE and the QSHRMEMCTL system value is 0, then the mmap() functions will fail and an error number of EACCES results.

When the mmap() function creates a memory map, the current value of the QSHRMEMCTL system value is stored with the mapping. This further restricts attempts to change the protection of the mapping through the use of the mprotect function. Changing the system valueonly affects memory maps created after the system value is changed.

If the size of the file increases after the mmap() function completes, then the whole pages beyond the original end of file will not be accessible via the mapping.

If the size of the mapped file is decreased after mmap(), attempts to reference beyond the end of the file are undefined and may result in an MCH0601 exception.

Any data written to that portion of the file that is allocated beyond end-of-file may not be preserved. Changes made beyond end of file via mapped access may not be preserved.

The portion of the file beyond end-of-file is assumed to be zero by the traditional file access APIs such as read(), readv(), write(), writev(), and ftruncate(). The system may clear a partial page, or whole pages allocated beyond end-of-file. This must be taken into account when directly changing a memory mapped file beyond end-of-file. It is not recommended that data be directly changed beyond end-of-file because the extra space allocated varies and unpredictable results may occur.

The mmap() function is only supported for *TYPE2 stream files (*STMF) existing in the "root" (/), QOpenSys, and user-defined file systems.

Journaling cannot be started while a file is memory mapped. Likewise, a journaled file cannot be memory mapped. The mmap() function will fail with Start of change ENOTSUP End of change if the file is journaled.

The off parameter must be zero or a multiple of the system page size. The _SC_PAGESIZE or _SC_PAGE_SIZE options on the sysconf() function may be used to retrieve the system page size.


Parameters

addr
(Input) The starting address of the memory area to be mapped. If the MAP_FIXED value is specified with the flag parameter, then address must be a multiple of the system page size. Use the _SC_PAGESIZE or _SC_PAGE_SIZE options of the sysconf() API to obtain the actual page size in an implementation-independent manner. When the MAP_FIXED flag is specified, this address must not be zero.

len
(Input) The length in bytes to map. A length of zero will result in an errno of EINVAL.

protection
(Input) The access allowed to this process for this mapping. Specify PROT_NONE, PROT_READ, PROT_WRITE, or a the inclusive-or of PROT_READ and PROT_WRITE. You cannot specify a protection value more permissive than the mode in which the file was opened.

The PROT_WRITE value requires that the file be opened for write and read access.

The following table shows the symbolic constants allowed for the protection parameter.

Symbolic Constant Decimal
Value
Description
PROT_READ 1 Read access is allowed.
PROT_WRITE 2 Write access is allowed. Note that this value assumes PROT_READ also.
PROT_NONE 8 No data access is allowed.
PROT_EXEC 4 This value is allowed, but is equivalent to PROT_READ.

flags
(Input) Further defines the type of mapping desired. There are actually two independent options controlled through the flags parameter.

The first attribute controls whether or not changes made through the mapping will be seen by other processes. The MAP_PRIVATE option will cause a copy on write mapping to be created. A change to the mapping results in a change to a private copy of the affected portion of the file. These changes cannot be seen by other processes. The MAP_SHARED option provides a memory mapping of the file where changes (if allowed by the protection parameter) are made to the file. Changes are shared with other processes when MAP_SHARED is specified.

The second control provided by the flags parameter in conjunction with the value of the addr parameter influences the address range assigned to the mapping. You may request one of the following address selection modes:

  1. An exact address range specification. The system will set up the mapping at this location if the address range is valid. Any mapping in the successfully mapping range that existed prior to the mapping operation is implicitly unmapped by this operation.

  2. A suggested address range. The system will select a range close to the suggested range.

  3. System selected. The system will select an address range. This usually is used to acquire the initial memory map range. Subsequent ranges can be mapped relative to this range.

The MAP_FIXED flag value specifies that the virtual address has been specified through the addr parameter. The mmap() function will use the value of addr as the starting point of the memory map.

When MAP_FIXED is set in the flags parameter, the system is informed that the return value must be equal to the value of addr. An invalid value of addr when MAP_FIXED is specified will result in a value of MAP_FAILED, which has a value of 0, for the returned value and the the value of errno will be set to EINVAL.

When MAP_FIXED is not specified, a value of zero for parameter addr indicates that the system may choose the value for the return value. If MAP_FIXED is not specified and a nonzero value is specified for addr, the system will take this as a suggestion to find a contiguous address range close to the specified address.

The following table shows the symbolic constants allowed for the flags parameter.

Symbolic Constant Decimal
Value
Description
MAP_SHARED 4 Changes are shared.
MAP_PRIVATE 2 Changes are private.
MAP_FIXED 1 Parameter addr has exact address

fildes
(Input) An open file descriptor.

off
(Input) The offset into the file, in bytes, where the map should begin.

Authorities

No authority checking is performed by the mmap() function because this was done by the open() functions which assigned the file descriptor, fildes, used by the mmap() function.

The following table shows the open access intent that is required for the various combinations of the mapping sharing mode and mapping intent.

Mapping Sharing Mode Mapping Intent Open access intents allowed
MAP_SHARED PROT_READ O_RDONLY or O_RDWR
MAP_SHARED PROT_WRITE O_RDWR
MAP_SHARED PROT_NONE O_RDONLY or O_RDWR
MAP_PRIVATE PROT_READ O_RDONLY or O_RDWR
MAP_PRIVATE PROT_WRITE O_RDONLY or O_RDWR
MAP_PRIVATE PROT_NONE O_RDONLY or O_RDWR


Return Value

Upon successful completion, the mmap() function returns the address at which the mapping was placed; otherwise, it returns a value of MAP_FAILED, which has a value of 0, and sets errno to indicate the error. The symbol MAP_FAILED is defined in the header <sys/mman.h>.

If successful, function mmap() will never return a value of MAP_FAILED.

If mmap() fails for reasons other than EBADF, EINVAL, or ENOTSUP, some of the mappings in the address range starting at addr and continuing for len bytes may have been unmapped and no new mappings are created.


Error Conditions

When the mmap() function fails, it returns MAP_FAILED, which has a value of 0, and sets the errno as follows.

Error condition Additional information
[EACCES]

If you are accessing a remote file through the Network File System, update operations to file permissions at the server are not reflected at the client until updates to data that is stored locally by the Network File System take place. (Several options on the Add Mounted File System (ADDMFS) command determine the time between refresh operations of local data.) Access to a remote file may also fail due to different mappings of user IDs (UID) or group IDs (GID) on the local and remote systems.

The file referenced by fildes is not open for read, or the file is not opened for write and PROT_WRITE for a shared mapping is being requested. This error also results when the QSHRMEMCTL system value is 0 and PROT_WRITE is specified.

[EBADFUNC]

A given file descriptor or directory pointer is not valid for this operation. The specified descriptor is incorrect, or does not refer to an open file.

[EINVAL]

The value of the addr parameter is not valid. This can occur when MAP_FIXED is specified and the value of the addr parameter is not a multiple of the system page size. This may also occur if the value for parameter addr is not a valid VOID* pointer or is not within the range allowed.

This error number is also returned if the value of the flags parameter does not indicate either MAP_SHARED or MAP_PRIVATE.

[ENODEV]

The fildes parameter does not refer to a *TYPE2 stream file (*STMF) in the "root" (/), QOpenSys, or user-defined file systems.

[ENOMEM]

This can occur if the portion of the local process address space reserved for memory mapping has been exceeded.

When MAP_FIXED is specified, it may also occur if the address range specified by the combination of the addr and len parameters results in a range outside the range reserved for process local storage.

[ENOTAVAIL]  
[ENOTSUP]
[ENXIO]

The portion of the file, as specified by off and len is not valid for the current size of the file.

[EOVERFLOW]
[EUNKNOWN]  

Error Messages

The following messages may be sent from this function.

Message ID Error Message Text
CPE3418 E Possible APAR condition or hardware failure.
CPFA0D4 E File system error occurred.
CPF3CF2 E Error(s) occurred during running of &1 API.
CPF9872 E Program or service program &1 in library &2 ended. Reason code &3.


Usage Notes

  1. This function will fail with error code [EBADF] when fildes is a scan descriptor that was passed to one of the scan-related exit programs. See Integrated File System Scan on Open Exit Programs and Integrated File System Scan on Close Exit Programs for more information.

  2. The msync() function must be used to write changed pages of a shared mapping to disk. If a system crash occurs before the msync function is executed, some data may not be preserved.

  3. If the application chooses to mix file access methods such as read(), readv(), write(), writev(), Start of change ftruncate(), fclear() or their related APIs End of change with mmap(), then the application must ensure proper synchronization. While operations such as read() , write() Start of change ftruncate(), and fclear() End of change are relatively atomic because of internal locking, access through the memory map created by mmap() does not synchronize with the read(), readv(), write(), writev() Start of change ftruncate(), and fclear() End of change functions. Several synchronization functions are available, including the fcntl() API, the DosDetFileLocks() API, and the mutex functions. Use one of these synchronization methods around access and modifications if atomic access is required. These techniques also will ensure atomic access in a multiprocessor environment.

  4. When using mmap(), it is necessary to first make a nonspecific mapping request to generate a valid address. This is easily done by specifying a requested address (addr) of 0 and not specifying MAP_FIXED. Then, using the returned address pa as the new requested address (addr) and also specifying MAP_FIXED for the flags parameter. The example below illustrates how this technique can be applied to achieve a contiguous mapping of several files.

  5. The address pointer returned by mmap() can only be used with the V4R4M0 or later versions of the following languages:
  6. Start of change The application cannot write or store any data via the memory mapping which includes any tagged (16-byte) pointers because the pointer attribute will be lost. Some examples of tagged pointers include space pointers, system pointers, invocation pointers etc..

    If the DTAMDL(*LLP64) parameter is used when compiling an ILE C program, this limitation does not apply as the pointers will be 8 byte pointers, and their pointer attribute will be preserved. End of change


Related Information


Example

See Code disclaimer information for information pertaining to code examples.

The following example creates two files and then produces a contiguous memory mapping of the first data page of each file using two invocations of mmap().

#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/mman.h>

main(void) {

  size_t bytesWritten = 0;
  int   my_offset = 0;
  char  text1Ý="Data for file 1.";
  char  text2Ý="Data for file 2.";
  int fd1,fd2;
  int PageSize;
  void *address;
  void *address2;
  fd1 = open("/tmp/mmaptest1",
             (O_CREAT | O_TRUNC | O_RDWR),
             (S_IRWXU | S_IRWXG | S_IRWXO) );
  if ( fd1 < 0 )
    perror("open() error");
  else {
    bytesWritten = write(fd1, text1, strlen(text1));
    if ( bytesWritten != strlen(text1) ) {
      perror("write() error");
      int closeRC = close(fd1);
      return -1;
    }

  fd2 = open("/tmp/mmaptest2",
             (O_CREAT | O_TRUNC | O_RDWR),
             (S_IRWXU | S_IRWXG | S_IRWXO) );
    if (fd2 < 0 )
      perror("open() error");
    else {
      bytesWritten = write(fd2, text2, strlen(text2));
      if ( bytesWritten != strlen(text2) )
        perror("write() error");

      PageSize = (int)sysconf(_SC_PAGESIZE);
      if ( PageSize < 0) {
        perror("sysconf() error");
      }
      else {

      off_t lastoffset = lseek( fd1, PageSize-1, SEEK_SET);
      if (lastoffset < 0 ) {
        perror("lseek() error");
      }
      else {
      bytesWritten = write(fd1, " ", 1);   /* grow file 1 to 1 page. */

      off_t lastoffset = lseek( fd2, PageSize-1, SEEK_SET);

      bytesWritten = write(fd2, " ", 1);   /* grow file 2 to 1 page. */
        /*
         *  We want to show how to memory map two files with
         *  the same memory map.  We are going to create a two page
         *  memory map over file number 1, even though there is only
         *  one page available. Then we will come back and remap
         *  the 2nd page of the address range returned from step 1
         *  over the first 4096 bytes of file 2.
         */

       int len;

       my_offset = 0;
       len = PageSize;   /* Map one page */
       address = mmap(NULL,
                      len,
                      PROT_READ,
                      MAP_SHARED,
                      fd1,
                      my_offset );
       if ( address != MAP_FAILED ) {
         address2 = mmap( ((char*)address)+PageSize,
                       len,
                       PROT_READ,
                       MAP_SHARED | MAP_FIXED, fd2,
                       my_offset );
         if ( address2 != MAP_FAILED ) {
               /* print data from file 1 */
            printf("\n%s",address);
               /* print data from file 2 */
            printf("\n%s",address2);
         } /* address 2 was okay. */
         else {
           perror("mmap() error=");
         } /* mmap for file 2 failed. */
       }
       else {
         perror("munmap() error=");
       }
         /*
          *  Unmap two pages.
          */
       if ( munmap(address, 2*PageSize) < 0) {
        perror("munmap() error");
      }
      else;

     }
    }
    close(fd2);
    unlink( "/tmp/mmaptest2");
    }
    close(fd1);
    unlink( "/tmp/mmaptest1");
  }
     /*
      *  Unmap two pages.
      */
  if ( munmap(address, 2*PageSize) <    0) {
     perror("munmap() error");
  }
  else;
}

Output:
Data for file 1
Data for file 2

API introduced: V5R1
Top | UNIX-Type APIs | APIs by category