------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                 S Y S T E M . S H A R E D _ S T O R A G E                --
--                                                                          --
--                                 S p e c                                  --
--                                                                          --
--          Copyright (C) 1998-2020, Free Software Foundation, Inc.         --
--                                                                          --
-- GNAT is free software;  you can  redistribute it  and/or modify it under --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
--                                                                          --
-- As a special exception under Section 7 of GPL version 3, you are granted --
-- additional permissions described in the GCC Runtime Library Exception,   --
-- version 3.1, as published by the Free Software Foundation.               --
--                                                                          --
-- You should have received a copy of the GNU General Public License and    --
-- a copy of the GCC Runtime Library Exception along with this program;     --
-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
-- <http://www.gnu.org/licenses/>.                                          --
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
--                                                                          --
------------------------------------------------------------------------------

--  This package manages the shared/persistent storage required for
--  full implementation of variables in Shared_Passive packages, more
--  precisely variables whose enclosing dynamic scope is a shared
--  passive package. This implementation is specific to GNAT and GLADE
--  provides a more general implementation not dedicated to file
--  storage.

--  --------------------------
--  -- Shared Storage Model --
--  --------------------------

--  The basic model used is that each partition that references the
--  Shared_Passive package has a local copy of the package data that
--  is initialized in accordance with the declarations of the package
--  in the normal manner. The routines in System.Shared_Storage are
--  then used to ensure that the values in these separate copies are
--  properly synchronized with the state of the overall system.

--  In the GNAT implementation, this synchronization is ensured by
--  maintaining a set of files, in a designated directory. The
--  directory is designated by setting the environment variable
--  SHARED_MEMORY_DIRECTORY. This variable must be set for all
--  partitions. If the environment variable is not defined, then the
--  current directory is used.

--  There is one storage for each variable. The name is the fully
--  qualified name of the variable with all letters forced to lower
--  case. For example, the variable Var in the shared passive package
--  Pkg results in the storage name pkg.var.

--  If the storage does not exist, it indicates that no partition has
--  assigned a new value, so that the initial value is the correct
--  one. This is the critical component of the model. It means that
--  there is no system-wide synchronization required for initializing
--  the package, since the shared storages need not (and do not)
--  reflect the initial state. There is therefore no issue of
--  synchronizing initialization and read/write access.

--  -----------------------
--  -- Read/Write Access --
--  -----------------------

--  The approach is as follows:

--    For each shared variable, var, an instantiation of the below generic
--    package is created which provides Read and Write supporting procedures.

--    The routine Read in package System.Shared_Storage.Shared_Var_Procs
--    ensures to assign variable V to the last written value among processes
--    referencing it. A call to this procedure is generated by the expander
--    before each read access to the shared variable.

--    The routine Write in package System.Shared_Storage.Shared_Var_Proc
--    set a new value to the shared variable and, according to the used
--    implementation, propagate this value among processes referencing it.
--    A call to this procedure is generated by the expander after each
--    assignment of the shared variable.

--  Note: a special circuit allows the use of stream attributes Read and
--  Write for limited types (using the corresponding attribute for the
--  full type), but there are limitations on the data that can be placed
--  in shared passive partitions. See sem_smem.ads/adb for details.

--  ----------------------------------------------------------------
--  -- Handling of Protected Objects in Shared Passive Partitions --
--  ----------------------------------------------------------------

--  In the context of GNAT, during the execution of a protected
--  subprogram call, access is locked out using a locking mechanism
--  per protected object, as provided by the GNAT.Lock_Files
--  capability in the specific case of GNAT. This package contains the
--  lock and unlock calls, and the expander generates a call to the
--  lock routine before the protected call and a call to the unlock
--  routine after the protected call.

--  Within the code of the protected subprogram, the access to the
--  protected object itself uses the local copy, without any special
--  synchronization.  Since global access is locked out, no other task
--  or partition can attempt to read or write this data as long as the
--  lock is held.

--  The data in the local copy does however need synchronizing with
--  the global values in the shared storage. This is achieved as
--  follows:

--    The protected object generates a read and assignment routine as
--    described for other shared passive variables. The code for the
--    'Read and 'Write attributes (not normally allowed, but allowed
--    in this special case) simply reads or writes the values of the
--    components in the protected record.

--    The lock call is followed by a call to the shared read routine to
--    synchronize the local copy to contain the proper global value.

--    The unlock call in the procedure case only is preceded by a call
--    to the shared assign routine to synchronize the global shared
--    storages with the (possibly modified) local copy.

--    These calls to the read and assign routines, as well as the lock
--    and unlock routines, are inserted by the expander (see exp_smem.adb).

package System.Shared_Storage is

   procedure Shared_Var_Lock (Var : String);
   --  This procedure claims the shared storage lock. It is used for
   --  protected types in shared passive packages. A call to this
   --  locking routine is generated as the first operation in the code
   --  for the body of a protected subprogram, and it busy waits if
   --  the lock is busy.

   procedure Shared_Var_Unlock (Var : String);
   --  This procedure releases the shared storage lock obtained by a
   --  prior call to the Shared_Var_Lock procedure, and is to be
   --  generated as the last operation in the body of a protected
   --  subprogram.

   --  This generic package is instantiated for each shared passive
   --  variable. It provides supporting procedures called upon each
   --  read or write access by the expanded code.

   generic

      type Typ is limited private;
      --  Shared passive variable type

      V : in out Typ;
      --  Shared passive variable

      Full_Name : String;
      --  Shared passive variable storage name

   package Shared_Var_Procs is

      procedure Read;
      --  Shared passive variable access routine. Each reference to the
      --  shared variable, V, is preceded by a call to the corresponding
      --  Read procedure, which either leaves the initial value unchanged
      --  if the storage does not exist, or reads the current value from
      --  the shared storage.

      procedure Write;
      --  Shared passive variable assignment routine. Each assignment to
      --  the shared variable, V, is followed by a call to the corresponding
      --  Write procedure, which writes the new value to the shared storage.

   end Shared_Var_Procs;

end System.Shared_Storage;
