Memory Mapped Files in Fortran - Crude documentation

August 22, 2025 ยท View on GitHub

See also the README

Generalities

Private feature:

  • The mapped file can still be bigger than the RAM+swap size, however the amount of writes is limited by the RAM+swap size (to overcome this, one can close the mapping with write-back and remap the file
  • Currently, write-back means the entire file is rewritten, whatever the amount of modifications. This can be inefficient. If the underlying filesystem natively supports copy-on-write, a better strategy consists in creating a copy of the file with a system call, and mapping the copy without the private feature.

Non blocking access

The files are opened with non-blocking read and write accesses, which means that nothing prevents multiples threads or other processes to concurrently open and write into the same files. This is the responsability of the user to take car of that.

Error status

In case of incorrect or inconsistent input arguments, the routines always print an explicit message and the program aborts.

In case something goes unexpectedly wrong internally (file can't be opened, or mapped, or closed...):

  • if the output stat argument is present the routines return an error code and the execution continues. The specific error can be inquired with the fmmap_errmsg() function.
  • if the output stat argument is not present, the routines print an explicit message and the program aborts.

Module

use fmmap

public kinds

public types

fmmap_t : derived type holding the properties of the mapping, with no public component.

public type-bound procedures

type(fmmap_t) :: x

type-bound procedure=> module procedures
x%create()create()creates a mapping
type(c_ptr) x%cptr()get_cptr()returns the C pointer of the mapping
integer(c_size_t) x%lengthget_length()returns the size of the mapping (in bytes)
x%destroy()destroy()destroys a mapping

public constants

FMMAP_SCRATCH : mapping of a temporary file which is deleted once the mapping is closed
FMMAP_NEW : mapping of newly created file
FMMAP_OLD : mapping of an existing file FMMAP_NOFILE : mapping without a backing file (anonymous mapping)

procedures pointed by the type-bound procedures

fmmap_t_create

   !********************************************************************************************
   subroutine fmmap_t_create(x,filestatus,filename,length,mold,private,stat)
   !********************************************************************************************
   !! Opens a file and creates a "generic" mapping to a C pointer.
   !! The whole file is mapped.
   !********************************************************************************************
   class(fmmap_t),        intent(out)           :: x
      !! descriptor of the mapped file
   integer,               intent(in)            :: filestatus
      !! FMMAP_SCRATCH: mapping a temporary file
      !! FMMAP_OLD    : mapping an already existing file
      !! FMMAP_NEW    : mapping a newly created created file
      !! FMMAP_NOFILE : no physical file
   character(*),          intent(in)            :: filename
      !! FMMAP_OLD or FMMAP_NEW:
      !! - name of the file (with or without path)
      !! FMMAP_SCRATCH:
      !! - name of the path where the temporary file is created; if blank:
      !!   - POSIX: the current directory ("./") is used
      !!   - WIN32: the Windows temporary path is inquired and used
      !! - a processor dependent unique filename is then generated and appended to the path
      !! FMMAP_NOFILE:
      !! - must be empty ("")
   integer(c_size_t)                            :: length
      !! FMMAP_SCRATCH, FMMAP_NEW, and FMMAP_NOFILE:
      !!    input length of the mapping (in number of bytes)
      !! FMMAP_OLD:
      !!    output length of the mapping (in number of bytes)
      !! This is actually the size of the file (or virtual file)
      !! ` length`  is expressed in bytes if `mold` is absent, or in elements of the `mold`
      !! type/kind if it is present
   class(*),              intent(in),  optional :: mold(..)
      !! if present, `length` is expressed in number of elements of the type/kind `mold`
   logical,               intent(in),  optional :: private
      !! if .true., all the changes made to the mapped file are visible only by the current
      !  mapping. All concurrent accesses to the file see the original data and not the
      !! changes. Technically the changes are permanently cached in memory pages dedicated
      !! to current mapping.
      !! - .false. by default with FMMAP_NEW, FMMAP_OLD, and FMMAP_SCRATCH
      !! - .true. by default with FMMAP_NOFILE
   integer,               intent(out), optional :: stat
      !! return status; is 0 if no error occurred

fmmap_t_get_cptr

   !********************************************************************************************
   function fmmap_t_get_cptr(x) result(cptr)
   !********************************************************************************************
   !! Returns the C pointer of a mapped file
   !********************************************************************************************
   class(fmmap_t), intent(in) :: x
      !! descriptor of the mapped file
   type(c_ptr)                :: cptr

fmmap_t_get_length

   !********************************************************************************************
   function fmmap_t_get_length(x,mold) result(length)
   !********************************************************************************************
   !! Returns the length of a mapped file
   !********************************************************************************************
   class(fmmap_t), intent(in)            :: x
      !! descriptor of the mapped file
   class(*),       intent(in),  optional :: mold(..)
      !! if present, the returned length is expressed in number of elements of the type/kind `mold`
   integer(c_size_t)                     :: length
      !! in bytes if `mold` is absent, or in elements of the type/kind of ` mold` if present

fmmap_t_destroy

   !********************************************************************************************
   subroutine fmmap_t_destroy(x,writeback,stat)
   !********************************************************************************************
   !! Destroys a generic mapping
   !********************************************************************************************
   class(fmmap_t), intent(inout)          :: x
      !! descriptor of the mapped file
   logical,        intent(in),   optional :: writeback
      !! If .true., the changes in memory in the private mode are written back to the file
      !! before unmapping.
      !! .false. by default with FFMAP_SCRATCH, FMMAP_OLD, and FFMAP_NOFILE
      !! .true. by default with FMMAP_NEW
   integer,       intent(out),   optional :: stat
      !! return status, is 0 if no error occurred

Public utility procedures

fmmap_e2b

   !********************************************************************************************
   function fmmap_e2b(nelems,ss) result(nbytes)
   !********************************************************************************************
   !! converts a number of elements to a number of bytes
   !! `ss` is typically obtained with the intrinsic function `ss = storage_size(var)`,
   !!  where `var` is any variable of the manipulated type+kind
   !********************************************************************************************
   integer(c_size_t), intent(in) :: nelems   !! number of elements
   integer,           intent(in) :: ss       !! storage size (in bits) of 1 element
   integer(c_size_t)             :: nbytes   !! number of bytes

fmmap_b2e

   !********************************************************************************************
   function fmmap_b2e(nbytes,ss) result(nelems)
   !********************************************************************************************
   !! converts a number of bytes to a number of elements
   !! `ss` is typically obtained with the intrinsic function `ss = storage_size(var)`,
   !!  where `var` is any variable of the manipulated type+kind
   !********************************************************************************************
   integer(c_size_t), intent(in) :: nbytes   !! number of nbytes
   integer,           intent(in) :: ss       !! storage size (in bits) of 1 element
   integer(c_size_t)             :: nelems   !! number of elements

fmmap_errmsg

   !********************************************************************************************
   function fmmap_errmsg(stat) result(msg)
   !********************************************************************************************
   !! Returns the error messages corresponding to an error code
   !********************************************************************************************
   integer, intent(in) :: stat
   character(len=:), allocatable :: msg