------------------------------------------------------------------------------
--                                                                          --
--                  GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS                --
--                                                                          --
--                  S Y S T E M . T A S K I N G . D E B U G                 --
--                                                                          --
--                                  B o d y                                 --
--                                                                          --
--          Copyright (C) 2008-2012, Free Software Foundation, Inc.         --
--                                                                          --
-- GNAT is free software;  you can  redistribute it  and/or modify it under --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
--                                                                          --
-- As a special exception under Section 7 of GPL version 3, you are granted --
-- additional permissions described in the GCC Runtime Library Exception,   --
-- version 3.1, as published by the Free Software Foundation.               --
--                                                                          --
-- You should have received a copy of the GNU General Public License and    --
-- a copy of the GCC Runtime Library Exception along with this program;     --
-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
-- <http://www.gnu.org/licenses/>.                                          --
--                                                                          --
-- GNARL was developed by the GNARL team at Florida State University.       --
-- Extensive contributions were provided by Ada Core Technologies, Inc.     --
--                                                                          --
------------------------------------------------------------------------------

--  OpenVMS Version

with Ada.Unchecked_Conversion;
with Ada.Unchecked_Deallocation;
with System.Aux_DEC;
with System.CRTL;
with System.Task_Primitives.Operations;
package body System.Tasking.Debug is

   package OSI renames System.OS_Interface;
   package STPO renames System.Task_Primitives.Operations;

   use System.Aux_DEC;

   --  Condition value type

   subtype Cond_Value_Type is Unsigned_Longword;

   type Trace_Flag_Set is array (Character) of Boolean;

   Trace_On : Trace_Flag_Set := ('A' .. 'Z' => False, others => True);

   --  Print_Routine fuction codes

   type Print_Functions is
     (No_Print, Print_Newline, Print_Control,
      Print_String, Print_Symbol, Print_FAO);
   for Print_Functions use
     (No_Print => 0, Print_Newline => 1, Print_Control => 2,
      Print_String => 3, Print_Symbol => 4, Print_FAO => 5);

   --  Counted ascii type declarations

   subtype Count_Type is Natural range 0 .. 255;
   for Count_Type'Object_Size use 8;

   type ASCIC (Count : Count_Type) is record
      Text  : String (1 .. Count);
   end record;

   for ASCIC use record
      Count at 0 range 0 .. 7;
   end record;
   pragma Pack (ASCIC);

   type AASCIC is access ASCIC;
   for AASCIC'Size use 32;

   type AASCIC_Array is array (Positive range <>) of AASCIC;

   type ASCIC127 is record
      Count : Count_Type;
      Text  : String (1 .. 127);
   end record;

   for ASCIC127 use record
      Count at 0 range 0 .. 7;
      Text  at 1 range 0 .. 127 * 8 - 1;
   end record;

   --  DEBUG Event record types used to signal DEBUG about Ada events

   type Debug_Event_Record is record
      Code     : Unsigned_Word; --  Event code that uniquely identifies event
      Flags    : Bit_Array_8;   --  Flag bits
      --                            Bit 0: This event allows a parameter list
      --                            Bit 1: Parameters are address expressions
      Sentinal : Unsigned_Byte; --  Sentinal valuye: Always K_EVENT_SENT
      TS_Kind  : Unsigned_Byte; --  DST type specification: Always K_TS_TASK
      DType    : Unsigned_Byte; --  DTYPE of parameter if of atomic data type
      --                            Always K_DTYPE_TASK
      MBZ      : Unsigned_Byte; --  Unused (must be zero)
      Minchr   : Count_Type;    --  Minimum chars needed to identify event
      Name     : ASCIC (31);    --  Event name uppercase only
      Help     : AASCIC;        --  Event description
   end record;

   for Debug_Event_Record use record
      Code     at 0 range 0 .. 15;
      Flags    at 2 range 0 .. 7;
      Sentinal at 3 range 0 .. 7;
      TS_Kind  at 4 range 0 .. 7;
      Dtype    at 5 range 0 .. 7;
      MBZ      at 6 range 0 .. 7;
      Minchr   at 7 range 0 .. 7;
      Name     at 8 range 0 .. 32 * 8 - 1;
      Help     at 40 range 0 .. 31;
   end record;

   type Ada_Event_Control_Block_Type is record
      Code      : Unsigned_Word;     --  Reserved and defined by DEBUG
      Unused1   : Unsigned_Byte;     --  Reserved and defined by DEBUG
      Sentinal  : Unsigned_Byte;     --  Reserved and defined by DEBUG
      Facility  : Unsigned_Word;     --  Reserved and defined by DEBUG
      Flags     : Unsigned_Word;     --  Reserved and defined by DEBUG
      Value     : Unsigned_Longword; --  Reserved and defined by DEBUG
      Unused2   : Unsigned_Longword; --  Reserved and defined by DEBUG
      Sigargs   : Unsigned_Longword;
      P1        : Unsigned_Longword;
      Sub_Event : Unsigned_Longword;
   end record;

   for Ada_Event_Control_Block_Type use record
      Code      at 0 range 0 .. 15;
      Unused1   at 2 range 0 .. 7;
      Sentinal  at 3 range 0 .. 7;
      Facility  at 4 range 0 .. 15;
      Flags     at 6 range 0 .. 15;
      Value     at 8 range 0 .. 31;
      Unused2   at 12 range 0 .. 31;
      Sigargs   at 16 range 0 .. 31;
      P1        at 20 range 0 .. 31;
      Sub_Event at 24 range 0 .. 31;
   end record;

   type Ada_Event_Control_Block_Access is access Ada_Event_Control_Block_Type;
   for Ada_Event_Control_Block_Access'Size use 32;

   --  Print_Routine_Type with max optional parameters

   type Print_Routine_Type is access procedure
     (Print_Function    : Print_Functions;
      Print_Subfunction : Print_Functions;
      P1                : Unsigned_Longword := 0;
      P2                : Unsigned_Longword := 0;
      P3                : Unsigned_Longword := 0;
      P4                : Unsigned_Longword := 0;
      P5                : Unsigned_Longword := 0;
      P6                : Unsigned_Longword := 0);
   for Print_Routine_Type'Size use 32;

   ---------------
   -- Constants --
   ---------------

   --  These are used to obtain and convert task values
   K_CVT_VALUE_NUM  : constant := 1;
   K_CVT_NUM_VALUE  : constant := 2;
   K_NEXT_TASK      : constant := 3;

   --  These are used to ask ADA to display task information
   K_SHOW_TASK     : constant := 4;
   K_SHOW_STAT     : constant := 5;
   K_SHOW_DEADLOCK : constant := 6;

   --  These are used to get and set various attributes of one or more tasks
   --    Task state
   --  K_GET_STATE  : constant := 7;
   --  K_GET_ACTIVE : constant := 8;
   --  K_SET_ACTIVE : constant := 9;
   K_SET_ABORT  : constant := 10;
   --  K_SET_HOLD   : constant := 11;

   --    Task priority
   K_GET_PRIORITY      : constant := 12;
   K_SET_PRIORITY      : constant := 13;
   K_RESTORE_PRIORITY  : constant := 14;

   --    Task registers
   --  K_GET_REGISTERS     : constant := 15;
   --  K_SET_REGISTERS     : constant := 16;

   --  These are used to control definable events
   K_ENABLE_EVENT   : constant := 17;
   K_DISABLE_EVENT  : constant := 18;
   K_ANNOUNCE_EVENT : constant := 19;

   --  These are used to control time-slicing.
   --  K_SHOW_TIME_SLICE : constant := 20;
   --  K_SET_TIME_SLICE  : constant := 21;

   --  This is used to symbolize task stack addresses.
   --  K_SYMBOLIZE_ADDRESS : constant := 22;

   K_GET_CALLER : constant := 23;
   --  This is used to obtain the task value of the caller task

   --  Miscellaneous functions - see below for details

   K_CLEANUP_EVENT  : constant := 24;
   K_SHOW_EVENT_DEF : constant := 25;
   --  K_CHECK_TASK_STACK : constant := 26;  --  why commented out ???

   --  This is used to obtain the DBGEXT-interface revision level
   --  K_GET_DBGEXT_REV : constant := 27; -- why commented out ???

   K_GET_STATE_1 : constant := 28;
   --  This is used to obtain additional state info, primarily for PCA

   K_FIND_EVENT_BY_CODE : constant := 29;
   K_FIND_EVENT_BY_NAME : constant := 30;
   --  These are used to search for user-defined event entries

   --  This is used to stop task schedulding. Why commented out ???
   --  K_STOP_ALL_OTHER_TASKS : constant := 31;

   --  Debug event constants

   K_TASK_NOT_EXIST  : constant := 3;
   K_SUCCESS         : constant := 1;
   K_EVENT_SENT      : constant := 16#9A#;
   K_TS_TASK         : constant := 18;
   K_DTYPE_TASK      : constant := 44;

   --  Status signal constants

   SS_BADPARAM       : constant := 20;
   SS_NORMAL         : constant := 1;

   --  Miscellaneous mask constants

   V_EVNT_ALL        : constant := 0;
   V_Full_Display    : constant := 11;
   V_Suppress_Header : constant := 13;

   --  CMA constants (why are some commented out???)

   CMA_C_DEBGET_GUARDSIZE     : constant := 1;
   CMA_C_DEBGET_IS_HELD       : constant := 2;
