OSDN Git Service

* c-decl.c (grokfield): Allow typedefs for anonymous structs and
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-shasto.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                 S Y S T E M . S H A R E D _ M E M O R Y                  --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 1998-2009, 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 3,  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.                                     --
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 with Ada.IO_Exceptions;
33 with Ada.Streams;
34 with Ada.Streams.Stream_IO;
35
36 with System.Global_Locks;
37 with System.Soft_Links;
38
39 with System;
40 with System.File_Control_Block;
41 with System.File_IO;
42 with System.HTable;
43
44 with Ada.Unchecked_Deallocation;
45 with Ada.Unchecked_Conversion;
46
47 package body System.Shared_Storage is
48
49    package AS renames Ada.Streams;
50
51    package IOX renames Ada.IO_Exceptions;
52
53    package FCB renames System.File_Control_Block;
54
55    package SFI renames System.File_IO;
56
57    package SIO renames Ada.Streams.Stream_IO;
58
59    type String_Access is access String;
60    procedure Free is new Ada.Unchecked_Deallocation
61      (Object => String, Name => String_Access);
62
63    Dir : String_Access;
64    --  Holds the directory
65
66    ------------------------------------------------
67    -- Variables for Shared Variable Access Files --
68    ------------------------------------------------
69
70    Max_Shared_Var_Files : constant := 20;
71    --  Maximum number of lock files that can be open
72
73    Shared_Var_Files_Open : Natural := 0;
74    --  Number of shared variable access files currently open
75
76    type File_Stream_Type is new AS.Root_Stream_Type with record
77       File : SIO.File_Type;
78    end record;
79    type File_Stream_Access is access all File_Stream_Type'Class;
80
81    procedure Read
82      (Stream : in out File_Stream_Type;
83       Item   : out AS.Stream_Element_Array;
84       Last   : out AS.Stream_Element_Offset);
85
86    procedure Write
87      (Stream : in out File_Stream_Type;
88       Item   : AS.Stream_Element_Array);
89
90    subtype Hash_Header is Natural range 0 .. 30;
91    --  Number of hash headers, related (for efficiency purposes only)
92    --  to the maximum number of lock files..
93
94    type Shared_Var_File_Entry;
95    type Shared_Var_File_Entry_Ptr is access Shared_Var_File_Entry;
96
97    type Shared_Var_File_Entry is record
98       Name : String_Access;
99       --  Name of variable, as passed to Read_File/Write_File routines
100
101       Stream : File_Stream_Access;
102       --  Stream_IO file for the shared variable file
103
104       Next : Shared_Var_File_Entry_Ptr;
105       Prev : Shared_Var_File_Entry_Ptr;
106       --  Links for LRU chain
107    end record;
108
109    procedure Free is new Ada.Unchecked_Deallocation
110      (Object => Shared_Var_File_Entry,
111       Name   => Shared_Var_File_Entry_Ptr);
112
113    procedure Free is new Ada.Unchecked_Deallocation
114      (Object => File_Stream_Type'Class,
115       Name   => File_Stream_Access);
116
117    function To_AFCB_Ptr is
118      new Ada.Unchecked_Conversion (SIO.File_Type, FCB.AFCB_Ptr);
119
120    LRU_Head : Shared_Var_File_Entry_Ptr;
121    LRU_Tail : Shared_Var_File_Entry_Ptr;
122    --  As lock files are opened, they are organized into a least recently
123    --  used chain, which is a doubly linked list using the Next and Prev
124    --  fields of Shared_Var_File_Entry records. The field LRU_Head points
125    --  to the least recently used entry, whose prev pointer is null, and
126    --  LRU_Tail points to the most recently used entry, whose next pointer
127    --  is null. These pointers are null only if the list is empty.
128
129    function Hash  (F : String_Access)      return Hash_Header;
130    function Equal (F1, F2 : String_Access) return Boolean;
131    --  Hash and equality functions for hash table
132
133    package SFT is new System.HTable.Simple_HTable
134      (Header_Num => Hash_Header,
135       Element    => Shared_Var_File_Entry_Ptr,
136       No_Element => null,
137       Key        => String_Access,
138       Hash       => Hash,
139       Equal      => Equal);
140
141    --------------------------------
142    -- Variables for Lock Control --
143    --------------------------------
144
145    Global_Lock : Global_Locks.Lock_Type;
146
147    Lock_Count : Natural := 0;
148    --  Counts nesting of lock calls, 0 means lock is not held
149
150    -----------------------
151    -- Local Subprograms --
152    -----------------------
153
154    procedure Initialize;
155    --  Called to initialize data structures for this package.
156    --  Has no effect except on the first call.
157
158    procedure Enter_SFE (SFE : Shared_Var_File_Entry_Ptr; Fname : String);
159    --  The first parameter is a pointer to a newly allocated SFE, whose
160    --  File field is already set appropriately. Fname is the name of the
161    --  variable as passed to Shared_Var_RFile/Shared_Var_WFile. Enter_SFE
162    --  completes the SFE value, and enters it into the hash table. If the
163    --  hash table is already full, the least recently used entry is first
164    --  closed and discarded.
165
166    function Retrieve (File : String) return Shared_Var_File_Entry_Ptr;
167    --  Given a file name, this function searches the hash table to see if
168    --  the file is currently open. If so, then a pointer to the already
169    --  created entry is returned, after first moving it to the head of
170    --  the LRU chain. If not, then null is returned.
171
172    function Shared_Var_ROpen (Var : String) return SIO.Stream_Access;
173    --  As described above, this routine returns null if the
174    --  corresponding shared storage does not exist, and otherwise, if
175    --  the storage does exist, a Stream_Access value that references
176    --  the shared storage, ready to read the current value.
177
178    function Shared_Var_WOpen (Var : String) return SIO.Stream_Access;
179    --  As described above, this routine returns a Stream_Access value
180    --  that references the shared storage, ready to write the new
181    --  value. The storage is created by this call if it does not
182    --  already exist.
183
184    procedure Shared_Var_Close (Var : SIO.Stream_Access);
185    --  This routine signals the end of a read/assign operation. It can
186    --  be useful to embrace a read/write operation between a call to
187    --  open and a call to close which protect the whole operation.
188    --  Otherwise, two simultaneous operations can result in the
189    --  raising of exception Data_Error by setting the access mode of
190    --  the variable in an incorrect mode.
191
192    ---------------
193    -- Enter_SFE --
194    ---------------
195
196    procedure Enter_SFE (SFE : Shared_Var_File_Entry_Ptr; Fname : String) is
197       Freed : Shared_Var_File_Entry_Ptr;
198
199    begin
200       SFE.Name := new String'(Fname);
201
202       --  Release least recently used entry if we have to
203
204       if Shared_Var_Files_Open =  Max_Shared_Var_Files then
205          Freed := LRU_Head;
206
207          if Freed.Next /= null then
208             Freed.Next.Prev := null;
209          end if;
210
211          LRU_Head := Freed.Next;
212          SFT.Remove (Freed.Name);
213          SIO.Close (Freed.Stream.File);
214          Free (Freed.Name);
215          Free (Freed.Stream);
216          Free (Freed);
217
218       else
219          Shared_Var_Files_Open := Shared_Var_Files_Open + 1;
220       end if;
221
222       --  Add new entry to hash table
223
224       SFT.Set (SFE.Name, SFE);
225
226       --  Add new entry at end of LRU chain
227
228       if LRU_Head = null then
229          LRU_Head := SFE;
230          LRU_Tail := SFE;
231
232       else
233          SFE.Prev := LRU_Tail;
234          LRU_Tail.Next := SFE;
235          LRU_Tail := SFE;
236       end if;
237    end Enter_SFE;
238
239    -----------
240    -- Equal --
241    -----------
242
243    function Equal (F1, F2 : String_Access) return Boolean is
244    begin
245       return F1.all = F2.all;
246    end Equal;
247
248    ----------
249    -- Hash --
250    ----------
251
252    function Hash (F : String_Access) return Hash_Header is
253       N : Natural := 0;
254
255    begin
256       --  Add up characters of name, mod our table size
257
258       for J in F'Range loop
259          N := (N + Character'Pos (F (J))) mod (Hash_Header'Last + 1);
260       end loop;
261
262       return N;
263    end Hash;
264
265    ----------------
266    -- Initialize --
267    ----------------
268
269    procedure Initialize is
270       procedure Get_Env_Value_Ptr (Name, Length, Ptr : Address);
271       pragma Import (C, Get_Env_Value_Ptr, "__gnat_getenv");
272
273       procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
274       pragma Import (C, Strncpy, "strncpy");
275
276       Dir_Name : aliased constant String :=
277                    "SHARED_MEMORY_DIRECTORY" & ASCII.NUL;
278
279       Env_Value_Ptr    : aliased Address;
280       Env_Value_Length : aliased Integer;
281
282    begin
283       if Dir = null then
284          Get_Env_Value_Ptr
285            (Dir_Name'Address, Env_Value_Length'Address, Env_Value_Ptr'Address);
286
287          Dir := new String (1 .. Env_Value_Length);
288
289          if Env_Value_Length > 0 then
290             Strncpy (Dir.all'Address, Env_Value_Ptr, Env_Value_Length);
291          end if;
292
293          System.Global_Locks.Create_Lock (Global_Lock, Dir.all & "__lock");
294       end if;
295    end Initialize;
296
297    ----------
298    -- Read --
299    ----------
300
301    procedure Read
302      (Stream : in out File_Stream_Type;
303       Item   : out AS.Stream_Element_Array;
304       Last   : out AS.Stream_Element_Offset)
305    is
306    begin
307       SIO.Read (Stream.File, Item, Last);
308
309    exception when others =>
310       Last := Item'Last;
311    end Read;
312
313    --------------
314    -- Retrieve --
315    --------------
316
317    function Retrieve (File : String) return Shared_Var_File_Entry_Ptr is
318       SFE : Shared_Var_File_Entry_Ptr;
319
320    begin
321       Initialize;
322       SFE := SFT.Get (File'Unrestricted_Access);
323
324       if SFE /= null then
325
326          --  Move to head of LRU chain
327
328          if SFE = LRU_Tail then
329             null;
330
331          elsif SFE = LRU_Head then
332             LRU_Head := LRU_Head.Next;
333             LRU_Head.Prev := null;
334
335          else
336             SFE.Next.Prev := SFE.Prev;
337             SFE.Prev.Next := SFE.Next;
338          end if;
339
340          SFE.Next := null;
341          SFE.Prev := LRU_Tail;
342          LRU_Tail.Next := SFE;
343          LRU_Tail := SFE;
344       end if;
345
346       return SFE;
347    end Retrieve;
348
349    ----------------------
350    -- Shared_Var_Close --
351    ----------------------
352
353    procedure Shared_Var_Close (Var : SIO.Stream_Access) is
354       pragma Warnings (Off, Var);
355
356    begin
357       System.Soft_Links.Unlock_Task.all;
358    end Shared_Var_Close;
359
360    ---------------------
361    -- Shared_Var_Lock --
362    ---------------------
363
364    procedure Shared_Var_Lock (Var : String) is
365       pragma Warnings (Off, Var);
366
367    begin
368       System.Soft_Links.Lock_Task.all;
369       Initialize;
370
371       if Lock_Count /= 0 then
372          Lock_Count := Lock_Count + 1;
373          System.Soft_Links.Unlock_Task.all;
374
375       else
376          Lock_Count := 1;
377          System.Soft_Links.Unlock_Task.all;
378          System.Global_Locks.Acquire_Lock (Global_Lock);
379       end if;
380
381    exception
382       when others =>
383          System.Soft_Links.Unlock_Task.all;
384          raise;
385    end Shared_Var_Lock;
386
387    ----------------------
388    -- Shared_Var_Procs --
389    ----------------------
390
391    package body Shared_Var_Procs is
392
393       use type SIO.Stream_Access;
394
395       ----------
396       -- Read --
397       ----------
398
399       procedure Read is
400          S : SIO.Stream_Access := null;
401       begin
402          S := Shared_Var_ROpen (Full_Name);
403          if S /= null then
404             Typ'Read (S, V);
405             Shared_Var_Close (S);
406          end if;
407       end Read;
408
409       ------------
410       -- Write --
411       ------------
412
413       procedure Write is
414          S : SIO.Stream_Access := null;
415       begin
416          S := Shared_Var_WOpen (Full_Name);
417          Typ'Write (S, V);
418          Shared_Var_Close (S);
419          return;
420       end Write;
421
422    end Shared_Var_Procs;
423
424    ----------------------
425    -- Shared_Var_ROpen --
426    ----------------------
427
428    function Shared_Var_ROpen (Var : String) return SIO.Stream_Access is
429       SFE : Shared_Var_File_Entry_Ptr;
430
431       use type Ada.Streams.Stream_IO.File_Mode;
432
433    begin
434       System.Soft_Links.Lock_Task.all;
435       SFE := Retrieve (Var);
436
437       --  Here if file is not already open, try to open it
438
439       if SFE = null then
440          declare
441             S  : aliased constant String := Dir.all & Var;
442
443          begin
444             SFE := new Shared_Var_File_Entry;
445             SFE.Stream := new File_Stream_Type;
446             SIO.Open (SFE.Stream.File, SIO.In_File, Name => S);
447             SFI.Make_Unbuffered (To_AFCB_Ptr (SFE.Stream.File));
448
449             --  File opened successfully, put new entry in hash table. Note
450             --  that in this case, file is positioned correctly for read.
451
452             Enter_SFE (SFE, Var);
453
454             exception
455                --  If we get an exception, it means that the file does not
456                --  exist, and in this case, we don't need the SFE and we
457                --  return null;
458
459                when IOX.Name_Error =>
460                   Free (SFE);
461                   System.Soft_Links.Unlock_Task.all;
462                   return null;
463          end;
464
465       --  Here if file is already open, set file for reading
466
467       else
468          if SIO.Mode (SFE.Stream.File) /= SIO.In_File then
469             SIO.Set_Mode (SFE.Stream.File, SIO.In_File);
470             SFI.Make_Unbuffered (To_AFCB_Ptr (SFE.Stream.File));
471          end if;
472
473          SIO.Set_Index (SFE.Stream.File, 1);
474       end if;
475
476       return SIO.Stream_Access (SFE.Stream);
477
478    exception
479       when others =>
480          System.Soft_Links.Unlock_Task.all;
481          raise;
482    end Shared_Var_ROpen;
483
484    -----------------------
485    -- Shared_Var_Unlock --
486    -----------------------
487
488    procedure Shared_Var_Unlock (Var : String) is
489       pragma Warnings (Off, Var);
490
491    begin
492       System.Soft_Links.Lock_Task.all;
493       Initialize;
494       Lock_Count := Lock_Count - 1;
495
496       if Lock_Count = 0 then
497          System.Global_Locks.Release_Lock (Global_Lock);
498       end if;
499       System.Soft_Links.Unlock_Task.all;
500
501    exception
502       when others =>
503          System.Soft_Links.Unlock_Task.all;
504          raise;
505    end Shared_Var_Unlock;
506
507    ---------------------
508    -- Share_Var_WOpen --
509    ---------------------
510
511    function Shared_Var_WOpen (Var : String) return SIO.Stream_Access is
512       SFE : Shared_Var_File_Entry_Ptr;
513
514       use type Ada.Streams.Stream_IO.File_Mode;
515
516    begin
517       System.Soft_Links.Lock_Task.all;
518       SFE := Retrieve (Var);
519
520       if SFE = null then
521          declare
522             S  : aliased constant String := Dir.all & Var;
523
524          begin
525             SFE := new Shared_Var_File_Entry;
526             SFE.Stream := new File_Stream_Type;
527             SIO.Open (SFE.Stream.File, SIO.Out_File, Name => S);
528             SFI.Make_Unbuffered (To_AFCB_Ptr (SFE.Stream.File));
529
530          exception
531             --  If we get an exception, it means that the file does not
532             --  exist, and in this case, we create the file.
533
534             when IOX.Name_Error =>
535
536                begin
537                   SIO.Create (SFE.Stream.File, SIO.Out_File, Name => S);
538
539                exception
540                   --  Error if we cannot create the file
541
542                   when others =>
543                      raise Program_Error with
544                         "Cannot create shared variable file for """ & S & '"';
545                end;
546          end;
547
548          --  Make new hash table entry for opened/created file. Note that
549          --  in both cases, the file is already in write mode at the start
550          --  of the file, ready to be written.
551
552          Enter_SFE (SFE, Var);
553
554       --  Here if file is already open, set file for writing
555
556       else
557          if SIO.Mode (SFE.Stream.File) /= SIO.Out_File then
558             SIO.Set_Mode (SFE.Stream.File, SIO.Out_File);
559             SFI.Make_Unbuffered (To_AFCB_Ptr (SFE.Stream.File));
560          end if;
561
562          SIO.Set_Index (SFE.Stream.File, 1);
563       end if;
564
565       return SIO.Stream_Access (SFE.Stream);
566
567    exception
568       when others =>
569          System.Soft_Links.Unlock_Task.all;
570          raise;
571    end Shared_Var_WOpen;
572
573    -----------
574    -- Write --
575    -----------
576
577    procedure Write
578      (Stream : in out File_Stream_Type;
579       Item   : AS.Stream_Element_Array)
580    is
581    begin
582       SIO.Write (Stream.File, Item);
583    end Write;
584
585 end System.Shared_Storage;