home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / gnat-2.06-src.tgz / tar.out / fsf / gnat / ada / s-taspri.adb < prev    next >
Text File  |  1996-09-28  |  34KB  |  1,027 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                 GNU ADA RUNTIME LIBRARY (GNARL) COMPONENTS               --
  4. --                                                                          --
  5. --                S Y S T E M . T A S K _ P R I M I T I V E S               --
  6. --                                                                          --
  7. --                                  B o d y                                 --
  8. --                                                                          --
  9. --                             $Revision: 1.38 $                            --
  10. --                                                                          --
  11. --     Copyright (c) 1991,1992,1993,1994,1995 FSU, All Rights Reserved      --
  12. --                                                                          --
  13. -- GNARL is free software; you can redistribute it  and/or modify it  under --
  14. -- terms  of  the  GNU  Library General Public License  as published by the --
  15. -- Free Software  Foundation;  either version 2, or (at  your  option)  any --
  16. -- later  version.  GNARL is distributed  in the hope that  it will be use- --
  17. -- ful, but but WITHOUT ANY WARRANTY;  without even the implied warranty of --
  18. -- MERCHANTABILITY  or  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Gen- --
  19. -- eral Library Public License  for more details.  You should have received --
  20. -- a  copy of the GNU Library General Public License along with GNARL;  see --
  21. -- file COPYING.LIB.  If not,  write to the  Free Software Foundation,  675 --
  22. -- Mass Ave, Cambridge, MA 02139, USA.                                      --
  23. --                                                                          --
  24. ------------------------------------------------------------------------------
  25.  
  26. with System.Task_Clock;
  27. --  Used for, Stimespec,
  28. --            Stimespec_Seconds,
  29. --            Stimespec_NSeconds
  30.  
  31. with Interfaces.C.POSIX_timers;
  32. --  Used for, timespec,
  33. --            Nanoseconds
  34.  
  35. with Interfaces.C.POSIX_Error;
  36. --  Used for, Return_Code,
  37. --            Failure,
  38. --            Get_Error_Code,
  39. --            Interrupted_Operation,
  40. --            Resource_Temporarily_Unavailable,
  41. --            Priority_Ceiling_Violation
  42.  
  43. with Interfaces.C.POSIX_RTE;
  44. --  Used for, Signal,
  45. --            Signal_Set,
  46. --            sigaddset,
  47. --            sigdelset,
  48. --            sigfillset,
  49. --            sigemptyset,
  50. --            sigprocmask,
  51. --            siginfo_ptr,
  52. --            struct_sigaction,
  53. --            sigaction,
  54. --            and various CONSTANTS
  55.  
  56. with Interfaces.C.Pthreads; use Interfaces.C.Pthreads;
  57.  
  58. with Unchecked_Deallocation;
  59.  
  60. with Unchecked_Conversion;
  61.  
  62. package body System.Task_Primitives is
  63.  
  64.    package RTE renames Interfaces.C.POSIX_RTE;
  65.  
  66.    Failure : Interfaces.C.POSIX_Error.Return_Code
  67.       renames Interfaces.C.POSIX_Error.Failure;
  68.  
  69.    Test_And_Set_Mutex : Lock;
  70.    --  Use a mutex to simulate test-and-set.  This is ridiculously inefficient;
  71.    --  it is just here so that I can fix the syntax errors without having to
  72.    --  worry about how to get machine code into the system in the absence
  73.    --  of machine code inserts.
  74.  
  75.    Abort_Signal : constant RTE.Signal := RTE.SIGABRT;
  76.  
  77.    function "=" (L, R : System.Address) return Boolean
  78.      renames System."=";
  79.  
  80.    ATCB_Key : pthread_key_t;
  81.  
  82.    Abort_Handler : Abort_Handler_Pointer;
  83.  
  84.    LL_Signals : aliased RTE.Signal_Set;
  85.    --  The set of signals that should be unblocked in a task.
  86.    --  This is in general the signals that can be generated synchronously,
  87.    --  and which should therefore be converted into Ada exceptions.
  88.    --  It also includes the Abort_Signal, to allow asynchronous abortion.
  89.  
  90.    Task_Signal_Mask : aliased RTE.Signal_Set;
  91.    --  The set of signals that should always be blocked in a task.
  92.  
  93.    Reserved_Signals : aliased RTE.Signal_Set;
  94.    --  The set of signals reserved for use by the runtime system.
  95.  
  96.    procedure Put_Character (C : Integer);
  97.    pragma Import (C, Put_Character, "putchar");
  98.  
  99.    procedure Prog_Exit (Status : Integer);
  100.    pragma Import (C, Prog_Exit, "exit");
  101.  
  102.    function Pointer_to_Address is new
  103.      Unchecked_Conversion (TCB_Ptr, System.Address);
  104.  
  105.    function Address_to_Pointer is new
  106.      Unchecked_Conversion (System.Address, TCB_Ptr);
  107.  
  108.    -----------------------
  109.    -- Local Subprograms --
  110.    -----------------------
  111.  
  112.    procedure Abort_Wrapper
  113.      (signo   : Integer;
  114.       info    : RTE.siginfo_ptr;
  115.       context : System.Address);
  116.    --  This is a signal handler procedure which calls the user-specified
  117.    --  abort handler procedure.
  118.  
  119.    function Get_Stack_Limit return System.Address;
  120.    pragma Inline (Get_Stack_Limit);
  121.    --  Obtains stack limit from TCB
  122.  
  123.    procedure LL_Wrapper (T : TCB_Ptr);
  124.    --  A wrapper procedure that is called from a new low-level task.
  125.    --  It performs initializations for the new task and calls the
  126.    --  user-specified startup procedure.
  127.  
  128.    procedure Write_Character (C : Character);
  129.    procedure Write_EOL;
  130.    procedure Write_String (S : String);
  131.    --  Debugging procedures used for assertion output
  132.  
  133.    function Stimespec_to_timespec (S : Task_Clock.Stimespec)
  134.      return Interfaces.C.POSIX_timers.timespec;
  135.  
  136.    function timespec_to_Stimespec (S : Interfaces.C.POSIX_timers.timespec)
  137.      return Task_Clock.Stimespec;
  138.  
  139.    ----------------------
  140.    -- Runtime_Shutdown --
  141.    ----------------------
  142.  
  143.    function Runtime_Assert_Shutdown (Msg : in String) return boolean;
  144.    --  There is another copy of the same function in s-tasuti.ads which
  145.    --  gnarl level routines use. These should be unified. However, we do not
  146.    --  want to modify the interface for Task_Primitives without synchronizing
  147.    --  with OS 2 runtime, hence created a duplicated local copy here
  148.    --  temporarily.
  149.  
  150.    function Runtime_Assert_Shutdown (Msg : in String) return boolean is
  151.    begin
  152.       LL_Assert (false, Msg);
  153.       --  This call should never return
  154.       return false;
  155.    end Runtime_Assert_Shutdown;
  156.  
  157.    ---------------------
  158.    -- Write_Character --
  159.    ---------------------
  160.  
  161.    procedure Write_Character (C : Character) is
  162.    begin
  163.       Put_Character (Character'Pos (C));
  164.    end Write_Character;
  165.  
  166.    ---------------
  167.    -- Write_Eol --
  168.    ---------------
  169.  
  170.    procedure Write_EOL is
  171.    begin
  172.       Write_Character (Ascii.LF);
  173.    end Write_EOL;
  174.  
  175.    ------------------
  176.    -- Write_String --
  177.    ------------------
  178.  
  179.    procedure Write_String (S : String) is
  180.    begin
  181.       for J in S'Range loop
  182.          Write_Character (S (J));
  183.       end loop;
  184.    end Write_String;
  185.  
  186.    ---------------
  187.    -- LL_Assert --
  188.    ---------------
  189.  
  190.    procedure LL_Assert (B : Boolean; M : String) is
  191.    begin
  192.       if not B then
  193.          Write_String ("Failed Runtime Assertion: ");
  194.          Write_String (M);
  195.          Write_String (".");
  196.          Write_EOL;
  197.          Prog_Exit (1);
  198.       end if;
  199.    end LL_Assert;
  200.  
  201.    -------------------------
  202.    -- Initialize_LL_Tasks --
  203.    -------------------------
  204.  
  205.    procedure Initialize_LL_Tasks (T : TCB_Ptr) is
  206.       Old_Set : aliased RTE.Signal_Set;
  207.       Mask    : RTE.Signal_Set;
  208.       Result  : Interfaces.C.POSIX_Error.Return_Code;
  209.  
  210.    begin
  211.    --  WARNING : SIGALRM should not be in the following mask.  SIGALRM should
  212.    --          be a normal user signal under 1, and should be enabled
  213.    --          by the client.  However, the current RTS built on 1
  214.    --          uses nanosleep () and pthread_cond_wait (), which fail if all
  215.    --          threads have SIGALRM masked. ???
  216.  
  217.       RTE.sigemptyset (LL_Signals'Access, Result);
  218.       pragma Assert (
  219.         Result /= Failure or else Runtime_Assert_Shutdown (
  220.           "GNULLI failure---sigemptyset"));
  221.       RTE.sigaddset (LL_Signals'Access, Abort_Signal, Result);
  222.       pragma Assert (
  223.         Result /= Failure or else Runtime_Assert_Shutdown (
  224.           "GNULLI failure---sigaddset"));
  225.       RTE.sigaddset (LL_Signals'Access, RTE.SIGALRM, Result);
  226.       pragma Assert (
  227.         Result /= Failure or else Runtime_Assert_Shutdown (
  228.           "GNULLI failure---sigaddset"));
  229.       RTE.sigaddset (LL_Signals'Access, RTE.SIGILL, Result);
  230.       pragma Assert (
  231.         Result /= Failure or else Runtime_Assert_Shutdown (
  232.           "GNULLI failure---sigaddset"));
  233.       RTE.sigaddset (LL_Signals'Access, RTE.SIGFPE, Result);
  234.       pragma Assert (
  235.         Result /= Failure or else Runtime_Assert_Shutdown (
  236.           "GNULLI failure---sigaddset"));
  237.       RTE.sigaddset (LL_Signals'Access, RTE.SIGSEGV, Result);
  238.       pragma Assert (
  239.         Result /= Failure or else Runtime_Assert_Shutdown (
  240.           "GNULLI failure---sigaddset"));
  241.  
  242.       --  OS specific Synchronous signals.
  243.       for i in RTE.OS_Specific_Sync_Signals'First + 1 ..
  244.         RTE.OS_Specific_Sync_Signals'Last loop
  245.          RTE.sigdelset
  246.            (LL_Signals'Access, RTE.OS_Specific_Sync_Signals (i), Result);
  247.          pragma Assert (
  248.            Result /= Failure or else Runtime_Assert_Shutdown (
  249.              "GNULLI failure---sigdelset"));
  250.       end loop;
  251.  
  252.       RTE.sigfillset (Task_Signal_Mask'Access, Result);
  253.       pragma Assert (
  254.         Result /= Failure or else Runtime_Assert_Shutdown (
  255.           "GNULLI failure---sigfillset"));
  256.       RTE.sigdelset (Task_Signal_Mask'Access, Abort_Signal, Result);
  257.       pragma Assert (
  258.         Result /= Failure or else Runtime_Assert_Shutdown (
  259.           "GNULLI failure---sigdelset"));
  260.       RTE.sigdelset (Task_Signal_Mask'Access, RTE.SIGALRM, Result);
  261.       pragma Assert (
  262.         Result /= Failure or else Runtime_Assert_Shutdown (
  263.           "GNULLI failure---sigdelset"));
  264.       RTE.sigdelset (Task_Signal_Mask'Access, RTE.SIGILL, Result);
  265.       pragma Assert (
  266.         Result /= Failure or else Runtime_Assert_Shutdown (
  267.           "GNULLI failure---sigdelset"));
  268.       RTE.sigdelset (Task_Signal_Mask'Access, RTE.SIGFPE, Result);
  269.       pragma Assert (
  270.         Result /= Failure or else Runtime_Assert_Shutdown (
  271.           "GNULLI failure---sigdelset"));
  272.       RTE.sigdelset (Task_Signal_Mask'Access, RTE.SIGSEGV, Result);
  273.       pragma Assert (
  274.         Result /= Failure or else Runtime_Assert_Shutdown (
  275.           "GNULLI failure---sigdelset"));
  276.  
  277.       --  OS specific Synchronous signals.
  278.       for i in RTE.OS_Specific_Sync_Signals'First + 1 ..
  279.         RTE.OS_Specific_Sync_Signals'Last loop
  280.          RTE.sigdelset
  281.            (Task_Signal_Mask'Access, RTE.OS_Specific_Sync_Signals (i), Result);
  282.          pragma Assert (
  283.            Result /= Failure or else Runtime_Assert_Shutdown (
  284.              "GNULLI failure---sigdelset"));
  285.       end loop;
  286.  
  287.       RTE.sigemptyset (Reserved_Signals'Access, Result);
  288.       pragma Assert (
  289.         Result /= Failure or else Runtime_Assert_Shutdown (
  290.           "GNULLI failure---sigemptyset"));
  291.       RTE.sigaddset (LL_Signals'Access, Abort_Signal, Result);
  292.       pragma Assert (
  293.         Result /= Failure or else Runtime_Assert_Shutdown (
  294.           "GNULLI failure---sigaddset"));
  295.       RTE.sigaddset (Reserved_Signals'Access, RTE.SIGILL, Result);
  296.       pragma Assert (
  297.         Result /= Failure or else Runtime_Assert_Shutdown (
  298.           "GNULLI failure---sigaddset"));
  299.       RTE.sigaddset (Reserved_Signals'Access, RTE.SIGFPE, Result);
  300.       pragma Assert (
  301.         Result /= Failure or else Runtime_Assert_Shutdown (
  302.           "GNULLI failure---sigaddset"));
  303.       RTE.sigaddset (Reserved_Signals'Access, RTE.SIGSEGV, Result);
  304.       pragma Assert (
  305.         Result /= Failure or else Runtime_Assert_Shutdown (
  306.           "GNULLI failure---sigaddset"));
  307.       RTE.sigaddset (Reserved_Signals'Access, Abort_Signal, Result);
  308.       pragma Assert (
  309.         Result /= Failure or else Runtime_Assert_Shutdown (
  310.           "GNULLI failure---sigaddset"));
  311.  
  312.       --  OS specific Synchronous signals.
  313.       for i in RTE.OS_Specific_Sync_Signals'First + 1 ..
  314.         RTE.OS_Specific_Sync_Signals'Last loop
  315.          RTE.sigdelset
  316.            (Reserved_Signals'Access, RTE.OS_Specific_Sync_Signals (i), Result);
  317.          pragma Assert (
  318.            Result /= Failure or else Runtime_Assert_Shutdown (
  319.              "GNULLI failure---sigdelset"));
  320.       end loop;
  321.  
  322.       pthread_key_create (ATCB_Key, System.Null_Address, Result);
  323.  
  324.       if Result = Failure then
  325.          raise Storage_Error;               --  Insufficient resources.
  326.       end if;
  327.  
  328.       RTE.sigprocmask (
  329.         RTE.SIG_SETMASK, Task_Signal_Mask'Access, Old_Set'Access, Result);
  330.       pragma Assert (
  331.         Result /= Failure or else Runtime_Assert_Shutdown (
  332.           "GNULLI failure---sigprocmask"));
  333.  
  334.       T.LL_Entry_Point := null;
  335.  
  336.       T.Thread := pthread_self;
  337.       pthread_setspecific (ATCB_Key, Pointer_to_Address (T), Result);
  338.       pragma Assert (
  339.         Result /= Failure or else Runtime_Assert_Shutdown (
  340.           "GNULLI failure---pthread_setspecific"));
  341.  
  342.    end Initialize_LL_Tasks;
  343.  
  344.    ----------
  345.    -- Self --
  346.    ----------
  347.  
  348.    function Self return TCB_Ptr is
  349.       Temp   : System.Address;
  350.       Result : Interfaces.C.POSIX_Error.Return_Code;
  351.  
  352.    begin
  353.       pthread_getspecific (ATCB_Key, Temp, Result);
  354.       pragma Assert (
  355.         Result /= Failure or else Runtime_Assert_Shutdown (
  356.           "GNULLI failure---pthread_getspecific"));
  357.       return Address_to_Pointer (Temp);
  358.    end Self;
  359.  
  360.    ---------------------
  361.    -- Initialize_Lock --
  362.    ---------------------
  363.  
  364.    procedure Initialize_Lock
  365.      (Prio : System.Priority;
  366.       L    : in out Lock)
  367.    is
  368.       Attributes : pthread_mutexattr_t;
  369.       Result     : Interfaces.C.POSIX_Error.Return_Code;
  370.  
  371.    begin
  372.       pthread_mutexattr_init (Attributes, Result);
  373.       if Result = Failure then
  374.          raise STORAGE_ERROR;  --  should be ENOMEM
  375.       end if;
  376.  
  377.       pthread_mutexattr_setprotocol (Attributes, PRIO_PROTECT, Result);
  378.  
  379.       pragma Assert (
  380.         Result /= Failure or else Runtime_Assert_Shutdown (
  381.           "GNULLI failure---pthread_mutexattr_setprotocol"));
  382.  
  383.       pthread_mutexattr_setprio_ceiling
  384.          (Attributes, Interfaces.C.int (Prio), Result);
  385.  
  386.       pragma Assert (
  387.         Result /= Failure or else Runtime_Assert_Shutdown (
  388.         "GNULLI failure---pthread_mutexattr_setprio_ceiling"));
  389.  
  390.       pthread_mutex_init (pthread_mutex_t (L), Attributes, Result);
  391.  
  392.       if Result = Failure then
  393.          raise STORAGE_ERROR;  --  should be ENOMEM ???
  394.       end if;
  395.    end Initialize_Lock;
  396.  
  397.    -------------------
  398.    -- Finalize_Lock --
  399.    -------------------
  400.  
  401.    procedure Finalize_Lock (L : in out Lock) is
  402.       Result : Interfaces.C.POSIX_Error.Return_Code;
  403.  
  404.    begin
  405.       pthread_mutex_destroy (pthread_mutex_t (L), Result);
  406.       pragma Assert (
  407.         Result /= Failure or else Runtime_Assert_Shutdown (
  408.           "GNULLI failure---pthread_mutex_destroy"));
  409.    end Finalize_Lock;
  410.  
  411.    ----------------
  412.    -- Write_Lock --
  413.    ----------------
  414.  
  415.    --  The error code EINVAL indicates either an uninitialized mutex or
  416.    --  a priority ceiling violation. We assume that the former cannot
  417.    --  occur in our system.
  418.    procedure Write_Lock (L : in out Lock; Ceiling_Violation : out Boolean) is
  419.       Result : Interfaces.C.POSIX_Error.Return_Code;
  420.       Ceiling_Error : Boolean;
  421.    begin
  422.       pthread_mutex_lock (pthread_mutex_t (L), Result);
  423.       Ceiling_Error := Result = Failure and then
  424.         Interfaces.C.POSIX_Error.Get_Error_Code =
  425.            Interfaces.C.POSIX_Error.Priority_Ceiling_Violation;
  426.       pragma Assert (
  427.         Result /= Failure or else Ceiling_Error
  428.           or else Runtime_Assert_Shutdown (
  429.             "GNULLI failure---pthread_mutex_lock"));
  430.  
  431.       Ceiling_Violation := Ceiling_Error;
  432.    end Write_Lock;
  433.  
  434.    ---------------
  435.    -- Read_Lock --
  436.    ---------------
  437.  
  438.    procedure Read_Lock (L : in out Lock; Ceiling_Violation : out Boolean) is
  439.    begin
  440.       Write_Lock (L, Ceiling_Violation);
  441.    end Read_Lock;
  442.  
  443.    ------------
  444.    -- Unlock --
  445.    ------------
  446.  
  447.    procedure Unlock (L : in out Lock) is
  448.       Result : Interfaces.C.POSIX_Error.Return_Code;
  449.  
  450.    begin
  451.       pthread_mutex_unlock (pthread_mutex_t (L), Result);
  452.       pragma Assert (
  453.         Result /= Failure or else Runtime_Assert_Shutdown (
  454.           "GNULLI failure---pthread_mutex_unlock"));
  455.    end Unlock;
  456.  
  457.    ---------------------
  458.    -- Initialize_Cond --
  459.    ---------------------
  460.  
  461.    procedure Initialize_Cond (Cond : in out Condition_Variable) is
  462.       Attributes : pthread_condattr_t;
  463.       Result     : Interfaces.C.POSIX_Error.Return_Code;
  464.  
  465.    begin
  466.       pthread_condattr_init (Attributes, Result);
  467.  
  468.       if Result = Failure then
  469.          raise STORAGE_ERROR;  --  should be ENOMEM ???
  470.       end if;
  471.  
  472.       pthread_cond_init (pthread_cond_t (Cond.CV), Attributes, Result);
  473.  
  474.       if Result = Failure then
  475.          raise STORAGE_ERROR;  --  should be ENOMEM  ???
  476.       end if;
  477.  
  478.       pthread_condattr_destroy (Attributes, Result);
  479.       pragma Assert (
  480.         Result /= Failure or else Runtime_Assert_Shutdown (
  481.           "GNULLI failure---pthread_condattr_destroy"));
  482.  
  483.       Cond.Someone_Is_Waiting := False;
  484.  
  485.    end Initialize_Cond;
  486.  
  487.    -------------------
  488.    -- Finalize_Cond --
  489.    -------------------
  490.  
  491.    procedure Finalize_Cond (Cond : in out Condition_Variable) is
  492.       Result : Interfaces.C.POSIX_Error.Return_Code;
  493.  
  494.    begin
  495.       pthread_cond_destroy (pthread_cond_t (Cond.CV), Result);
  496.       pragma Assert (
  497.         Result /= Failure or else Runtime_Assert_Shutdown (
  498.           "GNULLI failure---pthread_cond_destroy"));
  499.    end Finalize_Cond;
  500.  
  501.    ---------------
  502.    -- Cond_Wait --
  503.    ---------------
  504.  
  505.    procedure Cond_Wait
  506.      (Cond : in out Condition_Variable;
  507.       L    : in out Lock)
  508.    is
  509.       Result : Interfaces.C.POSIX_Error.Return_Code;
  510.  
  511.    begin
  512.  
  513.       --  Note that the following check is not perfect, since the
  514.       --  Someone_Is_Waiting flag is reset without synchronization.  There is
  515.       --  a window during which the flag is set but the wait has completed.
  516.       --  However, the associated mutex is still held; another thread
  517.       --  attempting to wait on the condition variable would have to use a
  518.       --  different mutex, which is also illegal, so the worst that will
  519.       --  happen is that the wrong error will be flagged.
  520.  
  521.       pragma Assert (
  522.         not Cond.Someone_Is_Waiting or else Runtime_Assert_Shutdown (
  523.           "GNULLI failure---More than one task" &
  524.             " waiting on a condition variable"));
  525.       Cond.Someone_Is_Waiting := True;
  526.  
  527.       pthread_cond_wait (
  528.         pthread_cond_t (Cond.CV),
  529.         pthread_mutex_t (L),
  530.         Result);
  531.  
  532.       Cond.Someone_Is_Waiting := False;
  533.  
  534.       --  EINTR is not considered a failure.  We have been assured that
  535.       --  Pthreads will soon guarantee that a thread will wake up from
  536.       --  a condition variable wait after it handles a signal.  EINTR will
  537.       --  probably go away at that point. ???
  538.  
  539.       pragma Assert (Result /= Failure or else
  540.         Interfaces.C.POSIX_Error.Get_Error_Code =
  541.            Interfaces.C.POSIX_Error.Interrupted_Operation or else
  542.               Runtime_Assert_Shutdown (
  543.         "GNULLI failure---pthread_cond_wait"));
  544.  
  545.    end Cond_Wait;
  546.  
  547.    -----------------------------
  548.    --  Stimespec_to_timespec  --
  549.    -----------------------------
  550.  
  551.    function Stimespec_to_timespec (S : Task_Clock.Stimespec)
  552.      return Interfaces.C.POSIX_timers.timespec is
  553.    begin
  554.       return Interfaces.C.POSIX_timers.timespec'
  555.         (tv_sec =>
  556.             Interfaces.C.POSIX_timers.time_t
  557.                (Task_Clock.Stimespec_Seconds (S)),
  558.          tv_nsec =>
  559.            Interfaces.C.POSIX_timers.Nanoseconds
  560.               (Task_Clock.Stimespec_NSeconds (S)));
  561.    end Stimespec_to_timespec;
  562.  
  563.    -----------------------------
  564.    --  timespec_to_Stimespec  --
  565.    -----------------------------
  566.  
  567.    function timespec_to_Stimespec (S : Interfaces.C.POSIX_timers.timespec)
  568.      return Task_Clock.Stimespec is
  569.    begin
  570.       return Task_Clock.Time_Of (integer (S.tv_sec), integer (S.tv_nsec));
  571.    end timespec_to_Stimespec;
  572.  
  573.    ---------------------
  574.    -- Cond_Timed_Wait --
  575.    ---------------------
  576.  
  577.    procedure Cond_Timed_Wait
  578.      (Cond      : in out Condition_Variable;
  579.       L         : in out Lock; Abs_Time : Task_Clock.Stimespec;
  580.       Timed_Out : out Boolean)
  581.    is
  582.       Result   : Interfaces.C.POSIX_Error.Return_Code;
  583.       I_Result : Integer;
  584.    begin
  585.  
  586.       --  Note that the following check is not perfect, since the
  587.       --  Someone_Is_Waiting flag is reset without synchronization.  There is
  588.       --  a window during which the flag is set but the wait has completed.
  589.       --  However, the associated mutex is still held; another thread
  590.       --  attempting to wait on the condition variable would have to use a
  591.       --  different mutex, which is also illegal, so the worst that will
  592.       --  happen is that the wrong error will be flagged.
  593.  
  594.       pragma Assert (
  595.         not Cond.Someone_Is_Waiting or else Runtime_Assert_Shutdown (
  596.           "GNULLI failure---More than one task " &
  597.             "waiting on a condition variable"));
  598.  
  599.       Cond.Someone_Is_Waiting := True;
  600.  
  601.       pthread_cond_timedwait (
  602.         pthread_cond_t (Cond.CV),
  603.         pthread_mutex_t (L),
  604.         Stimespec_to_timespec (Abs_Time),
  605.         Result);
  606.  
  607.       Cond.Someone_Is_Waiting := False;
  608.  
  609.       Timed_Out := Result = Failure and then
  610.         Interfaces.C.POSIX_Error.Get_Error_Code =
  611.           Interfaces.C.POSIX_Error.Resource_Temporarily_Unavailable;
  612.       pragma Assert (Result /= Failure or else
  613.             Interfaces.C.POSIX_Error.Get_Error_Code =
  614.               Interfaces.C.POSIX_Error.Resource_Temporarily_Unavailable or else
  615.                 Runtime_Assert_Shutdown (
  616.                   "GNULLI failure---pthread_cond_timedwait"));
  617.    end Cond_Timed_Wait;
  618.  
  619.    -----------------
  620.    -- Cond_Signal --
  621.    -----------------
  622.  
  623.    procedure Cond_Signal (Cond : in out Condition_Variable) is
  624.       Result : Interfaces.C.POSIX_Error.Return_Code;
  625.  
  626.    begin
  627.       pthread_cond_signal (pthread_cond_t (Cond.CV), Result);
  628.       pragma Assert (
  629.         Result /= Failure or else Runtime_Assert_Shutdown (
  630.           "GNULLI failure---pthread_cond_signal"));
  631.    end Cond_Signal;
  632.  
  633.    ------------------
  634.    -- Set_Priority --
  635.    ------------------
  636.  
  637.    procedure Set_Priority (T : TCB_Ptr; Prio : System.Priority) is
  638.       Attributes : pthread_attr_t;
  639.       Result     : Interfaces.C.POSIX_Error.Return_Code;
  640.  
  641.    begin
  642.       pthread_attr_init (Attributes, Result);
  643.       pragma Assert (
  644.         Result /= Failure or else Runtime_Assert_Shutdown (
  645.           "GNULLI failure---pthread_attr_init"));
  646.  
  647.       pthread_getschedattr (T.Thread, Attributes, Result);
  648.       pragma Assert (
  649.         Result /= Failure or else Runtime_Assert_Shutdown (
  650.           "GNULLI failure---pthread_getschedattr"));
  651.  
  652.       pthread_attr_setprio (Attributes, Priority_Type (Prio), Result);
  653.       pragma Assert (
  654.         Result /= Failure or else Runtime_Assert_Shutdown (
  655.           "GNULLI failure---pthread_attr_setprio"));
  656.  
  657.       pthread_setschedattr (T.Thread, Attributes, Result);
  658.       pragma Assert (
  659.         Result /= Failure or else Runtime_Assert_Shutdown (
  660.           "GNULLI failure---pthread_setschedattr"));
  661.  
  662.       pthread_attr_destroy (Attributes, Result);
  663.       pragma Assert (
  664.         Result /= Failure or else Runtime_Assert_Shutdown (
  665.           "GNULLI failure---pthread_attr_destroy"));
  666.  
  667.    end Set_Priority;
  668.  
  669.    ----------------------
  670.    -- Set_Own_Priority --
  671.    ----------------------
  672.  
  673.    procedure Set_Own_Priority (Prio : System.Priority) is
  674.       Attributes : pthread_attr_t;
  675.       Result     : Interfaces.C.POSIX_Error.Return_Code;
  676.    begin
  677.       Set_Priority (Self, Prio);
  678.    end Set_Own_Priority;
  679.  
  680.    ------------------
  681.    -- Get_Priority --
  682.    ------------------
  683.  
  684.    function Get_Priority (T : TCB_Ptr) return System.Priority is
  685.       Attributes : pthread_attr_t;
  686.       Prio       : Priority_Type;
  687.       Result     : Interfaces.C.POSIX_Error.Return_Code;
  688.  
  689.    begin
  690.       pthread_attr_init (Attributes, Result);
  691.       pragma Assert (
  692.         Result /= Failure or else Runtime_Assert_Shutdown (
  693.           "GNULLI failure---pthread_attr_init"));
  694.  
  695.       pthread_getschedattr (T.Thread, Attributes, Result);
  696.       pragma Assert (
  697.         Result /= Failure or else Runtime_Assert_Shutdown (
  698.           "GNULLI failure---pthread_getschedattr"));
  699.  
  700.       pthread_attr_getprio (Attributes, Prio, Result);
  701.       pragma Assert (
  702.         Result /= Failure or else Runtime_Assert_Shutdown (
  703.           "GNULLI failure---pthread_getprio"));
  704.  
  705.       pthread_attr_destroy (Attributes, Result);
  706.       pragma Assert (
  707.         Result /= Failure or else Runtime_Assert_Shutdown (
  708.           "GNULLI failure---pthread_attr_destroy"));
  709.  
  710.       return System.Priority (Prio);
  711.    end Get_Priority;
  712.  
  713.    -----------------------
  714.    --  Get_Own_Priority --
  715.    -----------------------
  716.  
  717.    --  Note: this is specialized (rather than being done using a default
  718.    --  parameter for Get_Priority) in case there is a specially efficient
  719.    --  way of getting your own priority, which might well be the case in
  720.    --  general (although is not the case in Pthreads).
  721.  
  722.    function Get_Own_Priority return System.Priority is
  723.    begin
  724.       return Get_Priority (Self);
  725.    end Get_Own_Priority;
  726.  
  727.    ----------------
  728.    -- LL_Wrapper --
  729.    ----------------
  730.  
  731.    procedure LL_Wrapper (T : TCB_Ptr) is
  732.       Result  : Interfaces.C.POSIX_Error.Return_Code;
  733.       Old_Set : aliased RTE.Signal_Set;
  734.  
  735.    begin
  736.       pthread_setspecific (ATCB_Key, Pointer_to_Address (T), Result);
  737.       pragma Assert (
  738.         Result /= Failure or else Runtime_Assert_Shutdown (
  739.           "GNULLI failure---pthread_setspecific"));
  740.  
  741.       RTE.sigprocmask (
  742.         RTE.SIG_UNBLOCK, LL_Signals'Access, Old_Set'Access, Result);
  743.       pragma Assert (
  744.         Result /= Failure or else Runtime_Assert_Shutdown (
  745.           "GNULLI failure---sigprocmask"));
  746.  
  747.       --  Note that the following call may not return!
  748.  
  749.       T.LL_Entry_Point (T.LL_Arg);
  750.    end LL_Wrapper;
  751.  
  752.    --------------------
  753.    -- Create_LL_Task --
  754.    --------------------
  755.  
  756.    procedure Create_LL_Task
  757.      (Priority       : System.Priority;
  758.       Stack_Size     :  Task_Storage_Size;
  759.       LL_Entry_Point : LL_Task_Procedure_Access;
  760.       Arg            : System.Address;
  761.       T              : TCB_Ptr)
  762.    is
  763.       Attributes : pthread_attr_t;
  764.       Result     : Interfaces.C.POSIX_Error.Return_Code;
  765.       Old_Set    : aliased RTE.Signal_Set;
  766.  
  767.    begin
  768.       T.LL_Entry_Point := LL_Entry_Point;
  769.       T.LL_Arg := Arg;
  770.       T.Stack_Size := Stack_Size;
  771.  
  772.       pthread_attr_init (Attributes, Result);
  773.       pragma Assert (
  774.         Result /= Failure or else Runtime_Assert_Shutdown (
  775.           "GNULLI failure---pthread_attr_init"));
  776.  
  777.       pthread_attr_setdetachstate (Attributes, 1, Result);
  778.       pragma Assert (
  779.         Result /= Failure or else Runtime_Assert_Shutdown (
  780.           "GNULLI failure---pthread_setdetachstate"));
  781.  
  782.       pthread_attr_setstacksize
  783.          (Attributes, Interfaces.C.size_t (Stack_Size), Result);
  784.       pragma Assert (
  785.         Result /= Failure or else Runtime_Assert_Shutdown (
  786.           "GNULLI failure---pthread_setstacksize"));
  787.  
  788.       pthread_attr_setprio (Attributes, Priority_Type (Priority), Result);
  789.       pragma Assert (
  790.         Result /= Failure or else Runtime_Assert_Shutdown (
  791.           "GNULLI failure---pthread_attr_setprio"));
  792.  
  793.       --  It is not safe for the task to be created to accept signals until it
  794.       --  has bound its TCB pointer to the thread with pthread_setspecific ().
  795.       --  The handler wrappers use the TCB pointers to restore the stack limit.
  796.  
  797.       RTE.sigprocmask (
  798.         RTE.SIG_BLOCK, LL_Signals'Access, Old_Set'Access, Result);
  799.       pragma Assert (
  800.         Result /= Failure or else Runtime_Assert_Shutdown (
  801.           "GNULLI failure---sigprocmask"));
  802.  
  803.       pthread_create (
  804.         T.Thread,
  805.         Attributes,
  806.         LL_Wrapper'Address,
  807.         Pointer_to_Address (T),
  808.         Result);
  809.       pragma Assert (
  810.         Result /= Failure or else Runtime_Assert_Shutdown (
  811.           "GNULLI failure---pthread_create"));
  812.  
  813.       pthread_attr_destroy (Attributes, Result);
  814.       pragma Assert (
  815.         Result /= Failure or else Runtime_Assert_Shutdown (
  816.           "GNULLI failure---pthread_attr_destroy"));
  817.  
  818.       RTE.sigprocmask (
  819.         RTE.SIG_UNBLOCK, LL_Signals'Access, Old_Set'Access, Result);
  820.       pragma Assert (
  821.         Result /= Failure or else Runtime_Assert_Shutdown (
  822.           "GNULLI failure---sigprocmask"));
  823.  
  824.    end Create_LL_Task;
  825.  
  826.    ------------------
  827.    -- Exit_LL_Task --
  828.    ------------------
  829.  
  830.    procedure Exit_LL_Task is
  831.    begin
  832.       pthread_exit (System.Null_Address);
  833.    end Exit_LL_Task;
  834.  
  835.    ----------------
  836.    -- Abort_Task --
  837.    ----------------
  838.  
  839.    procedure Abort_Task (T : TCB_Ptr) is
  840.       Result : Interfaces.C.POSIX_Error.Return_Code;
  841.  
  842.    begin
  843.       pthread_kill (T.Thread, Abort_Signal, Result);
  844.       pragma Assert (
  845.         Result /= Failure or else Runtime_Assert_Shutdown (
  846.           "GNULLI failure---pthread_kill"));
  847.    end Abort_Task;
  848.  
  849.    ----------------
  850.    -- Test_Abort --
  851.    ----------------
  852.  
  853.    --  This procedure does nothing.  It is intended for systems without
  854.    --  asynchronous abortion, where the runtime system would have to
  855.    --  synchronously poll for pending abortions.  This should be done
  856.    --  at least at every synchronization point.
  857.  
  858.    procedure Test_Abort is
  859.    begin
  860.       null;
  861.    end Test_Abort;
  862.  
  863.    ---------------------
  864.    -- Get_Stack_Limit --
  865.    ---------------------
  866.  
  867.    function Get_Stack_Limit return System.Address is
  868.    begin
  869.       return Self.Stack_Limit;
  870.    end Get_Stack_Limit;
  871.  
  872.    -------------------
  873.    -- Abort_Wrapper --
  874.    -------------------
  875.  
  876.    --  This is the handler called by the OS when an abort signal is
  877.    --  received; it in turn calls the handler installed by the client.
  878.    --  This procedure serves to isolate the client from the
  879.    --  implementation-specific calling conventions of asynchronous
  880.    --  handlers.
  881.  
  882.    procedure Abort_Wrapper
  883.      (signo   : Integer;
  884.       info    : RTE.siginfo_ptr;
  885.       context : System.Address)
  886.    is
  887.       function Address_To_Call_State is new
  888.         Unchecked_Conversion (System.Address, Pre_Call_State);
  889.  
  890.    begin
  891.       Abort_Handler (Address_To_Call_State (context));
  892.    end Abort_Wrapper;
  893.  
  894.    ---------------------------
  895.    -- Install_Abort_Handler --
  896.    ---------------------------
  897.  
  898.    procedure Install_Abort_Handler (Handler : Abort_Handler_Pointer) is
  899.       act     : aliased RTE.struct_sigaction;
  900.       old_act : aliased RTE.struct_sigaction;
  901.       Result  : Interfaces.C.POSIX_Error.Return_Code;
  902.  
  903.    begin
  904.       Abort_Handler := Handler;
  905.       act.sa_handler := Abort_Wrapper'Address;
  906.       RTE.sigemptyset (act.sa_mask'Access, Result);
  907.       pragma Assert (
  908.         Result /= Failure or else Runtime_Assert_Shutdown (
  909.           "GNULLI failure---sigemptyset"));
  910.       act.sa_flags := 0;
  911.  
  912.       RTE.sigaction (Abort_Signal, act'Access, old_act'Access, Result);
  913.       pragma Assert (
  914.         Result /= Failure or else Runtime_Assert_Shutdown (
  915.           "GNULLI failure---sigaction"));
  916.    end Install_Abort_Handler;
  917.  
  918.    ---------------------------
  919.    -- Install_Error_Handler --
  920.    ---------------------------
  921.  
  922.    procedure Install_Error_Handler (Handler : System.Address) is
  923.       act     : aliased RTE.struct_sigaction;
  924.       old_act : aliased RTE.struct_sigaction;
  925.       Result  : Interfaces.C.POSIX_Error.Return_Code;
  926.  
  927.    begin
  928.       act.sa_handler := Handler;
  929.  
  930.       RTE.sigemptyset (act.sa_mask'Access, Result);
  931.       pragma Assert (
  932.         Result /= Failure or else Runtime_Assert_Shutdown (
  933.           "GNULLI failure---sigemptyset"));
  934.       RTE.sigaddset (act.sa_mask'Access, RTE.SIGILL, Result);
  935.       pragma Assert (
  936.         Result /= Failure or else Runtime_Assert_Shutdown (
  937.           "GNULLI failure---sigaddset"));
  938.       RTE.sigaddset (act.sa_mask'Access, RTE.SIGFPE, Result);
  939.       pragma Assert (
  940.         Result /= Failure or else Runtime_Assert_Shutdown (
  941.           "GNULLI failure---sigaddset"));
  942.       RTE.sigaddset (act.sa_mask'Access, RTE.SIGSEGV, Result);
  943.       pragma Assert (
  944.         Result /= Failure or else Runtime_Assert_Shutdown (
  945.           "GNULLI failure---sigaddset"));
  946.       act.sa_flags := 0;
  947.  
  948.       RTE.sigaction (RTE.SIGILL, act'Access, old_act'Access, Result);
  949.       pragma Assert (
  950.         Result /= Failure or else Runtime_Assert_Shutdown (
  951.           "GNULLI failure---sigaction"));
  952.  
  953.       RTE.sigaction (RTE.SIGFPE, act'Access, old_act'Access, Result);
  954.       pragma Assert (
  955.         Result /= Failure or else Runtime_Assert_Shutdown (
  956.           "GNULLI failure---sigaction"));
  957.  
  958.       RTE.sigaction (RTE.SIGSEGV, act'Access, old_act'Access, Result);
  959.       pragma Assert (
  960.         Result /= Failure or else Runtime_Assert_Shutdown (
  961.           "GNULLI failure---sigaction"));
  962.  
  963.    end Install_Error_Handler;
  964.  
  965.    ------------------
  966.    -- Test_And_Set --
  967.    ------------------
  968.  
  969.    -------------------------
  970.    -- Initialize_TAS_Cell --
  971.    -------------------------
  972.    procedure Initialize_TAS_Cell (Cell :    out TAS_Cell) is
  973.    begin
  974.       Cell.Value := False;
  975.    end Initialize_TAS_Cell;
  976.    -----------------------
  977.    -- Finalize_TAS_Cell --
  978.    -----------------------
  979.    procedure Finalize_TAS_Cell   (Cell : in out TAS_Cell) is
  980.    begin
  981.       null;
  982.    end Finalize_TAS_Cell;
  983.    -----------
  984.    -- Clear --
  985.    -----------
  986.    --
  987.    --  This was not atomic with respect to another Test_and_Set in the
  988.    --  original code.  Need it be???
  989.    --
  990.    procedure Clear        (Cell : in out TAS_Cell) is
  991.    begin
  992.       Cell.Value := False;
  993.    end Clear;
  994.  
  995.    ------------
  996.    -- Is_Set --
  997.    ------------
  998.  
  999.    --
  1000.    --  This was not atomic with respect to another Test_and_Set in the
  1001.    --  original code.  Need it be???
  1002.    --
  1003.    function  Is_Set       (Cell : in     TAS_Cell) return Boolean is
  1004.    begin
  1005.       return Cell.Value;
  1006.    end Is_Set;
  1007.    ------------------
  1008.    -- Test_And_Set --
  1009.    ------------------
  1010.    procedure Test_And_Set (Cell : in out TAS_Cell; Result : out Boolean) is
  1011.       Error : Boolean;
  1012.    begin
  1013.       Write_Lock (Test_And_Set_Mutex, Error);
  1014.  
  1015.       if Cell.Value then
  1016.          Result := False;
  1017.       else
  1018.          Result :=  True;
  1019.          Cell.Value := True;
  1020.       end if;
  1021.       Unlock (Test_And_Set_Mutex);
  1022.    end Test_And_Set;
  1023.  
  1024. begin
  1025.    Initialize_Lock (System.Priority'Last, Test_And_Set_Mutex);
  1026. end System.Task_Primitives;
  1027.