8sa1-gcc/gcc/ada/s-shasto.adb
Pascal Obry 0022d9e31d adaint.h, adaint.c (DIR_SEPARATOR): Use _T() macro for Unicode support.
2006-02-13  Pascal Obry  <obry@adacore.com>
	    Nicolas Roche  <roche@adacore.com>
	    Arnaud Charlet  <charlet@adacore.com>

	* adaint.h, adaint.c (DIR_SEPARATOR): Use _T() macro for Unicode
	support.
	(__gnat_try_lock): Add unicode support by using a specific section on
	Windows.
	(__gnat_get_current_dir): Idem.
	(__gnat_open_read): Idem.
	(__gnat_open_rw): Idem.
	(__gnat_open_create): Idem.
	(__gnat_create_output_file): Idem.
	(__gnat_open_append): Idem.
	(__gnat_open_new): Idem.
	(__gnat_file_time_name): Idem.
	(__gnat_set_file_time_name): Idem.
	(__gnat_stat): Idem.
	(win32_no_block_spawn): Idem.
	(__gnat_locate_exec_on_path): Idem.
	(__gnat_opendir): New routine.
	(__gnat_closedir): Idem.
	(__gnat_readdir): Add new parameter length (pointer to int). Update
	implementation to use it and add specific Win32 code for Unicode
	support.
	(__gnat_get_env_value_ptr): Remove. Replaced by __gnat_getenv in env.c
	(__gnat_set_env_value): Remove. Replaced by __gnat_setenv in env.c
	(convert_addresses): Do not define this dummy routine on VMS.

	* mingw32.h (GNAT_UNICODE_SUPPORT): New definition, if set the GNAT
	runtime Unicode support will be activated.
	(S2WS): String to Wide-String conversion. This version just copy a
	string in non Unicode version.
	(WS2S): Wide-String to String conversion. This version just copy a
	string in non Unicode version.

	* g-dirope.adb: (Close): Now import __gnat_closedir from adaint.c.
	(Open): Now import __gnat_opendir from adaint.c.
	(Read): Change the implementation to support unicode characters. It is
	not possible to use strlen() on Windows as this version supports only
	standard ASCII characters. So the length of the directory entry is now
	returned from the imported __gnat_readdir routine.
	Update copyright notice.

	* s-crtl-vms64.ads, s-crtl.ads: (closedir): Moved to adaint.c.
	(opendir): Moved to adaint.c.

	* g-os_lib.adb (Copy_Time_Stamp): Fix off-by-one range computation.
	(Get_Directory): Fix wrong indexing.
	(Getenv): replace __gnat_get_env_value_ptr from adaint.c by
	__gnat_getenv from env.c
	(Setenv): replace __gnat_set_env_value from adaint.c by __gnat_setenv
	from env.c

	* env.h, env.c: New file.

	* s-scaval.adb (Initialize): Replace __gnat_get_env_value_ptr from
	adaint.c by __gnat_getenv from env.c

	* s-shasto.adb (Initialize): replace __gnat_get_env_value_ptr from
	adaint.c by __gnat_getenv from env.c

	* Make-lang.in: Add env.o in the list of C object needed by gnat1
	and gnatbind.
	Update dependencies.

From-SVN: r111029
2006-02-15 10:30:39 +01:00

531 lines
16 KiB
Ada

