1------------------------------------------------------------------------------ 2-- -- 3-- GNAT RUN-TIME COMPONENTS -- 4-- -- 5-- S Y S T E M . M M A P -- 6-- -- 7-- S p e c -- 8-- -- 9-- Copyright (C) 2007-2018, AdaCore -- 10-- -- 11-- This library is free software; you can redistribute it and/or modify it -- 12-- under terms of the GNU General Public License as published by the Free -- 13-- Software Foundation; either version 3, or (at your option) any later -- 14-- version. This library is distributed in the hope that it will be useful, -- 15-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- 16-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- 17-- -- 18-- As a special exception under Section 7 of GPL version 3, you are granted -- 19-- additional permissions described in the GCC Runtime Library Exception, -- 20-- version 3.1, as published by the Free Software Foundation. -- 21-- -- 22-- You should have received a copy of the GNU General Public License and -- 23-- a copy of the GCC Runtime Library Exception along with this program; -- 24-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- 25-- <http://www.gnu.org/licenses/>. -- 26-- -- 27-- GNAT was originally developed by the GNAT team at New York University. -- 28-- Extensive contributions were provided by Ada Core Technologies Inc. -- 29-- -- 30------------------------------------------------------------------------------ 31 32-- This package provides memory mapping of files. Depending on your operating 33-- system, this might provide a more efficient method for accessing the 34-- contents of files. 35-- A description of memory-mapping is available on the sqlite page, at: 36-- http://www.sqlite.org/mmap.html 37-- 38-- The traditional method for reading a file is to allocate a buffer in the 39-- application address space, then open the file and copy its contents. When 40-- memory mapping is available though, the application asks the operating 41-- system to return a pointer to the requested page, if possible. If the 42-- requested page has been or can be mapped into the application address 43-- space, the system returns a pointer to that page for the application to 44-- use without having to copy anything. Skipping the copy step is what makes 45-- memory mapped I/O faster. 46-- 47-- When memory mapping is not available, this package automatically falls 48-- back to the traditional copy method. 49-- 50-- Example of use for this package, when reading a file that can be fully 51-- mapped 52-- 53-- declare 54-- File : Mapped_File; 55-- Str : Str_Access; 56-- begin 57-- File := Open_Read ("/tmp/file_on_disk"); 58-- Read (File); -- read the whole file 59-- Str := Data (File); 60-- for S in 1 .. Last (File) loop 61-- Put (Str (S)); 62-- end loop; 63-- Close (File); 64-- end; 65-- 66-- When the file is big, or you only want to access part of it at a given 67-- time, you can use the following type of code. 68 69-- declare 70-- File : Mapped_File; 71-- Str : Str_Access; 72-- Offs : File_Size := 0; 73-- Page : constant Integer := Get_Page_Size; 74-- begin 75-- File := Open_Read ("/tmp/file_on_disk"); 76-- while Offs < Length (File) loop 77-- Read (File, Offs, Length => Long_Integer (Page) * 4); 78-- Str := Data (File); 79-- 80-- -- Print characters for this chunk: 81-- for S in Integer (Offs - Offset (File)) + 1 .. Last (File) loop 82-- Put (Str (S)); 83-- end loop; 84-- 85-- -- Since we are reading multiples of Get_Page_Size, we can simplify 86-- -- with 87-- -- for S in 1 .. Last (File) loop ... 88-- 89-- Offs := Offs + Long_Integer (Last (File)); 90-- end loop; 91 92with Interfaces.C; 93 94with System.Strings; 95 96package System.Mmap is 97 98 type Mapped_File is private; 99 -- File to be mapped in memory. 100 101 -- This package will use the fastest possible algorithm to load the 102 -- file in memory. On systems that support it, the file is not really 103 -- loaded in memory. Instead, a call to the mmap() system call (or 104 -- CreateFileMapping()) will keep the file on disk, but make it 105 -- accessible as if it was in memory. 106 107 -- When the system does not support it, the file is actually loaded in 108 -- memory through calls to read(), and written back with write() when you 109 -- close it. This is of course much slower. 110 111 -- Legacy: each mapped file has a "default" mapped region in it. 112 113 type Mapped_Region is private; 114 -- A representation of part of a file in memory. Actual reading/writing 115 -- is done through a mapped region. After being returned by Read, a mapped 116 -- region must be free'd when done. If the original Mapped_File was open 117 -- for reading, it can be closed before the mapped region is free'd. 118 119 Invalid_Mapped_File : constant Mapped_File; 120 Invalid_Mapped_Region : constant Mapped_Region; 121 122 type Unconstrained_String is new String (Positive); 123 type Str_Access is access all Unconstrained_String; 124 pragma No_Strict_Aliasing (Str_Access); 125 126 type File_Size is new Interfaces.C.size_t; 127 128 function To_Str_Access 129 (Str : System.Strings.String_Access) return Str_Access; 130 -- Convert Str. The returned value points to the same memory block, but no 131 -- longer includes the bounds, which you need to manage yourself 132 133 function Open_Read 134 (Filename : String; 135 Use_Mmap_If_Available : Boolean := True) return Mapped_File; 136 -- Open a file for reading. The same file can be shared by multiple 137 -- processes, that will see each others's changes as they occur. 138 -- Any attempt to write the data might result in a segmentation fault, 139 -- depending on how the file is open. 140 -- Name_Error is raised if the file does not exist. 141 -- Filename should be compatible with the filesystem. 142 143 function Open_Read_No_Exception 144 (Filename : String; 145 Use_Mmap_If_Available : Boolean := True) return Mapped_File; 146 -- Like Open_Read but return Invalid_Mapped_File in case of error 147 148 function Open_Write 149 (Filename : String; 150 Use_Mmap_If_Available : Boolean := True) return Mapped_File; 151 -- Open a file for writing. 152 -- You cannot change the length of the file. 153 -- Name_Error is raised if the file does not exist 154 -- Filename should be compatible with the filesystem. 155 156 procedure Close (File : in out Mapped_File); 157 -- Close the file, and unmap the memory that is used for the region 158 -- contained in File. If the system does not support the unmmap() system 159 -- call or equivalent, or these were not available for the file itself, 160 -- then the file is written back to the disk if it was opened for writing. 161 162 procedure Free (Region : in out Mapped_Region); 163 -- Unmap the memory that is used for this region and deallocate the region 164 165 procedure Read 166 (File : Mapped_File; 167 Region : in out Mapped_Region; 168 Offset : File_Size := 0; 169 Length : File_Size := 0; 170 Mutable : Boolean := False); 171 -- Read a specific part of File and set Region to the corresponding mapped 172 -- region, or re-use it if possible. 173 -- Offset is the number of bytes since the beginning of the file at which 174 -- we should start reading. Length is the number of bytes that should be 175 -- read. If set to 0, as much of the file as possible is read (presumably 176 -- the whole file unless you are reading a _huge_ file). 177 -- Note that no (un)mapping is is done if that part of the file is already 178 -- available through Region. 179 -- If the file was opened for writing, any modification you do to the 180 -- data stored in File will be stored on disk (either immediately when the 181 -- file is opened through a mmap() system call, or when the file is closed 182 -- otherwise). 183 -- Mutable is processed only for reading files. If set to True, the 184 -- data can be modified, even through it will not be carried through the 185 -- underlying file, nor it is guaranteed to be carried through remapping. 186 -- This function takes care of page size alignment issues. The accessors 187 -- below only expose the region that has been requested by this call, even 188 -- if more bytes were actually mapped by this function. 189 -- TODO??? Enable to have a private copy for readable files 190 191 function Read 192 (File : Mapped_File; 193 Offset : File_Size := 0; 194 Length : File_Size := 0; 195 Mutable : Boolean := False) return Mapped_Region; 196 -- Likewise, return a new mapped region 197 198 procedure Read 199 (File : Mapped_File; 200 Offset : File_Size := 0; 201 Length : File_Size := 0; 202 Mutable : Boolean := False); 203 -- Likewise, use the legacy "default" region in File 204 205 function Length (File : Mapped_File) return File_Size; 206 -- Size of the file on the disk 207 208 function Offset (Region : Mapped_Region) return File_Size; 209 -- Return the offset, in the physical file on disk, corresponding to the 210 -- requested mapped region. The first byte in the file has offest 0. 211 212 function Offset (File : Mapped_File) return File_Size; 213 -- Likewise for the region contained in File 214 215 function Last (Region : Mapped_Region) return Integer; 216 -- Return the number of requested bytes mapped in this region. It is 217 -- erroneous to access Data for indices outside 1 .. Last (Region). 218 -- Such accesses may cause Storage_Error to be raised. 219 220 function Last (File : Mapped_File) return Integer; 221 -- Return the number of requested bytes mapped in the region contained in 222 -- File. It is erroneous to access Data for indices outside of 1 .. Last 223 -- (File); such accesses may cause Storage_Error to be raised. 224 225 function Data (Region : Mapped_Region) return Str_Access; 226 pragma Inline (Data); 227 -- The data mapped in Region as requested. The result is an unconstrained 228 -- string, so you cannot use the usual 'First and 'Last attributes. 229 -- Instead, these are respectively 1 and Size. 230 231 function Data (File : Mapped_File) return Str_Access; 232 pragma Inline (Data); 233 -- Likewise for the region contained in File 234 235 function Is_Mutable (Region : Mapped_Region) return Boolean; 236 -- Return whether it is safe to change bytes in Data (Region). This is true 237 -- for regions from writeable files, for regions mapped with the "Mutable" 238 -- flag set, and for regions that are copied in a buffer. Note that it is 239 -- not specified whether empty regions are mutable or not, since there is 240 -- no byte no modify. 241 242 function Is_Mmapped (File : Mapped_File) return Boolean; 243 -- Whether regions for this file are opened through an mmap() system call 244 -- or equivalent. This is in general irrelevant to your application, unless 245 -- the file can be accessed by multiple concurrent processes or tasks. In 246 -- such a case, and if the file is indeed mmap-ed, then the various parts 247 -- of the file can be written simulatenously, and thus you cannot ensure 248 -- the integrity of the file. If the file is not mmapped, the latest 249 -- process to Close it overwrite what other processes have done. 250 251 function Get_Page_Size return Integer; 252 -- Returns the number of bytes in a page. Once a file is mapped from the 253 -- disk, its offset and Length should be multiples of this page size (which 254 -- is ensured by this package in any case). Knowing this page size allows 255 -- you to map as much memory as possible at once, thus potentially reducing 256 -- the number of system calls to read the file by chunks. 257 258 function Read_Whole_File 259 (Filename : String; 260 Empty_If_Not_Found : Boolean := False) 261 return System.Strings.String_Access; 262 -- Returns the whole contents of the file. 263 -- The returned string must be freed by the user. 264 -- This is a convenience function, which is of course slower than the ones 265 -- above since we also need to allocate some memory, actually read the file 266 -- and copy the bytes. 267 -- If the file does not exist, null is returned. However, if 268 -- Empty_If_Not_Found is True, then the empty string is returned instead. 269 -- Filename should be compatible with the filesystem. 270 271private 272 pragma Inline (Data, Length, Last, Offset, Is_Mmapped, To_Str_Access); 273 274 type Mapped_File_Record; 275 type Mapped_File is access Mapped_File_Record; 276 277 type Mapped_Region_Record; 278 type Mapped_Region is access Mapped_Region_Record; 279 280 Invalid_Mapped_File : constant Mapped_File := null; 281 Invalid_Mapped_Region : constant Mapped_Region := null; 282 283end System.Mmap; 284