After a number of iterations and delays I have finally
morphed my exploratory project from a Windows based set
of applications (loadable processes) to one to run under Linux and now, at
last, to one set of procedures and functions that, except for one interface
package, that can build applications to run under either operating system.
The one interface package body exec_itf, written in Ada, has two
versions – the one for use with Windows and the one to use with Linux. There are a few other packages that contain
code that takes different paths that are dependent upon the op sys under which
the application is running. These can
be used without change for use with either Windows or Linux.
All unit file names are now in lower case to satisfy Linux whereas
case doesn't matter for Windows. Also,
all references to the Win32Ada source files have been removed from the build
files.
In addition there are two C# applications that are used to interface
with the display. These are one and the
same except for the named pipe interface used to communicate with the Ada
worker applications; MS Pipes for Windows and the mkfifo named pipes for Linux. This application of the project is written
in Visual C# Express for Windows and uses MonoDevelop as a .NET application for
Linux.
Brief History:
The Exploratory Project started out to produce a Windows based
framework for producing applications.
The framework is used to isolate user components from each other with
message topics to communicate between the components rather than the use of
common memory. In addition, in the
exploratory project, the components can be moved from one application (separate
build) to another with the framework detecting the particular component and its
application upon startup. This is
possible since the components don't share memory, just like applications that
use the internet to communicate.
A number of previous posts to this blog have to do with creating the
framework and then a variation of it oriented towards communicating with the
display app (CDS) via the communications protocol of the ARINC-661 standard
{e.g.,
http://read.pudn.com/downloads111/ebook/462188/ARINC661-2005.pdf} to
replace the home grown protocol that was originally used.
The initial Exploratory Project had a display app that could treat
multiple display layers with each interfacing to its own user application. With the change to use as an example of a
user application with a different structure for the components that interface
with the A661 protocol display {
for instance, see past blog posts such
as
Using A661 in a Windows PC Environment – part 1 of July 31,
2012}, only one display layer was used.
In the future, the current version of the Exploratory Project may be
expanded to treat multiple layers once again with multiple user applications
each treating a layer or a particular user application treating more than one
layer (as illustrated in the July 31 post and below).
Starting with the Using Windows-like Events in Linux post of
August 29, 2012 this modification of the Exploratory Project began to be moved
to execute with interfacing to the Linux operating system. Now the changes have been made to allow the
same set of program units to be used for a build to be run under either Windows
or Linux (except for the one unit that acts as the direct interface to the
particular op sys).
Windows/Linux Interface:
Other than the interface to the op sys the main difference between
the Windows version and the Linux version is the method used to communicate
between the various loadable application processes. (Within a particular user application, the framework is
used.)
For Windows, Microsoft Pipes (MS Pipes) are used. With Linux, the mkfifo named pipes are
used. (Note, MS Pipes are also named
pipes).
For the single set of program units, the code to use either kind of
named pipes is included in the build with only one or the other selected at run
time depending upon which op sys is being used. Two methods of selecting the named pipe packages are used
depending upon whether communicating between other user apps or whether
communicating with the CDS display app for a particular display layer. That between other user apps uses the
framework while that between a user app and the CDS uses an instance of an Ada
generic for each layer.
Inter-User App Communications:
To communicate with other user apps that are based upon the framework,
a private subpackage (Remote) of the framework is used – that is, one not
visible to user components. Within this
private subpackage is another Method child package that is used to select the
communication method to be used. Each
communication method has its own child package, MS_Pipe and Named_Pipe in this
case. (Another method of WinSock is
left over from before the Exploratory Project forked off to use the A661
protocol. This can be restored at any
time with a complementary package for Linux oriented TCP/IP internet sockets.)
To select the procedures of the correct communication method, a
table is provided as follows.
separate( mC.Message.Remote )
package body Method is
type
Communication_Direction_Type
is ( Receive,
Transmit );
. . .
package MS_Pipe is
--| Communicate Between
Applications Using Microsoft Pipes
-- ++
--| Overview:
--| This package is to be used by communication
packages and procedures
--| to communicate between applications using
Microsoft Pipes.
--|
--| Each application of an application pair
will act as the Server for
--| one of a pair of pipes between the
application pair and as the Client
--| for the pipe.
--|
--| The Client will send/transmit/write a
message to the Server for the
--| Server to respond to. (The example has the Server waiting upon a
--| message and then sending a reply. The Client does a Write and then
--| waits for the reply.)
--|
--| Therefore, for the pipe where an
application will transmit to the
--| other application, the first application
will be the client and the
--| receiving application will be the server
for the pipe.
--|
--| Thus, for each application, the Client Open
will be invoked for the
--| pipe to which it will transmit and the
Server Open will be invoked
--| for the pipe for which it will wait for a
receive.
--|
--| Each pipe of the pair has to have a unique
name. For the application
--| pair 1 and 2, it application 1 is to
transmit it will be the client
--| and application 2 will receive and be the
server. But each must use
--| the same pipe name. Therefore, a name such as App 1 to App 2
might
--| be appropriate since such a name implies
that App 1 will transmit and
--| App 2 will receive.
--|
--| For connections of the user app to a
display app, the base portion of
--| the name is obtained from the
Apps-Configuration file and the layer
--| that the user application connects with is
obtained from the file and
--| use in the name so different user apps will
use different pairs of
--| pipes.
-- --
procedure
Close_Connection
( Index : in
Apps.Configuration.Connection_Index_Type
--| Index of
connection in Comm Pipe table for Receive
);
--| Close MS Pipe
Connection
-- ++
--| Overview:
--| This procedure closes the connection
identified by the Index.
-- --
procedure
Find_Remote_App( Pointless : in Boolean := True );
--| Find Remote
Applications that can communicate with this application
-- ++
--| Overview:
--| This procedure determines what remote
applications are running that
--| can communicate with this application via
MS Pipes.
-- --
procedure Initialize
( Method : in
mC.Itf_Types.Supported_Communication_Method_Type;
--| Supported
communication method of local application
App_Ident : in
Apps.Application_Id_Type
--| Identifier of
running application
);
--| Initialize
-- ++
--| Overview:
--| This procedure performs the necessary
initializations.
-- --
procedure Install(
Pointless : in Boolean := True );
--| Install
-- ++
--| Overview:
--| tbd
-- --
procedure Quit(
Pointless : in Boolean := True );
--| Terminate
Communications
-- ++
--| Overview:
--| This procedure performs the necessary
termination functions.
-- --
procedure Receive
( Topic : in Boolean
:= False
);
--| Receive thread to
read from the other application of application pair
-- ++
--| Overview:
--| This function is the reader thread that
reads from the Microsoft
--| Pipe, queues topic messages, and signals
the Producer Proxy to
--| interpret the message and publish it as a
topic.
-- --
procedure Transmit
( Remote_App : in
Apps.Component_Selector_Type;
--| Remote
application to which to transmit
Count : in Message_Size_Type;
--| Total number of
bytes in message including header
Message : in System.Address
--| Message to be
transmitted
);
--| Transmit to other
application of the application pair
-- ++
--| Overview:
--| This procedure runs under the mC Message
Remote Main thread to
--| transmit a message to the other application
of the pair.
-- --
end MS_Pipe;
---------------------------------------------------------------------------
package Named_Pipe is
--| Communicate Between
Applications Using Linux Named (fifo) Pipes
-- ++
--| Overview:
. . . clone of the
above declaring the MS_Pipe interface
end Named_Pipe;
---------------------------------------------------------------------------
--| Notes:
--| Access procedure pointers.
type
Remote_Thread_Ptr_Type
--| Procedure access to
communication method
is access procedure(
Pointless : in Boolean := True );
type
Remote_Close_Ptr_Type
--| Access to close
connection of communication method
is access procedure(
Index : in Apps.Configuration.Connection_Index_Type
--| Index of connection in its table
);
type
Remote_Initialize_Ptr_Type
--| Access to
initialize communication method
is access procedure
( Method : in
mC.Itf_Types.Supported_Communication_Method_Type;
--| Supported
communications methods of application
App_Ident : in
Apps.Application_Id_Type
--| Identifier of
running application
);
type
Remote_Transmit_Ptr_Type
--| Access to transmit
communication method
is access procedure( Remote : in Apps.Component_Selector_Type;
--| Remote destination of message
Count : in Message_Size_Type;
--| Total number of bytes to transmit including header
Message
: in System.Address
--| Message to be transmitted
);
type
Remote_Procedures_Type
--| One common access
procedure per communication method
is array(
mC.Itf_Types.Communication_Method_Type )
of Remote_Thread_Ptr_Type;
type Remote_Close_Type
--| One common access
procedure per communication Close Connection method
is array(
mC.Itf_Types.Communication_Method_Type )
of
Remote_Close_Ptr_Type;
type
Remote_Initialize_Type
--| One common access
procedure per communication Initialize method
is array(
mC.Itf_Types.Communication_Method_Type )
of
Remote_Initialize_Ptr_Type;
type
Remote_Transmit_Type
--| One common access
procedure per Topic protocol communication Transmit
--| method
is array(
mC.Itf_Types.Communication_Method_Type )
of
Remote_Transmit_Ptr_Type;
type
Remote_Procedures_Table_Type
is record
Close : Remote_Close_Type;
Install : Remote_Procedures_Type;
Initialize :
Remote_Initialize_Type;
Quit : Remote_Procedures_Type;
Find_App : Remote_Procedures_Type;
Transmit : Remote_Transmit_Type;
end record;
type
Remote_Procedures_Array_Type
is array (
Exec_Itf.Windows .. Exec_Itf.Linux )
of
Remote_Procedures_Table_Type;
Invoke
--| Table of top-level
communication method procedures
--| Notes:
--| This table must be changed depending on the
Op Sys being used.
:
Remote_Procedures_Array_Type
:= ( Exec_Itf.Windows
=>
( Close =>
( mC.Itf_Types.Pipes => MS_Pipe.Close_Connection'access,
mC.Itf_Types.Sockets => null ),
Install =>
(
mC.Itf_Types.Pipes =>
MS_Pipe.Install'access,
mC.Itf_Types.Sockets => null ),
Initialize =>
(
mC.Itf_Types.Pipes =>
MS_Pipe.Initialize'access,
mC.Itf_Types.Sockets => null ),
Quit =>
(
mC.Itf_Types.Pipes =>
MS_Pipe.Quit'access,
mC.Itf_Types.Sockets => null ),
Find_App =>
(
mC.Itf_Types.Pipes =>
MS_Pipe.Find_Remote_App'access,
mC.Itf_Types.Sockets => null ),
Transmit =>
(
mC.Itf_Types.Pipes =>
MS_Pipe.Transmit'access,
mC.Itf_Types.Sockets => null ) ),
Exec_Itf.Linux =>
( Close =>
(
mC.Itf_Types.Pipes =>
Named_Pipe.Close_Connection'access,
mC.Itf_Types.Sockets => null ),
Install =>
(
mC.Itf_Types.Pipes => Named_Pipe.Install'access,
mC.Itf_Types.Sockets => null ),
Initialize =>
(
mC.Itf_Types.Pipes =>
Named_Pipe.Initialize'access,
mC.Itf_Types.Sockets => null ),
Quit =>
( mC.Itf_Types.Pipes => Named_Pipe.Quit'access,
mC.Itf_Types.Sockets => null ),
Find_App =>
(
mC.Itf_Types.Pipes =>
Named_Pipe.Find_Remote_App'access,
mC.Itf_Types.Sockets => null ),
Transmit =>
(
mC.Itf_Types.Pipes =>
Named_Pipe.Transmit'access,
mC.Itf_Types.Sockets => null ) )
);
A sample communication method selection procedure is
procedure
Find_Remote_App is
use type
mC.Itf_Types.Supported_Communication_Method_Type;
begin -- Find_Remote_App
--| Logic_Step:
--| Find remote applications that can
communicate with this
--| application.
--| Notes:
--| Can only be done for MS Pipes or Named
Pipes to determine
--| what remote applications are running. WinSock has a null
--| procedure.
if Supported_Method =
mC.Itf_Types.Both then
for M in
mC.Itf_Types.Communication_Method_Type loop
if
Invoke(Exec_Itf.Op_Sys).Find_App(M) /= null then
Invoke(Exec_Itf.Op_Sys).Find_App(M)( Pointless => True );
end if;
end loop;
elsif Supported_Method
/= mC.Itf_Types.None then
Invoke(Exec_Itf.Op_Sys).Find_App(Supported_Method)( Pointless => True
);
end if;
end Find_Remote_App;
The currently running operation system is named by the globally
visible Op_Sys variable of the Exec_Itf package. Supported_Method is the communications method supported by the
application. That is, Pipes or Sockets
or, if both methods are supported then Both.
These array indexes select the table item to be invoked.
A661 User/Display App Communications:
To communicate between a user apps and the display app, an Ada
generic package is used; that is, one that can be instantiated multiple times
where each instantiation has its own data space but uses the same code. This is done to allow the use of a unique
instantiation for each display layer.
In the user program structure depicted by the following reproduction
of that of the Using A661 in a Windows PC Environment – part 1 blog
post, the top level interface to manage a particular layer is represented by
GUI Layer n to manage layer n.
In the following code samples, the Display_Pipe generic package
takes the place of "comm Method" in the figure. When instantiated by GUI1 (GUI Layer 1 of
the figure), it instantiates an instance of both the MS_Pipe and Named_Pipe
generic packages (rather than only MS Pipe of the figure). (Note:
The same names are used as for the framework packages for inter-user app
communications. However, these are
stand alone packages whereas these names in the framework are child packages of
the Remote Method package.)
package body GUI1 is
Layer_Id
--| Layer identifier
that this component manages
: constant
A661.Types.Layer_Id_Type := 1;
. . .
procedure
Add_to_Received_Messages_Queue
( Length : in Integer;
--| Number of bytes
of Message to be used
Message : in
A661.Types.Generic_Message_Type;
--| Received message
Valid : out Boolean
--| True if message
added to the queue
);
--| Add Message to
Queue and Publish Wakeup Event
-- ++
--| Overview:
--| This procedure queues the received A661
message and publishes the
--| wakeup event topic to cause the GUI1
component to execute.
--| Limitations:
--| This procedure runs under the Driver
Receive thread while the rest
--| of the methods of this component run under
the component's thread.
--| Therefore, this procedure and the one that
Gets a message from the
--| queue must execute in a thread safe manner.
-- --
package Driver
--| Instantiate MS_Pipe
communications driver for layer 1
is new Display_Pipe
( Id => Layer_Id,
Add_Received_Message_to_Queue =>
Add_to_Received_Messages_Queue'access,
Register_Component =>
mC.Itf.Register_Component'access );
. . .
procedure Initialize
( User_Name : in
Apps.Application_Name_Type;
User_Id : in Apps.Application_Id_Type
) is
. . .
Driver.Initialize(
User_Id => User_Id,
Display_Id => Display_Id,
Port_Name => Port_Name );
end Initialize;
. . .
end GUI1;
Other GUI1 procedures also call the Driver instantiation of
Display_Pipe such as GUI1's Install procedure calling that of Driver and
various procedures calling Driver Transmit.
The Display_Pipe package spec (that is, the visible interface) is
with A661;
with Apps;
with mC.Itf_Types;
generic
-- ++
--| Overview:
--| Generic package to
communicate, when instantiated, with the Display
--| Application for a
particular layer.
-- --
--| Notes:
--| Parameters to supply when instantiate an
instance of a topic.
Id
--| Layer identifier
:
A661.Types.Layer_Id_Type;
Add_Received_Message_to_Queue
--| Callback to Add a
Received Message to its Received Messages Queue
:
A661.Add_Received_Message_to_Queue_Type;
Register_Component
--| Callback to
Register the Receive component
:
A661.Register_Component_Type;
package Display_Pipe is
-- ++
--| Overview:
--| Package to access
to either read or write a selected named pipe as the
--| pipe client or the
pipe server. The use, by an
application, of either
--| the client or the
server and the use, by a different application, of
--| the reverse
instantiation, will result in a full duplex pipe with the
--| pair of
applications being able to communicate with each other when
--| both are running
under Windows or Linux on the same PC.
--|
--| At open, specify a
number for each of a pair of applications; the
--| currently running
application as the Client and the other application
--| as the Server. If the other application does the same it
will also
--| name itself as the
Client and the first application as the Server.
--|
--| When, for instance,
application 1 needs to send a request to
--| application 2, it
could have a named pipe called "NamedPipe01to02" as
--| the Client pipe and
will use it to transmit to application 2 and
--| application 2 will
have the same pipe as its Server pipe and use it to
--| receive from
application 1. While application 2 will
have a Client
--| named pipe named
such as "NamedPipe02to01" to use transmit to
--| application 1 and
application 1 will have the same pipe to use to
--| receive from
application 2.
-- --
procedure
Close_Connection;
--| Close Display Pipe
Connection
-- ++
--| Overview:
--| This procedure closes the connection
identified by the Index.
-- --
procedure Initialize
( User_Id : in Apps.Application_Id_Type;
--| User app id of
the current app
Display_Id : in
Apps.Application_Id_Type;
--| App id of the
display app
Port_Name : in mC.Itf_Types.Port_Name_Type
--| Port name to
access the display layer
);
--| Initialize
-- ++
--| Overview:
--| This procedure performs the necessary
initializations and returns the
--| name to register the receive component.
-- --
procedure Install;
--| Install
-- ++
--| Overview:
--| tbd
-- --
procedure Quit;
--| Terminate
Communications
-- ++
--| Overview:
--| This procedure performs the necessary
termination functions.
-- --
procedure Transmit
( Size : in Natural;
--| Number of bytes
in Message to be transmitted
Message : in
A661.Types.Generic_Message_Type
--| Message to be
transmitted
);
--| Transmit to Display
Application of the application pair
-- ++
--| Overview:
--| This procedure runs under the Layer
Management thread to transmit a
--| message to the Display Application of the
application pair.
-- --
end Display_Pipe;
The package body contains
with Exec_Itf;
with MS_Pipe;
with Named_Pipe;
package body Display_Pipe is
--| Communicate
Between this Application as Client of the A661 Display
--| Application
-- ++
--| Overview:
--| This package is to
be used by the A661 display Receive and Transmit
--| components to
supply procedures to communicate between this application
--| as a client of the
Display Application using either MS Pipes for
--| Windows or Named
Pipes for Linux.
--|
--| It will be
instantiated by a Layer Management component for a
--| particular layer
with the use of MS Pipes or Named Pipes determined by
--| the operating
system being used.
--|
--| Notes:
--| The layer
management package for the layer must invoke Initialize prior
--| to Install. Install must be invoked before Transmit and
the like.
-- --
type
Communications_Pipe_Type
is ( Windows_Pipe, --
for Windows
Linux_Pipe ); --
for Linux
Pipe
--| Pipe package to be
used
: Communications_Pipe_Type
:= Windows_Pipe;
package Pipe_Windows
--| Instantiate MS_Pipe
communications driver for the layer
is new MS_Pipe
( Id => Id,
Add_Received_Message_to_Queue => Add_Received_Message_to_Queue,
Register_Component
=> Register_Component );
package Pipe_Linux
--| Instantiate
Named_Pipe communications driver for the layer
is new Named_Pipe
( Id => Id,
Add_Received_Message_to_Queue => Add_Received_Message_to_Queue );
procedure Initialize
( User_Id : in Apps.Application_Id_Type;
--| User app id of
the current app
Display_Id : in
Apps.Application_Id_Type;
--| App id of the
display app
Port_Name : in mC.Itf_Types.Port_Name_Type
--| Port name to
access the display layer
) is
-- ++
--| Logic_Flow:
--| Determine which named pipe package to call
for the operation system
--| and then invoke its initialization.
-- --
use type Exec_Itf.Op_Sys_Type;
begin -- Initialize
if Exec_Itf.Op_Sys =
Exec_Itf.Linux then
Pipe := Linux_Pipe;
else
Pipe :=
Windows_Pipe;
end if;
case Pipe is
when
Windows_Pipe =>
Pipe_Windows.Initialize;
when Linux_Pipe
=>
Pipe_Linux.Initialize( User_Id
=> User_Id,
Display_Id => Display_Id,
Port_Name => Port_Name );
end case;
end Initialize;
procedure Install is
begin -- Install
case Pipe is
when
Windows_Pipe =>
Pipe_Windows.Install;
when Linux_Pipe
=>
Pipe_Linux.Install;
end case;
end Install;
procedure
Close_Connection is
begin --
Close_Connection
case Pipe is
when Windows_Pipe =>
Pipe_Windows.Close_Connection;
when Linux_Pipe
=>
Pipe_Linux.Close_Connection;
end case;
end Close_Connection;
procedure Quit is
begin -- Quit
case Pipe is
when
Windows_Pipe =>
Pipe_Windows.Quit;
when Linux_Pipe
=>
Pipe_Linux.Quit;
end case;
end Quit;
procedure Transmit
( Size : in Natural;
--| Number of bytes
in Message to be transmitted
Message : in
A661.Types.Generic_Message_Type
--| Message to be transmitted
) is
begin -- Transmit
case Pipe is
when
Windows_Pipe =>
Pipe_Windows.Transmit( Size
=> Size,
Message => Message );
when Linux_Pipe
=>
Pipe_Linux.Transmit( Size
=> Size,
Message =>
Message );
end case;
end Transmit;
end Display_Pipe;
exec_itf:
This is the only package that continues to exist in separate
versions for Windows and Linux. There
is a common Ada specification to present the global interface with separate
versions for the package body to actually interface with the operating system.
exec_itf.ads:
In the package spec that follows some "pragma Import"s
have been retained. That is, those that
both the GNAT Windows and Linux linkers recognize. The others have been moved to the package body so that its file
might be the only one that needs different versions. Also many type and constant declarations are, most likely, no
longer needed.
with Ada.Finalization;
with Ada.Task_Identification;
with GNAT.OS_Lib;
with GNAT.Sockets.Linker_Options; -- needed to link via GNAT to
its libwsock32.a library
with Interfaces.C;
with Interfaces.C.Pointers;
with System;
with Unchecked_Conversion;
package Exec_Itf is
---------------------------------------------------------------------------
--| Notes: |
--| Miscellaneous types, constants, and
functions. |
---------------------------------------------------------------------------
type Op_Sys_Type
--| Possible operating
system (i.e., executive) choices
is ( Unknown,
Windows,
Linux );
Op_Sys
--| Operating system
supported by this version of the executive
: Op_Sys_Type :=
Unknown;
procedure Set_Op_Sys;
--| Set Operating
System Running Under
subtype
Config_File_Name_Type is String(1..60);
type
Config_File_Name_Var_Type
is record
Count : Integer;
Value :
Config_File_Name_Type;
end record;
function Config_File_Name
return
Config_File_Name_Var_Type;
--| Return path name of
configuration file
procedure Exit_to_OS
( Status : Integer := 0
);
-- Exit to OS with
Status
function GetLastError
return Integer;
-- Return current last
error number
type BOOL is new
Interfaces.C.Int; -- same as
Win32 BOOL
subtype CHAR is Interfaces.C.Char; -- Win32
type PCHAR
is access all CHAR; --
Win32
subtype LPSTR is PCHAR; -- Win32
subtype DWORD is Interfaces.C.Unsigned_Long; -- same as
Win32 DLONG
subtype ULONG is Interfaces.C.Unsigned_Long; -- same as
Win32 DLONG
type PULONG
is access all ULONG; --
Win32
subtype PDWORD is PULONG; -- Win32
subtype LPDWORD is
PDWORD; -- Win32
procedure Log_Error;
-- Log the current last
error number
subtype
Computer_Name_Type
is Integer range
1..200;
function
GetComputerName
( Name : in System.Address;
--| Location of
buffer into which to store the name
Length : in
Computer_Name_Type
--| Number of
characters, including trailing NUL, that can be stored
) return Integer; -- 0
if no error
--| Return the computer
/ host name on which application is running
function GetComputerNameA -- winbase.h:6576
( Buffer : LPSTR;
Size : LPDWORD
) return BOOL;
pragma Import( Stdcall,
GetComputerNameA, "GetComputerNameA" ); -- winbase.h:6576
-- GetComputerName and
GetComputerNameA are the same function
type Integer_Pair_Type
is array( 1..2 ) of
Integer;
function
Unsigned_Long_to_Int
( Source : in
Interfaces.C.Unsigned_Long
) return
Integer_Pair_Type;
---------------------------------------------------------------------------
--| Notes: |
--| File types, constants, and functions. |
---------------------------------------------------------------------------
type File_Handle is
private;
--| Corresponds to the file handle values used
in the C routines
type Mode_Type
is ( Binary, Text );
for Mode_Type'Size use
Integer'Size;
for Mode_Type use (
Binary => 0, Text => 1 );
-- Used in all the Open
and Create calls to specify if the file is to be
-- opened in binary
mode or text mode. In systems like Unix, this has no
-- effect, but in
systems capable of text mode translation, the use of
-- Text as the mode
parameter causes the system to do CR/LF translation
-- and also to
recognize the DOS end of file character on input. The use
-- of Text where
appropriate allows programs to take a portable Unix view
-- of DOS-format files
and process them appropriately.
Invalid_File_Handle
--| File descriptor returned when error in
opening/creating file;
: constant File_Handle;
function Close_File
( Handle : File_Handle
) return Boolean;
-- Close file
referenced by Handle. Return False if the underlying service
-- failed. Reasons for
failure include: disk full, disk quotas exceeded
-- and invalid file
handle (the file may have been closed twice).
subtype PVOID is System.Address; -- same as Win32
subtype HANDLE is
PVOID; --
winnt.h:144
function
CloseHandle -- winbase.h:2171
( Object : HANDLE
) return BOOL;
function Create_File
( Name : String;
Mode : Mode_Type :=
Text
) return File_Handle;
-- Creates new file
with given name for writing, returning file descriptor
-- for subsequent use
in Write calls. The file handle is returned as
-- Invalid_Handle if
the file cannot be successfully created.
function
Create_New_File
( Name : String;
Mode : Mode_Type :=
Text
) return File_Handle;
-- Create new file with
given name for writing, returning file descriptor
-- for subsequent use
in Write calls. This differs from Create_File in
-- that it fails if the
file already exists. File handle returned is
-- Invalid_Handle if
the file exists or cannot be created.
Seek_Cur : constant :=
1; -- seek from current position
Seek_End : constant :=
2; -- seek from end of file
Seek_Set : constant :=
0; -- seek from start of file
-- Used to indicate origin for Seek call
procedure Seek
( Handle : File_Handle;
Offset : Long_Integer;
Origin : Integer
);
-- Sets the current file pointer to the
indicated offset value, relative
-- to the current position (origin = SEEK_CUR),
end of file (origin =
-- SEEK_END), or start of file (origin =
SEEK_SET).
pragma Import( C, Seek,
"__gnat_lseek" );
function Open_Read
( Name : String;
Mode : Mode_Type :=
Text
) return File_Handle;
-- Open file Name for
reading, returning file handle. File
handle is
-- returned as
Invalid_Handle if file cannot be opened.
function Open_Read_Write
( Name : String;
Mode : Mode_Type :=
Text
) return File_Handle;
-- Open file Name for
both reading and writing, returning file handle.
-- File handle returned
as Invalid_Handle if file cannot be opened.
type OVERLAPPED; --
winbase.h:179
type LPOVERLAPPED is
access all OVERLAPPED; --
winbase.h:185
subtype LPVOID is PVOID; -- windef.h
function ReadFile --
winbase.h:2095
( File : HANDLE;
Buffer : LPVOID;
NumberOfBytesToRead :
DWORD;
NumberOfBytesRead : LPDWORD;
Overlapped : LPOVERLAPPED
) return BOOL;
function Read_File
( File : File_Handle;
Addr :
System.Address;
Num : Integer
) return Integer;
-- Read Num bytes to
address Addr from file referenced by File.
-- Returned value is
count of bytes actually read, which can be
-- less than Num at
EOF.
function Write_File
--| Write Text to File
and return number of bytes written.
Strip internal
--| NULs if True.
( File : in File_Handle;
Text : in String;
Strip_NULs : in
Boolean := False
) return Integer;
function Write_File
--| Write Len bytes at
Addr to File and return number of bytes written.
( File : File_Handle;
Addr :
System.Address;
Len : Integer
) return Integer;
---------------------------------------------------------------------------
--| Notes:
|
--| Time types, constants, and functions. |
---------------------------------------------------------------------------
-- The following types
are duplicates of those in GNAT s-os_lib.ads.
subtype OS_Time is
GNAT.OS_Lib.OS_Time; --private;
-- The OS's notion of time is represented by
the private type OS_Time.
-- This is the type returned by the
File_Time_Stamp functions to obtain
-- the time stamp of a specified file.
Functions and a procedure (modeled
-- after the similar subprograms in package
Calendar) are provided for
-- extracting information from a value of this
type. Although these are
-- called GM, the intention is not that they
provide GMT times in all
-- cases but rather the actual (time-zone
independent) time stamp of the
-- file (of course in Unix systems, this *is*
in GMT form).
subtype SystemTimeType
is OS_Time;
Invalid_Time : constant
OS_Time := GNAT.OS_Lib.Invalid_Time;
-- A special unique value used to flag an
invalid time stamp value
subtype Year_Type is Integer range 1900 .. 2099;
subtype Month_Type is Integer range 1 .. 12;
subtype Day_Type is Integer range 1 ..
31;
subtype Hour_Type is Integer range 0 ..
23;
subtype
Minute_Type is Integer range 0 ..
59;
subtype
Second_Type is Integer range 0 ..
59;
subtype Millisec_Type
is Integer range 0 .. 999;
-- Declarations similar to those in Calendar,
breaking down the time
function Current_Time
return OS_Time;
-- Return the system clock value as OS_Time
type Split_Time_Type
--| Structure with the
Data and Time.
--| Notes: Not part of
GNAT but similar to C tm type.
--| Also, like SYSTEMTIME of System.Win32
except each field was of
--| type WORD where WORD is declared as
Interfaces.C.unsigned_short
--| where type unsigned_short is mod 2 **
short'Size; and short is
--| type short is new Short_Integer;
is record
Year : Year_Type;
Month : Month_Type;
Day : Day_Type;
Hour : Hour_Type;
Minute : Minute_Type;
Second : Second_Type;
Millisec :
Millisec_Type;
end record;
subtype
System_Time_Type is Split_Time_Type;
function System_Time
( Time : OS_Time
--| System clock value
) return
System_Time_Type;
--| Return system clock
value as a record.
--| Notes: This time
contains no adjustment for local time.
type FILETIME; --
winbase.h:204
type SYSTEMTIME1; -- same as Win32.WinBase SYSTEMTIME
type PFILETIME is
access all FILETIME; --
winbase.h:207
subtype LPFILETIME is
PFILETIME; --
winbase.h:207
type PSYSTEMTIME is
access all SYSTEMTIME1; --
winbase.h:222
subtype LPSYSTEMTIME is
PSYSTEMTIME; -- winbase.h:222
procedure
GetSystemTime --
winbase.h:2613
( SystemTime :
LPSYSTEMTIME );
pragma Import( Stdcall,
GetSystemTime, "GetSystemTime" ); -- winbase.h:2613
function SystemTime
return
System_Time_Type;
--| Return system clock
value as a record.
--| Notes: This time
contains no adjustment for local time.
procedure GM_Split
( Date : OS_Time;
Year : out Year_Type;
Month : out Month_Type;
Day :
out Day_Type;
Hour : out Hour_Type;
Minute : out Minute_Type;
Second : out Second_Type;
Millisec : out
Millisec_Type
);
-- Analogous to the Split routine in
Ada.Calendar, takes an OS_Time and
-- provides a representation of it as a set of
component parts, to be
-- interpreted as a date point in UTC.
function
File_Time_Stamp
( Name : String
) return OS_Time;
-- Given the name of a file or directory, Name,
obtains and returns the
-- time stamp. This function can be used for an
unopened file. Returns
-- Invalid_Time is Name doesn't correspond to
an existing file.
function
File_Time_Stamp
( Handle : File_Handle
) return OS_Time;
-- Get time stamp of file from file Handle and
returns Invalid_Time if
-- Handle doesn't correspond to an existing
file.
---------------------------------------------------------------------------
--| Notes: |
--| Process types, constants, and functions. |
---------------------------------------------------------------------------
type PId_t is private;
Invalid_PId : constant
PId_t;
function GetPId return
PId_t;
-- This function gets
system identifier of the current process / application.
pragma Import (C,
GetPId, "getpid");
function
Execute_Program
( Name : in String
--| Program name to
be executed
) return PId_t;
--| Spawn a new Process
and Execute the Command
-- ++
--| Overview:
--| Comments are from GNAT:
--| This is a non blocking call. The
Process_Id of the spawned process
--| is returned. Parameters are to be used as
in Spawn. If Invalid_Pid
--| is returned the program could not be
spawned.
--|
--| Spawning processes from tasking programs
is not recommended. See
--| "NOTE: Spawn in tasking
programs" below.
-- --
function
GetProcessShutdownParameters
( Level : in LPDWORD;
Flags : in LPDWord
) return BOOL;
function Is_Running
( Path : String
--| Full path of
executable
) return Boolean;
--| Return True if
executable is currently running
-- ++
--| Overview:
--| Determine if the executable named by the
Path is currently running.
--
--| Notes:
--| o It is expected that Path will be the full
path including the
--| trailing ".exe" of the
executable.
--| o The function iterates through the /proc
directory to obtain the
--| process identifiers of the running
processes and, for each one
--| for which ReadLink returns a value for an
executable path, it
--| compares that value with the supplied
Path. If it matches, True
--| is returned.
-- --
---------------------------------------------------------------------------
--| Notes: |
--| Event types, constants, and functions. |
---------------------------------------------------------------------------
procedure Create_Event
( Name : in String;
-- Event name
Id : in out Integer;
--| Event id on
input, 0 upon output for failure
Addr : in
System.Address
--| Address of handle
);
function
Reset_Event
-- winbase.h:1878
( Event : HANDLE
) return Boolean;
function Set_Event --
winbase.h:1871
( Event : HANDLE
) return Boolean;
---------------------------------------------------------------------------
--| Notes: |
--| Thread types, constants, and
functions. |
---------------------------------------------------------------------------
-- The following types
are duplicates of those in GNAT g-thread.ads and
-- those needed to
interface directly with Linux C functions.
type Void_Ptr is access
all Integer;
type Thread_Handle_Type
is private;
type Thread_Id_Type is
new Interfaces.C.unsigned_long;
Null_Thread_Id
: constant
Thread_Id_Type := 0;
Null_Thread_Handle
--| Null thread handle
value
: constant
Thread_Handle_Type;
PTHREAD_RWLOCK_SIZE
-- pthread_rwlock_t
-- as taken from
/usr/lib/gcc/i686-redhat-linux/4.7.0/adainclude/s-oscons.ads
-- of Fedora install on
removal drive
: constant := 32;
PTHREAD_ATTR_SIZE
-- pthread_attr_t
-- as taken from
/usr/lib/gcc/i686-redhat-linux/4.7.0/adainclude/s-oscons.ads
-- of Fedora install on
removal drive
: constant := 36;
PTHREAD_RWLOCKATTR_SIZE
-- pthread_rwlockattr_t
-- as taken from
/usr/lib/gcc/i686-redhat-linux/4.7.0/adainclude/s-oscons.ads
-- of Fedora install on
removal drive
: constant := 8;
subtype char_array
-- as taken from
/usr/lib/gcc/i686-redhat-linux/4.7.0/adainclude/s-osinte.ads
-- of Fedora install on
removal drive
is
Interfaces.C.char_array;
type WSA_CHAR_Array is
array(Natural range <>) of aliased CHAR;
type pthread_attr_t
-- as taken from
/usr/lib/gcc/i686-redhat-linux/4.7.0/adainclude/s-osinte.ads
-- of Fedora install on
removal drive
-- type pthread_attr_t
is record
Data : char_array(1
.. PTHREAD_ATTR_SIZE);
end record;
pragma Convention (C,
pthread_attr_t);
for
pthread_attr_t'Alignment use Interfaces.C.unsigned_long'Alignment;
type pthread_rwlock_t
is record
-- as taken from
/usr/lib/gcc/i686-redhat-linux/4.7.0/adainclude/s-osinte.ads
-- of Fedora install on
removal drive
Data : char_array(1
.. PTHREAD_RWLOCK_SIZE);
end record;
pragma Convention (C,
pthread_rwlock_t);
for
pthread_rwlock_t'Alignment use Interfaces.C.unsigned_long'Alignment;
type
pthread_rwlockattr_t is record
-- as taken from
/usr/lib/gcc/i686-redhat-linux/4.7.0/adainclude/s-osinte.ads
-- of Fedora install on
removal drive
Data : char_array(1
.. PTHREAD_RWLOCKATTR_SIZE);
end record;
pragma Convention (C,
pthread_rwlockattr_t);
for
pthread_rwlockattr_t'Alignment
use
Interfaces.C.unsigned_long'Alignment;
subtype
Thread_RWLock_Type is pthread_rwlock_t;
subtype
Thread_RWLock_Attr_Type is pthread_rwlockattr_t;
subtype Thread_Address_Type
--| System address of a
thread
is System.Address;
Null_Thread_Address
--| Null system address
for thread
: constant
Thread_Address_Type;
procedure Create_Thread
( Start : System.Address; -- pointer to start address of thread
Parameter : System.Address; -- pointer to parameters
Stack_Size : Natural; -- stack size in bytes
Thread_Priority :
Integer; -- priority for thread
Thread_Handle : out Thread_Handle_Type
);
-- Creates a thread
with the given (Size) stack size in bytes, and
-- the given (Prio)
priority. The task will execute a call to the
-- procedure whose
address is given by Code. This procedure has
-- the prototype
--
-- void thread_code (void *id, void *parm);
--
-- where id is the id
of the created task, and parm is the parameter
-- passed to
Create_Thread. The called procedure is the body of the
-- code for the task,
the task will be automatically terminated when
-- the procedure returns.
--
-- This function
returns the Ada Id of the created task that can then be
-- used as a parameter
to the procedures below.
--
-- C declaration:
--
-- extern void
*__gnat_create_thread
-- (void (*code)(void *, void *), void *parm,
int size, int prio);
--|
--| Notes:
--| This Create_Thread using GNAT.Threads. The Thread_Handle that is
--| returned is different from that of the C
pthread_create Create_Thread
--| below.
It needs the use of Get_Thread to return the Thread_Handle
--| to a Linux Thread_Id. Also, when the thread starts the pointer
that
--| is supposed to be the address of the
parameters passed to the thread
--| has a different value than that supplied to
Create_Thread.
function Create_Thread
( Start : in System.Address; -- pointer
Parameters : in
Void_Ptr; -- pointer
Stack_Size : in
Natural; -- int
Priority : in Integer -- int
) return HANDLE;
--| Create Thread
-- ++
--| Overview:
--| This function creates a thread with the
given stack size in bytes,
--| and the given Priority. The task will execute a call to the
--| procedure whose address is given by Start
and may pass the Parameters
--| at the address. The thread handle is at the returned address.
-- --
procedure
Create_Thread_Linux
( Stack_Size : in Integer;
--| Stack size to use
Start : in System.Address;
--| Pointer to start
address for thread
Thread_Number :
in Integer;
--| Application-defined
thread number
Thread_Id : out Integer;
--| Identifier
returned by pthread_create
Success : out Boolean
--| Whether create
was successful
);
--| Create Thread
-- ++
--| Overview:
--| Create thread and return its id at the
location specified and True if
--| created successfully.
-- --
procedure Get_Thread --
get thread identifier from handle
( Thread_Handle : in
HANDLE;
Thread_Id : out PId_t );
-- This procedure is
used to retrieve the thread id of a given task.
-- The value
Thread_Handle is the value that was passed to the thread
-- code procedure at
activation time.
-- Thread_Id is
obtained by this procedure.
procedure Get_Thread
( Thread_Handle : in
Thread_Handle_Type;
--| GNAT thread id
Thread_Id : out Thread_Id_Type
--| Linux thread id
);
-- Convert GNAT thread
identifier to that of Linux.
function To_Task_Id
( Thread_Handle : in
Thread_Handle_Type
) return
Ada.Task_Identification.Task_Id;
-- Ada interface only.
-- Given a low level
Id, as returned by Create_Thread, return a Task_Id,
-- so that operations
in Ada.Task_Identification can be used.
procedure
Destroy_Thread
( Thread_Handle :
Thread_Handle_Type
);
-- This procedure may
be used to prematurely abort the created thread.
-- The Thread_Handle is
the value that was returned by thread create.
-- Notes:
-- There are two sets of
procedures/functions. One using the
GNAT
-- thread identifier that I refer to as the
Thread Handle and one
-- using the Linux C functions that I refer to
as the Thread Id.
-- Matching routines need to be used that use
either the handle or
-- the identifier and not the wrong one for
the routine.
function
GetCurrentThreadId
return Thread_Id_Type;
-- This function gets
the system identifier of the currently running thread.
function
GetCurrentThread --
winbase.h:1623
return HANDLE;
type
Thread_RWLock_Ptr_Type
is access
Thread_RWLock_Type;
type Thread_RWLock_Attr_Ptr_Type
is access
Thread_RWLock_Attr_Type;
function
Thread_Lock_Init
( Lock :
Thread_RWLock_Ptr_Type;
Attr :
Thread_RWLock_Attr_Ptr_Type
) return
Interfaces.C.int;
-- Initalize thread
read/write lock semaphore
function Thread_Lock_Destroy
( Lock :
Thread_RWLock_Ptr_Type
) return
Interfaces.C.int;
-- Destroy thread
read/write lock semaphore
pragma Import( C,
Thread_Lock_Destroy, "pthread_rwlock_destroy" );
function Thread_Lock
( Lock :
Thread_RWLock_Ptr_Type
) return
Interfaces.C.int;
-- Lock the thread
read/write lock semaphore
function Thread_Unlock
( Lock :
Thread_RWLock_Ptr_Type
) return
Interfaces.C.int;
-- Unlock the thread
read/write lock semaphore
---------------------------------------------------------------------------
-- Named pipes
type mode_t is new
Integer;
subtype Pipe_Handle is
File_Handle; --private;
Invalid_Pipe_Handle
--| File descriptor returned when error in
opening/creating file;
: constant Pipe_Handle;
subtype Pipe_Name_Type
--| Pipe name
is String(1..79);
type
Named_Pipe_Name_Type
--| Name to use for the
pipe
is record
Count : Integer;
--| Number of
characters in name
Path : Pipe_Name_Type;
--| Path including
pipe name
end record;
type Open_Mode_Type is
new Integer;
-- see
Win32Ada/win32/src/crt/win32-crt-fcntl.ads and
--
/4.5.4/gcc-include/s-oscons.h of gnat of Linux
O_RDONLY : constant Open_Mode_Type := 16#0#;
O_WRONLY : constant Open_Mode_Type := 16#1#;
O_RDWR : constant Open_Mode_Type := 16#2#;
-- The above three
modes can't be or-ed together.
O_APPEND : constant Open_Mode_Type := 16#8#;
O_CREAT : constant Open_Mode_Type := 16#100#;
--O_NOCTTY : constant
Open_Mode_Type := 256; -- 16#100#
O_NDELAY : constant Open_Mode_Type := 2048; --
16#800#
function MkFifo
( Path :
System.Address;
Mode : Mode_t
) return Integer;
function Open
( Path :
System.Address;
Mode : Open_Mode_Type
) return Pipe_Handle;
pragma Import( C, Open,
"open" );
function Unlink
( Path : System.Address
) return Integer;
pragma Import( C,
Unlink, "unlink" );
subtype PSTR is PCHAR; -- winnt.h
type PCCH
is access constant CHAR; --
winnt.h
subtype LPCSTR is PCCH; -- Win32
subtype PCSTR is PCCH; -- Win32
subtype SHORT is Interfaces.C.Short; -- winnt.h
subtype USHORT is
Interfaces.C.Unsigned_Short; -- same as Win32
subtype WORD is USHORT; --
same as Win32
type VOID
is null record; --
same as Win32
subtype PCVOID is PVOID;
subtype LPCVOID is
PCVOID; -- Win32
type PVOID_Array -- rpcproxy.h
is array( Natural range <> ) of
aliased PVOID;
subtype INT is Interfaces.C.Int; -- Win32
subtype UINT is Interfaces.C.Unsigned; -- Win32
type SOCKET is new
UINT; --
winsock.h:45
subtype LONG is Interfaces.C.Long; -- Win32
type PLONG is access all LONG;
type
BY_HANDLE_FILE_INFORMATION;
-- winbase.h:2030
type
LPBY_HANDLE_FILE_INFORMATION
-- winbase.h:2041
is access all
BY_HANDLE_FILE_INFORMATION;
function
to_LPSYSTEMTIME -- convert address to pointer
is new
Unchecked_Conversion( Source => System.Address,
Target => LPSystemTime );
type
SECURITY_ATTRIBUTES;
-- winbase.h:187
type PSECURITY_ATTRIBUTES
is access all SECURITY_ATTRIBUTES; -- winbase.h:191
subtype
LPSECURITY_ATTRIBUTES is PSECURITY_ATTRIBUTES;
type PHANDLE is access
all HANDLE; -- winnt.h:145
type LIST_ENTRY; -- winnt.h:446
type PLIST_ENTRY is
access all LIST_ENTRY; --
winnt.h:449
type
RTL_CRITICAL_SECTION;
-- winnt.h:3953
type
PRTL_CRITICAL_SECTION is access all
-- winnt.h:3977
RTL_CRITICAL_SECTION;
type PCRITICAL_SECTION
is access all RTL_CRITICAL_SECTION;
subtype
LPCRITICAL_SECTION is PCRITICAL_SECTION; -- winbase.h:231
type
RTL_CRITICAL_SECTION_DEBUG;
-- winnt.h:3950
type
PRTL_CRITICAL_SECTION_DEBUG is access all -- winnt.h:3959
RTL_CRITICAL_SECTION_DEBUG;
type SOCKADDR; --
winsock.h:473
type PSOCKADDR is
access all SOCKADDR; --
winsock.h:830
type WSADATA; --
winsock.h:328
type LPWSADATA is
access all WSADATA; -- winsock.h:338
---------------------------------------------------------------------------
--| Notes: Constants
ERROR_ALREADY_EXISTS : constant
:= 183; -- winerror.h:1370
ERROR_IO_PENDING : constant := 997; -- winerror.h:1874
FILE_SHARE_READ : constant := 16#1#; -- winnt.h:1848
FILE_ATTRIBUTE_NORMAL :
constant := 16#80#; -- winnt.h:1855
GENERIC_READ : constant := 16#80000000#; -- winnt.h:1967
GENERIC_WRITE :
constant := 16#40000000#; --
winnt.h:1968
STATUS_WAIT_0 : constant DWORD := 16#0#; --
winnt.h:702
STATUS_TIMEOUT :
constant DWORD := 16#102#; -- winnt.h:705
WAIT_FAILED : constant DWORD := 16#ffffffff#; --
winbase.h:66
WAIT_OBJECT_0 : DWORD
renames STATUS_WAIT_0; -- winbase.h:67
WAIT_TIMEOUT : DWORD renames STATUS_TIMEOUT; -- winbase.h:72
PIPE_ACCESS_DUPLEX : constant := 16#3#; -- winbase.h:133
CREATE_SUSPENDED : constant := 16#4#; -- winbase.h:538
NORMAL_PRIORITY_CLASS :
constant := 16#20#; -- winbase.h:544
IDLE_PRIORITY_CLASS :
constant := 16#40#; -- winbase.h:545
HIGH_PRIORITY_CLASS :
constant := 16#80#; -- winbase.h:546
REALTIME_PRIORITY_CLASS :
constant := 16#100#; -- winbase.h:547
BELOW_NORMAL_PRIORITY_CLASS : constant := 16#4000#; -- newer windbase.h
ABOVE_NORMAL_PRIORITY_CLASS :
constant := 16#8000#; -- newer windbase.h
THREAD_PRIORITY_LOWEST :
constant := -2; -- winbase.h:557
THREAD_PRIORITY_BELOW_NORMAL :
constant := -1; -- winbase.h:558
THREAD_PRIORITY_NORMAL :
constant := 0; -- winbase.h:559
THREAD_PRIORITY_HIGHEST :
constant := 2; -- winbase.h:560
THREAD_PRIORITY_ABOVE_NORMAL :
constant := 1; -- winbase.h:561
THREAD_PRIORITY_ERROR_RETURN :
constant := 16#7fffffff#;
THREAD_PRIORITY_TIME_CRITICAL : constant := 15; -- winbase.h:564
THREAD_PRIORITY_IDLE :
constant := -15; -- winbase.h:565
FILE_END : constant := 2; -- winbase.h:62
CREATE_ALWAYS :
constant := 2; --
winbase.h:117
OPEN_EXISTING :
constant := 3; --
winbase.h:118
PIPE_WAIT : constant := 16#0#; -- winbase.h:146
PIPE_READMODE_MESSAGE : constant
:= 16#2#; -- winbase.h:149
PIPE_TYPE_MESSAGE : constant := 16#4#; -- winbase.h:151
PIPE_UNLIMITED_INSTANCES : constant := 255; -- winbase.h:157
function To_Handle is
new Unchecked_Conversion
( Source => Integer,
Target => HANDLE );
INVALID_HANDLE_VALUE -- winbase.h:57
: constant HANDLE :=
To_Handle(-1);
IPPROTO_TCP : constant := 6; -- winsock.h:202
WSADESCRIPTION_LEN : constant
:= 256; -- winsock.h:325
WSASYS_STATUS_LEN : constant := 128; -- winsock.h:326
SOCK_STREAM : constant := 1; -- winsock.h:377
AF_INET : constant := 2; -- winsock.h:448
PF_INET : constant := 2; -- winsock.h:492
INVALID_SOCKET : constant := UINT'Last;
---------------------------------------------------------------------------
--| Notes: Unchecked
Conversion functions
---------------------------------------------------------------------------
--| Notes: Ada
functions to access C functions
type
LPTHREAD_START_ROUTINE is access function
return DWORD;
pragma Convention(
Stdcall, LPTHREAD_START_ROUTINE ); -- winbase.h:227
type PHANDLER_ROUTINE
is access function -- same as
Win32.Wincon
( CtrlType : DWORD
) return BOOL;
pragma Convention(
Stdcall, PHANDLER_ROUTINE );
function to_PHandler --
convert one access type to the other
is new
Unchecked_Conversion( Source => System.Address,
Target => PHandler_Routine );
function Bind --
winsock.h:705
--| Bind WinSock server
socket
( S : SOCKET;
Addr : PSOCKADDR; --ac_SOCKADDR_t;
Namelen : INT
) return INT;
pragma Import( Stdcall,
bind, "bind" ); --
winsock.h:705
function C_Accept -- winsock.h:702
--| Accept WinSock
connection
( S : SOCKET;
Addr : access SOCKADDR;
Addrlen : access INT
) return SOCKET;
pragma Import( Stdcall,
c_accept, "accept" ); --
winsock.h:702
function
CloseSocket --
winsock.h:707
--| Close WinSock
Socket
( s : SOCKET
) return INT;
pragma Import( Stdcall,
closesocket, "closesocket" ); -- winsock.h:707
function
CreateFile --
winbase.h:4745
( FileName : LPCSTR;
DesiredAccess : DWORD;
ShareMode : DWORD;
SecurityAttributes :
LPSECURITY_ATTRIBUTES;
CreationDisposition :
DWORD;
FlagsAndAttributes : DWORD;
TemplateFile : HANDLE
) return HANDLE;
function
CreateMailslot --
winbase.h:2877
( Name : LPCSTR;
MaxMessageSize : DWORD;
ReadTimeout : DWORD;
SecurityAttributes :
LPSECURITY_ATTRIBUTES
) return HANDLE;
pragma Import( Stdcall,
CreateMailslot, "CreateMailslotA" ); -- winbase.h:2877
-- CreateMailslot and
CreateMailslotA are the same function
function
CreateThread -- winbase.h:1598
( ThreadAttributes :
LPSECURITY_ATTRIBUTES;
StackSize : DWORD;
StartAddress : LPTHREAD_START_ROUTINE;
Parameter : LPVOID;
CreationFlags : DWORD;
ThreadId : LPDWORD
) return HANDLE;
pragma Import( Stdcall,
CreateThread, "CreateThread" ); -- winbase.h:1598
function Connect --
winsock.h:709
--| Connect to WinSock
Socket
( s : SOCKET;
Name : PSOCKADDR;
Namelen : INT
) return INT;
pragma Import( Stdcall,
connect, "connect" ); --
winsock.h:709
function
ConnectNamedPipe --
winbase.h:2816
( NamedPipe : HANDLE;
Overlapped :
LPOVERLAPPED
) return BOOL;
function
CreateNamedPipe -- winbase.h:4987
( Name : LPCSTR;
OpenMode : DWORD;
PipeMode : DWORD;
MaxInstances : DWORD;
OutBufferSize : DWORD;
InBufferSize : DWORD;
DefaultTimeOut : DWORD;
SecurityAttributes :
LPSECURITY_ATTRIBUTES
) return HANDLE;
function
DisconnectNamedPipe --
winbase.h:2824
( NamedPipe : HANDLE
) return BOOL;
procedure
EnterCriticalSection --
winbase.h:1850
( CriticalSection :
LPCRITICAL_SECTION );
procedure
ExitProcess --
winbase.h:1500
( ExitCode : UINT );
MaxArguments: constant
:= 50; -- stdarg.ads
-- "&"
and Concat functions raise Constraint_Error if more than
-- MaxArguments integer
paramters are catenated.
-- If you change this,
change it in var.c also.
type ArgList is
private; --
stdarg.ads
-- An empty arglist, to
be used in constructors:
function Empty return
ArgList; -- stdarg.ads
subtype C_Param is
Interfaces.C.Long; --
stdarg.ads
type Param_Access is
private; --
stdarg-impl.ads
function
Address_of_First_Arg (Args: ArgList) return Param_Access;
function
FormatMessage -- winbase.h:2767
( Flags : DWORD;
Source : LPCVOID;
MessageId : DWORD;
LanguageId : DWORD;
Buffer : LPSTR;
Size : DWORD;
Arguments : ArgList := Empty
) return DWORD;
function GetCurrentProcess -- winbase.h:1486
return HANDLE;
function
GetCurrentProcessId --
winbase.h:1493
return DWORD;
function
GetExitCodeProcess --
winbase.h:1515
( Process : HANDLE;
ExitCode : LPDWORD
) return BOOL;
function
GetExitCodeThread --
winbase.h:1686
( Thread : HANDLE;
ExitCode : LPDWORD
) return BOOL;
function
GetFileInformationByHandle --
winbase.h:2046
( File : HANDLE;
FileInformation :
LPBY_HANDLE_FILE_INFORMATION
) return BOOL;
pragma Import( Stdcall,
GetFileInformationByHandle, -- winbase.h:2046
"GetFileInformationByHandle" );
function
GetHostname --
winsock.h:763
--| Get hostname for
WinSock
( Name : PSTR;
Namelen : INT
) return INT;
pragma Import( Stdcall,
gethostname, "gethostname" ); -- winsock.h:763
procedure
GetLocalTime --
winbase.h:2627
( SystemTime : LPSYSTEMTIME
);
function
GetPriorityClass --
winbase.h:6260
( Process : HANDLE
) return DWORD;
function
GetThreadPriority --
winbase.h:1653
( Thread : HANDLE
) return INT;
function htons -- winsock.h:724
( Hostshort : USHORT
) return USHORT;
pragma Import( Stdcall,
htons, "htons" ); --
winsock.h:724
function inet_addr -- winsock.h:726
( Cp : PCSTR
) return ULONG;
pragma Import( Stdcall,
inet_addr, "inet_addr" ); -- winsock.h:726
procedure
InitializeCriticalSection
-- winbase.h:1843
( CriticalSection :
LPCRITICAL_SECTION );
procedure
LeaveCriticalSection --
winbase.h:1857
( CriticalSection :
LPCRITICAL_SECTION );
function Listen --
winsock.h:730
--| Mark the WinSock
socket so it will listen for incoming connections
( S : SOCKET;
Backlog : INT
) return INT;
pragma Import( Stdcall,
listen, "listen" ); --
winsock.h:730
function Recv --
winsock.h:736
--| Receive from
WinSock socket
( S : SOCKET;
Buf : PSTR;
Len : INT;
Flags : INT
) return INT;
pragma Import( Stdcall,
recv, "recv" ); --
winsock.h:736
function
ResumeThread --
winbase.h:1805
( Thread : HANDLE
) return DWORD;
pragma Import( Stdcall,
ResumeThread, "ResumeThread" ); -- winbase.h:1805
function Send -- winsock.h:744
--| Transmit via
WinSock socket
( S : SOCKET;
Buf : PCSTR;
Len : INT;
Flags : INT
) return INT;
pragma Import( Stdcall,
send, "send" ); --
winsock.h:744
function
SetConsoleCtrlHandler -- same as Win32.Wincon
( HandlerRoutine :
PHANDLER_ROUTINE;
Add : BOOL
) return BOOL;
function
SetFilePointer --
winbase.h:2134
( File : HANDLE;
DistanceToMove : LONG;
DistanceToMoveHigh :
PLONG;
MoveMethod : DWORD
) return DWORD;
pragma Import( Stdcall,
SetFilePointer, "SetFilePointer" ); -- winbase.h:2134
function
SetPriorityClass --
winbase.h:6252
( Process : HANDLE;
PriorityClass : DWORD
) return BOOL;
function
SetThreadPriority --
winbase.h:1645
( Thread : HANDLE;
Priority : INT
) return Boolean;
--BOOL;
function
Socket_Func --
winsock.h:754
( Af : INT;
C_Type : INT;
Protocol : INT
) return SOCKET;
pragma Import( Stdcall,
socket_func, "socket" ); -- winsock.h:754
function
SystemTimeToFileTime --
winbase.h:2685
( SystemTime :
PSYSTEMTIME;
FileTime : LPFILETIME
) return BOOL;
pragma Import( Stdcall,
SystemTimeToFileTime, "SystemTimeToFileTime"); -- winbase.h:2685
function
TerminateThread --
winbase.h:1678
( Thread : HANDLE;
ExitCode : DWORD
) return BOOL;
function WaitForSingleObject -- winbase.h:1908
( ObjectHandle :
HANDLE;
Milliseconds : DWORD
) return DWORD;
function WriteFile -- winbase.h:2084
( File : HANDLE;
Buffer : LPCVOID;
NumberOfBytesToWrite : DWORD;
NumberOfBytesWritten
: LPDWORD;
Overlapped : LPOVERLAPPED
) return BOOL;
function WSACleanup
return INT; --
winsock.h:778
pragma Import( Stdcall,
WSACleanup, "WSACleanup" ); -- winsock.h:778
function
WSAGetLastError return INT; --
winsock.h:782
pragma Import( Stdcall,
WSAGetLastError, "WSAGetLastError" ); -- winsock.h:782
function
WSAStartup --
winsock.h:776
( VersionRequired :
WORD;
WSAData : LPWSADATA
) return INT;
pragma Import( Stdcall,
WSAStartup, "WSAStartup" ); -- winsock.h:776
---------------------------------------------------------------------------
--| Notes: Structures
type FILETIME -- winbase.h:204
is record
LowDateTime : DWORD;
HighDateTime : DWORD;
end record;
type
BY_HANDLE_FILE_INFORMATION
-- winbase.h:2030
is record
FileAttributes : DWORD;
CreationTime : FILETIME;
LastAccessTime : FILETIME;
LastWriteTime : FILETIME;
VolumeSerialNumber :
DWORD;
FileSizeHigh : DWORD;
FileSizeLow : DWORD;
NumberOfLinks : DWORD;
FileIndexHigh : DWORD;
FileIndexLow : DWORD;
end record;
type LIST_ENTRY -- winnt.h:446
is record
Flink: PLIST_ENTRY;
Blink: PLIST_ENTRY;
end record;
type OVERLAPPED --
winbase.h:179
is record
Internal : DWORD;
InternalHigh : DWORD;
Offset : DWORD;
OffsetHigh : DWORD;
Event : HANDLE;
end record;
type
RTL_CRITICAL_SECTION
-- winnt.h:3953
is record
DebugInfo : PRTL_CRITICAL_SECTION_DEBUG;
LockCount : LONG;
RecursionCount: LONG;
OwningThread : HANDLE;
LockSemaphore :
HANDLE;
Reserved : DWORD;
end record;
type
RTL_CRITICAL_SECTION_DEBUG
-- winnt.h:3950
is record
C_Type : WORD;
CreatorBackTraceIndex: WORD;
CriticalSection : PRTL_CRITICAL_SECTION;
ProcessLocksList : LIST_ENTRY;
EntryCount : DWORD;
ContentionCount : DWORD;
Depth : DWORD;
OwnerBackTrace : PVOID_Array(0..4);
end record;
type
SECURITY_ATTRIBUTES
-- winbase.h:187
is record
Length : DWORD;
SecurityDescriptor :
LPVOID;
InheritHandle : BOOL;
end record;
type SOCKADDR -- winsock.h:473
is record
Family : USHORT;
Data : WSA_CHAR_Array(0..13);
end record;
type SYSTEMTIME1 -- same as
Winbase SYSTEMTIME
is record
Year : WORD;
Month : WORD;
DayOfWeek
: WORD;
Day : WORD;
Hour : WORD;
Minute : WORD;
Second : WORD;
Milliseconds: WORD;
end record;
type WSADATA --
winsock.h:328
is record
Version : WORD;
HighVersion : WORD;
Description : WSA_CHAR_Array(0..WSADESCRIPTION_LEN);
SystemStatus :
WSA_CHAR_Array(0..WSASYS_STATUS_LEN);
MaxSockets : USHORT;
MaxUdpDg : USHORT;
VendorInfo : PSTR;
end record;
private
type File_Handle is new
Integer;
function to_File_Handle
-- convert integer to file handle
is new
Unchecked_Conversion( Source => Integer,
Target => File_Handle );
Invalid_File_Handle :
constant File_Handle := to_File_Handle(-1);
Invalid_Pipe_Handle :
constant Pipe_Handle := Invalid_File_Handle;
-- The following type
is similar to that in s-osinte.ads of GNAT rts native
-- for a system thread
id
type Thread_Handle_Type
is new Interfaces.C.unsigned_long;
Null_Thread_Handle
: constant
Thread_Handle_Type
:= 0;
type PId_t is new
Integer;
Invalid_PId : constant
PId_t := -1;
Null_Thread_Address
--| Null system address
for thread
: constant
Thread_Address_Type := Thread_Address_Type(System.Null_Address);
type ArgVector is
array(Integer range <>) of aliased C_Param; -- stdarg.ads
type ArgBlock is
record -- stdarg.ads
Vector : ArgVector(1..MaxArguments) := (others
=> 0);
RefCount : Natural := 1;
CurrentArgs : Natural
:= 0;
FirstHole : Natural := 0;
end record;
AS: constant :=
MaxArguments*C_Param'Size; -- stdarg.ads
NS: constant :=
Natural'Size; -- stdarg.ads
-- On HP target this
record must be aligned at mod 8, like a double.
-- Maybe on Alpha too,
not sure.
-- On other targets the
8 could be changed to 4.
-- For i386/NT 4 is the
size to use
for ArgBlock use record
at mod 4; -- stdarg.ads
Vector at 0 range 0..AS-1;
RefCount at AS range 0..NS-1;
CurrentArgs at
AS+NS range 0..NS-1;
FirstHole at AS+NS+NS range 0..NS-1;
end record;
type ArgBlockP is
access ArgBlock; -- stdarg.ads
type ArgList is -- stdarg.ads
new
Ada.Finalization.Controlled with
record
Contents:
ArgBlockP;
end record;
package Arith is new
Interfaces.C.Pointers( -- stdarg-impl.ads
Integer, C_Param, ArgVector, 0);
type Param_Access is
new Arith.Pointer; --
stdarg-impl.ads
pragma Convention( C,
BY_HANDLE_FILE_INFORMATION ); -- winbase.h:2030
pragma Convention( C,
FILETIME ); --
winbase.h:204
pragma Convention( C,
LIST_ENTRY ); --
winnt.h:446
pragma Convention( C,
OVERLAPPED ); -- winbase.h:179
pragma Convention( C,
SECURITY_ATTRIBUTES ); --
winbase.h:187
pragma Convention( C,
RTL_CRITICAL_SECTION ); --
winnt.h:3953
pragma Convention( C,
RTL_CRITICAL_SECTION_DEBUG ); -- winnt.h:3950
pragma Convention( C,
SOCKADDR ); --
winsock.h:473
pragma Convention( C,
SYSTEMTIME1 ); --
winbase.h:213
pragma Convention( C,
WSADATA ); --
winsock.h:328
end Exec_Itf;
exec_itf.adb:
Various exec_itf procedures and functions output a
"<<< … >>> message so that the user can detect if the
wrong routine is being used. That is,
these messages shouldn't appear in the log output.
The Windows version of exec_itf.adb is
with Ada.Directories;
with Console; --<<<debug>>>
with GNAT.OS_Lib;
with GNAT.Sockets.Thin;
with GNAT.Threads;
with Interfaces.C;
with Interfaces.C.Strings;
with Machine;
with Numeric_Conversion;
with String_Tools;
package body Exec_Itf is
-->>> temp
Length
--| Length of current
directory/folder path
: Integer := 0;
Current_Directory :
String(1..240);
-->>> temp above
FALSEint : constant :=
0; -- windef.h
TRUEint : constant := 1; -- windef.h
Linux_Config_File_Name
: constant Config_File_Name_Var_Type
:= ( Count => 46,
Value =>
"/home/clayton/Source/EP/Apps-Configuration.dat " );
Windows_Config_File_Name
: constant
Config_File_Name_Var_Type
:= ( Count =>
35, -- Windows
Value =>
"C:\Source\EP\Apps-Configuration.dat " );
function
Config_File_Name
return
Config_File_Name_Var_Type is
begin --
Config_File_Name
if Op_Sys = Linux
then
return
Linux_Config_File_Name;
else
return
Windows_Config_File_Name;
end if;
end Config_File_Name;
procedure Set_Op_Sys is
begin -- Set_Op_Sys
--| Logic_Step:
--| Obtain current folder name.
Length :=
Ada.Directories.Current_Directory'Length;
declare
Current_Dir
--| Path name sized
to that to be returned
:
String(1..Length);
begin
Current_Dir :=
Ada.Directories.Current_Directory;
Current_Directory := ( others => ' ' );
Current_Directory(1..Length) := Current_Dir;
--| Logic_Step:
--| Determine operating system that running
under from the name.
if Length > 2
and then
(
Current_Dir(1..2) = "C:" or else Current_Dir(1..2) = "c:" )
then
Op_Sys :=
Exec_Itf.Windows;
console.write("Set_Op_Sys is Windows");
elsif Length > 6
and then
(
Current_Dir(1..6) = "/home/" or else Current_Dir(1..6) =
"\home\" )
then
Op_Sys :=
Exec_Itf.Linux;
console.write("Set_Op_Sys is Linux");
end if;
end;
end Set_Op_Sys;
function GetHostName
( Name : in System.Address;
Length : in
Interfaces.C.int --Computer_Name_Type'last
) return
Interfaces.C.int; --Interfaces.C.int;
-- Return host name
pragma Import(C,
GetHostName, "gethostname");
function
GetComputerName
( Name : in System.Address;
Length : in
Computer_Name_Type
) return Integer is
ErrorCode :
Interfaces.C.int;
HostName :
String(1..Computer_Name_Type'last);
for HostName use at
Name;
Result : Integer;
begin --
GetComputerName
console.write_error("GetComputerName");
if Op_Sys = Linux
then
ErrorCode :=
GetHostName( Name => Name,
Length => Interfaces.C.int(Length) );
else
ErrorCode :=
GNAT.Sockets.Thin.C_Gethostname( Name
=> Name,
NameLen =>
Interfaces.C.int(Length) );
end if;
Result :=
Integer(ErrorCode);
if Result = 0 then --
no error
Result :=
Computer_Name_Type'last;
for I in
1..Computer_Name_Type'last loop
if HostName(I) = ASCII.NUL then --
trailing NUL found
Result := I-1;
-- return length of name
exit; -- loop
end if;
end loop;
console.write(HostName(1..Result),Result);
end if;
return Result; --
return -1 for error or # of chars in name
end GetComputerName;
procedure Exit_to_OS
( Status : Integer := 0
) is
begin -- Exit_to_OS
GNAT.OS_Lib.OS_Exit(
Status );
end Exit_to_OS;
function Errno return
Integer;
-- Return the task-safe
last error number
pragma Import (C,
Errno, "__get_errno");
function
GetLastErrorWindows return DWORD;
-- winbase.h:1703
pragma Import( Stdcall,
GetLastErrorWindows, "GetLastError" ); -- winbase.h:1703
--<<< not for Linux >>>
function GetLastError
return Integer is
LastError : DWORD;
begin -- GetLastError
if Op_Sys = Linux
then
return Errno;
else
LastError :=
GetLastErrorWindows;
return
Integer(LastError);
-- return 0; --
can't use above in Linux build
end if;
end GetLastError;
procedure Set_Errno
( Errno : Integer );
-- Set last error
number
pragma Import (C,
Set_Errno, "__set_errno");
type String255 is new
String(1..255);
type StrPtr is access
String255;
-- error messages are
no longer than 255 characters
function StrError
( Error_Number :
Integer
) return StrPtr;
pragma Import( C,
StrError, "strerror" );
procedure Log_Error is
Error_Num
: Integer;
Error_Ptr
: Exec_Itf.StrPtr;
begin -- Log_Error
Error_Num := Errno;
-- get last error number
if Error_Num = 4 then
--EINTR
end if;
Error_Ptr :=
StrError( Error_Number => Error_Num );
declare
Length : Integer :=
0;
function to_Addr is
new Unchecked_Conversion( Source => StrPtr,
Target =>
System.Address );
Error_Msg :
String255; -- overlay
Ada string on
for Error_Msg use
at to_Addr(Error_Ptr); -- error text
Err_No :
Numeric_Conversion.String_Type;
Err :
String(1..255) := ( others => ASCII.NUL );
Msg :
String(1..10+255);
begin
-- Copy error text
at StrPtr while ignoring following text
for I in 1..255
loop
exit when
Error_Msg(I) = ASCII.NUL;
Err(I) := Error_Msg(I);
Length := I;
end loop;
Msg(1..6) :=
"Error ";
Err_No :=
Numeric_Conversion.Integer_to_ASCII(Error_Num,3);
Msg(7..Err_No.Length+6) := Err_No.Value(1..Err_No.Length); -- ASCII
value
for I in Err_No.Length+7..10
loop -- insert following space(s)
Msg(I) := ' ';
end loop;
Msg(11..Length+10)
:= Err(1..Length); -- copy error text
Console.Write(
Msg(1..Length+10) );
end;
--| Logic_Step:
--| Clear the last reported error so the next
time this routine is
--| called, any last error will be different
from this one.
Set_Errno(0);
end Log_Error;
--
**********************************************************
-- This package
describes the differences in machine
-- architectures that
need to be known by Stdarg.
--
-- I386 is Intel
386/486/Pentium PC's
-- Sparc is Sun-4
Sparcstation and Sparcserver
-- HP is
Hewlett-Packard HP-9000 series 700 and 800
-- Mips is machines
based on the MIPS chip, such as SGI
-- PowerPC is
Apple-IBM-Motorola Power PC, and IBM RS/6000
-- Alpha is the Digital
Equipment Corporation chip.
--
-- To build these
packages for a different architecture,
-- change the constant
This_Arch to one of the allowed values
-- and recompile.
--
**********************************************************
type Arch is (I386,
Sparc, HP, Mips, Alpha, PowerPC); -- stdarg-machine.ads
This_Arch: constant
Arch := I386; --
stdarg-machine.ads
type Stack_Growth_Direction --
stdarg-machine.ads
is ( Up, -- toward address 0
Down ); -- toward high numbered addresses
type Which_Arg is
(Ellipsis, VA_List); -- Stdarg-impl.adb
type
Arch_Description_Rec
is record
Int_Param_Alignment,
Float_Param_Alignment
: Positive;
Stack_Growth : Stack_Growth_Direction;
end record;
SU : constant :=
System.Storage_Unit;
Arch_Description
: constant array (Arch)
of Arch_Description_Rec
:= ( I386 => (
Int_Param_Alignment => C_Param'Size/SU,
Float_Param_Alignment =>
C_Param'Size/SU,
Stack_Growth => Up )
, Sparc => (
Int_Param_Alignment => C_Param'Size/SU,
Float_Param_Alignment =>
C_Param'Size/SU,
Stack_Growth => Up )
, HP => (
Int_Param_Alignment => C_Param'Size/SU,
Float_Param_Alignment =>
Interfaces.C.Double'Size/SU,
Stack_Growth => Down )
, Mips => (
Int_Param_Alignment => C_Param'Size/SU,
Float_Param_Alignment =>
Interfaces.C.Double'Size/SU,
Stack_Growth => Up )
, Alpha => (
Int_Param_Alignment => C_Param'Size/SU,
Float_Param_Alignment =>
Interfaces.C.Double'Size/SU,
Stack_Growth => Up )
, PowerPC => (
Int_Param_Alignment =>
C_Param'Size/SU,
Float_Param_Alignment =>
C_Param'Size/SU,
Stack_Growth => Up )
);
Desc : Arch_Description_Rec
renames -- stdarg-machine.ads
Arch_Description(This_Arch);
Int_Param_Alignment : Positive renames
Desc.Int_Param_Alignment; --
stdarg-machine.ads
Float_Param_Alignment:
Positive renames Desc.Float_Param_Alignment; -- stdarg-machine.ads
Stack_Growth : Stack_Growth_Direction renames
Desc.Stack_Growth; -- stdarg-machine.ads
Param_Size : constant Positive :=
C_Param'Size/SU; --
stdarg-machine.ads
function
Address_of_Arg --
Stdarg-impl.adb
( Args : ArgList;
Which : Which_Arg
) return Param_Access
is
begin
if
Args.Contents.CurrentArgs = 0 then
return null; --
might not be an error
end if;
if This_Arch = Alpha
then
return
Args.Contents.Vector(7)'access;
elsif Stack_Growth =
Up then
return
Args.Contents.Vector(1)'access;
elsif Which =
Ellipsis then
return
Args.Contents.Vector(MaxArguments-Args.Contents.CurrentArgs+1)'access;
else
declare
use Arith;
P : Pointer :=
Args.Contents.Vector(MaxArguments)'access;
begin
return
Param_Access(P+1);
end;
end if;
end Address_of_Arg;
function
Address_of_First_Arg --
Stdarg-impl.adb
( Args : ArgList
) return Param_Access
is
begin
return
Address_of_Arg(Args, Ellipsis);
end
Address_of_First_Arg;
function Empty return ArgList
is -- Stdarg.adb
Res: ArgList;
begin
Res.Contents := new
ArgBlock;
--
Res.Contents.RefCount := 2; -- GNAT bug
return Res;
end Empty;
function FormatMessage
-- only for Windows
( Flags : DWORD;
Source : LPCVOID;
MessageId : DWORD;
LanguageId : DWORD;
Buffer : LPSTR;
Size : DWORD;
Arguments : ArgList := Empty
) return DWORD is
function Doit --<<< can't use with Linux
>>>
( dwFlags : DWORD;
lpSource : LPCVOID;
dwMessageId : DWORD;
dwLanguageId :
DWORD;
lpBuffer : LPSTR;
nSize : DWORD;
Arguments : access Param_Access
--Stdarg.Impl.Param_Access
) return DWORD;
pragma Import( Stdcall,
Doit, "FormatMessageA" );
--<<< not for Linux >>>
Param_Addr
: aliased
Param_Access
:=
Address_of_First_Arg(Arguments);
begin
if Op_Sys = Linux
then
Console.Write_Error("<<<FormatMessage Linux
entered>>>");
return Falseint;
else
return Doit( Flags,
Source, MessageId, LanguageId,
Buffer, Size, Param_Addr'access );
-- strange
end if;
end FormatMessage;
--<<< not for Linux >>>
function
SetConsoleCtrlHandlerWindows
-- same as Win32.Wincon
( HandlerRoutine :
PHANDLER_ROUTINE;
Add : BOOL
) return BOOL;
pragma Import( Stdcall,
SetConsoleCtrlHandlerWindows, "SetConsoleCtrlHandler" ); --
wincon.h:571
function
SetConsoleCtrlHandler --
same as Win32.Wincon
( HandlerRoutine :
PHANDLER_ROUTINE;
Add : BOOL
) return BOOL is
begin
if Op_Sys = Linux
then
Console.Write_Error("<<<SetConsoleCtrlHandler Linux
entered>>>");
return Falseint;
else
return SetConsoleCtrlHandlerWindows(
HandlerRoutine => HandlerRoutine,
Add => Add );
end if;
end
SetConsoleCtrlHandler;
--<<< not for Linux >>>
procedure
InitializeCriticalSectionWindows -- winbase.h:1843
( CriticalSection :
LPCRITICAL_SECTION
);
pragma Import( Stdcall,
InitializeCriticalSectionWindows, --
winbase.h:1843
"InitializeCriticalSection");
procedure
InitializeCriticalSection
-- winbase.h:1843
( CriticalSection :
LPCRITICAL_SECTION
) is
begin --
InitializeCriticalSection
if Op_Sys = Linux
then
console.Write_Error("<<<InitializeCriticalSection Linux
entered>>>");
else
InitializeCriticalSectionWindows( CriticalSection => CriticalSection
);
end if;
end
InitializeCriticalSection;
--<<< not for Linux >>>
procedure
LeaveCriticalSectionWindows
-- winbase.h:1857
( CriticalSection :
LPCRITICAL_SECTION
);
pragma Import( Stdcall,
LeaveCriticalSectionWindows, --
winbase.h:1857
"LeaveCriticalSection" );
procedure
LeaveCriticalSection --
winbase.h:1857
( CriticalSection :
LPCRITICAL_SECTION
) is
begin --
LeaveCriticalSection
if Op_Sys = Linux
then
Console.Write_Error("<<<LeaveCriticalSection Linux
entered>>>");
else
LeaveCriticalSectionWindows( CriticalSection => CriticalSection );
end if;
end
LeaveCriticalSection;
---------------------------------------------------------------------------
-- Directories
type
Dir_Entity_Struct_Type
--| Linux note:
--| The only fields in the dirent structure that
are mandated by POSIX.1 are:
--| o d_name[], of unspecified size, with at
most NAME_MAX characters
--| preceding the terminating null byte; and
--| o (as an XSI extension) d_ino.
--| The other fields are unstandardized, and not
present on all systems.
is record
D_INo : Machine.Unsigned_Longword; -- File
system i-node number
-- The file serial
number, which distinguishes this file from all other
-- files on the same
device.
D_Off : Machine.Unsigned_Longword; -- i.e., of
type off_t
-- File offset,
measured in bytes from the beginning of a file or device.
-- off_t is normally
defined as a signed, 32-bit integer. In the
-- programming
environment which enables large files, off_t is defined
-- to be a signed,
64-bit integer.
D_Reclen :
Machine.Unsigned_Word;
D_Type : Machine.Unsigned_Byte;
D_Name : String(1..256); -- null terminated
end record;
type
Dir_Entity_Ptr_Type is access Dir_Entity_Struct_Type;
function OpenDir
( File_Name : String
--| Name of
directory; null terminated
) return
System.Address;
--| Pointer to opened
directory
pragma Import (C,
OpenDir, "__gnat_opendir");
function ReadDir
( Directory :
System.Address
--| Pointer to opened
directory
) return
Dir_Entity_Ptr_Type;
--| Return pointer to
directory entity
pragma Import( C,
ReadDir, "readdir" );
function ReadLink
( Proc : System.Address;
--| Pointer to null
terminated string
Buffer :
System.Address;
--| Pointer to buffer
for path
Length : Integer
--| Length of buffer
) return Integer;
--| Return number of
characters output to Buffer
-- pragma Import( C,
ReadLink, "readlink" );
-- needed for Linux
function ReadLink
( Proc : System.Address;
--| Pointer to null
terminated string
Buffer :
System.Address;
--| Pointer to buffer
for path
Length : Integer
--| Length of buffer
) return Integer is
begin -- ReadLink
Console.Write_Error("<<< ReadLink entered
>>>");
return -1;
end ReadLink;
--above to compile for Windows
---------------------------------------------------------------------------
-- Files
function
File_Descriptor_to_Handle
is new
Unchecked_Conversion( Source => GNAT.OS_Lib.File_Descriptor,
Target => File_Handle );
function
Handle_to_File_Descriptor
is new
Unchecked_Conversion( Source => File_Handle,
Target => GNAT.OS_Lib.File_Descriptor );
function to_Mode is new
Unchecked_Conversion( Source => Mode_Type,
Target =>
GNAT.OS_Lib.Mode );
function Close_File
( Handle : File_Handle
) return Boolean is
Status : Boolean;
begin -- Close_File
GNAT.OS_Lib.Close(
FD =>
Handle_to_File_Descriptor(Handle),
Status => Status );
return Status;
end Close_File;
function Create_File
( Name : String;
Mode : Mode_Type :=
Text
) return File_Handle is
-- Creates new file
with given name for writing, returning the file
-- descriptor for
subsequent use in Write calls. The file descriptor
-- returned is
Invalid_File_Handle if file cannot be successfully created
FileDesc :
GNAT.OS_Lib.File_Descriptor;
function
File_Descriptor_to_Handle
is new
Unchecked_Conversion( Source => GNAT.OS_Lib.File_Descriptor,
Target => File_Handle );
function to_Mode is
new Unchecked_Conversion( Source => Mode_Type,
Target =>
GNAT.OS_Lib.Mode );
begin -- Create_File
FileDesc :=
GNAT.OS_Lib.Create_File( Name =>
Name'address,
FMode =>
to_Mode(Mode) );
return
File_Descriptor_to_Handle( FileDesc );
end Create_File;
function
Create_New_File
( Name : String;
Mode : Mode_Type :=
Text
) return File_Handle is
-- Create new file with
given name for writing, returning file descriptor
-- for subsequent use
in Write calls. This differs from Create_File in
-- that it fails if the
file already exists. File descriptor returned is
-- Invalid_FD if the
file exists or cannot be created.
FileDesc :
GNAT.OS_Lib.File_Descriptor;
begin --
Create_New_File
FileDesc :=
GNAT.OS_Lib.Create_New_File( Name =>
Name,
FMode =>
to_Mode(Mode) );
return
File_Descriptor_to_Handle( FileDesc );
end Create_New_File;
function Open_Read
( Name : String;
Mode : Mode_Type :=
Text
) return File_Handle is
FileDesc :
GNAT.OS_Lib.File_Descriptor;
function
File_Descriptor_to_Handle
is new
Unchecked_Conversion( Source => GNAT.OS_Lib.File_Descriptor,
Target => File_Handle );
function to_Mode is
new Unchecked_Conversion( Source => Mode_Type,
Target =>
GNAT.OS_Lib.Mode );
begin -- Open_Read
FileDesc :=
GNAT.OS_Lib.Open_Read( Name =>
Name'address,
FMode => to_Mode(Mode) );
return
File_Descriptor_to_Handle( FileDesc );
end Open_Read;
function
Open_Read_Write
( Name : String;
Mode : Mode_Type :=
Text
) return File_Handle is
-- Open file Name for both reading and writing,
returning file
-- descriptor. File descriptor returned is
Invalid_FD if file cannot be
-- opened.
Handle :
GNAT.OS_Lib.File_Descriptor;
begin -- Open_Read_Write
Handle :=
GNAT.OS_Lib.Open_Read_Write( Name =>
Name,
FMode =>
to_Mode(Mode) );
return
File_Descriptor_to_Handle( Handle );
end Open_Read_Write;
function Read_File
( File : File_Handle;
Addr :
System.Address;
Num : Integer
) return Integer is
Bytes_Read : Integer
:= 0;
begin -- Read_File
Bytes_Read :=
GNAT.OS_Lib.Read( FD => Handle_to_File_Descriptor(File),
A => Addr, --Bytes'address,
N => Num );
return Bytes_Read;
exception
when others =>
Console.Write_Error("exec_itf Read_File exception");
return 0;
end Read_File;
function Write_File
--| Write Text to File
and return number of bytes written.
Strip internal
--| NULs if True.
( File : in File_Handle;
Text : in String;
Strip_NULs : in
Boolean := False
) return Integer is
Index : Integer := 0;
Length : Integer;
Result : Integer;
Text_Out :
String(1..Text'length+1);
begin -- Write_File
Length :=
Text'length;
Text_Out(1..Length)
:= Text;
Text_Out(Length+1) := ASCII.NUL;
-- Avoid the output
of nulls embedded in the text.
if Strip_NULs then
for I in 1..Length
loop
if Text_Out(I) /=
ASCII.NUL then
Index := Index
+ 1;
Text_Out(Index)
:= Text_Out(I);
end if;
end loop;
Length := Index;
Text_Out(Length+1)
:= ASCII.NUL;
end if;
Result :=
GNAT.OS_Lib.Write( FD => Handle_to_File_Descriptor(File),
A => Text_Out'address,
N => Length );
return Result;
end Write_File;
function Write_File
--| Write Len bytes at
Addr to File and return number of bytes written.
( File : File_Handle;
Addr :
System.Address;
Len : Integer
) return Integer is
Result : Integer;
begin -- Write_File
Result :=
GNAT.OS_Lib.Write( FD => Handle_to_File_Descriptor(File),
A => Addr,
--Bytes_Out'address,
N => Len );
return Result;
end Write_File;
---------------------------------------------------------------------------
-- Pipes
function MkFifo_Linux
( Path :
System.Address;
Mode : Mode_t
) return Integer;
-- pragma Import( C,
MkFifo_Linux, "mkfifo" );
-- above for Linux
function MkFifo_Linux
( Path :
System.Address;
Mode : Mode_t
) return Integer is
begin
Console.Write_Error("<<< MkFifo entered
>>>");
return -1;
end;
--<<< above to compile for Windows >>>
function MkFifo
( Path :
System.Address;
Mode : Mode_t
) return Integer is
begin -- MkFifo
if Op_Sys = Linux
then
return
MkFifo_Linux( Path => Path,
Mode => Mode );
else
return -1;
end if;
end MkFifo;
function
CloseHandleWindows
-- winbase.h:2171
( Object : HANDLE
) return BOOL;
--<<< not for Linux >>>
pragma Import( Stdcall,
CloseHandleWindows, "CloseHandle" ); -- winbase.h:2171
function
CloseHandle --
winbase.h:2171
( Object : HANDLE
) return BOOL is
begin -- CloseHandle
if Op_Sys = Linux
then
Console.Write_Error("<<<CloseHandle Linux
entered>>>");
return FALSEint;
else
return
CloseHandleWindows( Object => Object );
end if;
end CloseHandle;
function
CreateFileWindows
-- winbase.h:4745
( FileName : LPCSTR;
DesiredAccess : DWORD;
ShareMode : DWORD;
SecurityAttributes :
LPSECURITY_ATTRIBUTES;
CreationDisposition :
DWORD;
FlagsAndAttributes : DWORD;
TemplateFile : HANDLE
) return HANDLE;
pragma Import( Stdcall,
CreateFileWindows, "CreateFileA" ); -- winbase.h:4745
-- CreateFile and
CreateFileA are the same function
--<<< not for Linux >>>
function
CreateFile --
winbase.h:4745
( FileName : LPCSTR;
DesiredAccess : DWORD;
ShareMode : DWORD;
SecurityAttributes :
LPSECURITY_ATTRIBUTES;
CreationDisposition :
DWORD;
FlagsAndAttributes : DWORD;
TemplateFile : HANDLE
) return HANDLE is
begin -- CreateFile
if Op_Sys = Linux
then
Console.Write_Error("<<<CreateFile Linux
entered>>>");
return
System.Null_Address;
else
return
CreateFileWindows( FileName
=> FileName,
DesiredAccess =>
DesiredAccess,
ShareMode => ShareMode,
SecurityAttributes =>
SecurityAttributes,
CreationDisposition => CreationDisposition,
FlagsAndAttributes => FlagsAndAttributes,
TemplateFile =>
TemplateFile );
end if;
end CreateFile;
function
ConnectNamedPipeWindows
-- winbase.h:2816
( NamedPipe : HANDLE;
Overlapped :
LPOVERLAPPED
) return BOOL;
pragma Import( Stdcall,
ConnectNamedPipeWindows, "ConnectNamedPipe" ); -- winbase.h:2816
-- above for Windows
-- function
ConnectNamedPipeWindows
-- winbase.h:2816
-- ( NamedPipe : HANDLE;
-- Overlapped :
LPOVERLAPPED
-- ) return BOOL is
-- begin
-- return FALSEint;
-- end;
--<<< not for Linux >>>
function
ConnectNamedPipe
( NamedPipe : HANDLE;
Overlapped :
LPOVERLAPPED
) return BOOL is
begin --
ConnectNamedPipe
if Op_Sys = Linux
then
console.write_error("<<<ConnectNamedPipe Linux
entered>>>");
return FALSEint;
else
return
ConnectNamedPipeWindows( NamedPipe
=> NamedPipe,
Overlapped => Overlapped
);
end if;
end ConnectNamedPipe;
function
CreateNamedPipeWindows
-- winbase.h:4987
( Name : LPCSTR;
OpenMode : DWORD;
PipeMode : DWORD;
MaxInstances : DWORD;
OutBufferSize : DWORD;
InBufferSize : DWORD;
DefaultTimeOut : DWORD;
SecurityAttributes :
LPSECURITY_ATTRIBUTES
) return HANDLE;
pragma Import( Stdcall,
CreateNamedPipeWindows, "CreateNamedPipeA" ); -- winbase.h:4987
-- CreateNamedPipe and
CreateNamedPipeA are the same function
--<<< not for Linux >>>
-- function
CreateNamedPipeWindows
-- winbase.h:4987
-- ( Name : LPCSTR;
-- OpenMode : DWORD;
-- PipeMode : DWORD;
-- MaxInstances : DWORD;
-- OutBufferSize : DWORD;
-- InBufferSize : DWORD;
-- DefaultTimeOut : DWORD;
-- SecurityAttributes
: LPSECURITY_ATTRIBUTES
-- ) return HANDLE is
-- begin
--Console.Write_Error("<<<CreateNamedPipeWindows
entered>>>");
-- return
System.Null_Address;
-- end;
function
CreateNamedPipe
( Name : LPCSTR;
OpenMode : DWORD;
PipeMode : DWORD;
MaxInstances : DWORD;
OutBufferSize : DWORD;
InBufferSize : DWORD;
DefaultTimeOut :
DWORD;
SecurityAttributes :
LPSECURITY_ATTRIBUTES
) return HANDLE is
begin --
CreateNamedPipe
if Op_Sys = Linux
then
Console.Write_Error("<<<CreateNamedPipe Linux
entered>>>");
return
System.Null_Address;
else
return CreateNamedPipeWindows
( Name => Name,
OpenMode =>
OpenMode,
PipeMode =>
PipeMode,
MaxInstances =>
MaxInstances,
OutBufferSize =>
OutBufferSize,
InBufferSize =>
InBufferSize,
DefaultTimeOut =>
DefaultTimeOut,
SecurityAttributes => SecurityAttributes );
end if;
end CreateNamedPipe;
function
DisconnectNamedPipeWindows
-- winbase.h:2824
( NamedPipe : HANDLE
) return BOOL;
--<<< not for Linux >>>
pragma Import( Stdcall,
DisconnectNamedPipeWindows, "DisconnectNamedPipe" ); --
winbase.h:2824
function
DisconnectNamedPipe --
winbase.h:2824
( NamedPipe : HANDLE
) return BOOL is
begin --
DisconnectNamedPipe
if Op_Sys = Linux
then
Console.Write_Error("<<<DisconnectNamedPipe Linux
entered>>>");
return FALSEint;
else
return
DisconnectNamedPipeWindows( NamedPipe => NamedPipe );
end if;
end
DisconnectNamedPipe;
function
ReadFileWindows
-- winbase.h:2095
( File : HANDLE;
Buffer : LPVOID;
NumberOfBytesToRead :
DWORD;
NumberOfBytesRead : LPDWORD;
Overlapped : LPOVERLAPPED
) return BOOL;
--<<< not for Linux >>>
pragma Import( Stdcall,
ReadFileWindows, "ReadFile"); -- winbase.h:2095
function ReadFile --
winbase.h:2095
( File : HANDLE;
Buffer : LPVOID;
NumberOfBytesToRead :
DWORD;
NumberOfBytesRead : LPDWORD;
Overlapped : LPOVERLAPPED
) return BOOL is
begin -- ReadFile
if Op_Sys = Linux
then
Console.Write_Error("<<<ReadFile Linux entered>>>");
return FALSEint;
else
return
ReadFileWindows( File => File,
Buffer => Buffer,
NumberOfBytesToRead => NumberOfBytesToRead,
NumberOfBytesRead => NumberOfBytesRead,
Overlapped =>
Overlapped );
end if;
end ReadFile;
function
WriteFileWindows
-- winbase.h:2084
( File : HANDLE;
Buffer : LPCVOID;
NumberOfBytesToWrite
: DWORD;
NumberOfBytesWritten
: LPDWORD;
Overlapped : LPOVERLAPPED
) return BOOL;
--<<< not for Linux >>>
pragma Import( Stdcall,
WriteFileWindows, "WriteFile" ); -- winbase.h:2084
function WriteFile -- winbase.h:2084
( File : HANDLE;
Buffer : LPCVOID;
NumberOfBytesToWrite
: DWORD;
NumberOfBytesWritten
: LPDWORD;
Overlapped : LPOVERLAPPED
) return BOOL is
begin -- WriteFile
if Op_Sys = Linux
then
Console.Write_Error("<<<WriteFile Linux
entered>>>");
return FALSEint;
else
return
WriteFileWindows( File
=> File,
Buffer =>
Buffer,
NumberOfBytesToWrite
=> NumberOfBytesToWrite,
NumberOfBytesWritten => NumberOfBytesWritten,
Overlapped =>
Overlapped );
end if;
end WriteFile;
---------------------------------------------------------------------------
-- Events
function
CreateEventWindows
-- winbase.h:3457
( EventAttributes :
LPSECURITY_ATTRIBUTES;
ManualReset : BOOL;
InitialState : BOOL;
Name : LPCSTR
) return HANDLE;
pragma Import( Stdcall,
CreateEventWindows, "CreateEventA" ); -- winbase.h:3457
-->>> above not for Linux
-- ) return HANDLE is
-- begin
-- return
System.Null_Address;
-- end;
--<<< to compile for Linux >>>
function Pipe -->> Linux
( Handle :
System.Address --File_Handle
) return Integer;
--pragma Import( C, Pipe, "pipe" );
--needed for Linux
function Pipe
( Handle :
System.Address --File_Handle
) return Integer is
begin -- Pipe
console.write_error("<<<Pipe
entered>>>");
return -1;
end Pipe;
-- only to compile in Windows
function
Thread_Lock_Init_Linux --> Linux
( Lock :
Thread_RWLock_Ptr_Type;
Attr :
Thread_RWLock_Attr_Ptr_Type
) return
Interfaces.C.int;
-- pragma Import( C,
Thread_Lock_Init_Linux, "pthread_rwlock_init" ); -- needed for Linux
--<<< not for Windows >>>
function
Thread_Lock_Init_Linux --> to compile for Windows
( Lock :
Thread_RWLock_Ptr_Type;
Attr :
Thread_RWLock_Attr_Ptr_Type
) return Interfaces.C.int
is
begin --
Thread_Lock_Init_Linux
Console.Write_Error("<<<Thread_Lock_Init_Linux
entered>>>");
return
Interfaces.C.int(-1);
end
Thread_Lock_Init_Linux;
function
Thread_Lock_Linux --> Linux
( Lock :
Thread_RWLock_Ptr_Type
) return
Interfaces.C.int;
-- Lock the thread
read/write lock semaphore
-- pragma Import( C,
Thread_Lock_Linux, "pthread_rwlock_wrlock" );
--<<< not for Windows >>>
function
Thread_Lock_Linux --> to compile for Windows
( Lock :
Thread_RWLock_Ptr_Type
) return
Interfaces.C.int is
begin --
Thread_Lock_Linux
Console.Write_Error("<<<Thread_Lock_Linux
entered>>>");
return
Interfaces.C.int(-1);
end Thread_Lock_Linux;
--needed for Linux
function
Thread_Lock_Init --> Linux
( Lock : Thread_RWLock_Ptr_Type;
Attr :
Thread_RWLock_Attr_Ptr_Type
) return
Interfaces.C.int is
begin
if Op_Sys = Linux
then
-- return
Thread_Lock_Init_Linux( Lock => Lock,
-- Attr => Attr );
Console.Write_Error("<<<Thread_Lock_Init_Linux
entered>>>");
return Interfaces.C.int(-1);
else -- Windows
return
Interfaces.C.int(-1);
end if;
end Thread_Lock_Init;
--needed for Linux
function Thread_Lock
--> Linux
( Lock :
Thread_RWLock_Ptr_Type
) return Interfaces.C.int
is
begin
if Op_Sys = Linux
then
-- return Thread_Lock_Linux( Lock =>
Lock );
Console.Write_Error("<<<Thread_Lock_Linux
entered>>>");
return
Interfaces.C.int(-1);
else -- Windows
return
Interfaces.C.int(-1);
end if;
end Thread_Lock;
function
Thread_Unlock_Linux
( Lock :
Thread_RWLock_Ptr_Type
) return
Interfaces.C.int;
-- Unlock the thread
read/write lock semaphore
-- pragma Import( C,
Thread_Unlock_Linux, "pthread_rwlock_unlock" );
-- above needed for Linux
function
Thread_Unlock_Linux
( Lock :
Thread_RWLock_Ptr_Type
) return
Interfaces.C.int is
begin
Console.Write_Error("<<<Thread_Unlock_Linux
entered>>>");
return
Interfaces.C.int(-1);
end
Thread_Unlock_Linux;
-- above to compile in Windows
function Thread_Unlock
( Lock :
Thread_RWLock_Ptr_Type
) return
Interfaces.C.int is
begin
if Op_Sys = Linux
then
return
Thread_Unlock_Linux( Lock => Lock );
else -- Windows
Console.Write_Error("<<<Thread_Unlock
entered>>>");
return Interfaces.C.int(-1);
end if;
end Thread_Unlock;
procedure Create_Event
( Name : in String;
--Thread_Event_Name_Type; --LPCSTR;
--<<< change to string
Id : in out Integer; --<<< change to string
Addr : in
System.Address --HANDLE
) is
begin -- Create_Event
if Exec_Itf.Op_Sys =
Exec_Itf.Linux then
declare
Result : Integer
:= -1;
begin
Result := Pipe(
Addr );
if Result < 0
then
Id := 0;
--else
-- Id leave unchanged
-- Handle leave unchanged
-- Status
:= No_Error;
end if;
end;
else
declare
Result : HANDLE
:= System.Null_Address;
for Result use at
Addr;
function to_Ptr
is new Unchecked_Conversion( Source => System.Address,
Target =>
LPCSTR );
use type
System.Address;
begin
Result :=
CreateEventWindows
(
EventAttributes => null,
ManualReset => TRUEint,
InitialState => FALSEint,
Name =>
to_Ptr(Name'address) );
if Result =
System.Null_Address then
Id := 0;
end if;
end;
end if;
end Create_Event;
function
ResetEventWindows --
winbase.h:1878
( Event : HANDLE
) return BOOL;
pragma Import( Stdcall,
ResetEventWindows, "ResetEvent" ); -- winbase.h:1878
--<<< not for Linux >>>
function Reset_Event
( Event : HANDLE
) return Boolean is
Result : BOOL :=
FALSEint;
begin -- Reset_Event
if Op_Sys = Linux
then
Console.Write_Error("<<<Reset_Event Linux
entered>>>");
return False; -- no
such function
else
Result :=
ResetEventWindows( Event => Event );
return Result /=
FALSEint;
end if;
end Reset_Event;
function SetEvent --
winbase.h:1871
( Event : HANDLE
) return BOOL;
pragma Import( Stdcall,
SetEvent, "SetEvent" ); -- winbase.h:1871
--<<< not for Linux >>>
function
WaitForSingleObjectWindows
-- winbase.h:1908
( ObjectHandle :
HANDLE;
Milliseconds : DWORD
) return DWORD;
--<<< not for Linux >>>
pragma Import( Stdcall,
WaitForSingleObjectWindows, "WaitForSingleObject" ); --
winbase.h:1908
function
WaitForSingleObject --
winbase.h:1908
( ObjectHandle :
HANDLE;
Milliseconds : DWORD
) return DWORD is
begin --
WaitForSingleObject
if Op_Sys = Linux
then
Console.Write_Error("<<<WaitForSingleObject Linux
entered>>>");
return 0;
else
return
WaitForSingleObjectWindows( ObjectHandle => ObjectHandle,
Milliseconds =>
Milliseconds );
end if;
end
WaitForSingleObject;
procedure
EnterCriticalSectionWindows
-- winbase.h:1850
( CriticalSection :
LPCRITICAL_SECTION );
--<<< not for Linux >>>
pragma Import( Stdcall,
EnterCriticalSectionWindows, "EnterCriticalSection" ); --
winbase.h:1850
procedure
EnterCriticalSection -- winbase.h:1850
( CriticalSection :
LPCRITICAL_SECTION ) is
begin --
EnterCriticalSection
if Op_Sys = Linux
then
Console.Write_Error("<<<EnterCriticalSection
entered>>>");
else
EnterCriticalSectionWindows( CriticalSection => CriticalSection );
end if;
end
EnterCriticalSection;
function Set_Event
( Event : HANDLE
) return Boolean is
begin -- Set_Event
if Op_Sys = Linux
then
declare
Message
--| One byte
"message" to write to pipe
: constant String(1..1) := ( others
=> 'e' );
Written
--| Number of
bytes written
: Integer := 0;
function to_FH is
new Unchecked_Conversion( Source => HANDLE,
Target =>
File_Handle );
begin
Written :=
Write_File -- use write
pipe
(
to_FH(Event), --(Send)),
Message(1..1) );
return Written
= 1;
end;
else
declare
Result : BOOL := TRUEint;
begin
Result :=
SetEvent( Event => Event );
--<<< can't use with Linux >>>
return Result /=
FALSEint;
end;
end if;
end Set_Event;
---------------------------------------------------------------------------
-- Processes
function
Execute_Program
( Name : in String
--| Program name to
be executed
) return PId_t is
-- ++
--| Notes:
--| GNAT s-os_lib.ads for the Spawn procedure
has the following:
-- This procedure spawns a program with a given
list of arguments. The
-- first parameter of is the name of the
executable. The second parameter
-- contains the arguments to be passed to this
program. Success is False
-- if the named program could not be spawned or
its execution completed
-- unsuccessfully. Note that the caller will be
blocked until the
-- execution of the spawned program is
complete. For maximum portability,
-- use a full path name for the Program_Name
argument. On some systems
-- (notably Unix systems) a simple file name
may also work (if the
-- executable can be located in the path).
--
-- Spawning processes from tasking programs is
not recommended. See
-- "NOTE: Spawn in tasking programs"
below.
--
-- Note: Arguments in Args that contain spaces
and/or quotes such as
-- "--GCC=gcc -v" or
"--GCC=""gcc -v""" are not portable across all
-- operating systems, and would not have the
desired effect if they were
-- passed directly to the operating system. To
avoid this problem, Spawn
-- makes an internal call to
Normalize_Arguments, which ensures that such
-- arguments are modified in a manner that
ensures that the desired effect
-- is obtained on all operating systems. The
caller may call
-- Normalize_Arguments explicitly before the
call (e.g. to print out the
-- exact form of arguments passed to the
operating system). In this case
-- the guarantee a second call to
Normalize_Arguments has no effect
-- ensures that the internal call will not
affect the result. Note that
-- the implicit call to Normalize_Arguments may
free and reallocate some
-- of the individual arguments.
--
-- This function will always set Success to
False under VxWorks and other
-- similar operating systems which have no
notion of the concept of
-- dynamically executable file. Otherwise
Success is set True if the exit
-- status of the spawned process is zero.
--|
--| Argument_List is a subtype of
String_List. String_List is in
--| s-string.ads as
--| type String_List is array (Positive range
<>) of String_Access;
--| where String_Access is
--| type String_Access is access all String;
-- --
Arg : GNAT.OS_Lib.Argument_List(1..1) := (
others => null );
Arg1 :
GNAT.OS_Lib.String_Access := new String(1..10);
Id : GNAT.OS_Lib.Process_Id;
use type
System.Address;
function to_PId is
new Unchecked_Conversion
( Source => GNAT.OS_Lib.Process_Id,
Target => PId_t );
begin -- Execute_Program
console.write("Execute_Program",1,Name);--ArgV_Type'last,Name);
Arg1.all := ( others
=> ' ' ); -- empty argument
Arg(1) := Arg1;
-- for I in
1..ArgV_Type'last loop
--if Args(I) /=
System.Null_Address then
--console.write(" ",I,to_Int(Args(I)));
-- Arg(I) :=
to_Access(Args(I));
--else
-- Arg(I) := ASCII.NUL;
-- exit when Args(I)
= System.Null_Address;
--declare
--gx : string(1..50);
--J : integer;
--begin
--J := 1;
--while Args(I)
-- for K in N_Args'Range
loop
-- N_Args (K) :=
new String'(Args (K).all);
-- end loop;
--console.write(Args(I));
--end;
-- end loop;
-->>> could check that string pointed to by Arg is null
terminated
console.write("Execute_Program call");
Id := GNAT.OS_Lib.Non_Blocking_Spawn(
Program_Name => Name,
Args => Arg );
return to_PId(Id);
end Execute_Program;
procedure
ExitProcessWindows
-- winbase.h:1500
( ExitCode : UINT );
--<<< not for Linux >>>
pragma Import( Stdcall,
ExitProcessWindows, "ExitProcess" ); -- winbase.h:1500
procedure
ExitProcess --
winbase.h:1500
( ExitCode : UINT
) is
begin -- ExitProcess
if Op_Sys = Linux
then
Console.Write_Error("<<<
ExitProcess Linux entered >>>");
else
ExitProcessWindows(
ExitCode => ExitCode );
end if;
end ExitProcess;
function
GetExitCodeProcessWindows
-- winbase.h:1515
( Process : HANDLE;
ExitCode : LPDWORD
) return BOOL;
--<<< not for Linux >>>
pragma Import( Stdcall,
GetExitCodeProcessWindows, "GetExitCodeProcess" ); -- winbase.h:1515
function
GetExitCodeProcess --
winbase.h:1515
( Process : HANDLE;
ExitCode : LPDWORD
) return BOOL is
begin --
GetExitCodeProcess
if Op_Sys = Linux
then
Console.Write_Error("<<<GetExitCodeProcess Linux
entered>>>");
return Falseint;
else
return
GetExitCodeProcessWindows( Process
=> Process,
ExitCode =>
ExitCode );
end if;
end GetExitCodeProcess;
function
GetExitCodeThreadWindows
-- winbase.h:1686
( Thread : HANDLE;
ExitCode : LPDWORD
) return BOOL;
--<<< not for Linux >>>
pragma Import( Stdcall,
GetExitCodeThreadWindows, "GetExitCodeThread" ); -- winbase.h:1686
function
GetExitCodeThread --
winbase.h:1686
( Thread : HANDLE;
ExitCode : LPDWORD
) return BOOL is
begin --
GetExitCodeThread
if Op_Sys = Linux
then
Console.Write_Error("<<<GetExitCodeThread Linux
entered>>>");
return Falseint;
else
return
GetExitCodeThreadWindows( Thread =>
Thread,
ExitCode => ExitCode );
end if;
end GetExitCodeThread;
function
GetCurrentProcessWindows
-- winbase.h:1486
return HANDLE;
pragma Import( Stdcall,
GetCurrentProcessWindows, "GetCurrentProcess" ); -- winbase.h:1486
--<<< not for Linux >>>
function GetCurrentProcess -- winbase.h:1486
return HANDLE is
begin --
GetCurrentProcess
if Op_Sys = Linux
then
console.write_error("<<<In
GetCurrentProcess>>>");
return
System.Null_Address;
else
return
GetCurrentProcessWindows;
end if;
end GetCurrentProcess;
function
GetCurrentProcessIdWindows
-- winbase.h:1493
return DWORD;
pragma Import( Stdcall,
GetCurrentProcessIdWindows, "GetCurrentProcessId" ); --
winbase.h:1493
--<<< not for Linux >>>
-- function
GetCurrentProcessIdWindows
-- winbase.h:1493
-- return DWORD is
-- use type DWORD;
-- begin
--console.write_error("<<<In
GetCurrentProcessId>>>");
-- return -1;
-- end;
function
GetCurrentProcessId --
winbase.h:1493
return DWORD is
use type DWORD;
begin --
GetCurrentProcessId
if Op_Sys = Linux
then
console.write_error("<<<In GetCurrentProcessId
Linux>>>");
return -1;
else
return
GetCurrentProcessIdWindows;
end if;
end GetCurrentProcessId;
function
GetProcessShutdownParametersWindows
( Level : in LPDWORD;
Flags : in LPDWord
) return Bool;
--<<< not for Linux >>>
pragma Import( Stdcall,
GetProcessShutdownParametersWindows, -- winbase.h:3748
"GetProcessShutdownParameters" );
function
GetProcessShutdownParameters
( Level : in LPDWORD;
Flags : in LPDWord
) return Bool is
begin --
GetProcessShutdownParameters
if Op_Sys = Linux
then
console.write_error("<<<In GetProcessShutdownParameters
Linux>>>");
return Falseint;
else
return
GetProcessShutdownParametersWindows( Level => Level,
Flags => Flags
);
end if;
end
GetProcessShutdownParameters;
-- function Is_Running -- for Linux
-- ( Path : String
--| Full path of
executable
-- ) return Boolean is
-- Dir_Entity
--| Pointer to
process directory entity
-- :
Dir_Entity_Ptr_Type := null;
-- Dir_Proc
--| Pointer to
process directory
-- : System.Address :=
System.Null_Address;
-- Lookup_Name
--| Process id for
/proc lookup
-- : String(1..50);
-- Name_Len
--| Number of
characters in name
-- : Integer;
-- Proc_Directory
--| Null-terminated
name of directory containing running processes
-- : String(1..10) :=
( others => ASCII.NUL );
-- Running_Process
--| Path of running
process
-- : String(1..256);
-- use type
String_Tools.Comparison_Type;
-- use type
System.Address;
-- begin -- Is_Running
--| Logic_Step:
--| Open the /proc directory.
--
Proc_Directory(1..6) := "/proc/"; -- nul terminated
-- Dir_Proc :=
OpenDir( File_Name => Proc_Directory );
-- if Dir_Proc =
System.Null_Address then
--
Console.Write_Error( "Couldn't open the /proc/ directory" );
-- return False;
-- end if;
--| Logic_Step:
--| Search through the processes looking for
the one with the
--| specified path and executable name.
-- loop
-- Read next item
-- Dir_Entity :=
ReadDir(Dir_Proc);
-- exit when
Dir_Entity = null;
-- Form lookup name
-- Name_Len := 0;
-- for I in
1..Dir_Entity.d_name'length loop
-- exit when
Dir_Entity.d_name(I) = ASCII.NUL; -- trailing NUL
-- Name_Len := I; --
set length of name to last non-NUL character
-- end loop;
-- if Name_Len >
0 then
--
Lookup_Name(1..6) := "/proc/";
--
Lookup_Name(7..6+Name_Len) := Dir_Entity.d_name(1..Name_Len);
--
Lookup_Name(7+Name_Len..10+Name_Len) := "/exe";
--
Lookup_Name(11+Name_Len) := ASCII.NUL; -- trailing NUL
----declare
----name_len1 : Integer := Name_Len;
----begin
-- Get path
-- Name_Len :=
ReadLink( Lookup_Name'address,
--
Running_Process'address,
--
Running_Process'length );
----console.write("Is_Running",Name_Len,Name_Len1,Path'length,
----Dir_Entity.d_name(1..Name_Len1));
----end;
-- Compare path
of running executable with that input
-- if Name_Len =
Path'length and then
--
String_Tools.Blind_Compare
-- ( Left => Running_Process(1..Name_Len),
-- Right
=> Path ) = String_Tools.Equal
-- then
-- return True;
-- process is running
-- end if;
-- end if; --
Name_Len > 0
-- end loop;
-- return False; --
Path not found in running processes
-- end Is_Running;
function App_Running
( Application : in
Interfaces.C.Strings.Chars_Ptr
) return
Interfaces.C.char;
pragma Import(C, App_Running,
"appRunningC");
--<<< not for Linux >>>
function
Is_Running_Linux
( Path : String
--| Full path of
executable
) return Boolean is
Dir_Entity
--| Pointer to
process directory entity
: Dir_Entity_Ptr_Type
:= null;
Dir_Proc
--| Pointer to
process directory
: System.Address :=
System.Null_Address;
Lookup_Name
--| Process id for
/proc lookup
: String(1..50);
Name_Len
--| Number of
characters in name
: Integer;
Proc_Directory
--| Null-terminated
name of directory containing running processes
: String(1..10) := (
others => ASCII.NUL );
Running_Process
--| Path of running
process
: String(1..256);
use type
String_Tools.Comparison_Type;
use type
System.Address;
begin --
Is_Running_Linux
--| Logic_Step:
--| Open the /proc directory.
Proc_Directory(1..6)
:= "/proc/"; -- nul terminated
Dir_Proc := OpenDir(
File_Name => Proc_Directory );
if Dir_Proc =
System.Null_Address then
Console.Write_Error(
"Couldn't open the /proc/ directory" );
return False;
end if;
--| Logic_Step:
--| Search through the processes looking for
the one with the
--| specified path and executable name.
loop
-- Read next item
Dir_Entity :=
ReadDir(Dir_Proc);
exit when
Dir_Entity = null;
-- Form lookup name
Name_Len := 0;
for I in
1..Dir_Entity.d_name'length loop
exit when
Dir_Entity.d_name(I) = ASCII.NUL; -- trailing NUL
Name_Len := I; --
set length of name to last non-NUL character
end loop;
if Name_Len > 0
then
Lookup_Name(1..6)
:= "/proc/";
Lookup_Name(7..6+Name_Len) := Dir_Entity.d_name(1..Name_Len);
Lookup_Name(7+Name_Len..10+Name_Len) := "/exe";
Lookup_Name(11+Name_Len) := ASCII.NUL; -- trailing NUL
--declare
--name_len1 : Integer := Name_Len;
--begin
-- Get path
Name_Len :=
ReadLink( Lookup_Name'address,
Running_Process'address,
Running_Process'length
);
--console.write("Is_Running",Name_Len,Name_Len1,Path'length,
--Dir_Entity.d_name(1..Name_Len1));
--end;
-- Compare path
of running executable with that input
if Name_Len =
Path'length and then
String_Tools.Blind_Compare
( Left => Running_Process(1..Name_Len),
Right =>
Path ) = String_Tools.Equal
then
return True; --
process is running
end if;
end if; -- Name_Len
> 0
end loop;
return False; -- Path
not found in running processes
end Is_Running_Linux;
function
Is_Running_Windows
( Path : String
) return Boolean is
function to_Byte is
new Unchecked_Conversion
( Source => Interfaces.C.char,
Target => Machine.Unsigned_Byte );
function to_Char is
new Unchecked_Conversion
( Source => Machine.Unsigned_Byte,
Target => Interfaces.C.char );
Result
: Interfaces.C.char
:= to_Char(16#0#);
use type
Machine.Unsigned_Byte;
function to_Ptr is
new Unchecked_Conversion
( Source => System.Address,
Target => Interfaces.C.Strings.Chars_Ptr );
begin --
Is_Running_Windows
Result :=
App_Running( Application => to_Ptr(Path'address) );
-- <<< not for Linux >>>
return
to_Byte(Result) = 16#01#;
end Is_Running_Windows;
function Is_Running
( Path : String
) return Boolean is
begin -- Is_Running
if Op_Sys = Linux
then
return
Is_Running_Linux( Path => Path );
else
return
Is_Running_Windows( Path => Path );
end if;
end Is_Running;
function
GetPriorityClassWindows
-- winbase.h:6260
( Process : HANDLE
) return DWORD;
--<<<< not for Linux >>>>
pragma Import( Stdcall,
GetPriorityClassWindows, --
winbase.h:6260
"GetPriorityClass");
function
GetPriorityClass --
winbase.h:6260
( Process : HANDLE
) return DWORD is
begin --
GetPriorityClass
if Op_Sys = Linux
then
console.write_error("<<<Entered GetPriorityClass
Linux>>>");
return 0;
else
return
GetPriorityClassWindows( Process => Process );
end if;
end GetPriorityClass;
function
SetPriorityClassWindows
-- winbase.h:6252
( Process : HANDLE;
PriorityClass : DWORD
) return BOOL;
--<<< can't be used for Linux >>>
pragma Import( Stdcall,
SetPriorityClassWindows, "SetPriorityClass" ); -- winbase.h:6252
function
SetPriorityClass --
winbase.h:6252
( Process : HANDLE;
PriorityClass : DWORD
) return BOOL is
begin --
SetPriorityClass
if Op_Sys = Linux
then
console.write_error("<<<SetPriorityClass Linux
entered>>>");
return FALSEint;
else
return
SetPriorityClassWindows( Process
=> Process,
PriorityClass =>
PriorityClass );
end if;
end SetPriorityClass;
---------------------------------------------------------------------------
-- Threads
type PThread_t is new
Interfaces.C.Unsigned_Long; -- unsigned long int --Machine.Unsigned_Longword;
--<<<< need to be pointer?? >>>
function
Unsigned_Long_to_Int
( Source : in
Interfaces.C.Unsigned_Long
) return
Integer_Pair_Type is
type Pair_Type
is record
Two :
Machine.Unsigned_Word; -- to order for correct endian
One :
Machine.Unsigned_Word;
end record;
Temp1 : Pair_Type;
for Temp1 use at
Source'address;
Temp2 :
Integer_Pair_Type;
begin --
Unsigned_Long_to_Int
Temp2(1) :=
Integer(Temp1.One);
Temp2(2) :=
Integer(Temp1.Two);
return Temp2;
end
Unsigned_Long_to_Int;
function
PThread_Attr_Init -- for Linux
( Attributes : access
PThread_Attr_t
) return
Interfaces.C.int;
-- Return attribute
structure with default attribute values
-- pragma Import(C,
PThread_Attr_Init, "pthread_attr_init");
-- above needed for Linux
-- below to compile for Windows
function
PThread_Attr_Init -- to compile for Windows
( Attributes : access
PThread_Attr_t
) return
Interfaces.C.int is
begin
Console.Write_Error("<<<PThread_Attr_Init
entered>>>");
return
Interfaces.C.int(-1);
end;
function
PThread_Attr_SetStacksize
( Attributes : access
PThread_Attr_t;
Stack_Size : Natural
) return
Interfaces.C.int;
-- Set stack size into
thread attributes
-- pragma Import(C,
PThread_Attr_SetStacksize, "pthread_attr_setstacksize");
-- above needed for Linux
-- below to compile for Windows
function
PThread_Attr_SetStacksize
( Attributes : access
PThread_Attr_t;
Stack_Size : Natural
) return
Interfaces.C.int is
begin
Console.Write_Error("<<<PThread_Attr_SetStacksize
entered>>>");
return Interfaces.C.int(-1);
end;
function PThread_Create
( Thread_Id : in System.Address; -- location for thread
id
Attributes : in
System.Address; -- location of thread attributes to use
Start : in System.Address; -- pointer to start
address for thread
Arg : in System.Address -- location of arguments for Start
) return
Interfaces.C.int;
-- Create a thread and
return its identifier at Thread_Id. The
return
-- value is whether the
create was successful (0) or an error number of
-- EAGAIN Insufficient resources to create
another thread, or a
-- system-imposed limit on the number of
threads was encountered.
-- The latter case may occur in two
ways: the RLIMIT_NPROC soft
-- resource limit (set via setrlimit(2)),
which limits the number
-- of process for a real user ID, was
reached; or the kernel's
-- system-wide limit on the number of
threads,
-- /proc/sys/kernel/threads-max, was
reached.
-- EINVAL Invalid settings in attr.
-- EPERM
No permission to set the scheduling policy and parameters
-- specified in attr.
--|
--| Notes:
--| This Create_Thread uses the C
pthread_create. It returns the thread
--| id that the other C functions use. It also results in the Arg
--| address being the same when the thread
starts as that supplied to
--| Create.
--> Need to find out the format of Attributes to know how to
pass stack size, etc.
--> pthread_attr_t
--> /*
Initialize thread creation attributes */
--> s =
pthread_attr_init(&attr);
--> if (s !=
0)
-->
handle_error_en(s, "pthread_attr_init");
--> if
(stack_size > 0) {
--> s =
pthread_attr_setstacksize(&attr, stack_size);
--> if (s != 0)
-->
handle_error_en(s, "pthread_attr_setstacksize");
--> }
-- pragma Import(C,
PThread_Create, "pthread_create");
-- needed for Linux
function PThread_Create
( Thread_Id : in System.Address; -- location for thread
id
Attributes : in
System.Address; -- location of thread attributes to use
Start : in System.Address; -- pointer to start
address for thread
Arg : in System.Address -- location of arguments for Start
) return Interfaces.C.int
is
begin -- PThread_Create
Console.Write_Error("<<<PThread_Create
entered>>>");
return
Interfaces.C.int(-1);
end PThread_Create;
-- needed to compile for Windows
-- for Linux
procedure
Create_Thread_Linux
(-- Attributes : in
PThread_Attr_t;
Stack_Size : in Integer;
Start : in System.Address;
Thread_Number :
in Integer;
Thread_Id : out Integer;
Success : out Boolean
) is --return Boolean
is
Attributes
: PThread_Attr_t;
type Attributes_Ptr_Type
is access PThread_Attr_t;
function to_Attr_Ptr
is new Unchecked_Conversion
( Source => System.Address,
Target => Attributes_Ptr_Type
);
Attributes_Ptr :
Attributes_Ptr_Type := to_Attr_Ptr(Attributes'address);
Result
: Interfaces.C.int;
StackSize
: Integer :=
Stack_Size;
type Dummy_Type is
array(1..10) of Integer;
type Thread_Info_Type
is record
Thread_Id :
PThread_t; -- Identifier returned
by pthread_create
Argv : System.Address; -- pointer to
command-line argument
Spare : Dummy_Type; -- be sure reserve enough space
end record;
Thread_Info
: Thread_Info_Type;
pragma
Volatile(Thread_Info);
use type
Interfaces.C.int;
begin --
Create_Thread_Linux
Result :=
PThread_Attr_Init( Attributes => Attributes_Ptr );
console.write("Create_Thread
attr_init",integer(Result),stack_size);
if StackSize <= 0
then
StackSize := 16384;
end if;
Result :=
PThread_Attr_SetStacksize( Attributes_Ptr,
StackSize );
Exec_Itf.Log_Error;
console.write("Create_Thread
setstacksize",integer(Result));
--console.write("call exec_itf Thread_Create",integer(Thread_Number));
-- Result := Thread_Create
-- ( Thread_Id => Thread_Id, -- location for thread id
-- Attributes =>
Attributes'address, -- location of thread attributes to use
-- Start => Start, -- pointer to start address
-- Arg => Parameters ); -- parameters
--| Notes:
--| Parameters needs to be of the form
--| Parameters.thread_num where thread number
starts at 1 and increases for each thread
--| Parameters.argv_string = argv[optind +
tnum] where tnum is one less than thread_num
-- Thread_Info.Thread_Id := 0;
-- Thread_Info.Thread_Num := Thread_Number;
Thread_Info.Thread_Id :=
PThread_t(Thread_Number);
Thread_Info.Argv := System.Null_Address;
console.write("call exec_itf
PThread_Create",integer(Thread_Number));
Result :=
PThread_Create
(
Thread_Id => Thread_Number'address,
--Thread_Info.Thread_Id'address, --
&tinfo[tnum].thread_id, &attr,
Attributes => Attributes'address,
Start => Start, -- &thread_start, &tinfo[tnum]);
Arg => Thread_Info'address );
--Parameters );
console.write("Create_Thread r1",integer(Result));
--,integer(Thread_Info.Thread_Id));--,integer(thread_number));
--declare
-- CTId1 :
Integer_Pair_Type;
-- CTId2 :
Integer_Pair_Type;
--begin
----CTId1 :=
unsigned_long_to_int(Interfaces.C.unsigned_long(thread_number));
--CTId2 := unsigned_long_to_int(Interfaces.C.unsigned_long(Thread_Info.Thread_Id));
----console.write_hex("Create_Thread
r2",CTId1(1),CTId1(2));
--console.write_hex("Create_Thread
r3",CTId2(1),CTId2(2));
--null;
--end;
if Result = 0 then
Thread_Id :=
Integer(Thread_Info.Thread_Id);
Success := True;
else
Thread_Id := -1;
Success := False;
end if;
--| Logic_Step:
--| Return true if thread created.
-- return Result = 0;
end
Create_Thread_Linux;
-- for Linux
-- function
Create_Thread
-- (-- Attributes : in
PThread_Attr_t;
-- Stack_Size : in
Integer;
-- Start : in System.Address;
-- Parameters : in
System.Address;
-- Thread_Id : in System.Address
-- ) return Boolean is
-- Attributes
-- : PThread_Attr_t;
-- type
Attributes_Ptr_Type is access PThread_Attr_t;
-- function
to_Attr_Ptr is new Unchecked_Conversion
-- ( Source => System.Address,
-- Target => Attributes_Ptr_Type
);
-- Attributes_Ptr :
Attributes_Ptr_Type := to_Attr_Ptr(Attributes'address);
-- Result
-- : Interfaces.C.int;
-- use type
Interfaces.C.int;
-- begin --
Create_Thread
-- Result :=
PThread_Attr_Init( Attributes => Attributes_Ptr );
--console.write("Thread_Create
attr_init",integer(Result));
-- if Stack_Size >
0 then
-- Result :=
PThread_Attr_SetStacksize( Attributes_Ptr,
-- Stack_Size );
--
Exec_Itf.Log_Error;
--console.write("Thread_Create
setstacksize",integer(Result));
-- end if;
-- Result :=
Thread_Create
-- (
Thread_Id => Thread_Id, -- location for thread id
--
Attributes => Attributes'address, -- location of thread attributes to
use
--
Start => Start, -- pointer to start address
--
Arg => Parameters ); --
parameters
--console.write("Create_Thread",integer(Result));--,TId_to_Int(TId));
--| Logic_Step:
--| Return true if thread created.
-- return Result = 0;
-- end Create_Thread;
--<<< above not for Windows >>>
function Create_Thread
( Start : in System.Address; -- pointer
Parameters : in
Void_Ptr; -- pointer
Stack_Size : in
Natural; -- int
Priority : in Integer -- int
) return HANDLE is
begin -- Create_Thread
return
GNAT.Threads.Create_Thread
( Code =>
Start,
Parm =>
GNAT.Threads.Void_Ptr(Parameters),
Size =>
Stack_Size,
Prio =>
Priority );
end Create_Thread;
procedure Create_Thread
( Start : System.Address; -- pointer to start address of thread
Parameter : System.Address; -- pointer to parameters
Stack_Size : Natural; -- stack size in bytes
Thread_Priority : Integer; -- priority for thread
Thread_Handle : out Thread_Handle_Type
) is
--| Notes:
--| This procedure does not return a Thread_Id
that matches that of
--| GetCurrentThreadId.
Thread_Ident :
System.Address;
function to_Id is new
Unchecked_Conversion
( Source => System.Address,
Target => Thread_Handle_Type );
function to_Int is new
Unchecked_Conversion
(
Source => System.Address,
Target => Integer );
function to_Ptr is new
Unchecked_Conversion
(
Source => System.Address,
Target => GNAT.Threads.Void_Ptr );
begin -- Create_Thread
Thread_Ident :=
GNAT.Threads.Create_Thread
(
Code => Start,
Parm => to_Ptr(Parameter),
Size => Stack_Size,
Prio => Thread_Priority );
Thread_Handle :=
to_Id(Thread_Ident);
end Create_Thread;
procedure
Destroy_Thread
( Thread_Handle :
Thread_Handle_Type
) is
function to_Addr is
new Unchecked_Conversion
( Source => Thread_Handle_Type,
Target => System.Address );
begin -- Destroy_Thread
GNAT.Threads.Destroy_Thread( to_Addr(Thread_Handle) );
end Destroy_Thread;
function PThread_Self
--GetCurrentThreadIdLinux
return Thread_Id_Type;
--pThread_t;
-- This function gets
the system identifier of the currently running thread.
-- pragma Import (C,
PThread_Self, "pthread_self");
--<<< above
pragma necessary for Linux >>>
function PThread_Self
--<<< this is just to compile for Windows >>>
return Thread_Id_Type
is
begin
Console.Write("<<<PThread_Self entered>>>");
return 0;
end PThread_Self;
--<< Windows version >>
function
GetCurrentThreadIdWindows --
winbase.h:1630
return DWORD;
pragma Import( Stdcall,
GetCurrentThreadIdWindows, "GetCurrentThreadId" ); -- winbase.h:1630
--<<< not for Linux >>>
function
GetCurrentThreadId
return Thread_Id_Type
is
use type
Interfaces.C.unsigned_long;
Thread_Id : DWORD :=
-1;
T_Id :
Thread_Id_Type;
begin --
GetCurrentThreadId
if Op_Sys = Linux
then
T_Id :=
PThread_Self;
declare
CTId :
Integer_Pair_Type;
begin
CTId := unsigned_long_to_int(Interfaces.C.unsigned_long(T_Id));
console.write_hex("GetCurrentThreadId",CTId(1),CTId(2));
end;
return T_Id;
else
Thread_Id :=
GetCurrentThreadIdWindows;
return
Thread_Id_Type(Thread_Id);
end if;
end GetCurrentThreadId;
function
GetCurrentThreadWindows
-- winbase.h:1623
return HANDLE;
pragma Import( Stdcall,
GetCurrentThreadWindows, "GetCurrentThread" ); -- winbase.h:1623
--<<< only for Windows >>>
function
GetCurrentThread --
winbase.h:1623
return HANDLE is
begin --
GetCurrentThread
if Op_Sys = Linux
then
console.Write_Error("<<<GetCurrentThread Linux
entered>>>");
return System.Null_Address;
else
return
GetCurrentThreadWindows;
end if;
end GetCurrentThread;
procedure Get_Thread --
get thread identifier from handle
( Thread_Handle : in
HANDLE;
Thread_Id : out PId_t
) is
Id_Addr : System.Address;--
:= System.Null_Address;
pragma
Volatile(Id_Addr);
Id : PId_t;
for Id use at
Id_Addr;
pragma Volatile(Id);
function to_int is new unchecked_conversion( Source => PId_t,
Target => Integer );
function TH_to_Int is
new Unchecked_Conversion
( Source => Handle,
Target => Integer );
begin -- Get_Thread
GNAT.Threads.Get_Thread( Id
=> Thread_Handle,
Thread => Id_Addr );
Thread_Id := Id;
end Get_Thread;
procedure Get_Thread
( Thread_Handle : in
Thread_Handle_Type;
Thread_Id : out Thread_Id_Type
) is
function TH_to_Addr
is new Unchecked_Conversion
( Source => Thread_Handle_Type,
Target =>
System.Address );
function TH_to_Int is
new Unchecked_Conversion
( Source => Thread_Handle_Type,
Target => Integer );
function TId_to_Int
is new Unchecked_Conversion
( Source => Thread_Id_Type,
Target => Integer );
begin
console.write("Get_Thread
b",TH_to_Int(Thread_Handle));
GNAT.Threads.Get_Thread( Id
=> TH_To_Addr(Thread_Handle),
Thread =>
Thread_Id'address );
console.write("Get_Thread",TH_to_Int(Thread_Handle),TId_to_Int(Thread_Id));
end Get_Thread;
function
GetThreadPriorityWindows
-- winbase.h:1653
( Thread : HANDLE
) return INT;
--<<< not for Linux >>>
pragma Import( Stdcall,
GetThreadPriorityWindows, "GetThreadPriority" ); -- winbase.h:1653
function
GetThreadPriority --
winbase.h:1653
( Thread : HANDLE
) return INT is
begin --
GetThreadPriority
if Op_Sys = Linux then
console.write_error("<<<GetThreadPriority Linux
entered>>>");
return 0;
else
return
GetThreadPriorityWindows( Thread => Thread );
end if;
end GetThreadPriority;
function
SetThreadPriorityWindows -- winbase.h:1645
( Thread : HANDLE;
Priority : INT
) return BOOL;
pragma Import( Stdcall,
SetThreadPriorityWindows, "SetThreadPriority" ); -- winbase.h:1645
--<<< not for Linux >>>
function
SetThreadPriority
( Thread : HANDLE;
Priority : INT
) return Boolean is
Result : BOOL :=
FALSEint;
begin --
SetThreadPriority
if Op_Sys = Windows
then
Result :=
SetThreadPriorityWindows( Thread =>
Thread,
Priority => Priority
);
--<<< can't use with Linux >>>
return Result /=
FALSEint;
else
console.Write_Error("<<<SetThreadPriority
entered>>>");
return False; --
not for Linux
end if;
end SetThreadPriority;
function
TerminateThreadWindows -- winbase.h:1678
( Thread : HANDLE;
ExitCode : DWORD
) return BOOL;
pragma Import( Stdcall,
TerminateThreadWindows, "TerminateThread" ); -- winbase.h:1678
--<<< not for Linux >>>
function
TerminateThread -- winbase.h:1678
( Thread : HANDLE;
ExitCode : DWORD
) return BOOL is
begin --
TerminateThread
if Op_Sys = Linux
then
Console.Write_Error("<<<TerminateThread
entered>>>");
return FALSEint;
else
return
TerminateThreadWindows( Thread =>
Thread,
ExitCode => ExitCode );
end if;
end TerminateThread;
function To_Task_Id
( Thread_Handle : in
Thread_Handle_Type
) return
Ada.Task_Identification.Task_Id is
begin -- To_Task_Id
return GNAT.Threads.To_Task_Id(
Thread_Handle'address );
end To_Task_Id;
---------------------------------------------------------------------------
-- Time
function Current_Time
return OS_Time is
-- Return the system clock value as OS_Time
begin -- Current_Time
return
GNAT.OS_Lib.Current_Time;
end Current_Time;
procedure
GetLocalTimeWindows
-- winbase.h:2627
( SystemTime :
LPSYSTEMTIME
);
--<<< not usable for Linux >>>
pragma Import( Stdcall,
GetLocalTimeWindows, "GetLocalTime" ); -- winbase.h:2627
procedure
GetLocalTime --
winbase.h:2627
( SystemTime :
LPSYSTEMTIME
) is
begin
if Op_Sys = Linux
then
console.write("<<<GetLocalTime Linux
entered>>>");
else
GetLocalTimeWindows( SystemTime => SystemTime );
end if;
end;
procedure GM_Split
( Date : OS_Time;
Year : out Year_Type;
Month : out Month_Type;
Day : out Day_Type;
Hour : out Hour_Type;
Minute : out Minute_Type;
Second : out Second_Type;
Millisec : out
Millisec_Type
) is
begin -- GM_Split
GNAT.OS_Lib.GM_Split
( Date => Date,
Year => Year,
Month => Month,
Day => Day,
Hour => Hour,
Minute =>
Minute,
Second => Second
);
Millisec := 0;
end GM_Split;
function System_Time
( Time : OS_Time
--| System clock
value
) return
System_Time_Type is
--| Return system clock
value as a record.
Year : Year_Type;
Month :
Month_Type;
Day : Day_Type;
Hour : Hour_Type;
Minute : Minute_Type;
Second : Second_Type;
Millisec :
Millisec_Type;
Tm :
System_Time_Type; --Split_Time_Type;
begin -- System_Time
GM_Split( Date => Time,
Year => Year,
Month => Month,
Day => Day,
Hour => Hour,
Minute => Minute,
Second => Second,
Millisec
=> Millisec );
Tm := ( Year => Year,
Month => Month,
Day => Day,
Hour => Hour,
Minute => Minute,
Second => Second,
Millisec
=> Millisec );
return Tm;
end System_Time;
function SystemTime
return System_Time_Type
is
Time : OS_Time;
begin -- SystemTime
Time := Current_Time;
return System_Time(
Time );
end SystemTime;
function
File_Time_Stamp
( Name : String
) return OS_Time is
-- Given the name of a file or directory, Name,
obtains and returns the
-- time stamp. This function can be used for an
unopened file. Returns
-- Invalid_Time is Name doesn't correspond to
an existing file.
begin --
File_Time_Stamp
return
GNAT.OS_Lib.File_Time_Stamp( Name => Name );
end File_Time_Stamp;
function
File_Time_Stamp
( Handle : File_Handle
) return OS_Time is
begin --
File_Time_Stamp
return
GNAT.OS_Lib.File_Time_Stamp( Handle_to_File_Descriptor(Handle) );
end File_Time_Stamp;
end Exec_Itf;
The Linux version is, of course, much like the above but with the
pragma Import lines enabled for Linux and disabled for Windows and the code
that is to provide a function in place of the Import commented out and vice
versa for the Windows pragma Imports.
Notice that the detection of the operating system is done, via
Set_Op_Sys, by obtaining the folder/directory from which the app was started
and checking its beginning characters to see if C: or /home.
Packages with separate paths:
The units that have code that is dependent upon the operation system
are
2) display_pipe
3) exec-text_log
4) mc-exec
5) mc-message-remote-method and mc-message-remote-method-transmit
The usage in display pipe and in mc-message-remote-method has already
been illustrated.
The usage in apps-configuration-initialize is for checking the
configuration file designation of the supported communications file.
The usage in exec-text_log is to form a valid path for the log file.
The usage in mc-exec is to determine which exec_itf routines to call
in instances where data is stored in the thread control block. Different paths are mainly used for how
events are treated and in the Thread_Create procedure that is reproduced below.
procedure Thread_Create
( Thread_Name : in Thread_Name_Type;
Start : in Exec_Itf.Thread_Address_Type;
Parameter : in System.Address;
Stack_Size : in Natural;
Thread_Priority : in
Thread_Priority_Type;
Immediate_Start : in
Boolean := False;
Thread_Id : out Thread_Id_Type;
Status : out Status_Type
) is
Assigned_Thread_Id
--| Thread id
assigned by Linux
: Integer;
pragma Volatile(
Assigned_Thread_Id );
T_Id
--| Internal Thread
identifier
: Thread_Id_Ext_Type;
pragma Volatile( T_Id
);
Thread_Created
--| True if thread
was created successfully
: Boolean;
Thread_Ident
--| Thread identifier
: Exec_Itf.PId_t;
Thread_Handle
--| Handle returned
by Create_Thread
: Exec_Itf.HANDLE;
--Thread_Handle_Type; used in Linux version
TId
--| Thread identifier
as converted type
:
Exec_Itf.Thread_Id_Type;
pragma Volatile( TId
);
function to_Int is
new Unchecked_Conversion
( Source => Thread_Priority_Type,
Target => Integer );
function TH_to_Int is
new Unchecked_Conversion
( Source => Exec_Itf.HANDLE,
Target => Integer );
function TId_to_Int
is new Unchecked_Conversion
( Source => Exec_Itf.Thread_Id_Type,
Target => Integer );
function to_Int2 is
new Unchecked_Conversion
( Source => System.Address,
Target => Integer );
function to_Addr is
new Unchecked_Conversion
( Source => Exec_Itf.Void_Ptr,
Target => System.Address );
function to_Void_Ptr
is new Unchecked_Conversion
( Source => System.Address,
Target => Exec_Itf.Void_Ptr );
use type
Exec_Itf.Op_Sys_Type;
use type
Exec_Itf.Thread_Id_Type;
use type
Interfaces.C.int;
use type
System.Address;
begin -- Thread_Create
--| Logic_Step:
--| Lock the thread semaphore to prevent
another thread from
--| accessing the critical region.
--| Note:
--| The created thread can starting running
immediately suspending
--| the thread that invoked this Create and
preventing it from
--| updating the TCB. Therefore, the other thread can attempt other
--| Exec-mC procedures that would access the
incomplete TCB.
Thread_Lock;
T_Id := 0;
for I in
Thread_Id_Type loop
if not
TCB(I).Created or else
TCB(I).Status.Attributes.Name = Thread_Name
then
T_Id := I;
exit;
end if;
end loop;
if T_Id = 0 or else
Thread_Name =
Null_Thread_Name or else
Start = Exec_Itf.Null_Thread_Address
then
Status :=
Invalid_Config;
elsif
TCB(T_Id).Created then
Status :=
No_Action;
else
--| Logic_Step:
--| Buffer thread TCB index to be saved by
Thread_Wait_for_Start that
--| is used as the start address for the thread
for it to save on its
--| stack.
Also save the actual start address and the pointer to any
--| parameters for the thread to be used by Thread_Wait_for_Start
to
--| invoke the actual thread code when
Thread_Start is invoked.
TCB(T_Id).FW_T_Id :=
T_Id;
TCB(T_Id).Thread_Address :=
Start;
TCB(T_Id).Thread_Parameter := Parameter;
if Exec_Itf.Op_Sys =
Exec_Itf.Windows then
if
Immediate_Start then
Thread_Handle
:=
Exec_Itf.Create_Thread
( Start => Thread_Immediate_Start'address,
Parameters
=> to_Void_Ptr(TCB(T_Id).FW_T_Id'address),
Stack_Size => Stack_Size,
Priority =>
Integer(Thread_Priority) );
else -- not
Immediate_Start
Thread_Handle
:=
Exec_Itf.Create_Thread
( Start => Thread_Wait_to_Start'address,
Parameters =>
to_Void_Ptr(TCB(T_Id).FW_T_Id'address),
Stack_Size
=> Stack_Size,
Priority =>
Integer(Thread_Priority) );
end if; --
Immediate_Start
Thread_Created :=
Thread_Handle > System.Null_Address;
else -- Linux
if
Immediate_Start then
Exec_Itf.Create_Thread_Linux
(
Stack_Size => Stack_Size,
Start => Thread_Immediate_Start'address,
Thread_Number
=> Integer(T_Id),
Thread_Id => Assigned_Thread_Id,
Success => Thread_Created );
TCB(T_Id).FW_T_Id := Thread_Id_Ext_Type(Assigned_Thread_Id);
else -- not
Immediate_Start
Exec_Itf.Create_Thread_Linux
(
Stack_Size => Stack_Size,
Thread_Number
=> Integer(T_Id),
Thread_Id =>
Assigned_Thread_Id,
Success => Thread_Created );
TCB(T_Id).FW_T_Id := Thread_Id_Ext_Type(Assigned_Thread_Id);
end if; --
Immediate_Start
Thread_Handle :=
Exec_Itf.INVALID_HANDLE_VALUE;
end if; --
Exec_Itf.Op_Sys = Exec_Itf.Windows
if Thread_Created
then
if
Exec_Itf.Op_Sys = Exec_Itf.Windows then
declare
function
to_Id is new Unchecked_Conversion
( Source => Exec_Itf.PId_t,
Target =>
Exec_Itf.Thread_Id_Type );
begin
Exec_Itf.Get_Thread -- get thread identifier from handle
(
Thread_Handle => Thread_Handle,
Thread_Id => Thread_Ident
);
TId :=
to_Id(Thread_Ident);
end;
TCB(T_Id).Thread_Handle := Thread_Handle;
else -- Op_Sys =
Linux
--| Notes:
--| The pseudo thread instance that is started
by the
--| Create_Thread above obtains the thread id
in the case of
--| Windows.
Therefore, avoid overwriting the value here.
TId :=
Exec_Itf.Thread_Id_Type(Assigned_Thread_Id);
-- TCB(T_Id).Thread_Handle := Thread_Handle; --
no handle for Linux
end if; --
Exec_Itf.Op_Sys = Exec_Itf.Windows;
-- TCB(T_Id).Status.Attributes := Attributes;
TCB(T_Id).Status.Current_Priority := 0;
TCB(T_Id).Status.Deadline_Time
:= Aperiodic;
TCB(T_Id).Status.Thread_State
:= Dormant;
--
TCB(T_Id).Win_Priority :=
Thread_Priority;
--
TCB(T_Id).Win_Thread_Class :=
Thread_Class;
TCB(T_Id).Created := True;
Thread_Names_First_Letters(T_Id) := Thread_Name(1);
Thread_Id :=
T_Id;
Status := No_Error;
else -- Exec_Itf
error
TCB(T_Id).FW_T_Id := 0;
TCB(T_Id).Thread_Id := 0;
TCB(T_Id).Created := False;
Thread_Id := 1;
Status := Invalid_Config;
Console.Write("Exec Thread Create Error");
-- raise Thread_Create_Fail;
end if;
end if;
--| Logic_Step:
--| Unlock the thread semaphore to allow
another thread to
--| access the critical region.
Thread_Unlock;
end Thread_Create;
Thread_Create initially starts the thread in one of two of the
mc-exec packages own procedures to capture the currently running thread
identifier as that of the started thread.
Then, for immediate start, the actual code of the thread is
invoked. For non-immediate start, the
mc-exec code loops until the signal is received to start all the threads. When each thread receives the signal in its
instance of the Thread_Wait_to_Start procedure, the wait code invokes the
actual code of the thread.