--   CMA_C_DEBGET_IS_INITIAL    : constant := 3;
--   CMA_C_DEBGET_NUMBER        : constant := 4;
   CMA_C_DEBGET_STACKPTR      : constant := 5;
   CMA_C_DEBGET_STACK_BASE    : constant := 6;
   CMA_C_DEBGET_STACK_TOP     : constant := 7;
   CMA_C_DEBGET_SCHED_STATE   : constant := 8;
   CMA_C_DEBGET_YELLOWSIZE    : constant := 9;
--   CMA_C_DEBGET_BASE_PRIO     : constant := 10;
--   CMA_C_DEBGET_REGS          : constant := 11;
--   CMA_C_DEBGET_ALT_PENDING   : constant := 12;
--   CMA_C_DEBGET_ALT_A_ENABLE  : constant := 13;
--   CMA_C_DEBGET_ALT_G_ENABLE  : constant := 14;
--   CMA_C_DEBGET_SUBSTATE      : constant := 15;
--   CMA_C_DEBGET_OBJECT_ADDR   : constant := 16;
--   CMA_C_DEBGET_THKIND        : constant := 17;
--   CMA_C_DEBGET_DETACHED      : constant := 18;
   CMA_C_DEBGET_TCB_SIZE      : constant := 19;
--   CMA_C_DEBGET_START_PC      : constant := 20;
--   CMA_C_DEBGET_NEXT_PC       : constant := 22;
--   CMA_C_DEBGET_POLICY        : constant := 23;
--   CMA_C_DEBGET_STACK_YELLOW  : constant := 24;
--   CMA_C_DEBGET_STACK_DEFAULT : constant := 25;

   --  Miscellaneous counted ascii constants

   Star     : constant AASCIC := new ASCIC'(2, ("* "));
   NoStar   : constant AASCIC := new ASCIC'(2, ("  "));
   Hold     : constant AASCIC := new ASCIC'(4, ("HOLD"));
   NoHold   : constant AASCIC := new ASCIC'(4, ("    "));
   Header   : constant AASCIC := new ASCIC '
     (60, ("  task id     pri hold state   substate          task object"));
   Empty_Text : constant AASCIC := new ASCIC (0);

   --  DEBUG Ada tasking states equated to their GNAT tasking equivalents

   Ada_State_Invalid_State     : constant AASCIC :=
     new ASCIC'(17, "Invalid state    ");
--   Ada_State_Abnormal          : constant AASCIC :=
--     new ASCIC'(17, "Abnormal         ");
   Ada_State_Aborting          : constant AASCIC :=
     new ASCIC'(17, "Aborting         "); --  Aborting (new)
--   Ada_State_Completed_Abn     : constant AASCIC :=
--     new ASCIC'(17, "Completed  [abn] ");
--   Ada_State_Completed_Exc     : constant AASCIC :=
--     new ASCIC'(17, "Completed  [exc] ");
   Ada_State_Completed         : constant AASCIC :=
     new ASCIC'(17, "Completed        "); --  Master_Completion_Sleep
   Ada_State_Runnable          : constant AASCIC :=
     new ASCIC'(17, "Runnable         "); --  Runnable
   Ada_State_Activating        : constant AASCIC :=
     new ASCIC'(17, "Activating       ");
   Ada_State_Accept            : constant AASCIC :=
     new ASCIC'(17, "Accept           "); --  Acceptor_Sleep
   Ada_State_Select_or_Delay   : constant AASCIC :=
     new ASCIC'(17, "Select or delay  "); --  Acceptor_Delay_Sleep
   Ada_State_Select_or_Term    : constant AASCIC :=
     new ASCIC'(17, "Select or term.  "); -- Terminate_Alternative
   Ada_State_Select_or_Abort   : constant AASCIC :=
     new ASCIC'(17, "Select or abort  "); --  Async_Select_Sleep (new)
--   Ada_State_Select            : constant AASCIC :=
--     new ASCIC'(17, "Select           ");
   Ada_State_Activating_Tasks  : constant AASCIC :=
     new ASCIC'(17, "Activating tasks "); --  Activator_Sleep
   Ada_State_Delay             : constant AASCIC :=
     new ASCIC'(17, "Delay            "); --  AST_Pending
--   Ada_State_Dependents        : constant AASCIC :=
--     new ASCIC'(17, "Dependents       ");
   Ada_State_Entry_Call        : constant AASCIC :=
     new ASCIC'(17, "Entry call       "); --  Entry_Caller_Sleep
   Ada_State_Cond_Entry_Call   : constant AASCIC :=
     new ASCIC'(17, "Cond. entry call "); --  Call.Mode.Conditional_Call
   Ada_State_Timed_Entry_Call  : constant AASCIC :=
     new ASCIC'(17, "Timed entry call "); --  Call.Mode.Timed_Call
   Ada_State_Async_Entry_Call  : constant AASCIC :=
     new ASCIC'(17, "Async entry call "); --  Call.Mode.Asynchronous_Call (new)
--   Ada_State_Dependents_Exc    : constant AASCIC :=
--     new ASCIC'(17, "Dependents [exc] ");
   Ada_State_IO_or_AST         : constant AASCIC :=
     new ASCIC'(17, "I/O or AST       "); --  AST_Server_Sleep
--   Ada_State_Shared_Resource   : constant AASCIC :=
--     new ASCIC'(17, "Shared resource  ");
   Ada_State_Not_Yet_Activated : constant AASCIC :=
     new ASCIC'(17, "Not yet activated"); --  Unactivated
