diff -uNr a/cryostat/MANIFEST.TXT b/cryostat/MANIFEST.TXT --- a/cryostat/MANIFEST.TXT false +++ b/cryostat/MANIFEST.TXT 918f663e25951adbd3792c4dff930a38a97d7e65fe2b7b288e8de6a6c1f8cbada12b30173273f10827fc46e54cdea3ce089f3ee6dab8705c6446e24bf2b1077f @@ -0,0 +1 @@ +633037 cryostat_genesis "Genesis." diff -uNr a/cryostat/README.TXT b/cryostat/README.TXT --- a/cryostat/README.TXT false +++ b/cryostat/README.TXT 14911a5f1df993eade542652d5d20431017a872cad0a367de56ba0164564f68a58fa5e846a3835f601a055762d203b7866879937b59f51a2710ec45a4157cb5b @@ -0,0 +1,93 @@ +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- This file is part of 'Cryostat', an Ada library for persistent storage. -- +-- -- +-- (C) 2020 Stanislav Datskovskiy ( www.loper-os.org ) -- +-- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html -- +-- -- +-- You do not have, nor can you ever acquire the right to use, copy or -- +-- distribute this software ; Should you use this software for any purpose, -- +-- or copy and distribute it to anyone or in any manner, you are breaking -- +-- the laws of whatever soi-disant jurisdiction, and you promise to -- +-- continue doing so for the indefinite future. In any case, please -- +-- always : read and understand any software ; verify any PGP signatures -- +-- that you use - for any purpose. -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + +------------------------------------------------------------------------------ +"Cryostat" is a Fits-in-Head minimal library for adding persistent storage to +Ada data structures. It uses the MMap() system call, present in Linux (kernel +2.4 and newer) and all compatible operating systems. + +Cryostat does NOT require enabling the use of pointerism, the secondary stack, +heap, or other bulky and objectionable GNAT features, in the calling program. +It does however require "finalization" to be enabled. This is used to +guarantee the safe sync-to-disk and closing of the backing MMap when the +data structure it contains goes out of scope. + +See introductory article : http://www.loper-os.org/?p=3791 +------------------------------------------------------------------------------ + +------------------------------------------------------------------------------ +BUILD, TEST : +------------------------------------------------------------------------------ + +cd demo +gprbuild +./bin/cryodemo + +Will produce this output : + +T(0) before : 0 +T(Last) before : 0 +T(0) after : 1 +T(Last) after : 1 +OK. + +On a second invocation : + +T(0) before : 1 +T(Last) before : 1 +T(0) after : 2 +T(Last) after : 2 +OK. + +... on the N-th invocation : + +T(0) before : N-1 +T(Last) before : N-1 +T(0) after : N +T(Last) after : N +OK. + +"cryotest.bin", the demo backing file, will consist of 512 megabytes of +byte value N, where N is the number of times the demo has executed. + +E.g. after the first execution of "cryodemo" , + +$ hexdump -C cryotest.bin + +00000000 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 |................| +* +20000000 + +------------------------------------------------------------------------------ +TODO (as of version 633037) : +------------------------------------------------------------------------------ + +1) Add support for offsetted maps, and for maps which do not span the entire + length of their backing file; likewise support runtime expansion of the + backing file. + +2) Currently, Cryostat is C-free. However, if added a .C for pulling constants + from system headers, instead of the hardcoded MMap() flag values + currently in unix.ads, could support architectures where non-standard values + are used for these; in particular, MIPS32, MIPS64; and possibly others. + See also: http://logs.nosuchlabs.com/log/trilema/2018-10-24#1865524 + +3) Add support for "anonymous" (i.e. not backed to disk storage) MMap, as a + cleaner (when using large data structures) replacement for Ada's standard + heap mechanism. + +------------------------------------------------------------------------------ diff -uNr a/cryostat/demo/bin/README b/cryostat/demo/bin/README --- a/cryostat/demo/bin/README false +++ b/cryostat/demo/bin/README 5fdbae897eb301a711bf95707f329517db540e34c182a5beec96e93d5d0d856cec2ed6b01c1191f865e8d1c45709a462c70c3005d4aa3676eb445d1479edf2e5 @@ -0,0 +1 @@ +Placeholder. diff -uNr a/cryostat/demo/cryodemo.adb b/cryostat/demo/cryodemo.adb --- a/cryostat/demo/cryodemo.adb false +++ b/cryostat/demo/cryodemo.adb 88af8572f4610d88a155e834189f6fa61f21cfd3198aa73c3f68042d4b60299061c58b3770cdf7086f6c834fb7b39f8c604171fc156ca041f6fcdfe24607c970 @@ -0,0 +1,76 @@ +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- This file is part of 'CryoDemo', a tutorial example for 'Cryostat'. -- +-- -- +-- (C) 2020 Stanislav Datskovskiy ( www.loper-os.org ) -- +-- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html -- +-- -- +-- You do not have, nor can you ever acquire the right to use, copy or -- +-- distribute this software ; Should you use this software for any purpose, -- +-- or copy and distribute it to anyone or in any manner, you are breaking -- +-- the laws of whatever soi-disant jurisdiction, and you promise to -- +-- continue doing so for the indefinite future. In any case, please -- +-- always : read and understand any software ; verify any PGP signatures -- +-- that you use - for any purpose. -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + +with Interfaces; use Interfaces; +with ada.text_io; use ada.text_io; + +with Cryostat; + + +procedure CryoDemo is + + -- Path on disk for the example Cryostat backing file : + File_Path : constant String := "cryotest.bin"; + + -- Now, let's define an example data structure to place in a Cryostat : + + -- Example payload array's element type: byte. + subtype ADatum is Unsigned_8; + + -- Let's make it 512MB - far bigger than a typical stack, to demonstrate + -- that it will in fact reside in the Cryostat, rather than on the stack : + A_MBytes : constant Unsigned_32 := 512; + + -- Example payload: an array. + subtype ARange is Unsigned_32 range 0 .. (A_MBytes * 1024 * 1024) - 1; + + -- Complete the definition of the payload data structure : + type TestArray is array(ARange) of ADatum; + + -- Declare a Cryostat which stores a TestArray : + package Cryo is new Cryostat(Form => TestArray, + Path => File_Path, + Writable => True, -- Permit writing + Create => True); -- Create file if not exists + + -- Handy reference to the payload; no pointerisms needed ! + T : TestArray renames Cryo.Item; + + -- T can now be treated as if it lived on the stack : + +begin + + Put_Line("T(0) before : " & ADatum'Image(T(0))); + Put_Line("T(Last) before : " & ADatum'Image(T(T'Last))); + + -- Increment each of the elements of T : + for i in T'Range loop + T(i) := T(i) + 1; + end loop; + + Put_Line("T(0) after : " & ADatum'Image(T(0))); + Put_Line("T(Last) after : " & ADatum'Image(T(T'Last))); + + --- Optional, finalizer always syncs in this example + -- Cryo.Sync; + + --- Test of Zap -- uncomment and get zeroized payload every time : + -- Cryo.Zap; + + Put_Line("OK."); + +end CryoDemo; diff -uNr a/cryostat/demo/cryodemo.gpr b/cryostat/demo/cryodemo.gpr --- a/cryostat/demo/cryodemo.gpr false +++ b/cryostat/demo/cryodemo.gpr 88610367d612a781967bb6e3e82377404f8007e79ce2b664a1f64e6b79d2985236144fa6205fd3824df2712c68e3bcd1124b3ec528bd4dae588b1db1370750ef @@ -0,0 +1,68 @@ +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- This file is part of 'CryoDemo', a tutorial example for 'Cryostat'. -- +-- -- +-- (C) 2020 Stanislav Datskovskiy ( www.loper-os.org ) -- +-- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html -- +-- -- +-- You do not have, nor can you ever acquire the right to use, copy or -- +-- distribute this software ; Should you use this software for any purpose, -- +-- or copy and distribute it to anyone or in any manner, you are breaking -- +-- the laws of whatever soi-disant jurisdiction, and you promise to -- +-- continue doing so for the indefinite future. In any case, please -- +-- always : read and understand any software ; verify any PGP signatures -- +-- that you use - for any purpose. -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + +with "../libcryo/cryostat.gpr"; + +project CryoDemo is + + for Object_Dir use "obj"; + + type Mode_Type is ("debug", "release"); + Mode : Mode_Type := external ("mode", "release"); + + for Languages use ("Ada"); + for Source_Dirs use ("."); + for Exec_Dir use "bin"; + for Main use ("cryodemo.adb"); + + package Compiler is + case Mode is + when "debug" => + for Switches ("Ada") + use ("-g"); + when "release" => + for Switches ("Ada") + use ("-O2", "-fdump-scos", "-gnata", "-fstack-check", + "-gnatyd", "-gnatym", + "-fdata-sections", "-ffunction-sections", + "-gnatec=" & CryoDemo'Project_Dir & "restrict.adc"); + end case; + end Compiler; + + package Binder is + case Mode is + when "debug" => + for Switches ("Ada") + use (); + when "release" => + for Switches ("Ada") + use ("-static"); + end case; + end Binder; + + package Linker is + case Mode is + when "debug" => + for Switches ("Ada") + use (); + when "release" => + for Switches ("Ada") + use ("-Wl,--gc-sections", "-static"); + end case; + end Linker; + +end CryoDemo; diff -uNr a/cryostat/demo/obj/README b/cryostat/demo/obj/README --- a/cryostat/demo/obj/README false +++ b/cryostat/demo/obj/README 5fdbae897eb301a711bf95707f329517db540e34c182a5beec96e93d5d0d856cec2ed6b01c1191f865e8d1c45709a462c70c3005d4aa3676eb445d1479edf2e5 @@ -0,0 +1 @@ +Placeholder. diff -uNr a/cryostat/demo/restrict.adc b/cryostat/demo/restrict.adc --- a/cryostat/demo/restrict.adc false +++ b/cryostat/demo/restrict.adc a341db13126e582bb4eac515d56975ea7ee4e83f04bb94ac0a831c2bc17b6521445cab5cdd9112e164300e898a88c1e747a25ed989b347547018a9864dfe6a1f @@ -0,0 +1,83 @@ +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- This file is part of 'CryoDemo', a tutorial example for 'Cryostat'. -- +-- -- +-- (C) 2020 Stanislav Datskovskiy ( www.loper-os.org ) -- +-- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html -- +-- -- +-- You do not have, nor can you ever acquire the right to use, copy or -- +-- distribute this software ; Should you use this software for any purpose, -- +-- or copy and distribute it to anyone or in any manner, you are breaking -- +-- the laws of whatever soi-disant jurisdiction, and you promise to -- +-- continue doing so for the indefinite future. In any case, please -- +-- always : read and understand any software ; verify any PGP signatures -- +-- that you use - for any purpose. -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + +pragma Restrictions(Immediate_Reclamation); +pragma Restrictions(Max_Asynchronous_Select_Nesting => 0); +pragma Restrictions(Max_Protected_Entries => 0); +pragma Restrictions(Max_Select_Alternatives => 0); +pragma Restrictions(Max_Task_Entries => 0); +pragma Restrictions(Max_Tasks => 0); +pragma Restrictions(No_Abort_Statements); +pragma Restrictions(No_Access_Parameter_Allocators); +pragma Restrictions(No_Allocators); +pragma Restrictions(No_Asynchronous_Control); +pragma Restrictions(No_Calendar); +pragma Restrictions(No_Coextensions); +pragma Restrictions(No_Default_Stream_Attributes); +pragma Restrictions(No_Delay); +pragma Restrictions(No_Dispatch); +pragma Restrictions(No_Dispatching_Calls); +pragma Restrictions(No_Dynamic_Attachment); +pragma Restrictions(No_Dynamic_Priorities); +pragma Restrictions(No_Entry_Calls_In_Elaboration_Code); +pragma Restrictions(No_Entry_Queue); +pragma Restrictions(No_Enumeration_Maps); +pragma Restrictions(No_Exception_Propagation); +pragma Restrictions(No_Exception_Registration); +pragma Restrictions(No_Fixed_Io); +pragma Restrictions(No_Floating_Point); +pragma Restrictions(No_Implementation_Aspect_Specifications); +pragma Restrictions(No_Implementation_Units); +pragma Restrictions(No_Implicit_Dynamic_Code); +pragma Restrictions(No_Implicit_Heap_Allocations); +pragma Restrictions(No_Implicit_Protected_Object_Allocations); +pragma Restrictions(No_Implicit_Task_Allocations); +pragma Restrictions(No_Initialize_Scalars); +pragma Restrictions(No_Local_Protected_Objects); +pragma Restrictions(No_Local_Timing_Events); +pragma Restrictions(No_Protected_Type_Allocators); +pragma Restrictions(No_Protected_Types); +pragma Restrictions(No_Relative_Delay); +pragma Restrictions(No_Requeue_Statements); +pragma Restrictions(No_Secondary_Stack); +pragma Restrictions(No_Select_Statements); +pragma Restrictions(No_Specific_Termination_Handlers); +pragma Restrictions(No_Standard_Allocators_After_Elaboration); +pragma Restrictions(No_Stream_Optimizations); +pragma Restrictions(No_Streams); +pragma Restrictions(No_Task_Allocators); +pragma Restrictions(No_Task_At_Interrupt_Priority); +pragma Restrictions(No_Task_Attributes_Package); +pragma Restrictions(No_Task_Hierarchy); +pragma Restrictions(No_Tasking); +pragma Restrictions(No_Task_Termination); +pragma Restrictions(No_Terminate_Alternatives); +pragma Restrictions(No_Unchecked_Access); +pragma Restrictions(No_Unchecked_Conversion); +pragma Restrictions(No_Unchecked_Deallocation); +pragma Restrictions(No_Wide_Characters); +pragma Restrictions(Pure_Barriers); +pragma Restrictions(Simple_Barriers); +pragma Restrictions(Static_Priorities); +pragma Restrictions(Static_Storage_Size); +pragma Validity_Checks(ALL_CHECKS); + +----- Deliberately omitted (we use these) : + +-- pragma Restrictions(No_Finalization); +-- pragma Restrictions(No_Nested_Finalization); +-- pragma Restrictions(No_Multiple_Elaboration); diff -uNr a/cryostat/libcryo/cryostat.adb b/cryostat/libcryo/cryostat.adb --- a/cryostat/libcryo/cryostat.adb false +++ b/cryostat/libcryo/cryostat.adb 9ff9efba6ab1874687e60c939775cd8388575e3bfcaee80a3b0f38055437f6890a1bd90be40cf2e43ce15c6452e7b95fa355d8b13c8e3389030bb382273f6de6 @@ -0,0 +1,48 @@ +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- This file is part of 'Cryostat', an Ada library for persistent storage. -- +-- -- +-- (C) 2020 Stanislav Datskovskiy ( www.loper-os.org ) -- +-- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html -- +-- -- +-- You do not have, nor can you ever acquire the right to use, copy or -- +-- distribute this software ; Should you use this software for any purpose, -- +-- or copy and distribute it to anyone or in any manner, you are breaking -- +-- the laws of whatever soi-disant jurisdiction, and you promise to -- +-- continue doing so for the indefinite future. In any case, please -- +-- always : read and understand any software ; verify any PGP signatures -- +-- that you use - for any purpose. -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + +package body Cryostat is + + -- Test if the Cryostat is usable + function IsReady return Boolean is + begin + return PMaps.IsReady(Map); + end IsReady; + + + -- If the Cryostat is writable, sync to disk immediately. + procedure Sync is + begin + PMaps.Sync(Map); + end Sync; + + + -- Zero the entire mapped space of the Cryostat. + procedure Zap is + begin + PMaps.Zap(Map); + end Zap; + + + -- Close the Cryostat and mark it unusable. + -- Normally, this is unnecessary (Finalize will do it) + procedure Stop is + begin + PMaps.Stop(Map); + end Stop; + +end Cryostat; diff -uNr a/cryostat/libcryo/cryostat.ads b/cryostat/libcryo/cryostat.ads --- a/cryostat/libcryo/cryostat.ads false +++ b/cryostat/libcryo/cryostat.ads fd821e9f56895a467493c1408ac51c9e9029dfa6ff556c31ee31c06a2b200c3020c7b45cab7877e77bb88f3b4c3d66985eef06a5fb25ac425dea459582d55e52 @@ -0,0 +1,74 @@ +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- This file is part of 'Cryostat', an Ada library for persistent storage. -- +-- -- +-- (C) 2020 Stanislav Datskovskiy ( www.loper-os.org ) -- +-- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html -- +-- -- +-- You do not have, nor can you ever acquire the right to use, copy or -- +-- distribute this software ; Should you use this software for any purpose, -- +-- or copy and distribute it to anyone or in any manner, you are breaking -- +-- the laws of whatever soi-disant jurisdiction, and you promise to -- +-- continue doing so for the indefinite future. In any case, please -- +-- always : read and understand any software ; verify any PGP signatures -- +-- that you use - for any purpose. -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + +with System; +with Unix; use Unix; +with PMaps; use PMaps; + + +generic + + -- The type of the item that will live in the Cryostat : + type Form is limited private; + + -- The path of the backing file : + Path : in String; + + -- Whether the contents of the Cryostat will be writable : + Writable : in Boolean; + + -- Whether the backing file is to be created if it does not already exist : + Create : in Boolean; + +package Cryostat is + + pragma Preelaborate; + + -- The concrete datum of type Form that will live in the Cryostat : + Item : Form; + + -- Test if the Cryostat is usable + function IsReady return Boolean; + + -- If the Cryostat is writable, sync it to disk immediately + procedure Sync; + + -- Zero the entire mapped space of the Cryostat + procedure Zap; + + -- Close the Cryostat and mark it unusable. + -- Normally, this is unnecessary (Finalize will do it) + procedure Stop; + +private + + -- The actual number of bytes occupied by an instance of the Form type : + Footprint : constant Word := Form'Size / System.Storage_Unit; + + -- Instantiate a memory map using the given params : + Map : PMap(Handle => OpenMapFile(Path => Path, + Writable => Writable, + Create => Create), + Length => Footprint, + Offset => 0, -- Offsetted maps not supported yet! + Create => Create, + Writable => Writable); + + -- Force Item to reside at the obtained address : + for Item'Address use GetAddress(Map); + +end Cryostat; diff -uNr a/cryostat/libcryo/cryostat.gpr b/cryostat/libcryo/cryostat.gpr --- a/cryostat/libcryo/cryostat.gpr false +++ b/cryostat/libcryo/cryostat.gpr 473c8a9419d78f8d7e0b870de97f735065f3f1c4ae031cdc5d617f0a1c28139a3cbe09cec75afc7a3bfd2c6207122f4ca7b471faf71b7542fa2ef62da4a092e7 @@ -0,0 +1,63 @@ +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- This file is part of 'Cryostat', an Ada library for persistent storage. -- +-- -- +-- (C) 2020 Stanislav Datskovskiy ( www.loper-os.org ) -- +-- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html -- +-- -- +-- You do not have, nor can you ever acquire the right to use, copy or -- +-- distribute this software ; Should you use this software for any purpose, -- +-- or copy and distribute it to anyone or in any manner, you are breaking -- +-- the laws of whatever soi-disant jurisdiction, and you promise to -- +-- continue doing so for the indefinite future. In any case, please -- +-- always : read and understand any software ; verify any PGP signatures -- +-- that you use - for any purpose. -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + +project Cryostat is + + for Object_Dir use "obj"; + + type Mode_Type is ("debug", "release"); + Mode : Mode_Type := external ("mode", "release"); + + for Languages use ("Ada"); + for Source_Dirs use ("."); + for Library_Dir use "lib"; + for Library_Name use "Cryostat"; + for Library_Kind use "static"; + + package Compiler is + case Mode is + when "debug" => + for Switches ("Ada") + use ("-g"); + when "release" => + for Switches ("Ada") + use ("-O2", "-fdump-scos", "-gnata", "-fstack-check", + "-gnatyd", "-gnatym", + "-fdata-sections", "-ffunction-sections", "-gnatwr", "-gnatw.d", + "-gnatec=" & Cryostat'Project_Dir & "restrict.adc"); + for Switches ("C") + use ("-O2", "-Wall", "-fstack-check"); + end case; + end Compiler; + + package Builder is + for Switches ("Ada") + use ("-nostdlib"); + end Builder; + + package Binder is + case Mode is + when "debug" => + for Switches ("Ada") + use (); + when "release" => + for Switches ("Ada") + use ("-static"); + end case; + end Binder; + +end Cryostat; diff -uNr a/cryostat/libcryo/lib/README b/cryostat/libcryo/lib/README --- a/cryostat/libcryo/lib/README false +++ b/cryostat/libcryo/lib/README 5fdbae897eb301a711bf95707f329517db540e34c182a5beec96e93d5d0d856cec2ed6b01c1191f865e8d1c45709a462c70c3005d4aa3676eb445d1479edf2e5 @@ -0,0 +1 @@ +Placeholder. diff -uNr a/cryostat/libcryo/obj/README b/cryostat/libcryo/obj/README --- a/cryostat/libcryo/obj/README false +++ b/cryostat/libcryo/obj/README 5fdbae897eb301a711bf95707f329517db540e34c182a5beec96e93d5d0d856cec2ed6b01c1191f865e8d1c45709a462c70c3005d4aa3676eb445d1479edf2e5 @@ -0,0 +1 @@ +Placeholder. diff -uNr a/cryostat/libcryo/pmaps.adb b/cryostat/libcryo/pmaps.adb --- a/cryostat/libcryo/pmaps.adb false +++ b/cryostat/libcryo/pmaps.adb f32079aac09ac289e830f64803d3aaf2c0a31309900340d9548af67ff86fe07741238beed1e25741c33d2cb67c9ac8afd4b23fa9b1e652ccbbeddd0b50f1a31a @@ -0,0 +1,243 @@ +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- This file is part of 'Cryostat', an Ada library for persistent storage. -- +-- -- +-- (C) 2020 Stanislav Datskovskiy ( www.loper-os.org ) -- +-- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html -- +-- -- +-- You do not have, nor can you ever acquire the right to use, copy or -- +-- distribute this software ; Should you use this software for any purpose, -- +-- or copy and distribute it to anyone or in any manner, you are breaking -- +-- the laws of whatever soi-disant jurisdiction, and you promise to -- +-- continue doing so for the indefinite future. In any case, please -- +-- always : read and understand any software ; verify any PGP signatures -- +-- that you use - for any purpose. -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + +with System; use System; + + +package body PMaps is + + -- Open a backing file at Path, with given params, for use with Initialize + function OpenMapFile(Path : in String; + Writable : in Boolean := False; + Create : in Boolean := False) return FD is + + -- Buffer for converting the civilized Path string to a C-style string : + CPath : String(1 .. Path'Length + 1) := (others => Character'Val(0)); + + -- Unix FD handle for the backing file, obtained by Open() + FileFD : FD; + + -- Flags provided to Open() -- default 'read only' + COpenFlag : O_Flags := O_RDONLY; + + begin + + -- Convert civilized string to the barbaric type expected by Open() : + CPath(Path'Range) := Path; + + -- Set the writability flag for Open() if Writable is enabled : + if Writable then + COpenFlag := O_RDWR; + end if; + + -- If file does not exist, and Create is enabled, it will be created : + if Create then + COpenFlag := COpenFlag or O_CREAT; + end if; + + -- Open the file : + FileFD := Open(CPath'Address, COpenFlag); + + -- If Open() failed, eggog : + if FileFD = FD_EGGOG then + raise PMapFailedOpen with "PMap: Failed to Open backing file"; + end if; + + -- Return the FD of the backing file : + return FileFD; + + end OpenMapFile; + + + -- Initialize a new map + procedure Initialize(Map : in out PMap) is + + -- Prot flags to be given to MMap() + MProtFlag : MM_Prot := PROT_READ; + + -- Result code returned by FTruncate() + CErr : Unix_Int; + + begin + + -- Check that we have not already Open'd: + if Map.Status /= Stop then + Map.Status := Eggog; + raise PMapFailedOpen with "PMap: already Opened backing file"; + end if; + + -- If Write is enabled, set the appropriate flag for MMap() : + if Map.MapWritable then + MProtFlag := PROT_READ or PROT_WRITE; + end if; + + -- If creating, pad the backing file to the payload size : + if Map.MapCreate then + CErr := FTruncate(Map.FileFD, Map.MapLength); + if CErr /= 0 then + Map.Status := Eggog; + raise PMapFailedOpen with "PMap: Failed to FTruncate backing file"; + end if; + end if; + + -- Ask the OS to set up the map itself: + Map.Address := MMap(Length => Map.MapLength, + Off_T => Map.MapOffset, + Prot => MProtFlag, + Flags => MAP_SHARED, + Handle => Map.FileFD); + + -- Test for failure of MMap() call : + if Map.Address = MAP_FAILED then + Map.Status := Eggog; + raise PMapFailedMMap with "PMap: MAP_FAILED"; + end if; + + if Map.Address = NullPtr then + Map.Status := Eggog; + raise PMapFailedAddr with "PMap: Map Address is Null"; + end if; + + -- If no failure detected, mark the map as usable : + Map.Status := Run; + + end Initialize; + + + -- Test whether a map is operating + function IsReady(Map : in PMap) return Boolean is + begin + + return Map.Status = Run; + + end IsReady; + + + -- Retrieve the memory address where the map payload resides + function GetAddress(Map : in PMap) return MapAddress is + begin + + -- Ensure that the map is active : + if not IsReady(Map) then + raise PMapNotRunning with "PMap: GetAddress on inactive Map"; + end if; + + -- Return the address : + return Map.Address; + + end GetAddress; + + + -- Zeroize the map, if it is writable + procedure Zap(Map : in out PMap) is + + -- Represent the map's payload as a byte array across full length : + RawArray : array(1 .. Map.MapLength) of Byte; + for RawArray'Address use Map.Address; + + begin + + -- If map is inactive, do nothing : + if not IsReady(Map) then + return; + end if; + + -- If tried to zap a read-only map, eggog : + if Map.MapWritable = False then + raise PMapNotWritable with "PMap: Tried to Zap a Read-Only Map"; + end if; + + -- Zeroize the payload of the map : + RawArray := (others => 0); + + end Zap; + + + -- Sync the map to disk + procedure Sync(Map : in out PMap) is + + -- Result code returned by MSync() and Close() + CErr : Unix_Int := 0; + + begin + + -- If map is inactive, do nothing : + if not IsReady(Map) then + return; + end if; + + -- If map is writable, sync it to disk : + if Map.MapWritable then + CErr := MSync(Map.Address, Map.MapLength, MS_SYNC); + end if; + + -- If eggog during MSync() : + if CErr /= 0 then + Map.Status := Eggog; + CErr := Close(Map.FileFD); + raise PMapFailedSync with "PMap: Failed to Sync"; + end if; + + end Sync; + + + -- Close map and mark it unusable + procedure Stop(Map : in out PMap) is + + -- Result code returned by MUnmap() and Close() + CErr : Unix_Int; + + begin + + -- If map is already inactive, do nothing : + if not IsReady(Map) then + return; + end if; + + -- Sync all changes to disk, if map was writable : + Sync(Map); + + -- Mark map as inactive : + Map.Status := Stop; + + -- Unmap the map : + CErr := MUnmap(Map.Address, Map.MapLength); + if CErr /= 0 then + Map.Status := Eggog; + raise PMapFailedUnmap with "PMap: Failed to Unmap"; + end if; + + -- Lastly, close out the FD : + CErr := Close(Map.FileFD); + if CErr /= 0 then + Map.Status := Eggog; + raise PMapFailedClose with "PMap: Failed to Close backing file"; + end if; + + end Stop; + + + -- Sync and close a given map, if fell out of scope + procedure Finalize(Map : in out PMap) is + begin + + -- Close the map : + Stop(Map); + + end Finalize; + +end PMaps; diff -uNr a/cryostat/libcryo/pmaps.ads b/cryostat/libcryo/pmaps.ads --- a/cryostat/libcryo/pmaps.ads false +++ b/cryostat/libcryo/pmaps.ads 20747487186412cb602107eed5503448cd19d59ef195dd8b44611efc6bf40ddd566d1f6630bd50d602a84ce820238236c6ca67567897226870a718f9ecb4f584 @@ -0,0 +1,110 @@ +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- This file is part of 'Cryostat', an Ada library for persistent storage. -- +-- -- +-- (C) 2020 Stanislav Datskovskiy ( www.loper-os.org ) -- +-- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html -- +-- -- +-- You do not have, nor can you ever acquire the right to use, copy or -- +-- distribute this software ; Should you use this software for any purpose, -- +-- or copy and distribute it to anyone or in any manner, you are breaking -- +-- the laws of whatever soi-disant jurisdiction, and you promise to -- +-- continue doing so for the indefinite future. In any case, please -- +-- always : read and understand any software ; verify any PGP signatures -- +-- that you use - for any purpose. -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + +with System; +with Ada.Finalization; +with Unix; use Unix; + + +package PMaps is + + pragma Preelaborate; + + -- Open file for map + function OpenMapFile(Path : in String; + Writable : in Boolean := False; + Create : in Boolean := False) + return FD + with Pre => not ((not Writable) and Create); + + -- The address in memory where the map resides + subtype MapAddress is System.Address; + + -- Internal representation of the map + type PMap(Handle : FD; -- Unix FD handle of the open file + Length : Word; -- The length (bytes) of the map + Offset : Word; -- Offset into the file (normally zero) + Create : Boolean; -- Whether to create the file if not exists + Writable : Boolean) -- Whether the map is writeable + is new Ada.Finalization.Limited_Controlled with private; + + -- Test if map is usable + function IsReady(Map : in PMap) return Boolean; + + -- Zero the entire map space + procedure Zap(Map : in out PMap); + + -- Sync map to disk immediately + procedure Sync(Map : in out PMap); + + -- Close map and mark it unusable + procedure Stop(Map : in out PMap); + + -- Retrieve the address at which map resides + function GetAddress(Map : in PMap) return MapAddress; + + -- Eggogs + PMapFailedOpen : exception; -- Could not open the given file + PMapFailedMMap : exception; -- Eggog when performed MMap() + PMapFailedAddr : exception; -- MMap() returned an unusable address + PMapFailedSync : exception; -- Sync failed + PMapFailedUnmap : exception; -- Unmap failed + PMapFailedClose : exception; -- Closing backing file failed + PMapNotRunning : exception; -- Tried to use an inactive map + PMapNotWritable : exception; -- Tried to zap a read-only map + +private + + -- Current state of the map + type State is (Stop, Run, Eggog); + + type PMap(Handle : FD; + Length : Word; + Offset : Word; + Create : Boolean; + Writable : Boolean) is + new Ada.Finalization.Limited_Controlled with + record + -- Unix FD handle of the open file + FileFD : FD := Handle; + + -- Whether to create the file if not exists + MapCreate : Boolean := Create; + + -- Whether the map is writeable + MapWritable : Boolean := Writable; + + -- The length (bytes) of the map + MapLength : Word := Length; + + -- Offset into the file (normally zero) + MapOffset : Word := Offset; + + -- The address in memory where the map resides + Address : MapAddress := NullPtr; + + -- Current condition of this map + Status : State := Stop; + end record; + + -- Initialization + overriding procedure Initialize(Map : in out PMap); + + -- Automatic sync and close of the map when leaving scope + overriding procedure Finalize(Map : in out PMap); + +end PMaps; diff -uNr a/cryostat/libcryo/restrict.adc b/cryostat/libcryo/restrict.adc --- a/cryostat/libcryo/restrict.adc false +++ b/cryostat/libcryo/restrict.adc 0e5000fdca8d5ab593884582163f29d0458c1f36b8cc1e3da59b3e4f4b33f11407247d10cf279f748f7fe500f2dc4c9ad0eed7aa409c70a865c4bdd953005612 @@ -0,0 +1,83 @@ +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- This file is part of 'Cryostat', an Ada library for persistent storage. -- +-- -- +-- (C) 2020 Stanislav Datskovskiy ( www.loper-os.org ) -- +-- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html -- +-- -- +-- You do not have, nor can you ever acquire the right to use, copy or -- +-- distribute this software ; Should you use this software for any purpose, -- +-- or copy and distribute it to anyone or in any manner, you are breaking -- +-- the laws of whatever soi-disant jurisdiction, and you promise to -- +-- continue doing so for the indefinite future. In any case, please -- +-- always : read and understand any software ; verify any PGP signatures -- +-- that you use - for any purpose. -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + +pragma Restrictions(Immediate_Reclamation); +pragma Restrictions(Max_Asynchronous_Select_Nesting => 0); +pragma Restrictions(Max_Protected_Entries => 0); +pragma Restrictions(Max_Select_Alternatives => 0); +pragma Restrictions(Max_Task_Entries => 0); +pragma Restrictions(Max_Tasks => 0); +pragma Restrictions(No_Abort_Statements); +pragma Restrictions(No_Access_Parameter_Allocators); +pragma Restrictions(No_Allocators); +pragma Restrictions(No_Asynchronous_Control); +pragma Restrictions(No_Calendar); +pragma Restrictions(No_Coextensions); +pragma Restrictions(No_Default_Stream_Attributes); +pragma Restrictions(No_Delay); +pragma Restrictions(No_Dispatch); +pragma Restrictions(No_Dispatching_Calls); +pragma Restrictions(No_Dynamic_Attachment); +pragma Restrictions(No_Dynamic_Priorities); +pragma Restrictions(No_Entry_Calls_In_Elaboration_Code); +pragma Restrictions(No_Entry_Queue); +pragma Restrictions(No_Enumeration_Maps); +pragma Restrictions(No_Exception_Propagation); +pragma Restrictions(No_Exception_Registration); +pragma Restrictions(No_Fixed_Io); +pragma Restrictions(No_Floating_Point); +pragma Restrictions(No_Implementation_Aspect_Specifications); +pragma Restrictions(No_Implementation_Units); +pragma Restrictions(No_Implicit_Dynamic_Code); +pragma Restrictions(No_Implicit_Heap_Allocations); +pragma Restrictions(No_Implicit_Protected_Object_Allocations); +pragma Restrictions(No_Implicit_Task_Allocations); +pragma Restrictions(No_Initialize_Scalars); +pragma Restrictions(No_Local_Protected_Objects); +pragma Restrictions(No_Local_Timing_Events); +pragma Restrictions(No_Protected_Type_Allocators); +pragma Restrictions(No_Protected_Types); +pragma Restrictions(No_Relative_Delay); +pragma Restrictions(No_Requeue_Statements); +pragma Restrictions(No_Secondary_Stack); +pragma Restrictions(No_Select_Statements); +pragma Restrictions(No_Specific_Termination_Handlers); +pragma Restrictions(No_Standard_Allocators_After_Elaboration); +pragma Restrictions(No_Stream_Optimizations); +pragma Restrictions(No_Streams); +pragma Restrictions(No_Task_Allocators); +pragma Restrictions(No_Task_At_Interrupt_Priority); +pragma Restrictions(No_Task_Attributes_Package); +pragma Restrictions(No_Task_Hierarchy); +pragma Restrictions(No_Tasking); +pragma Restrictions(No_Task_Termination); +pragma Restrictions(No_Terminate_Alternatives); +pragma Restrictions(No_Unchecked_Access); +pragma Restrictions(No_Unchecked_Conversion); +pragma Restrictions(No_Unchecked_Deallocation); +pragma Restrictions(No_Wide_Characters); +pragma Restrictions(Pure_Barriers); +pragma Restrictions(Simple_Barriers); +pragma Restrictions(Static_Priorities); +pragma Restrictions(Static_Storage_Size); +pragma Validity_Checks(ALL_CHECKS); + +----- Deliberately omitted (we use these) : + +-- pragma Restrictions(No_Finalization); +-- pragma Restrictions(No_Nested_Finalization); +-- pragma Restrictions(No_Multiple_Elaboration); diff -uNr a/cryostat/libcryo/unix.ads b/cryostat/libcryo/unix.ads --- a/cryostat/libcryo/unix.ads false +++ b/cryostat/libcryo/unix.ads d7db32741f25095335308c2efcc1060161b184bfd2fea87556de3af2f7709c0adf6e7083356dd9a185460083c5fc772d02838a6af881c9fa93a930011e6a5e24 @@ -0,0 +1,111 @@ +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- This file is part of 'Cryostat', an Ada library for persistent storage. -- +-- -- +-- (C) 2020 Stanislav Datskovskiy ( www.loper-os.org ) -- +-- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html -- +-- -- +-- You do not have, nor can you ever acquire the right to use, copy or -- +-- distribute this software ; Should you use this software for any purpose, -- +-- or copy and distribute it to anyone or in any manner, you are breaking -- +-- the laws of whatever soi-disant jurisdiction, and you promise to -- +-- continue doing so for the indefinite future. In any case, please -- +-- always : read and understand any software ; verify any PGP signatures -- +-- that you use - for any purpose. -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ + +------------------------------------------------------------------------------ +-- WARNING : MIPS32/64 currently unsupported! -- +-- See also: http://logs.nosuchlabs.com/log/trilema/2018-10-24#1865524 -- +------------------------------------------------------------------------------ + +with Interfaces; use Interfaces; +with Interfaces.C; +with System; use System; + + +package Unix is + + pragma Preelaborate; + + -- Machine Word + type Word is mod 2**Standard'Address_Size; + + -- Byte + type Byte is mod 2**8; + + -- Unit int + type Unix_Int is mod 2**Interfaces.C.int'Size; + + -- File descriptors + type FD is new Unix_Int; + + type MM_Prot is new Unix_Int; + PROT_READ : constant MM_Prot := 1; + PROT_WRITE : constant MM_Prot := 2; + + type MM_Flags is new Unix_Int; + MAP_NONE : constant MM_Flags := 16#00#; + MAP_FIXED : constant MM_Flags := 16#10#; + MAP_SHARED : constant MM_Flags := 16#01#; + MAP_PRIVATE : constant MM_Flags := 16#02#; + -- TODO: MAP_HUGETLB + + -- Null Pointer + NullPtr : constant Address := System'To_Address(0); + + function MMap + (Start : Address := NullPtr; + Length : Word; + Prot : MM_Prot; + Flags : MM_Flags; + Handle : FD; + Off_T : Word := 0) + return Address; + pragma Import(C, MMap, "mmap"); + + -- Eggog code '-1' (posix uses instead of null here) + MAP_FAILED : constant Address := System'To_Address(Word'Last); + + function MUnmap + (Start : Address; + Length : Word) + return Unix_Int; + pragma Import(C, MUnmap, "munmap"); + + type O_Flags is new Unix_Int; + O_RDONLY : constant O_Flags := 8#00#; + O_WRONLY : constant O_Flags := 8#01#; + O_RDWR : constant O_Flags := 8#02#; + O_CREAT : constant O_Flags := 8#0100#; + + type M_Flags is new Unix_Int; + MS_ASYNC : constant M_Flags := 1; + MS_INVALIDATE : constant M_Flags := 2; + MS_SYNC : constant M_Flags := 4; + + function MSync + (Addr : Address; + Length : Word; + Flags : M_Flags) + return Unix_Int; + pragma Import(C, MSync, "msync"); + + function Open + (Name : System.Address; + Flags : O_Flags; + Mode : Unix_Int := 8#666#) -- TODO + return FD; + pragma Import(C, Open, "open"); + + -- '-1' + FD_EGGOG : constant FD := FD'Last; + + function Close(Handle : FD) return Unix_Int; + pragma Import(C, Close, "close"); + + function FTruncate(Handle : FD; Length : Word) return Unix_Int; + pragma Import(C, FTruncate, "ftruncate"); + +end Unix;