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