1------------------------------------------------------------------------------ 2-- -- 3-- GNAT COMPILER COMPONENTS -- 4-- -- 5-- S Y S T E M . S H A R E D _ S T O R A G E -- 6-- -- 7-- S p e c -- 8-- -- 9-- Copyright (C) 1998-2003 Free Software Foundation, Inc. -- 10-- -- 11-- GNAT is free software; you can redistribute it and/or modify it under -- 12-- terms of the GNU General Public License as published by the Free Soft- -- 13-- ware Foundation; either version 2, or (at your option) any later ver- -- 14-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- 15-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- 16-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- 17-- for more details. You should have received a copy of the GNU General -- 18-- Public License distributed with GNAT; see file COPYING. If not, write -- 19-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- 20-- MA 02111-1307, USA. -- 21-- -- 22-- As a special exception, if other files instantiate generics from this -- 23-- unit, or you link this unit with other files to produce an executable, -- 24-- this unit does not by itself cause the resulting executable to be -- 25-- covered by the GNU General Public License. This exception does not -- 26-- however invalidate any other reasons why the executable file might be -- 27-- covered by the GNU Public License. -- 28-- -- 29-- GNAT was originally developed by the GNAT team at New York University. -- 30-- Extensive contributions were provided by Ada Core Technologies Inc. -- 31-- -- 32------------------------------------------------------------------------------ 33 34-- This package manages the shared/persistant storage required for 35-- full implementation of variables in Shared_Passive packages, more 36-- precisely variables whose enclosing dynamic scope is a shared 37-- passive package. This implementation is specific to GNAT and GLADE 38-- provides a more general implementation not dedicated to file 39-- storage. 40 41-- This unit (and shared passive partitions) are supported on all 42-- GNAT implementations except on OpenVMS (where problems arise from 43-- trying to share files, and with version numbers of files) 44 45-- -------------------------- 46-- -- Shared Storage Model -- 47-- -------------------------- 48 49-- The basic model used is that each partition that references the 50-- Shared_Passive package has a local copy of the package data that 51-- is initialized in accordance with the declarations of the package 52-- in the normal manner. The routines in System.Shared_Storage are 53-- then used to ensure that the values in these separate copies are 54-- properly synchronized with the state of the overall system. 55 56-- In the GNAT implementation, this synchronization is ensured by 57-- maintaining a set of files, in a designated directory. The 58-- directory is designated by setting the environment variable 59-- SHARED_MEMORY_DIRECTORY. This variable must be set for all 60-- partitions. If the environment variable is not defined, then the 61-- current directory is used. 62 63-- There is one storage for each variable. The name is the fully 64-- qualified name of the variable with all letters forced to lower 65-- case. For example, the variable Var in the shared passive package 66-- Pkg results in the storage name pkg.var. 67 68-- If the storage does not exist, it indicates that no partition has 69-- assigned a new value, so that the initial value is the correct 70-- one. This is the critical component of the model. It means that 71-- there is no system-wide synchronization required for initializing 72-- the package, since the shared storages need not (and do not) 73-- reflect the initial state. There is therefore no issue of 74-- synchronizing initialization and read/write access. 75 76-- ----------------------- 77-- -- Read/Write Access -- 78-- ----------------------- 79 80-- The approach is as follows: 81 82-- For each shared variable, var, an access routine varR is created whose 83-- body has the following form (this example is for Pkg.Var): 84 85-- procedure varR is 86-- S : Ada.Streams.Stream_IO.Stream_Access; 87-- begin 88-- S := Shared_Var_ROpen ("pkg.var"); 89-- if S /= null then 90-- typ'Read (S); 91-- Shared_Var_Close (S); 92-- end if; 93-- end varR; 94 95-- The routine Shared_Var_ROpen in package System.Shared_Storage 96-- either returns null if the storage does not exist, or otherwise a 97-- Stream_Access value that references the corresponding shared 98-- storage, ready to read the current value. 99 100-- Each reference to the shared variable, var, is preceded by a 101-- call to the corresponding varR procedure, which either leaves the 102-- initial value unchanged if the storage does not exist, or reads 103-- the current value from the shared storage. 104 105-- In addition, for each shared variable, var, an assignment routine 106-- is created whose body has the following form (again for Pkg.Var) 107 108-- procedure VarA is 109-- S : Ada.Streams.Stream_IO.Stream_Access; 110-- begin 111-- S := Shared_Var_WOpen ("pkg.var"); 112-- typ'Write (S, var); 113-- Shared_Var_Close (S); 114-- end VarA; 115 116-- The routine Shared_Var_WOpen in package System.Shared_Storage 117-- returns a Stream_Access value that references the corresponding 118-- shared storage, ready to write the new value. 119 120-- Each assignment to the shared variable, var, is followed by a call 121-- to the corresponding varA procedure, which writes the new value to 122-- the shared storage. 123 124-- Note that there is no general synchronization for these storage 125-- read and write operations, since it is assumed that a correctly 126-- operating programs will provide appropriate synchronization. In 127-- particular, variables can be protected using protected types with 128-- no entries. 129 130-- The routine Shared_Var_Close is called to indicate the end of a 131-- read/write operations. This can be useful even in the context of 132-- the GNAT implementation. For instance, when a read operation and a 133-- write operation occur at the same time on the same partition, as 134-- the same stream is used simultaneously, both operations can 135-- terminate abruptly by raising exception Mode_Error because the 136-- stream has been opened in read mode and then in write mode and at 137-- least used by the read opartion. To avoid this unexpected 138-- behaviour, we introduce a synchronization at the partition level. 139 140-- Note: a special circuit allows the use of stream attributes Read and 141-- Write for limited types (using the corresponding attribute for the 142-- full type), but there are limitations on the data that can be placed 143-- in shared passive partitions. See sem_smem.ads/adb for details. 144 145-- ---------------------------------------------------------------- 146-- -- Handling of Protected Objects in Shared Passive Partitions -- 147-- ---------------------------------------------------------------- 148 149-- In the context of GNAT, during the execution of a protected 150-- subprogram call, access is locked out using a locking mechanism 151-- per protected object, as provided by the GNAT.Lock_Files 152-- capability in the specific case of GNAT. This package contains the 153-- lock and unlock calls, and the expander generates a call to the 154-- lock routine before the protected call and a call to the unlock 155-- routine after the protected call. 156 157-- Within the code of the protected subprogram, the access to the 158-- protected object itself uses the local copy, without any special 159-- synchronization. Since global access is locked out, no other task 160-- or partition can attempt to read or write this data as long as the 161-- lock is held. 162 163-- The data in the local copy does however need synchronizing with 164-- the global values in the shared storage. This is achieved as 165-- follows: 166 167-- The protected object generates a read and assignment routine as 168-- described for other shared passive variables. The code for the 169-- 'Read and 'Write attributes (not normally allowed, but allowed 170-- in this special case) simply reads or writes the values of the 171-- components in the protected record. 172 173-- The lock call is followed by a call to the shared read routine to 174-- synchronize the local copy to contain the proper global value. 175 176-- The unlock call in the procedure case only is preceded by a call 177-- to the shared assign routine to synchronize the global shared 178-- storages with the (possibly modified) local copy. 179 180-- These calls to the read and assign routines, as well as the lock 181-- and unlock routines, are inserted by the expander (see exp_smem.adb). 182 183with Ada.Streams.Stream_IO; 184 185package System.Shared_Storage is 186 187 package SIO renames Ada.Streams.Stream_IO; 188 189 function Shared_Var_ROpen (Var : String) return SIO.Stream_Access; 190 -- As described above, this routine returns null if the 191 -- corresponding shared storage does not exist, and otherwise, if 192 -- the storage does exist, a Stream_Access value that references 193 -- the shared storage, ready to read the current value. 194 195 function Shared_Var_WOpen (Var : String) return SIO.Stream_Access; 196 -- As described above, this routine returns a Stream_Access value 197 -- that references the shared storage, ready to write the new 198 -- value. The storage is created by this call if it does not 199 -- already exist. 200 201 procedure Shared_Var_Close (Var : in SIO.Stream_Access); 202 -- This routine signals the end of a read/assign operation. It can 203 -- be useful to embrace a read/write operation between a call to 204 -- open and a call to close which protect the whole operation. 205 -- Otherwise, two simultaneous operations can result in the 206 -- raising of exception Data_Error by setting the access mode of 207 -- the variable in an incorrect mode. 208 209 procedure Shared_Var_Lock (Var : String); 210 -- This procedure claims the shared storage lock. It is used for 211 -- protected types in shared passive packages. A call to this 212 -- locking routine is generated as the first operation in the code 213 -- for the body of a protected subprogram, and it busy waits if 214 -- the lock is busy. 215 216 procedure Shared_Var_Unlock (Var : String); 217 -- This procedure releases the shared storage lock obtaind by a 218 -- prior call to the Shared_Mem_Lock procedure, and is to be 219 -- generated as the last operation in the body of a protected 220 -- subprogram. 221 222end System.Shared_Storage; 223