--   Ada_State_Terminated_Abn    : constant AASCIC :=
--     new ASCIC'(17, "Terminated [abn] ");
--   Ada_State_Terminated_Exc    : constant AASCIC :=
--     new ASCIC'(17, "Terminated [exc] ");
   Ada_State_Terminated        : constant AASCIC :=
     new ASCIC'(17, "Terminated       "); --  Terminated
   Ada_State_Server            : constant AASCIC :=
     new ASCIC'(17, "Server           "); --  Servers
   Ada_State_Async_Hold        : constant AASCIC :=
     new ASCIC'(17, "Async_Hold       "); --  Async_Hold

   --  Task state counted ascii constants

   Debug_State_Emp : constant AASCIC := new ASCIC'(5, "     ");
   Debug_State_Run : constant AASCIC := new ASCIC'(5, "RUN  ");
   Debug_State_Rea : constant AASCIC := new ASCIC'(5, "READY");
   Debug_State_Sus : constant AASCIC := new ASCIC'(5, "SUSP ");
   Debug_State_Ter : constant AASCIC := new ASCIC'(5, "TERM ");

   --  Priority order of event display

   Global_Event_Display_Order : constant array (Event_Kind_Type)
     of Event_Kind_Type := (
      Debug_Event_Abort_Terminated,
      Debug_Event_Activating,
      Debug_Event_Dependents_Exception,
      Debug_Event_Exception_Terminated,
      Debug_Event_Handled,
      Debug_Event_Handled_Others,
      Debug_Event_Preempted,
      Debug_Event_Rendezvous_Exception,
      Debug_Event_Run,
      Debug_Event_Suspended,
      Debug_Event_Terminated);

   --  Constant array defining all debug events

   Event_Directory : constant array (Event_Kind_Type)
     of Debug_Event_Record := (
      (Debug_Event_Activating,
       (False, False, False, False, False, False, False, True),
       K_EVENT_SENT,
       K_TS_TASK,
       K_DTYPE_TASK,
       0,
       2,
       (31, "ACTIVATING                     "),
       new ASCIC'(41, "!_a task is about to begin its activation")),

      (Debug_Event_Run,
       (False, False, False, False, False, False, False, True),
       K_EVENT_SENT,
       K_TS_TASK,
       K_DTYPE_TASK,
       0,
       2,
       (31, "RUN                            "),
       new ASCIC'(24, "!_a task is about to run")),

      (Debug_Event_Suspended,
       (False, False, False, False, False, False, False, True),
       K_EVENT_SENT,
       K_TS_TASK,
       K_DTYPE_TASK,
       0,
       1,
       (31, "SUSPENDED                      "),
       new ASCIC'(33, "!_a task is about to be suspended")),

      (Debug_Event_Preempted,
       (False, False, False, False, False, False, False, True),
       K_EVENT_SENT,
       K_TS_TASK,
       K_DTYPE_TASK,
       0,
       1,
       (31, "PREEMPTED                      "),
       new ASCIC'(33, "!_a task is about to be preempted")),

      (Debug_Event_Terminated,
       (False, False, False, False, False, False, False, True),
       K_EVENT_SENT,
       K_TS_TASK,
       K_DTYPE_TASK,
       0,
       1,
       (31, "TERMINATED                     "),
       new ASCIC'(57,
        "!_a task is terminating (including by abort or exception)")),

      (Debug_Event_Abort_Terminated,
       (False, False, False, False, False, False, False, True),
       K_EVENT_SENT,
       K_TS_TASK,
       K_DTYPE_TASK,
       0,
       2,
       (31, "ABORT_TERMINATED               "),
       new ASCIC'(40, "!_a task is terminating because of abort")),

      (Debug_Event_Exception_Terminated,
       (False, False, False, False, False, False, False, True),
       K_EVENT_SENT,
       K_TS_TASK,
       K_DTYPE_TASK,
       0,
       1,
       (31, "EXCEPTION_TERMINATED           "),
       new ASCIC'(47, "!_a task is terminating because of an exception")),

      (Debug_Event_Rendezvous_Exception,
       (False, False, False, False, False, False, False, True),
       K_EVENT_SENT,
       K_TS_TASK,
       K_DTYPE_TASK,
       0,
       3,
       (31, "RENDEZVOUS_EXCEPTION           "),
       new ASCIC'(49, "!_an exception is propagating out of a rendezvous")),

      (Debug_Event_Handled,
       (False, False, False, False, False, False, False, True),
       K_EVENT_SENT,
       K_TS_TASK,
       K_DTYPE_TASK,
       0,
       1,
       (31, "HANDLED                        "),
       new ASCIC'(37, "!_an exception is about to be handled")),

      (Debug_Event_Dependents_Exception,
       (False, False, False, False, False, False, False, True),
       K_EVENT_SENT,
       K_TS_TASK,
       K_DTYPE_TASK,
       0,
       1,
       (31, "DEPENDENTS_EXCEPTION           "),
       new ASCIC'(64,
        "!_an exception is about to cause a task to await dependent tasks")),

      (Debug_Event_Handled_Others,
       (False, False, False, False, False, False, False, True),
       K_EVENT_SENT,
       K_TS_TASK,
       K_DTYPE_TASK,
       0,
       1,
       (31, "HANDLED_OTHERS                 "),
       new ASCIC'(58,
        "!_an exception is about to be handled in an OTHERS handler")));

   --  Help on events displayed in DEBUG

   Event_Def_Help : constant AASCIC_Array := (
     new ASCIC'(0,  ""),
     new ASCIC'(65,
      "  The general forms of commands to set a breakpoint or tracepoint"),
     new ASCIC'(22, "  on an Ada event are:"),
     new ASCIC'(73, "    SET BREAK/EVENT=event [task[, ... ]] " &
                    "[WHEN(expr)] [DO(comnd[; ... ])]"),
     new ASCIC'(73, "    SET TRACE/EVENT=event [task[, ... ]] " &
                    "[WHEN(expr)] [DO(comnd[; ... ])]"),
     new ASCIC'(0,  ""),
     new ASCIC'(65,
      "  If tasks are specified, the breakpoint will trigger only if the"),
     new ASCIC'(40, "  event occurs for those specific tasks."),
     new ASCIC'(0,  ""),
     new ASCIC'(39, "  Ada event names and their definitions"),
     new ASCIC'(0,  ""));

   -----------------------
   -- Package Variables --
   -----------------------

   AC_Buffer : ASCIC127;

   Events_Enabled_Count : Integer := 0;

   Print_Routine_Bufsiz : constant := 132;
   Print_Routine_Bufcnt : Integer := 0;
   Print_Routine_Linbuf : String (1 .. Print_Routine_Bufsiz);

   Global_Task_Debug_Events : Debug_Event_Array :=
     (False, False, False, False, False, False, False, False,
      False, False, False, False, False, False, False, False);
   --  Global table of task debug events set by the debugger

   --------------------------
   -- Exported Subprograms --
   --------------------------

   procedure Default_Print_Routine
     (Print_Function    : Print_Functions;
      Print_Subfunction : Print_Functions;
      P1                : Unsigned_Longword := 0;
      P2                : Unsigned_Longword := 0;
      P3                : Unsigned_Longword := 0;
      P4                : Unsigned_Longword := 0;
      P5                : Unsigned_Longword := 0;
      P6                : Unsigned_Longword := 0);
   --  The default print routine if not overridden.
   --  Print_Function determines option argument formatting.
   --  Print_Subfunction buffers output if No_Print, calls Put_Output if
   --  Print_Newline

   pragma Export_Procedure
     (Default_Print_Routine,
      Mechanism => (Value, Value, Reference, Reference, Reference));

   --------------------------
   -- Imported Subprograms --
   --------------------------

   procedure Debug_Get
     (Thread_Id : OSI.Thread_Id;
      Item_Req  : Unsigned_Word;
      Out_Buff  : System.Address;
      Buff_Siz  : Unsigned_Word);

   procedure Debug_Get
     (Thread_Id : OSI.Thread_Id;
      Item_Req  : Unsigned_Word;
      Out_Buff  : Unsigned_Longword;
      Buff_Siz  : Unsigned_Word);
   pragma Import (External, Debug_Get);

   pragma Import_Procedure (Debug_Get, "CMA$DEBUG_GET",
     (OSI.Thread_Id, Unsigned_Word, System.Address, Unsigned_Word),
     (Reference, Value, Reference, Value));

   pragma Import_Procedure (Debug_Get, "CMA$DEBUG_GET",
     (OSI.Thread_Id, Unsigned_Word, Unsigned_Longword, Unsigned_Word),
     (Reference, Value, Reference, Value));

   procedure FAOL
     (Status : out Cond_Value_Type;
      Ctrstr : String;
      Outlen : out Unsigned_Word;
      Outbuf : out String;
      Prmlst : Unsigned_Longword_Array);
   pragma Import (External, FAOL);

   pragma Import_Valued_Procedure (FAOL, "SYS$FAOL",
     (Cond_Value_Type, String, Unsigned_Word, String, Unsigned_Longword_Array),
     (Value, Descriptor (S), Reference, Descriptor (S), Reference));

   procedure Put_Output (
     Status         : out Cond_Value_Type;
     Message_String : String);

   procedure Put_Output (Message_String : String);
   pragma Import (External, Put_Output);

   pragma Import_Valued_Procedure (Put_Output, "LIB$PUT_OUTPUT",
     (Cond_Value_Type, String),
     (Value, Short_Descriptor (S)));

   pragma Import_Procedure (Put_Output, "LIB$PUT_OUTPUT",
     (String),
     (Short_Descriptor (S)));

   procedure Signal
     (Condition_Value     : Cond_Value_Type;
      Number_Of_Arguments : Integer := Integer'Null_Parameter;
      FAO_Argument_1      : Unsigned_Longword :=
                              Unsigned_Longword'Null_Parameter);
   pragma Import (External, Signal);

   pragma Import_Procedure (Signal, "LIB$SIGNAL",
      (Cond_Value_Type, Integer, Unsigned_Longword),
      (Value, Value, Value),
       Number_Of_Arguments);

   ----------------------------
   -- Generic Instantiations --
   ----------------------------

   function Fetch is new Fetch_From_Address (Unsigned_Longword);
   pragma Unreferenced (Fetch);

   procedure Free is new Ada.Unchecked_Deallocation
     (Object => Ada_Event_Control_Block_Type,
      Name   => Ada_Event_Control_Block_Access);

   function To_AASCIC is new
     Ada.Unchecked_Conversion (Unsigned_Longword, AASCIC);

   function To_Addr is new
     Ada.Unchecked_Conversion (Task_Procedure_Access, Address);
   pragma Unreferenced (To_Addr);

   function To_EVCB is new
     Ada.Unchecked_Conversion
      (Unsigned_Longword, Ada_Event_Control_Block_Access);

   function To_Integer is new
     Ada.Unchecked_Conversion (Task_Id, System.Task_Primitives.Task_Address);

   function To_Print_Routine_Type is new
     Ada.Unchecked_Conversion (Short_Address, Print_Routine_Type);

   --  Optional argumements passed to Print_Routine have to be
   --  Unsigned_Longwords so define the required Unchecked_Conversions

   function To_UL is new
     Ada.Unchecked_Conversion (AASCIC, Unsigned_Longword);

   function To_UL is new
     Ada.Unchecked_Conversion (Integer, Unsigned_Longword);

   function To_UL is new
     Ada.Unchecked_Conversion (Task_Id, Unsigned_Longword);

   pragma Warnings (Off); --  Different sizes
   function To_UL is new
     Ada.Unchecked_Conversion (Task_Entry_Index, Unsigned_Longword);
   pragma Warnings (On);

   function To_UL is new
     Ada.Unchecked_Conversion (Short_Address, Unsigned_Longword);

   function To_UL is new
     Ada.Unchecked_Conversion
      (Ada_Event_Control_Block_Access, Unsigned_Longword);

   -----------------------
   -- Local Subprograms --
   -----------------------

   subtype Function_Codes is System.Aux_DEC.Unsigned_Word range 1 .. 31;
   --  The 31 function codes sent by the debugger needed to implement
   --  tasking support, enumerated below.

   type Register_Array is array (Natural range 0 .. 16) of
     System.Aux_DEC.Unsigned_Longword;
   --  The register array is a holdover from VAX and not used
   --  on Alpha or I64 but is kept as a filler below.

   type DBGEXT_Control_Block (Function_Code : Function_Codes) is record
      Facility_ID         : System.Aux_DEC.Unsigned_Word;
      --  For GNAT use the "Ada" facility ID
      Status              : System.Aux_DEC.Unsigned_Longword;
      --  Successful or otherwise returned status
      Flags               : System.Aux_DEC.Bit_Array_32;
      --   Used to flag event as global
      Print_Routine       : System.Aux_DEC.Short_Address;
      --  The print subprogram the caller wants to use for output
      Event_Code_or_EVCB  : System.Aux_DEC.Unsigned_Longword;
      --  Dual use Event Code or EVent Control Block
      Event_Value_or_Name : System.Aux_DEC.Unsigned_Longword;
      --  Dual use Event Value or Event Name string pointer
      Event_Entry         : System.Aux_DEC.Unsigned_Longword;
      Task_Value          : Task_Id;
      Task_Number         : Integer;
      Ada_Flags           : System.Aux_DEC.Bit_Array_32;
      Priority            : System.Aux_DEC.Bit_Array_32;
      Active_Registers    : System.Aux_DEC.Short_Address;

      case Function_Code is
         when K_GET_STATE_1 =>
            Base_Priority       : System.Aux_DEC.Bit_Array_32;
            Task_Type_Name      : System.Aux_DEC.Short_Address;
            Creation_PC         : System.Aux_DEC.Short_Address;
            Parent_Task_ID      : Task_Id;

         when others =>
            Ignored_Unused      : Register_Array;

      end case;
   end record;

   for DBGEXT_Control_Block use record
      Function_Code       at 0  range 0 .. 15;
      Facility_ID         at 2  range 0 .. 15;
      Status              at 4  range 0 .. 31;
      Flags               at 8  range 0 .. 31;
      Print_Routine       at 12 range 0 .. 31;
      Event_Code_or_EVCB  at 16 range 0 .. 31;
      Event_Value_or_Name at 20 range 0 .. 31;
      Event_Entry         at 24 range 0 .. 31;
      Task_Value          at 28 range 0 .. 31;
      Task_Number         at 32 range 0 .. 31;
      Ada_Flags           at 36 range 0 .. 31;
      Priority            at 40 range 0 .. 31;
      Active_Registers    at 44 range 0 .. 31;
      Ignored_Unused      at 48 range 0 .. 17 * 32 - 1;
      Base_Priority       at 48 range 0 .. 31;
      Task_Type_Name      at 52 range 0 .. 31;
      Creation_PC         at 56 range 0 .. 31;
      Parent_Task_ID      at 60 range 0 .. 31;
   end record;

   type DBGEXT_Control_Block_Access is access all DBGEXT_Control_Block;

   function DBGEXT (Control_Block : DBGEXT_Control_Block_Access)
     return System.Aux_DEC.Unsigned_Word;
   --  Exported to s-taprop.adb to avoid having a VMS specific s-tasdeb.ads
   pragma Convention (C, DBGEXT);
   pragma Export_Function (DBGEXT, "GNAT$DBGEXT");
   --  This routine is called by CMA when VMS DEBUG wants the Gnat RTL
   --  to give it some assistance (primarily when tasks are debugged).
   --
   --  The single parameter is an "external control block". On input to
   --  the Gnat RTL this control block determines the debugging function
   --  to be performed, and supplies parameters.  This routine cases on
   --  the function code, and calls the appropriate Gnat RTL routine,
   --  which returns values by modifying the external control block.

   procedure Announce_Event
      (Event_EVCB    : Unsigned_Longword;
       Print_Routine : Print_Routine_Type := Default_Print_Routine'Access);
   --  Announce the occurence of a DEBUG tasking event

   procedure Cleanup_Event (Event_EVCB : Unsigned_Longword);
   --  After DEBUG has processed an event that has signalled, the signaller
   --  must cleanup. Cleanup consists of freeing the event control block.

   procedure Disable_Event
      (Flags       : Bit_Array_32;
       Event_Value : Unsigned_Longword;
       Event_Code  : Unsigned_Longword;
       Status      : out Cond_Value_Type);
   --  Disable a DEBUG tasking event

   function DoAC (S : String) return Address;
   --  Convert a string to the address of an internal buffer containing
   --  the counted ASCII.

   procedure Enable_Event
      (Flags       : Bit_Array_32;
       Event_Value : Unsigned_Longword;
       Event_Code  : Unsigned_Longword;
       Status      : out Cond_Value_Type);
   --  Enable a requested DEBUG tasking event

   procedure Find_Event_By_Code
      (Event_Code  : Unsigned_Longword;
       Event_Entry : out Unsigned_Longword;
       Status      : out Cond_Value_Type);
   --  Convert an event code to the address of the event entry

   procedure Find_Event_By_Name
      (Event_Name  : Unsigned_Longword;
       Event_Entry : out Unsigned_Longword;
       Status      : out Cond_Value_Type);
   --  Find an event entry given the event name

   procedure List_Entry_Waiters
     (Task_Value      : Task_Id;
      Full_Display    : Boolean := False;
      Suppress_Header : Boolean := False;
      Print_Routine   : Print_Routine_Type := Default_Print_Routine'Access);
   --  List information about tasks waiting on an entry

   procedure Put (S : String);
   --  Display S on standard output

   procedure Put_Line (S : String := "");
   --  Display S on standard output with an additional line terminator

   procedure Show_Event
      (Print_Routine : Print_Routine_Type := Default_Print_Routine'Access);
   --  Show what events are available

   procedure Show_One_Task
     (Task_Value      : Task_Id;
      Full_Display    : Boolean := False;
      Suppress_Header : Boolean := False;
      Print_Routine   : Print_Routine_Type := Default_Print_Routine'Access);
   --  Display information about one task

   procedure Show_Rendezvous
     (Task_Value      : Task_Id;
      Ada_State       : AASCIC := Empty_Text;
      Full_Display    : Boolean := False;
      Suppress_Header : Boolean := False;
      Print_Routine   : Print_Routine_Type := Default_Print_Routine'Access);
   --  Display information about a task rendezvous

   procedure Trace_Output (Message_String : String);
   --  Call Put_Output if Trace_on ("VMS")

   procedure Write (Fd : Integer; S : String; Count : Integer);

   --------------------
   -- Announce_Event --
   --------------------

   procedure Announce_Event
      (Event_EVCB    : Unsigned_Longword;
       Print_Routine : Print_Routine_Type := Default_Print_Routine'Access)
   is
      EVCB : constant Ada_Event_Control_Block_Access := To_EVCB (Event_EVCB);

      Event_Kind : constant Event_Kind_Type :=
                     (if EVCB.Sub_Event /= 0
                      then Event_Kind_Type (EVCB.Sub_Event)
                      else Event_Kind_Type (EVCB.Code));

      TI : constant String := "   Task %TASK !UI is ";
      --  Announce prefix

   begin
      Trace_Output ("Announce called");

      case Event_Kind is
         when Debug_Event_Activating =>
            Print_Routine (Print_FAO, Print_Newline,
              To_UL (DoAC (TI & "about to begin its activation")),
              EVCB.Value);
         when Debug_Event_Exception_Terminated =>
            Print_Routine (Print_FAO, Print_Newline,
              To_UL (DoAC (TI & "terminating because of an exception")),
              EVCB.Value);
         when Debug_Event_Run =>
            Print_Routine (Print_FAO, Print_Newline,
              To_UL (DoAC (TI & "about to run")),
              EVCB.Value);
         when Debug_Event_Abort_Terminated =>
            Print_Routine (Print_FAO, Print_Newline,
              To_UL (DoAC (TI & "terminating because of abort")),
              EVCB.Value);
         when Debug_Event_Terminated =>
            Print_Routine (Print_FAO, Print_Newline,
              To_UL (DoAC (TI & "terminating normally")),
              EVCB.Value);
         when others => null;
      end case;
   end Announce_Event;

   -------------------
   -- Cleanup_Event --
   -------------------

   procedure Cleanup_Event (Event_EVCB  : Unsigned_Longword) is
      EVCB : Ada_Event_Control_Block_Access := To_EVCB (Event_EVCB);
   begin
      Free (EVCB);
   end Cleanup_Event;

   ------------------------
   -- Continue_All_Tasks --
   ------------------------

   procedure Continue_All_Tasks is
   begin
      null; --  VxWorks
   end Continue_All_Tasks;

   ------------
   -- DBGEXT --
   ------------

   function DBGEXT
     (Control_Block : DBGEXT_Control_Block_Access)
      return System.Aux_DEC.Unsigned_Word
   is
      Print_Routine : Print_Routine_Type := Default_Print_Routine'Access;
   begin
      Trace_Output ("DBGEXT called");

      if Control_Block.Print_Routine /= Address_Zero then
         Print_Routine := To_Print_Routine_Type (Control_Block.Print_Routine);
      end if;

      case Control_Block.Function_Code is

         --  Convert a task value to a task number.
         --  The output results are stored in the CONTROL_BLOCK.

         when K_CVT_VALUE_NUM =>
            Trace_Output ("DBGEXT param 1 - CVT Value to NUM");
            Control_Block.Task_Number :=
              Control_Block.Task_Value.Known_Tasks_Index + 1;
            Control_Block.Status := K_SUCCESS;
            Trace_Output ("Task Number: ");
            Trace_Output (Integer'Image (Control_Block.Task_Number));
            return SS_NORMAL;

         --  Convert a task number to a task value.
         --  The output results are stored in the CONTROL_BLOCK.

         when K_CVT_NUM_VALUE =>
            Trace_Output ("DBGEXT param 2 - CVT NUM to Value");
            Trace_Output ("Task Number: ");
            Trace_Output (Integer'Image (Control_Block.Task_Number));
            Control_Block.Task_Value :=
              Known_Tasks (Control_Block.Task_Number - 1);
            Control_Block.Status := K_SUCCESS;
            Trace_Output ("Task Value: ");
            Trace_Output (Unsigned_Longword'Image
              (To_UL (Control_Block.Task_Value)));
            return SS_NORMAL;

         --  Obtain the "next" task after a specified task.
         --  ??? To do: If specified check the PRIORITY, STATE, and HOLD
         --  fields to restrict the selection of the next task.
         --  The output results are stored in the CONTROL_BLOCK.

         when K_NEXT_TASK =>
            Trace_Output ("DBGEXT param 3 - Next Task");
            Trace_Output ("Task Value: ");
            Trace_Output (Unsigned_Longword'Image
              (To_UL (Control_Block.Task_Value)));

            if Control_Block.Task_Value = null then
               Control_Block.Task_Value := Known_Tasks (Known_Tasks'First);
            else
               Control_Block.Task_Value :=
                 Known_Tasks (Control_Block.Task_Value.Known_Tasks_Index + 1);
            end if;

            if Control_Block.Task_Value = null then
               Control_Block.Task_Value := Known_Tasks (Known_Tasks'First);
            end if;

            Control_Block.Status := K_SUCCESS;
            return SS_NORMAL;

         --  Display the state of a task. The FULL bit is checked to decide if
         --  a full or brief task display is desired. The output results are
         --  stored in the CONTROL_BLOCK.

         when K_SHOW_TASK =>
            Trace_Output ("DBGEXT param 4 - Show Task");

            if Control_Block.Task_Value = null then
               Control_Block.Status := K_TASK_NOT_EXIST;
            else
               Show_One_Task
                 (Control_Block.Task_Value,
                  Control_Block.Ada_Flags (V_Full_Display),
                  Control_Block.Ada_Flags (V_Suppress_Header),
                  Print_Routine);

               Control_Block.Status := K_SUCCESS;
            end if;

            return SS_NORMAL;

         --  Enable a requested DEBUG tasking event

         when K_ENABLE_EVENT =>
            Trace_Output ("DBGEXT param 17 - Enable Event");
            Enable_Event
              (Control_Block.Flags,
               Control_Block.Event_Value_or_Name,
               Control_Block.Event_Code_or_EVCB,
               Control_Block.Status);

            return SS_NORMAL;

         --  Disable a DEBUG tasking event

         when K_DISABLE_EVENT =>
            Trace_Output ("DBGEXT param 18 - Disable Event");
            Disable_Event
              (Control_Block.Flags,
               Control_Block.Event_Value_or_Name,
               Control_Block.Event_Code_or_EVCB,
               Control_Block.Status);

            return SS_NORMAL;

         --  Announce the occurence of a DEBUG tasking event

         when K_ANNOUNCE_EVENT =>
            Trace_Output ("DBGEXT param 19 - Announce Event");
            Announce_Event
              (Control_Block.Event_Code_or_EVCB,
               Print_Routine);

            Control_Block.Status := K_SUCCESS;
            return SS_NORMAL;

         --  After DEBUG has processed an event that has signalled,
         --  the signaller must cleanup.
         --  Cleanup consists of freeing the event control block.

         when K_CLEANUP_EVENT =>
            Trace_Output ("DBGEXT param 24 - Cleanup Event");
            Cleanup_Event (Control_Block.Event_Code_or_EVCB);

            Control_Block.Status := K_SUCCESS;
            return SS_NORMAL;

         --  Show what events are available

         when K_SHOW_EVENT_DEF =>
            Trace_Output ("DBGEXT param 25 - Show Event Def");
            Show_Event (Print_Routine);

            Control_Block.Status := K_SUCCESS;
            return SS_NORMAL;

         --  Convert an event code to the address of the event entry

         when K_FIND_EVENT_BY_CODE =>
            Trace_Output ("DBGEXT param 29 - Find Event by Code");
            Find_Event_By_Code
              (Control_Block.Event_Code_or_EVCB,
               Control_Block.Event_Entry,
               Control_Block.Status);

            return SS_NORMAL;

         --  Find an event entry given the event name

         when K_FIND_EVENT_BY_NAME =>
            Trace_Output ("DBGEXT param 30 - Find Event by Name");
            Find_Event_By_Name
              (Control_Block.Event_Value_or_Name,
               Control_Block.Event_Entry,
               Control_Block.Status);
            return SS_NORMAL;

         --  ??? To do: Implement priority events
         --  Get, set or restore a task's priority

         when K_GET_PRIORITY or K_SET_PRIORITY or K_RESTORE_PRIORITY =>
            Trace_Output ("DBGEXT priority param - Not yet implemented");
            Trace_Output (Function_Codes'Image
             (Control_Block.Function_Code));
            return SS_BADPARAM;

         --  ??? To do: Implement show statistics event
         --  Display task statistics

         when K_SHOW_STAT =>
            Trace_Output ("DBGEXT show stat param - Not yet implemented");
            Trace_Output (Function_Codes'Image
             (Control_Block.Function_Code));
            return SS_BADPARAM;

         --  ??? To do: Implement get caller event
         --  Obtain the caller of a task in a rendezvous. If no rendezvous,
         --  null is returned

         when K_GET_CALLER =>
            Trace_Output ("DBGEXT get caller param - Not yet implemented");
            Trace_Output (Function_Codes'Image
             (Control_Block.Function_Code));
            return SS_BADPARAM;

         --  ??? To do: Implement set terminate event
         --  Terminate a task

         when K_SET_ABORT =>
            Trace_Output ("DBGEXT set terminate param - Not yet implemented");
            Trace_Output (Function_Codes'Image
             (Control_Block.Function_Code));
            return SS_BADPARAM;

         --  ??? To do: Implement show deadlock event
         --  Detect a deadlock

         when K_SHOW_DEADLOCK =>
            Trace_Output ("DBGEXT show deadlock param - Not yet implemented");
            Trace_Output (Function_Codes'Image
             (Control_Block.Function_Code));
            return SS_BADPARAM;

         when others =>
            Trace_Output ("DBGEXT bad param: ");
            Trace_Output (Function_Codes'Image
             (Control_Block.Function_Code));
            return SS_BADPARAM;

      end case;
   end DBGEXT;

   ---------------------------
   -- Default_Print_Routine --
   ---------------------------

   procedure Default_Print_Routine
     (Print_Function    : Print_Functions;
      Print_Subfunction : Print_Functions;
      P1                : Unsigned_Longword := 0;
      P2                : Unsigned_Longword := 0;
      P3                : Unsigned_Longword := 0;
      P4                : Unsigned_Longword := 0;
      P5                : Unsigned_Longword := 0;
      P6                : Unsigned_Longword := 0)
   is
      Status    : Cond_Value_Type;
      Linlen    : Unsigned_Word;
      Item_List : Unsigned_Longword_Array (1 .. 17) :=
        (1 .. 17 => 0);
   begin

      case Print_Function is
         when Print_Control | Print_String =>
            null;

         --  Formatted Ascii Output

         when Print_FAO =>
            Item_List (1) := P2;
            Item_List (2) := P3;
            Item_List (3) := P4;
            Item_List (4) := P5;
            Item_List (5) := P6;
            FAOL
              (Status,
               To_AASCIC (P1).Text,
               Linlen,
               Print_Routine_Linbuf
                 (1 + Print_Routine_Bufcnt .. Print_Routine_Bufsiz),
               Item_List);

            Print_Routine_Bufcnt := Print_Routine_Bufcnt + Integer (Linlen);

         --  Symbolic output

         when Print_Symbol =>
            Item_List (1) := P1;
            FAOL
              (Status,
               "!XI",
               Linlen,
               Print_Routine_Linbuf
                 (1 + Print_Routine_Bufcnt .. Print_Routine_Bufsiz),
               Item_List);

            Print_Routine_Bufcnt := Print_Routine_Bufcnt + Integer (Linlen);

         when others =>
            null;
      end case;

      case Print_Subfunction is

         --  Output buffer with a terminating newline

         when Print_Newline =>
            Put_Output (Status,
              Print_Routine_Linbuf (1 .. Print_Routine_Bufcnt));
            Print_Routine_Bufcnt := 0;

         --  Buffer the output

         when No_Print =>
            null;

         when others =>
            null;
      end case;

   end Default_Print_Routine;

   -------------------
   -- Disable_Event --
   -------------------

   procedure Disable_Event
      (Flags       : Bit_Array_32;
       Event_Value : Unsigned_Longword;
       Event_Code  : Unsigned_Longword;
       Status      : out Cond_Value_Type)
   is
      Task_Value : Task_Id;
      Task_Index : constant Integer := Integer (Event_Value) - 1;
   begin

      Events_Enabled_Count := Events_Enabled_Count - 1;

      if Flags (V_EVNT_ALL) then
         Global_Task_Debug_Events (Integer (Event_Code)) := False;
         Status := K_SUCCESS;
      else
         if Task_Index in Known_Tasks'Range then
            Task_Value := Known_Tasks (Task_Index);
            if Task_Value /= null then
               Task_Value.Common.Debug_Events (Integer (Event_Code)) := False;
               Status := K_SUCCESS;
            else
               Status := K_TASK_NOT_EXIST;
            end if;
         else
            Status := K_TASK_NOT_EXIST;
         end if;
      end if;

      --  Keep count of events for efficiency

      if Events_Enabled_Count <= 0 then
         Events_Enabled_Count := 0;
         Global_Task_Debug_Event_Set := False;
      end if;

   end Disable_Event;

   ----------
   -- DoAC --
   ----------

   function DoAC (S : String) return Address is
   begin
      AC_Buffer.Count := S'Length;
      AC_Buffer.Text (1 .. AC_Buffer.Count) := S;
      return AC_Buffer'Address;
   end DoAC;

   ------------------
   -- Enable_Event --
   ------------------

   procedure Enable_Event
      (Flags       : Bit_Array_32;
       Event_Value : Unsigned_Longword;
       Event_Code  : Unsigned_Longword;
       Status      : out Cond_Value_Type)
   is
      Task_Value : Task_Id;
      Task_Index : constant Integer := Integer (Event_Value) - 1;
   begin

      --  At least one event enabled, any and all events will cause a
      --  condition to be raised and checked. Major tasking slowdown!

      Global_Task_Debug_Event_Set := True;
      Events_Enabled_Count := Events_Enabled_Count + 1;

      if Flags (V_EVNT_ALL) then
         Global_Task_Debug_Events (Integer (Event_Code)) := True;
         Status := K_SUCCESS;
      else
         if Task_Index in Known_Tasks'Range then
            Task_Value := Known_Tasks (Task_Index);
            if Task_Value /= null then
               Task_Value.Common.Debug_Events (Integer (Event_Code)) := True;
               Status := K_SUCCESS;
            else
               Status := K_TASK_NOT_EXIST;
            end if;
         else
            Status := K_TASK_NOT_EXIST;
         end if;
      end if;

   end Enable_Event;

   ------------------------
   -- Find_Event_By_Code --
   ------------------------

   procedure Find_Event_By_Code
      (Event_Code  : Unsigned_Longword;
       Event_Entry : out Unsigned_Longword;
       Status      : out Cond_Value_Type)
   is
      K_SUCCESS        : constant := 1;
      K_NO_SUCH_EVENT  : constant := 9;

   begin
      Trace_Output ("Looking for Event: ");
      Trace_Output (Unsigned_Longword'Image (Event_Code));

      for I in Event_Kind_Type'Range loop
         if Event_Code = Unsigned_Longword (Event_Directory (I).Code) then
            Event_Entry := To_UL (Event_Directory (I)'Address);
            Trace_Output ("Found Event # ");
            Trace_Output (Integer'Image (I));
            Status := K_SUCCESS;
            return;
         end if;
      end loop;

      Status := K_NO_SUCH_EVENT;
   end Find_Event_By_Code;

   ------------------------
   -- Find_Event_By_Name --
   ------------------------

   procedure Find_Event_By_Name
      (Event_Name  : Unsigned_Longword;
       Event_Entry : out Unsigned_Longword;
       Status      : out Cond_Value_Type)
   is
      K_SUCCESS        : constant := 1;
      K_NO_SUCH_EVENT  : constant := 9;

      Event_Name_Cstr : constant ASCIC := To_AASCIC (Event_Name).all;
   begin
      Trace_Output ("Looking for Event: ");
      Trace_Output (Event_Name_Cstr.Text);

      for I in Event_Kind_Type'Range loop
         if Event_Name_Cstr.Count >= Event_Directory (I).Minchr
            and then Event_Name_Cstr.Count <= Event_Directory (I).Name.Count
            and then Event_Name_Cstr.Text (1 .. Event_Directory (I).Minchr) =
                Event_Directory (I).Name.Text (1 .. Event_Directory (I).Minchr)
         then
            Event_Entry := To_UL (Event_Directory (I)'Address);
            Trace_Output ("Found Event # ");
            Trace_Output (Integer'Image (I));
            Status := K_SUCCESS;
            return;
         end if;
      end loop;

      Status := K_NO_SUCH_EVENT;
   end Find_Event_By_Name;

   --------------------
   -- Get_User_State --
   --------------------

   function Get_User_State return Long_Integer is
   begin
      return STPO.Self.User_State;
   end Get_User_State;

   ------------------------
   -- List_Entry_Waiters --
   ------------------------

   procedure List_Entry_Waiters
     (Task_Value      : Task_Id;
      Full_Display    : Boolean := False;
      Suppress_Header : Boolean := False;
      Print_Routine   : Print_Routine_Type := Default_Print_Routine'Access)
   is
      pragma Unreferenced (Suppress_Header);

      Entry_Call : Entry_Call_Link;
      Have_Some  : Boolean := False;
   begin
      if not Full_Display then
         return;
      end if;

      if Task_Value.Entry_Queues'Length > 0 then
         Print_Routine (Print_FAO, Print_Newline,
           To_UL (DoAC ("        Waiting entry callers:")));
      end if;
      for I in Task_Value.Entry_Queues'Range loop
         Entry_Call := Task_Value.Entry_Queues (I).Head;
         if Entry_Call /= null then
            Have_Some := True;

            Print_Routine (Print_FAO, Print_Newline,
              To_UL (DoAC ("          Waiters for entry !UI:")),
              To_UL (I));

            loop
               declare
                  Task_Image : ASCIC :=
                   (Entry_Call.Self.Common.Task_Image_Len,
                    Entry_Call.Self.Common.Task_Image
                     (1 .. Entry_Call.Self.Common.Task_Image_Len));
               begin
                  Print_Routine (Print_FAO, Print_Newline,
                    To_UL (DoAC ("              %TASK !UI, type: !AC")),
                    To_UL (Entry_Call.Self.Known_Tasks_Index + 1),
                    To_UL (Task_Image'Address));
                  if Entry_Call = Task_Value.Entry_Queues (I).Tail then
                     exit;
                  end if;
                  Entry_Call := Entry_Call.Next;
               end;
            end loop;
         end if;
      end loop;
      if not Have_Some then
         Print_Routine (Print_FAO, Print_Newline,
           To_UL (DoAC ("          none.")));
      end if;
   end List_Entry_Waiters;

   ----------------
   -- List_Tasks --
   ----------------

   procedure List_Tasks is
      C : Task_Id;
   begin
      C := All_Tasks_List;

      while C /= null loop
         Print_Task_Info (C);
         C := C.Common.All_Tasks_Link;
      end loop;
   end List_Tasks;

   ------------------------
   -- Print_Current_Task --
   ------------------------

   procedure Print_Current_Task is
   begin
      Print_Task_Info (STPO.Self);
   end Print_Current_Task;

   ---------------------
   -- Print_Task_Info --
   ---------------------

   procedure Print_Task_Info (T : Task_Id) is
      Entry_Call : Entry_Call_Link;
      Parent     : Task_Id;

   begin
      if T = null then
         Put_Line ("null task");
         return;
      end if;

      Put (T.Common.Task_Image (1 .. T.Common.Task_Image_Len) & ": " &
           Task_States'Image (T.Common.State));

      Parent := T.Common.Parent;

      if Parent = null then
         Put (", parent: <none>");
      else
         Put (", parent: " &
              Parent.Common.Task_Image (1 .. Parent.Common.Task_Image_Len));
      end if;

      Put (", prio:" & T.Common.Current_Priority'Img);

      if not T.Callable then
         Put (", not callable");
      end if;

      if T.Aborting then
         Put (", aborting");
      end if;

      if T.Deferral_Level /= 0 then
         Put (", abort deferred");
      end if;

      if T.Common.Call /= null then
         Entry_Call := T.Common.Call;
         Put (", serving:");

         while Entry_Call /= null loop
            Put (To_Integer (Entry_Call.Self)'Img);
            Entry_Call := Entry_Call.Acceptor_Prev_Call;
         end loop;
      end if;

      if T.Open_Accepts /= null then
         Put (", accepting:");

         for J in T.Open_Accepts'Range loop
            Put (T.Open_Accepts (J).S'Img);
         end loop;

         if T.Terminate_Alternative then
            Put (" or terminate");
         end if;
      end if;

      if T.User_State /= 0 then
         Put (", state:" & T.User_State'Img);
      end if;

      Put_Line;
   end Print_Task_Info;

   ---------
   -- Put --
   ---------

   procedure Put (S : String) is
   begin
      Write (2, S, S'Length);
   end Put;

   --------------
   -- Put_Line --
   --------------

   procedure Put_Line (S : String := "") is
   begin
      Write (2, S & ASCII.LF, S'Length + 1);
   end Put_Line;

   ----------------------
   -- Resume_All_Tasks --
   ----------------------

   procedure Resume_All_Tasks (Thread_Self : OS_Interface.Thread_Id) is
      pragma Unreferenced (Thread_Self);
   begin
      null; --  VxWorks
   end Resume_All_Tasks;

   ---------------
   -- Set_Trace --
   ---------------

   procedure Set_Trace (Flag  : Character; Value : Boolean := True) is
   begin
      Trace_On (Flag) := Value;
   end Set_Trace;

   --------------------
   -- Set_User_State --
   --------------------

   procedure Set_User_State (Value : Long_Integer) is
   begin
      STPO.Self.User_State := Value;
   end Set_User_State;

   ----------------
   -- Show_Event --
   ----------------

   procedure Show_Event
      (Print_Routine : Print_Routine_Type := Default_Print_Routine'Access)
   is
   begin
      for I in Event_Def_Help'Range loop
         Print_Routine (Print_FAO, Print_Newline, To_UL (Event_Def_Help (I)));
      end loop;

      for I in Event_Kind_Type'Range loop
         Print_Routine (Print_FAO, Print_Newline,
           To_UL (Event_Directory
                   (Global_Event_Display_Order (I)).Name'Address));
         Print_Routine (Print_FAO, Print_Newline,
           To_UL (Event_Directory (Global_Event_Display_Order (I)).Help));
      end loop;
   end Show_Event;

   --------------------
   -- Show_One_Task --
   --------------------

   procedure Show_One_Task
     (Task_Value      : Task_Id;
      Full_Display    : Boolean := False;
      Suppress_Header : Boolean := False;
      Print_Routine   : Print_Routine_Type := Default_Print_Routine'Access)
   is
      Task_SP            : System.Address := Address_Zero;
      Stack_Base         : System.Address := Address_Zero;
      Stack_Top          : System.Address := Address_Zero;
      TCB_Size           : Unsigned_Longword := 0;
      CMA_TCB_Size       : Unsigned_Longword := 0;
      Stack_Guard_Size   : Unsigned_Longword := 0;
      Total_Task_Storage : Unsigned_Longword := 0;
      Stack_In_Use       : Unsigned_Longword := 0;
      Reserved_Size      : Unsigned_Longword := 0;
      Hold_Flag          : Unsigned_Longword := 0;
      Sched_State        : Unsigned_Longword := 0;
      User_Prio          : Unsigned_Longword := 0;
      Stack_Size         : Unsigned_Longword := 0;
      Run_State          : Boolean := False;
      Rea_State          : Boolean := False;
      Sus_State          : Boolean := False;
      Ter_State          : Boolean := False;

      Current_Flag : AASCIC := NoStar;
      Hold_String  : AASCIC := NoHold;
      Ada_State    : AASCIC := Ada_State_Invalid_State;
      Debug_State  : AASCIC := Debug_State_Emp;

      Ada_State_Len   : constant Unsigned_Longword := 17;
      Debug_State_Len : constant Unsigned_Longword := 5;

      Entry_Call : Entry_Call_Record;

   begin

      --  Initialize local task info variables

      Task_SP := Address_Zero;
      Stack_Base := Address_Zero;
      Stack_Top := Address_Zero;
      CMA_TCB_Size := 0;
      Stack_Guard_Size := 0;
      Reserved_Size := 0;
      Hold_Flag := 0;
      Sched_State := 0;
      TCB_Size := Unsigned_Longword (Task_Id'Size);

      if not Suppress_Header or else Full_Display then
         Print_Routine (Print_FAO, Print_Newline, To_UL (Empty_Text));
         Print_Routine (Print_FAO, Print_Newline, To_UL (Header));
      end if;

      Trace_Output ("Show_One_Task Task Value: ");
      Trace_Output (Unsigned_Longword'Image (To_UL (Task_Value)));

      --  Callback to DEBUG to get some task info

      if Task_Value.Common.State /= Terminated then
         Debug_Get
           (STPO.Get_Thread_Id (Task_Value),
            CMA_C_DEBGET_STACKPTR,
            Task_SP,
            8);

         Debug_Get
           (STPO.Get_Thread_Id (Task_Value),
            CMA_C_DEBGET_TCB_SIZE,
            CMA_TCB_Size,
            4);

         Debug_Get
           (STPO.Get_Thread_Id (Task_Value),
            CMA_C_DEBGET_GUARDSIZE,
            Stack_Guard_Size,
            4);

         Debug_Get
           (STPO.Get_Thread_Id (Task_Value),
            CMA_C_DEBGET_YELLOWSIZE,
            Reserved_Size,
            4);

         Debug_Get
           (STPO.Get_Thread_Id (Task_Value),
            CMA_C_DEBGET_STACK_BASE,
            Stack_Base,
            8);

         Debug_Get
           (STPO.Get_Thread_Id (Task_Value),
            CMA_C_DEBGET_STACK_TOP,
            Stack_Top,
            8);

         Stack_Size := Unsigned_Longword (Stack_Base - Stack_Top)
           - Reserved_Size - Stack_Guard_Size;
         Stack_In_Use := Unsigned_Longword (Stack_Base - Task_SP) + 4;
         Total_Task_Storage := TCB_Size + Stack_Size + Stack_Guard_Size
           + Reserved_Size + CMA_TCB_Size;

         Debug_Get
           (STPO.Get_Thread_Id (Task_Value),
            CMA_C_DEBGET_IS_HELD,
            Hold_Flag,
            4);

         Hold_String := (if Hold_Flag /= 0 then Hold else NoHold);

         Debug_Get
           (STPO.Get_Thread_Id (Task_Value),
            CMA_C_DEBGET_SCHED_STATE,
            Sched_State,
            4);
      end if;

      Run_State := False;
      Rea_State := False;
      Sus_State := Task_Value.Common.State = Unactivated;
      Ter_State := Task_Value.Common.State = Terminated;

      if not Ter_State then
         Run_State := Sched_State = 0;
         Rea_State := Sched_State = 1;
         Sus_State := Sched_State /= 0 and Sched_State /= 1;
      end if;

      --  Set the debug state

      if Run_State then
         Debug_State := Debug_State_Run;
      elsif Rea_State then
         Debug_State := Debug_State_Rea;
      elsif Sus_State then
         Debug_State := Debug_State_Sus;
      elsif Ter_State then
         Debug_State := Debug_State_Ter;
      end if;

      Trace_Output ("Before case State: ");
      Trace_Output (Task_States'Image (Task_Value.Common.State));

      --  Set the Ada state

      case Task_Value.Common.State is
         when Unactivated =>
            Ada_State := Ada_State_Not_Yet_Activated;

         when Activating =>
            Ada_State := Ada_State_Activating;

         when Runnable =>
            Ada_State := Ada_State_Runnable;

         when Terminated =>
            Ada_State := Ada_State_Terminated;

         when Activator_Sleep =>
            Ada_State := Ada_State_Activating_Tasks;

         when Acceptor_Sleep =>
            Ada_State := Ada_State_Accept;

         when Acceptor_Delay_Sleep =>
            Ada_State := Ada_State_Select_or_Delay;

         when Entry_Caller_Sleep =>
            Entry_Call :=
              Task_Value.Entry_Calls (Task_Value.ATC_Nesting_Level);

            case Entry_Call.Mode is
               when Simple_Call =>
                  Ada_State := Ada_State_Entry_Call;
               when Conditional_Call =>
                  Ada_State := Ada_State_Cond_Entry_Call;
               when Timed_Call =>
                  Ada_State := Ada_State_Timed_Entry_Call;
               when Asynchronous_Call =>
                  Ada_State := Ada_State_Async_Entry_Call;
            end case;

         when Async_Select_Sleep =>
            Ada_State := Ada_State_Select_or_Abort;

         when Delay_Sleep =>
            Ada_State := Ada_State_Delay;

         when Master_Completion_Sleep =>
            Ada_State := Ada_State_Completed;

         when Master_Phase_2_Sleep =>
            Ada_State := Ada_State_Completed;

         when Interrupt_Server_Idle_Sleep |
              Interrupt_Server_Blocked_Interrupt_Sleep |
              Timer_Server_Sleep |
              Interrupt_Server_Blocked_On_Event_Flag =>
            Ada_State := Ada_State_Server;

         when AST_Server_Sleep =>
            Ada_State := Ada_State_IO_or_AST;

         when Asynchronous_Hold =>
            Ada_State := Ada_State_Async_Hold;

      end case;

      if Task_Value.Terminate_Alternative then
         Ada_State := Ada_State_Select_or_Term;
      end if;

      if Task_Value.Aborting then
         Ada_State := Ada_State_Aborting;
      end if;

      User_Prio := To_UL (Task_Value.Common.Current_Priority);
      Trace_Output ("After user_prio");

      --  Flag the current task

      Current_Flag := (if Task_Value = Self then Star else NoStar);

      --  Show task info

      Print_Routine (Print_FAO, No_Print, To_UL (DoAC ("!AC%TASK !5<!UI!>")),
        To_UL (Current_Flag), To_UL (Task_Value.Known_Tasks_Index + 1));

      Print_Routine (Print_FAO, No_Print, To_UL (DoAC ("!2UB")), User_Prio);

      Print_Routine (Print_FAO, No_Print, To_UL (DoAC (" !AC !5AD !17AD ")),
        To_UL (Hold_String), Debug_State_Len, To_UL (Debug_State),
        Ada_State_Len, To_UL (Ada_State));

--      Print_Routine (Print_Symbol, Print_Newline,
--         Fetch (To_Addr (Task_Value.Common.Task_Entry_Point)));

      Print_Routine (Print_FAO, Print_Newline, To_UL (Empty_Text));

      --  If /full qualfier passed, show detailed info

      if Full_Display then
         Show_Rendezvous (Task_Value, Ada_State, Full_Display,
           Suppress_Header, Print_Routine);

         List_Entry_Waiters (Task_Value, Full_Display,
           Suppress_Header, Print_Routine);

         Print_Routine (Print_FAO, Print_Newline, To_UL (Empty_Text));

         declare
            Task_Image : ASCIC := (Task_Value.Common.Task_Image_Len,
              Task_Value.Common.Task_Image
               (1 .. Task_Value.Common.Task_Image_Len));
         begin
            Print_Routine (Print_FAO, Print_Newline,
              To_UL (DoAC ("        Task type:      !AC")),
              To_UL (Task_Image'Address));
         end;

         --  How to find Creation_PC ???
--         Print_Routine (Print_FAO, No_Print,
--           To_UL (DoAC ("        Created at PC:  ")),
--         Print_Routine (Print_FAO, Print_Newline, Creation_PC);

         if Task_Value.Common.Parent /= null then
            Print_Routine (Print_FAO, Print_Newline,
              To_UL (DoAC ("        Parent task:    %TASK !UI")),
              To_UL (Task_Value.Common.Parent.Known_Tasks_Index + 1));
         else
            Print_Routine (Print_FAO, Print_Newline,
             To_UL (DoAC ("        Parent task:    none")));
         end if;

--         Print_Routine (Print_FAO, No_Print,
--           To_UL (DoAC ("        Start PC:       ")));
--         Print_Routine (Print_Symbol, Print_Newline,
--            Fetch (To_Addr (Task_Value.Common.Task_Entry_Point)));

         Print_Routine (Print_FAO, Print_Newline,
          To_UL (DoAC (
           "        Task control block:             Stack storage (bytes):")));

         Print_Routine (Print_FAO, Print_Newline,
          To_UL (DoAC (
           "          Task value:   !10<!UI!>        RESERVED_BYTES:  !10UI")),
          To_UL (Task_Value), Reserved_Size);

         Print_Routine (Print_FAO, Print_Newline,
          To_UL (DoAC (
           "          Entries:      !10<!UI!>        TOP_GUARD_SIZE:  !10UI")),
          To_UL (Task_Value.Entry_Num), Stack_Guard_Size);

         Print_Routine (Print_FAO, Print_Newline,
          To_UL (DoAC (
           "          Size:         !10<!UI!>        STORAGE_SIZE:    !10UI")),
          TCB_Size + CMA_TCB_Size, Stack_Size);

         Print_Routine (Print_FAO, Print_Newline,
          To_UL (DoAC (
           "        Stack addresses:                 Bytes in use:    !10UI")),
          Stack_In_Use);

         Print_Routine (Print_FAO, Print_Newline,
          To_UL (DoAC ("          Top address:  !10<!XI!>")),
          To_UL (Stack_Top));

         Print_Routine (Print_FAO, Print_Newline,
          To_UL (DoAC (
           "          Base address: !10<!XI!>      Total storage:     !10UI")),
          To_UL (Stack_Base), Total_Task_Storage);
      end if;

   end Show_One_Task;

   ---------------------
   -- Show_Rendezvous --
   ---------------------

   procedure Show_Rendezvous
     (Task_Value      : Task_Id;
      Ada_State       : AASCIC := Empty_Text;
      Full_Display    : Boolean := False;
      Suppress_Header : Boolean := False;
      Print_Routine   : Print_Routine_Type := Default_Print_Routine'Access)
   is
      pragma Unreferenced (Ada_State);
      pragma Unreferenced (Suppress_Header);

      Temp_Entry  : Entry_Index;
      Entry_Call  : Entry_Call_Record;
      Called_Task : Task_Id;
      AWR         : constant String := "        Awaiting rendezvous at: ";
      --  Common prefix

      procedure Print_Accepts;
      --  Display information about task rendezvous accepts

      procedure Print_Accepts is
      begin
         if Task_Value.Open_Accepts /= null then
            for I in Task_Value.Open_Accepts'Range loop
               Temp_Entry := Entry_Index (Task_Value.Open_Accepts (I).S);
               declare
                  Entry_Name_Image : ASCIC :=
                    (Task_Value.Entry_Names (Temp_Entry).all'Length,
                     Task_Value.Entry_Names (Temp_Entry).all);
               begin
                  Trace_Output ("Accept at: " & Entry_Name_Image.Text);
                  Print_Routine (Print_FAO, Print_Newline,
                    To_UL (DoAC ("             accept at: !AC")),
                    To_UL (Entry_Name_Image'Address));
               end;
            end loop;
         end if;
      end Print_Accepts;
   begin
      if not Full_Display then
         return;
      end if;

      Trace_Output ("Show_Rendezvous Task Value: ");
      Trace_Output (Unsigned_Longword'Image (To_UL (Task_Value)));

      if Task_Value.Common.State = Acceptor_Sleep and then
         not Task_Value.Terminate_Alternative
      then
         if Task_Value.Open_Accepts /= null then
            Temp_Entry := Entry_Index (Task_Value.Open_Accepts
              (Task_Value.Open_Accepts'First).S);
            declare
               Entry_Name_Image : ASCIC :=
                 (Task_Value.Entry_Names (Temp_Entry).all'Length,
                  Task_Value.Entry_Names (Temp_Entry).all);
            begin
               Trace_Output (AWR & "accept " & Entry_Name_Image.Text);
               Print_Routine (Print_FAO, Print_Newline,
                 To_UL (DoAC (AWR & "accept !AC")),
                 To_UL (Entry_Name_Image'Address));
            end;

         else
            Print_Routine (Print_FAO, Print_Newline,
              To_UL (DoAC ("        entry name unavailable")));
         end if;
      else
         case Task_Value.Common.State is
            when Acceptor_Sleep =>
               Print_Routine (Print_FAO, Print_Newline,
                 To_UL (DoAC (AWR & "select with terminate.")));
               Print_Accepts;

            when Async_Select_Sleep =>
               Print_Routine (Print_FAO, Print_Newline,
                 To_UL (DoAC (AWR & "select.")));
               Print_Accepts;

            when Acceptor_Delay_Sleep =>
               Print_Routine (Print_FAO, Print_Newline,
                 To_UL (DoAC (AWR & "select with delay.")));
               Print_Accepts;

            when Entry_Caller_Sleep =>
               Entry_Call :=
                 Task_Value.Entry_Calls (Task_Value.ATC_Nesting_Level);

               case Entry_Call.Mode is
                  when Simple_Call =>
                     Print_Routine (Print_FAO, Print_Newline,
                       To_UL (DoAC (AWR & "entry call")));
                  when Conditional_Call =>
                     Print_Routine (Print_FAO, Print_Newline,
                       To_UL (DoAC (AWR & "entry call with else")));
                  when Timed_Call =>
                     Print_Routine (Print_FAO, Print_Newline,
                       To_UL (DoAC (AWR & "entry call with delay")));
                  when Asynchronous_Call =>
                     Print_Routine (Print_FAO, Print_Newline,
                        To_UL (DoAC (AWR & "entry call with abort")));
               end case;
               Called_Task := Entry_Call.Called_Task;
               declare
                  Task_Image : ASCIC := (Called_Task.Common.Task_Image_Len,
                    Called_Task.Common.Task_Image
                     (1 .. Called_Task.Common.Task_Image_Len));
                  Entry_Name_Image : ASCIC :=
                    (Called_Task.Entry_Names (Entry_Call.E).all'Length,
                     Called_Task.Entry_Names (Entry_Call.E).all);
               begin
                  Print_Routine (Print_FAO, Print_Newline,
                    To_UL (DoAC
                     ("        for entry !AC in %TASK !UI type !AC")),
                    To_UL (Entry_Name_Image'Address),
                    To_UL (Called_Task.Known_Tasks_Index),
                    To_UL (Task_Image'Address));
               end;

            when others =>
               return;
         end case;
      end if;

   end Show_Rendezvous;

   ------------------------
   -- Signal_Debug_Event --
   ------------------------

   procedure Signal_Debug_Event
    (Event_Kind : Event_Kind_Type; Task_Value : Task_Id)
   is
      Do_Signal : Boolean;
      EVCB      : Ada_Event_Control_Block_Access;

      EVCB_Sent    : constant := 16#9B#;
      Ada_Facility : constant := 49;
      SS_DBGEVENT  : constant := 1729;
   begin
      Do_Signal := Global_Task_Debug_Events (Event_Kind);

      if not Do_Signal then
         if Task_Value /= null then
            Do_Signal := Do_Signal
              or else Task_Value.Common.Debug_Events (Event_Kind);
         end if;
      end if;

      if Do_Signal then
         --  Build an a tasking event control block and signal DEBUG

         EVCB := new Ada_Event_Control_Block_Type;
         EVCB.Code := Unsigned_Word (Event_Kind);
         EVCB.Sentinal := EVCB_Sent;
         EVCB.Facility := Ada_Facility;

         if Task_Value /= null then
            EVCB.Value := Unsigned_Longword (Task_Value.Known_Tasks_Index + 1);
         else
            EVCB.Value := 0;
         end if;

         EVCB.Sub_Event := 0;
         EVCB.P1 := 0;
         EVCB.Sigargs := 0;
         EVCB.Flags := 0;
         EVCB.Unused1 := 0;
         EVCB.Unused2 := 0;

         Signal (SS_DBGEVENT, 1, To_UL (EVCB));
      end if;
   end Signal_Debug_Event;

   --------------------
   -- Stop_All_Tasks --
   --------------------

   procedure Stop_All_Tasks is
   begin
      null; --  VxWorks
   end Stop_All_Tasks;

   ----------------------------
   -- Stop_All_Tasks_Handler --
   ----------------------------

   procedure Stop_All_Tasks_Handler is
   begin
      null; --  VxWorks
   end Stop_All_Tasks_Handler;

   -----------------------
   -- Suspend_All_Tasks --
   -----------------------

   procedure Suspend_All_Tasks (Thread_Self : OS_Interface.Thread_Id) is
      pragma Unreferenced (Thread_Self);
   begin
      null; --  VxWorks
   end Suspend_All_Tasks;

   ------------------------
   -- Task_Creation_Hook --
   ------------------------

   procedure Task_Creation_Hook (Thread : OS_Interface.Thread_Id) is
      pragma Unreferenced (Thread);
   begin
      null; --  VxWorks
   end Task_Creation_Hook;

   ---------------------------
   -- Task_Termination_Hook --
   ---------------------------

   procedure Task_Termination_Hook is
   begin
      null; --  VxWorks
   end Task_Termination_Hook;

   -----------
   -- Trace --
   -----------

   procedure Trace
     (Self_Id  : Task_Id;
      Msg      : String;
      Flag     : Character;
      Other_Id : Task_Id := null)
   is
   begin
      if Trace_On (Flag) then
         Put (To_Integer (Self_Id)'Img &
              ':' & Flag & ':' &
              Self_Id.Common.Task_Image (1 .. Self_Id.Common.Task_Image_Len) &
              ':');

         if Other_Id /= null then
            Put (To_Integer (Other_Id)'Img & ':');
         end if;

         Put_Line (Msg);
      end if;
   end Trace;

   ------------------
   -- Trace_Output --
   ------------------

   procedure Trace_Output (Message_String : String) is
   begin
      if Trace_On ('V') and Trace_On ('M') and Trace_On ('S') then
         Put_Output (Message_String);
      end if;
   end Trace_Output;

   -----------
   -- Write --
   -----------

   procedure Write (Fd : Integer; S : String; Count : Integer) is
      Discard : System.CRTL.ssize_t;
      pragma Unreferenced (Discard);
   begin
      Discard := System.CRTL.write (Fd, S (S'First)'Address,
                                    System.CRTL.size_t (Count));
      --  Is it really right to ignore write errors here ???
   end Write;

end System.Tasking.Debug;