Add hppa-openbsd target
[official-gcc.git] / gcc / ada / s-shasto.adb
blob63fa072d342ca1ade176c3696c63e8706b762248
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 -- --
10 -- Copyright (C) 1998-2001 Free Software Foundation, Inc. --
11 -- --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
21 -- MA 02111-1307, USA. --
22 -- --
23 -- As a special exception, if other files instantiate generics from this --
24 -- unit, or you link this unit with other files to produce an executable, --
25 -- this unit does not by itself cause the resulting executable to be --
26 -- covered by the GNU General Public License. This exception does not --
27 -- however invalidate any other reasons why the executable file might be --
28 -- covered by the GNU Public License. --
29 -- --
30 -- GNAT was originally developed by the GNAT team at New York University. --
31 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
32 -- --
33 ------------------------------------------------------------------------------
35 with Ada.Exceptions;
36 with Ada.IO_Exceptions;
37 with Ada.Streams;
38 with Ada.Streams.Stream_IO;
40 with GNAT.HTable;
41 with System.Global_Locks;
42 with GNAT.OS_Lib;
43 with GNAT.Task_Lock;
45 use type GNAT.OS_Lib.String_Access;
47 with System;
48 with System.File_Control_Block;
49 with System.File_IO;
50 with Unchecked_Deallocation;
51 with Unchecked_Conversion;
53 package body System.Shared_Storage is
55 package AS renames Ada.Streams;
57 package OS renames GNAT.OS_Lib;
59 package IOX renames Ada.IO_Exceptions;
61 package FCB renames System.File_Control_Block;
63 package SFI renames System.File_IO;
65 package TSL renames GNAT.Task_Lock;
67 Dir : OS.String_Access;
68 -- Holds the directory
70 ------------------------------------------------
71 -- Variables for Shared Variable Access Files --
72 ------------------------------------------------
74 Max_Shared_Var_Files : constant := 20;
75 -- Maximum number of lock files that can be open
77 Shared_Var_Files_Open : Natural := 0;
78 -- Number of shared variable access files currently open
80 type File_Stream_Type is new AS.Root_Stream_Type with record
81 File : SIO.File_Type;
82 end record;
83 type File_Stream_Access is access all File_Stream_Type'Class;
85 procedure Read
86 (Stream : in out File_Stream_Type;
87 Item : out AS.Stream_Element_Array;
88 Last : out AS.Stream_Element_Offset);
90 procedure Write
91 (Stream : in out File_Stream_Type;
92 Item : in AS.Stream_Element_Array);
94 subtype Hash_Header is Natural range 0 .. 30;
95 -- Number of hash headers, related (for efficiency purposes only)
96 -- to the maximum number of lock files..
98 type Shared_Var_File_Entry;
99 type Shared_Var_File_Entry_Ptr is access Shared_Var_File_Entry;
101 type Shared_Var_File_Entry is record
102 Name : OS.String_Access;
103 -- Name of variable, as passed to Read_File/Write_File routines
105 Stream : File_Stream_Access;
106 -- Stream_IO file for the shared variable file
108 Next : Shared_Var_File_Entry_Ptr;
109 Prev : Shared_Var_File_Entry_Ptr;
110 -- Links for LRU chain
111 end record;
113 procedure Free is new Unchecked_Deallocation
114 (Object => Shared_Var_File_Entry,
115 Name => Shared_Var_File_Entry_Ptr);
117 procedure Free is new Unchecked_Deallocation
118 (Object => File_Stream_Type'Class,
119 Name => File_Stream_Access);
121 function To_AFCB_Ptr is
122 new Unchecked_Conversion (SIO.File_Type, FCB.AFCB_Ptr);
124 LRU_Head : Shared_Var_File_Entry_Ptr;
125 LRU_Tail : Shared_Var_File_Entry_Ptr;
126 -- As lock files are opened, they are organized into a least recently
127 -- used chain, which is a doubly linked list using the Next and Prev
128 -- fields of Shared_Var_File_Entry records. The field LRU_Head points
129 -- to the least recently used entry, whose prev pointer is null, and
130 -- LRU_Tail points to the most recently used entry, whose next pointer
131 -- is null. These pointers are null only if the list is empty.
133 function Hash (F : OS.String_Access) return Hash_Header;
134 function Equal (F1, F2 : OS.String_Access) return Boolean;
135 -- Hash and equality functions for hash table
137 package SFT is new GNAT.HTable.Simple_HTable
138 (Header_Num => Hash_Header,
139 Element => Shared_Var_File_Entry_Ptr,
140 No_Element => null,
141 Key => OS.String_Access,
142 Hash => Hash,
143 Equal => Equal);
145 --------------------------------
146 -- Variables for Lock Control --
147 --------------------------------
149 Global_Lock : Global_Locks.Lock_Type;
151 Lock_Count : Natural := 0;
152 -- Counts nesting of lock calls, 0 means lock is not held
154 -----------------------
155 -- Local Subprograms --
156 -----------------------
158 procedure Initialize;
159 -- Called to initialize data structures for this package.
160 -- Has no effect except on the first call.
162 procedure Enter_SFE (SFE : Shared_Var_File_Entry_Ptr; Fname : String);
163 -- The first parameter is a pointer to a newly allocated SFE, whose
164 -- File field is already set appropriately. Fname is the name of the
165 -- variable as passed to Shared_Var_RFile/Shared_Var_WFile. Enter_SFE
166 -- completes the SFE value, and enters it into the hash table. If the
167 -- hash table is already full, the least recently used entry is first
168 -- closed and discarded.
170 function Retrieve (File : String) return Shared_Var_File_Entry_Ptr;
171 -- Given a file name, this function searches the hash table to see if
172 -- the file is currently open. If so, then a pointer to the already
173 -- created entry is returned, after first moving it to the head of
174 -- the LRU chain. If not, then null is returned.
176 ---------------
177 -- Enter_SFE --
178 ---------------
180 procedure Enter_SFE (SFE : Shared_Var_File_Entry_Ptr; Fname : String) is
181 Freed : Shared_Var_File_Entry_Ptr;
183 begin
184 SFE.Name := new String'(Fname);
186 -- Release least recently used entry if we have to
188 if Shared_Var_Files_Open = Max_Shared_Var_Files then
189 Freed := LRU_Head;
191 if Freed.Next /= null then
192 Freed.Next.Prev := null;
193 end if;
195 LRU_Head := Freed.Next;
196 SFT.Remove (Freed.Name);
197 SIO.Close (Freed.Stream.File);
198 OS.Free (Freed.Name);
199 Free (Freed.Stream);
200 Free (Freed);
202 else
203 Shared_Var_Files_Open := Shared_Var_Files_Open + 1;
204 end if;
206 -- Add new entry to hash table
208 SFT.Set (SFE.Name, SFE);
210 -- Add new entry at end of LRU chain
212 if LRU_Head = null then
213 LRU_Head := SFE;
214 LRU_Tail := SFE;
216 else
217 SFE.Prev := LRU_Tail;
218 LRU_Tail.Next := SFE;
219 LRU_Tail := SFE;
220 end if;
221 end Enter_SFE;
223 -----------
224 -- Equal --
225 -----------
227 function Equal (F1, F2 : OS.String_Access) return Boolean is
228 begin
229 return F1.all = F2.all;
230 end Equal;
232 ----------
233 -- Hash --
234 ----------
236 function Hash (F : OS.String_Access) return Hash_Header is
237 N : Natural := 0;
239 begin
240 -- Add up characters of name, mod our table size
242 for J in F'Range loop
243 N := (N + Character'Pos (F (J))) mod (Hash_Header'Last + 1);
244 end loop;
246 return N;
247 end Hash;
249 ----------------
250 -- Initialize --
251 ----------------
253 procedure Initialize is
254 begin
255 if Dir = null then
256 Dir := OS.Getenv ("SHARED_MEMORY_DIRECTORY");
257 System.Global_Locks.Create_Lock (Global_Lock, Dir.all & "__lock");
258 end if;
259 end Initialize;
261 ----------
262 -- Read --
263 ----------
265 procedure Read
266 (Stream : in out File_Stream_Type;
267 Item : out AS.Stream_Element_Array;
268 Last : out AS.Stream_Element_Offset) is
269 begin
270 SIO.Read (Stream.File, Item, Last);
271 exception when others =>
272 Last := Item'Last;
273 end Read;
275 --------------
276 -- Retrieve --
277 --------------
279 function Retrieve (File : String) return Shared_Var_File_Entry_Ptr is
280 SFE : Shared_Var_File_Entry_Ptr;
282 begin
283 Initialize;
284 SFE := SFT.Get (File'Unrestricted_Access);
286 if SFE /= null then
288 -- Move to head of LRU chain
290 if SFE = LRU_Tail then
291 null;
293 elsif SFE = LRU_Head then
294 LRU_Head := LRU_Head.Next;
295 LRU_Head.Prev := null;
297 else
298 SFE.Next.Prev := SFE.Prev;
299 SFE.Prev.Next := SFE.Next;
300 end if;
302 SFE.Next := null;
303 SFE.Prev := LRU_Tail;
304 LRU_Tail.Next := SFE;
305 LRU_Tail := SFE;
306 end if;
308 return SFE;
309 end Retrieve;
311 ----------------------
312 -- Shared_Var_Close --
313 ----------------------
315 procedure Shared_Var_Close (Var : in SIO.Stream_Access) is
316 pragma Warnings (Off, Var);
317 begin
318 TSL.Unlock;
319 end Shared_Var_Close;
321 ---------------------
322 -- Shared_Var_Lock --
323 ---------------------
325 procedure Shared_Var_Lock (Var : in String) is
326 pragma Warnings (Off, Var);
328 begin
329 TSL.Lock;
330 Initialize;
332 if Lock_Count /= 0 then
333 Lock_Count := Lock_Count + 1;
334 TSL.Unlock;
336 else
337 Lock_Count := 1;
338 TSL.Unlock;
339 System.Global_Locks.Acquire_Lock (Global_Lock);
340 end if;
342 exception
343 when others =>
344 TSL.Unlock;
345 raise;
346 end Shared_Var_Lock;
348 ----------------------
349 -- Shared_Var_ROpen --
350 ----------------------
352 function Shared_Var_ROpen (Var : String) return SIO.Stream_Access is
353 SFE : Shared_Var_File_Entry_Ptr;
355 use type Ada.Streams.Stream_IO.File_Mode;
357 begin
358 TSL.Lock;
359 SFE := Retrieve (Var);
361 -- Here if file is not already open, try to open it
363 if SFE = null then
364 declare
365 S : aliased constant String := Dir.all & Var;
367 begin
368 SFE := new Shared_Var_File_Entry;
369 SFE.Stream := new File_Stream_Type;
370 SIO.Open (SFE.Stream.File, SIO.In_File, Name => S);
371 SFI.Make_Unbuffered (To_AFCB_Ptr (SFE.Stream.File));
373 -- File opened successfully, put new entry in hash table. Note
374 -- that in this case, file is positioned correctly for read.
376 Enter_SFE (SFE, Var);
378 exception
379 -- If we get an exception, it means that the file does not
380 -- exist, and in this case, we don't need the SFE and we
381 -- return null;
383 when IOX.Name_Error =>
384 Free (SFE);
385 TSL.Unlock;
386 return null;
387 end;
389 -- Here if file is already open, set file for reading
391 else
392 if SIO.Mode (SFE.Stream.File) /= SIO.In_File then
393 SIO.Set_Mode (SFE.Stream.File, SIO.In_File);
394 SFI.Make_Unbuffered (To_AFCB_Ptr (SFE.Stream.File));
395 end if;
397 SIO.Set_Index (SFE.Stream.File, 1);
398 end if;
400 return SIO.Stream_Access (SFE.Stream);
402 exception
403 when others =>
404 TSL.Unlock;
405 raise;
406 end Shared_Var_ROpen;
408 -----------------------
409 -- Shared_Var_Unlock --
410 -----------------------
412 procedure Shared_Var_Unlock (Var : in String) is
413 pragma Warnings (Off, Var);
415 begin
416 TSL.Lock;
417 Initialize;
418 Lock_Count := Lock_Count - 1;
420 if Lock_Count = 0 then
421 System.Global_Locks.Release_Lock (Global_Lock);
422 end if;
423 TSL.Unlock;
425 exception
426 when others =>
427 TSL.Unlock;
428 raise;
429 end Shared_Var_Unlock;
431 ---------------------
432 -- Share_Var_WOpen --
433 ---------------------
435 function Shared_Var_WOpen (Var : String) return SIO.Stream_Access is
436 SFE : Shared_Var_File_Entry_Ptr;
438 use type Ada.Streams.Stream_IO.File_Mode;
440 begin
441 TSL.Lock;
442 SFE := Retrieve (Var);
444 if SFE = null then
445 declare
446 S : aliased constant String := Dir.all & Var;
448 begin
449 SFE := new Shared_Var_File_Entry;
450 SFE.Stream := new File_Stream_Type;
451 SIO.Open (SFE.Stream.File, SIO.Out_File, Name => S);
452 SFI.Make_Unbuffered (To_AFCB_Ptr (SFE.Stream.File));
454 exception
455 -- If we get an exception, it means that the file does not
456 -- exist, and in this case, we create the file.
458 when IOX.Name_Error =>
460 begin
461 SIO.Create (SFE.Stream.File, SIO.Out_File, Name => S);
463 exception
464 -- Error if we cannot create the file
466 when others =>
467 Ada.Exceptions.Raise_Exception
468 (Program_Error'Identity,
469 "Cannot create shared variable file for """ &
470 S & '"'); -- "
471 end;
472 end;
474 -- Make new hash table entry for opened/created file. Note that
475 -- in both cases, the file is already in write mode at the start
476 -- of the file, ready to be written.
478 Enter_SFE (SFE, Var);
480 -- Here if file is already open, set file for writing
482 else
483 if SIO.Mode (SFE.Stream.File) /= SIO.Out_File then
484 SIO.Set_Mode (SFE.Stream.File, SIO.Out_File);
485 SFI.Make_Unbuffered (To_AFCB_Ptr (SFE.Stream.File));
486 end if;
488 SIO.Set_Index (SFE.Stream.File, 1);
489 end if;
491 return SIO.Stream_Access (SFE.Stream);
493 exception
494 when others =>
495 TSL.Unlock;
496 raise;
497 end Shared_Var_WOpen;
499 -----------
500 -- Write --
501 -----------
503 procedure Write
504 (Stream : in out File_Stream_Type;
505 Item : in AS.Stream_Element_Array) is
506 begin
507 SIO.Write (Stream.File, Item);
508 end Write;
510 end System.Shared_Storage;