------------------------------------------------------------------------------
-- --
-- GNAT COMPILER COMPONENTS --
-- --
-- S Y S T E M . S H A R E D _ M E M O R Y --
-- --
-- B o d y --
-- --
-- Copyright (C) 1998-2006, 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 2, 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. See the GNU General Public License --
-- for more details. You should have received a copy of the GNU General --
-- Public License distributed with GNAT; see file COPYING. If not, write --
-- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
-- Boston, MA 02110-1301, USA. --
-- --
-- As a special exception, if other files instantiate generics from this --
-- unit, or you link this unit with other files to produce an executable, --
-- this unit does not by itself cause the resulting executable to be --
-- covered by the GNU General Public License. This exception does not --
-- however invalidate any other reasons why the executable file might be --
-- covered by the GNU Public License. --
-- --
-- GNAT was originally developed by the GNAT team at New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc. --
-- --
------------------------------------------------------------------------------
with Ada.Exceptions;
with Ada.IO_Exceptions;
with Ada.Streams;
with System.Global_Locks;
with System.Soft_Links;
with System;
with System.File_Control_Block;
with System.File_IO;
with System.HTable;
with Unchecked_Deallocation;
with Unchecked_Conversion;
package body System.Shared_Storage is
package AS renames Ada.Streams;
package IOX renames Ada.IO_Exceptions;
package FCB renames System.File_Control_Block;
package SFI renames System.File_IO;
type String_Access is access String;
procedure Free is new Unchecked_Deallocation
(Object => String, Name => String_Access);
Dir : String_Access;
-- Holds the directory
------------------------------------------------
-- Variables for Shared Variable Access Files --
------------------------------------------------
Max_Shared_Var_Files : constant := 20;
-- Maximum number of lock files that can be open
Shared_Var_Files_Open : Natural := 0;
-- Number of shared variable access files currently open
type File_Stream_Type is new AS.Root_Stream_Type with record
File : SIO.File_Type;
end record;
type File_Stream_Access is access all File_Stream_Type'Class;
procedure Read
(Stream : in out File_Stream_Type;
Item : out AS.Stream_Element_Array;
Last : out AS.Stream_Element_Offset);
procedure Write
(Stream : in out File_Stream_Type;
Item : AS.Stream_Element_Array);
subtype Hash_Header is Natural range 0 .. 30;
-- Number of hash headers, related (for efficiency purposes only)
-- to the maximum number of lock files..
type Shared_Var_File_Entry;
type Shared_Var_File_Entry_Ptr is access Shared_Var_File_Entry;
type Shared_Var_File_Entry is record
Name : String_Access;
-- Name of variable, as passed to Read_File/Write_File routines
Stream : File_Stream_Access;
-- Stream_IO file for the shared variable file
Next : Shared_Var_File_Entry_Ptr;
Prev : Shared_Var_File_Entry_Ptr;
-- Links for LRU chain
end record;
procedure Free is new Unchecked_Deallocation
(Object => Shared_Var_File_Entry,
Name => Shared_Var_File_Entry_Ptr);
procedure Free is new Unchecked_Deallocation
(Object => File_Stream_Type'Class,
Name => File_Stream_Access);
function To_AFCB_Ptr is
new Unchecked_Conversion (SIO.File_Type, FCB.AFCB_Ptr);
LRU_Head : Shared_Var_File_Entry_Ptr;
LRU_Tail : Shared_Var_File_Entry_Ptr;
-- As lock files are opened, they are organized into a least recently
-- used chain, which is a doubly linked list using the Next and Prev
-- fields of Shared_Var_File_Entry records. The field LRU_Head points
-- to the least recently used entry, whose prev pointer is null, and
-- LRU_Tail points to the most recently used entry, whose next pointer
-- is null. These pointers are null only if the list is empty.
function Hash (F : String_Access) return Hash_Header;
function Equal (F1, F2 : String_Access) return Boolean;
-- Hash and equality functions for hash table
package SFT is new System.HTable.Simple_HTable
(Header_Num => Hash_Header,
Element => Shared_Var_File_Entry_Ptr,
No_Element => null,
Key => String_Access,
Hash => Hash,
Equal => Equal);
--------------------------------
-- Variables for Lock Control --
--------------------------------
Global_Lock : Global_Locks.Lock_Type;
Lock_Count : Natural := 0;
-- Counts nesting of lock calls, 0 means lock is not held
-----------------------
-- Local Subprograms --
-----------------------
procedure Initialize;
-- Called to initialize data structures for this package.
-- Has no effect except on the first call.
procedure Enter_SFE (SFE : Shared_Var_File_Entry_Ptr; Fname : String);
-- The first parameter is a pointer to a newly allocated SFE, whose
-- File field is already set appropriately. Fname is the name of the
-- variable as passed to Shared_Var_RFile/Shared_Var_WFile. Enter_SFE
-- completes the SFE value, and enters it into the hash table. If the
-- hash table is already full, the least recently used entry is first
-- closed and discarded.
function Retrieve (File : String) return Shared_Var_File_Entry_Ptr;
-- Given a file name, this function searches the hash table to see if
-- the file is currently open. If so, then a pointer to the already
-- created entry is returned, after first moving it to the head of
-- the LRU chain. If not, then null is returned.
---------------
-- Enter_SFE --
---------------
procedure Enter_SFE (SFE : Shared_Var_File_Entry_Ptr; Fname : String) is
Freed : Shared_Var_File_Entry_Ptr;
begin
SFE.Name := new String'(Fname);
-- Release least recently used entry if we have to
if Shared_Var_Files_Open = Max_Shared_Var_Files then
Freed := LRU_Head;
if Freed.Next /= null then
Freed.Next.Prev := null;
end if;
LRU_Head := Freed.Next;
SFT.Remove (Freed.Name);
SIO.Close (Freed.Stream.File);
Free (Freed.Name);
Free (Freed.Stream);
Free (Freed);
else
Shared_Var_Files_Open := Shared_Var_Files_Open + 1;
end if;
-- Add new entry to hash table
SFT.Set (SFE.Name, SFE);
-- Add new entry at end of LRU chain
if LRU_Head = null then
LRU_Head := SFE;
LRU_Tail := SFE;
else
SFE.Prev := LRU_Tail;
LRU_Tail.Next := SFE;
LRU_Tail := SFE;
end if;
end Enter_SFE;
-----------
-- Equal --
-----------
function Equal (F1, F2 : String_Access) return Boolean is
begin
return F1.all = F2.all;
end Equal;
----------
-- Hash --
----------
function Hash (F : String_Access) return Hash_Header is
N : Natural := 0;
begin
-- Add up characters of name, mod our table size
for J in F'Range loop
N := (N + Character'Pos (F (J))) mod (Hash_Header'Last + 1);
end loop;
return N;
end Hash;
----------------
-- Initialize --
----------------
procedure Initialize is
procedure Get_Env_Value_Ptr (Name, Length, Ptr : Address);
pragma Import (C, Get_Env_Value_Ptr, "__gnat_getenv");
procedure Strncpy (Astring_Addr, Cstring : Address; N : Integer);
pragma Import (C, Strncpy, "strncpy");
Dir_Name : aliased constant String :=
"SHARED_MEMORY_DIRECTORY" & ASCII.NUL;
Env_Value_Ptr : aliased Address;
Env_Value_Length : aliased Integer;
begin
if Dir = null then
Get_Env_Value_Ptr
(Dir_Name'Address, Env_Value_Length'Address, Env_Value_Ptr'Address);
Dir := new String (1 .. Env_Value_Length);
if Env_Value_Length > 0 then
Strncpy (Dir.all'Address, Env_Value_Ptr, Env_Value_Length);
end if;
System.Global_Locks.Create_Lock (Global_Lock, Dir.all & "__lock");
end if;
end Initialize;
----------
-- Read --
----------
procedure Read
(Stream : in out File_Stream_Type;
Item : out AS.Stream_Element_Array;
Last : out AS.Stream_Element_Offset)
is
begin
SIO.Read (Stream.File, Item, Last);
exception when others =>
Last := Item'Last;
end Read;
--------------
-- Retrieve --
--------------
function Retrieve (File : String) return Shared_Var_File_Entry_Ptr is
SFE : Shared_Var_File_Entry_Ptr;
begin
Initialize;
SFE := SFT.Get (File'Unrestricted_Access);
if SFE /= null then
-- Move to head of LRU chain
if SFE = LRU_Tail then
null;
elsif SFE = LRU_Head then
LRU_Head := LRU_Head.Next;
LRU_Head.Prev := null;
else
SFE.Next.Prev := SFE.Prev;
SFE.Prev.Next := SFE.Next;
end if;
SFE.Next := null;
SFE.Prev := LRU_Tail;
LRU_Tail.Next := SFE;
LRU_Tail := SFE;
end if;
return SFE;
end Retrieve;
----------------------
-- Shared_Var_Close --
----------------------
procedure Shared_Var_Close (Var : SIO.Stream_Access) is
pragma Warnings (Off, Var);
begin
System.Soft_Links.Unlock_Task.all;
end Shared_Var_Close;
---------------------
-- Shared_Var_Lock --
---------------------
procedure Shared_Var_Lock (Var : String) is
pragma Warnings (Off, Var);
begin
System.Soft_Links.Lock_Task.all;
Initialize;
if Lock_Count /= 0 then
Lock_Count := Lock_Count + 1;
System.Soft_Links.Unlock_Task.all;
else
Lock_Count := 1;
System.Soft_Links.Unlock_Task.all;
System.Global_Locks.Acquire_Lock (Global_Lock);
end if;
exception
when others =>
System.Soft_Links.Unlock_Task.all;
raise;
end Shared_Var_Lock;
----------------------
-- Shared_Var_ROpen --
----------------------
function Shared_Var_ROpen (Var : String) return SIO.Stream_Access is
SFE : Shared_Var_File_Entry_Ptr;
use type Ada.Streams.Stream_IO.File_Mode;
begin
System.Soft_Links.Lock_Task.all;
SFE := Retrieve (Var);
-- Here if file is not already open, try to open it
if SFE = null then
declare
S : aliased constant String := Dir.all & Var;
begin
SFE := new Shared_Var_File_Entry;
SFE.Stream := new File_Stream_Type;
SIO.Open (SFE.Stream.File, SIO.In_File, Name => S);
SFI.Make_Unbuffered (To_AFCB_Ptr (SFE.Stream.File));
-- File opened successfully, put new entry in hash table. Note
-- that in this case, file is positioned correctly for read.
Enter_SFE (SFE, Var);
exception
-- If we get an exception, it means that the file does not
-- exist, and in this case, we don't need the SFE and we
-- return null;
when IOX.Name_Error =>
Free (SFE);
System.Soft_Links.Unlock_Task.all;
return null;
end;
-- Here if file is already open, set file for reading
else
if SIO.Mode (SFE.Stream.File) /= SIO.In_File then
SIO.Set_Mode (SFE.Stream.File, SIO.In_File);
SFI.Make_Unbuffered (To_AFCB_Ptr (SFE.Stream.File));
end if;
SIO.Set_Index (SFE.Stream.File, 1);
end if;
return SIO.Stream_Access (SFE.Stream);
exception
when others =>
System.Soft_Links.Unlock_Task.all;
raise;
end Shared_Var_ROpen;
-----------------------
-- Shared_Var_Unlock --
-----------------------
procedure Shared_Var_Unlock (Var : String) is
pragma Warnings (Off, Var);
begin
System.Soft_Links.Lock_Task.all;
Initialize;
Lock_Count := Lock_Count - 1;
if Lock_Count = 0 then
System.Global_Locks.Release_Lock (Global_Lock);
end if;
System.Soft_Links.Unlock_Task.all;
exception
when others =>
System.Soft_Links.Unlock_Task.all;
raise;
end Shared_Var_Unlock;
---------------------
-- Share_Var_WOpen --
---------------------
function Shared_Var_WOpen (Var : String) return SIO.Stream_Access is
SFE : Shared_Var_File_Entry_Ptr;
use type Ada.Streams.Stream_IO.File_Mode;
begin
System.Soft_Links.Lock_Task.all;
SFE := Retrieve (Var);
if SFE = null then
declare
S : aliased constant String := Dir.all & Var;
begin
SFE := new Shared_Var_File_Entry;
SFE.Stream := new File_Stream_Type;
SIO.Open (SFE.Stream.File, SIO.Out_File, Name => S);
SFI.Make_Unbuffered (To_AFCB_Ptr (SFE.Stream.File));
exception
-- If we get an exception, it means that the file does not
-- exist, and in this case, we create the file.
when IOX.Name_Error =>
begin
SIO.Create (SFE.Stream.File, SIO.Out_File, Name => S);
exception
-- Error if we cannot create the file
when others =>
Ada.Exceptions.Raise_Exception
(Program_Error'Identity,
"Cannot create shared variable file for """ &
S & '"'); -- "
end;
end;
-- Make new hash table entry for opened/created file. Note that
-- in both cases, the file is already in write mode at the start
-- of the file, ready to be written.
Enter_SFE (SFE, Var);
-- Here if file is already open, set file for writing
else
if SIO.Mode (SFE.Stream.File) /= SIO.Out_File then
SIO.Set_Mode (SFE.Stream.File, SIO.Out_File);
SFI.Make_Unbuffered (To_AFCB_Ptr (SFE.Stream.File));
end if;
SIO.Set_Index (SFE.Stream.File, 1);
end if;
return SIO.Stream_Access (SFE.Stream);
exception
when others =>
System.Soft_Links.Unlock_Task.all;
raise;
end Shared_Var_WOpen;
-----------
-- Write --
-----------
procedure Write
(Stream : in out File_Stream_Type;
Item : AS.Stream_Element_Array)
is
begin
SIO.Write (Stream.File, Item);
end Write;
end System.Shared_Storage;