-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2006, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2008, Free Software Foundation, Inc. --
-- --
-- GNARL 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- --
-- This is a Solaris (native) version of this package
--- This package contains all the GNULL primitives that interface directly
--- with the underlying OS.
+-- This package contains all the GNULL primitives that interface directly with
+-- the underlying OS.
pragma Polling (Off);
--- Turn off polling, we do not want ATC polling to take place during
--- tasking operations. It causes infinite loops and other problems.
+-- Turn off polling, we do not want ATC polling to take place during tasking
+-- operations. It causes infinite loops and other problems.
-with System.Tasking.Debug;
--- used for Known_Tasks
+with Ada.Unchecked_Deallocation;
-with System.Interrupt_Management;
--- used for Keep_Unmasked
--- Abort_Task_Interrupt
--- Interrupt_ID
+with Interfaces.C;
+with System.Tasking.Debug;
+with System.Interrupt_Management;
with System.OS_Primitives;
--- used for Delay_Modes
+with System.Task_Info;
pragma Warnings (Off);
-with GNAT.OS_Lib;
--- used for String_Access, Getenv
-
+with System.OS_Lib;
pragma Warnings (On);
-with Interfaces.C;
--- used for int
--- size_t
-
-with System.Task_Info;
--- to initialize Task_Info for a C thread, in function Self
-
with System.Soft_Links;
--- used for Defer/Undefer_Abort
-
-- We use System.Soft_Links instead of System.Tasking.Initialization
-- because the later is a higher level package that we shouldn't depend on.
-- For example when using the restricted run time, it is replaced by
-- System.Tasking.Restricted.Stages.
-with Unchecked_Deallocation;
-
package body System.Task_Primitives.Operations is
package SSL renames System.Soft_Links;
-- controls whether we emulate priority ceiling locking
-- To get a scheduling close to annex D requirements, we use the real-time
- -- class provided for LWP's and map each task/thread to a specific and
+ -- class provided for LWPs and map each task/thread to a specific and
-- unique LWP (there is 1 thread per LWP, and 1 LWP per thread).
-- The real time class can only be set when the process has root
- -- priviledges, so in the other cases, we use the normal thread scheduling
+ -- privileges, so in the other cases, we use the normal thread scheduling
-- and priority handling.
Using_Real_Time_Class : Boolean := False;
- -- indicates wether the real time class is being used (i.e the process
- -- has root priviledges).
+ -- indicates whether the real time class is being used (i.e. the process
+ -- has root privileges).
Prio_Param : aliased struct_pcparms;
-- Hold priority info (Real_Time) initialized during the package
-- External Configuration Values --
-----------------------------------
- Time_Slice_Val : Interfaces.C.long;
+ Time_Slice_Val : Integer;
pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
Locking_Policy : Character;
pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
Foreign_Task_Elaborated : aliased Boolean := True;
- -- Used to identified fake tasks (i.e., non-Ada Threads).
+ -- Used to identified fake tasks (i.e., non-Ada Threads)
-----------------------
-- Local Subprograms --
procedure Abort_Handler
(Sig : Signal;
- Code : access siginfo_t;
- Context : access ucontext_t);
+ Code : not null access siginfo_t;
+ Context : not null access ucontext_t);
-- Target-dependent binding of inter-thread Abort signal to
-- the raising of the Abort_Signal exception.
-- See also comments in 7staprop.adb
procedure Initialize (Environment_Task : Task_Id);
pragma Inline (Initialize);
- -- Initialize various data needed by this package.
+ -- Initialize various data needed by this package
function Is_Valid_Task return Boolean;
pragma Inline (Is_Valid_Task);
procedure Set (Self_Id : Task_Id);
pragma Inline (Set);
- -- Set the self id for the current task.
+ -- Set the self id for the current task
function Self return Task_Id;
pragma Inline (Self);
- -- Return a pointer to the Ada Task Control Block of the calling task.
+ -- Return a pointer to the Ada Task Control Block of the calling task
end Specific;
package body Specific is separate;
- -- The body of this package is target specific.
+ -- The body of this package is target specific
---------------------------------
-- Support for foreign threads --
---------------------------------
function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
- -- Allocate and Initialize a new ATCB for the current Thread.
+ -- Allocate and Initialize a new ATCB for the current Thread
function Register_Foreign_Thread
(Thread : Thread_Id) return Task_Id is separate;
procedure Abort_Handler
(Sig : Signal;
- Code : access siginfo_t;
- Context : access ucontext_t)
+ Code : not null access siginfo_t;
+ Context : not null access ucontext_t)
is
pragma Unreferenced (Sig);
pragma Unreferenced (Code);
Old_Set : aliased sigset_t;
Result : Interfaces.C.int;
+ pragma Warnings (Off, Result);
begin
-- It is not safe to raise an exception when using ZCX and the GCC
-- Make sure signals used for RTS internal purpose are unmasked
- Result := thr_sigsetmask (SIG_UNBLOCK,
- Unblocked_Signal_Mask'Unchecked_Access, Old_Set'Unchecked_Access);
+ Result :=
+ thr_sigsetmask
+ (SIG_UNBLOCK,
+ Unblocked_Signal_Mask'Unchecked_Access,
+ Old_Set'Unchecked_Access);
pragma Assert (Result = 0);
raise Standard'Abort_Signal;
-- _SC_NPROCESSORS_CONF, minus one.
procedure Configure_Processors is
- Proc_Acc : constant GNAT.OS_Lib.String_Access :=
- GNAT.OS_Lib.Getenv ("GNAT_PROCESSOR");
+ Proc_Acc : constant System.OS_Lib.String_Access :=
+ System.OS_Lib.Getenv ("GNAT_PROCESSOR");
Proc : aliased processorid_t; -- User processor #
Last_Proc : processorid_t; -- Last processor #
begin
if Proc_Acc.all'Length /= 0 then
+
-- Environment variable is defined
Last_Proc := Num_Procs - 1;
Proc := processorid_t'Value (Proc_Acc.all);
if Proc <= -2 or else Proc > Last_Proc then
+
-- Use the default configuration
+
null;
+
elsif Proc = -1 then
+
-- Choose a processor
Result := 0;
-
while Proc < Last_Proc loop
Proc := Proc + 1;
Result := p_online (Proc, PR_STATUS);
-- If a pragma Time_Slice is specified, takes the value in account
if Time_Slice_Val > 0 then
- -- Convert Time_Slice_Val (microseconds) into seconds and
- -- nanoseconds
- Secs := Time_Slice_Val / 1_000_000;
- Nsecs := (Time_Slice_Val rem 1_000_000) * 1_000;
+ -- Convert Time_Slice_Val (microseconds) to seconds/nanosecs
+
+ Secs := Interfaces.C.long (Time_Slice_Val / 1_000_000);
+ Nsecs :=
+ Interfaces.C.long ((Time_Slice_Val rem 1_000_000) * 1_000);
-- Otherwise, default to no time slicing (i.e run until blocked)
Nsecs := RT_TQINF;
end if;
- -- Get the real time class id.
+ -- Get the real time class id
Class_Info.pc_clname (1) := 'R';
Class_Info.pc_clname (2) := 'T';
Prio_Param.rt_tqsecs := Secs;
Prio_Param.rt_tqnsecs := Nsecs;
- Result := priocntl (PC_VERSION, P_LWPID, P_MYID, PC_SETPARMS,
- Prio_Param'Address);
+ Result :=
+ priocntl
+ (PC_VERSION, P_LWPID, P_MYID, PC_SETPARMS, Prio_Param'Address);
Using_Real_Time_Class := Result /= -1;
end;
Specific.Set (Environment_Task);
- -- Initialize the lock used to synchronize chain of all ATCBs.
+ -- Initialize the lock used to synchronize chain of all ATCBs
Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
-- Install the abort-signal handler
- if State (System.Interrupt_Management.Abort_Task_Interrupt)
- /= Default
+ if State
+ (System.Interrupt_Management.Abort_Task_Interrupt) /= Default
then
-- Set sa_flags to SA_NODEFER so that during the handler execution
-- we do not change the Signal_Mask to be masked for the Abort_Signal
act.sa_mask := Tmp_Set;
Result :=
- sigaction (
- Signal (System.Interrupt_Management.Abort_Task_Interrupt),
- act'Unchecked_Access,
- old_act'Unchecked_Access);
+ sigaction
+ (Signal (System.Interrupt_Management.Abort_Task_Interrupt),
+ act'Unchecked_Access,
+ old_act'Unchecked_Access);
pragma Assert (Result = 0);
end if;
-- Initialize_Lock --
---------------------
- -- Note: mutexes and cond_variables needed per-task basis are
- -- initialized in Initialize_TCB and the Storage_Error is
- -- handled. Other mutexes (such as RTS_Lock, Memory_Lock...)
- -- used in RTS is initialized before any status change of RTS.
- -- Therefore rasing Storage_Error in the following routines
- -- should be able to be handled safely.
+ -- Note: mutexes and cond_variables needed per-task basis are initialized
+ -- in Initialize_TCB and the Storage_Error is handled. Other mutexes (such
+ -- as RTS_Lock, Memory_Lock...) used in RTS is initialized before any
+ -- status change of RTS. Therefore raising Storage_Error in the following
+ -- routines should be able to be handled safely.
procedure Initialize_Lock
(Prio : System.Any_Priority;
- L : access Lock)
+ L : not null access Lock)
is
Result : Interfaces.C.int;
end Initialize_Lock;
procedure Initialize_Lock
- (L : access RTS_Lock;
+ (L : not null access RTS_Lock;
Level : Lock_Level)
is
Result : Interfaces.C.int;
begin
- pragma Assert (Check_Initialize_Lock
- (To_Lock_Ptr (RTS_Lock_Ptr (L)), Level));
+ pragma Assert
+ (Check_Initialize_Lock (To_Lock_Ptr (RTS_Lock_Ptr (L)), Level));
Result := mutex_init (L.L'Access, USYNC_THREAD, System.Null_Address);
pragma Assert (Result = 0 or else Result = ENOMEM);
-- Finalize_Lock --
-------------------
- procedure Finalize_Lock (L : access Lock) is
+ procedure Finalize_Lock (L : not null access Lock) is
Result : Interfaces.C.int;
-
begin
pragma Assert (Check_Finalize_Lock (Lock_Ptr (L)));
Result := mutex_destroy (L.L'Access);
pragma Assert (Result = 0);
end Finalize_Lock;
- procedure Finalize_Lock (L : access RTS_Lock) is
+ procedure Finalize_Lock (L : not null access RTS_Lock) is
Result : Interfaces.C.int;
-
begin
pragma Assert (Check_Finalize_Lock (To_Lock_Ptr (RTS_Lock_Ptr (L))));
Result := mutex_destroy (L.L'Access);
-- Write_Lock --
----------------
- procedure Write_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
+ procedure Write_Lock
+ (L : not null access Lock;
+ Ceiling_Violation : out Boolean)
+ is
Result : Interfaces.C.int;
begin
end Write_Lock;
procedure Write_Lock
- (L : access RTS_Lock;
+ (L : not null access RTS_Lock;
Global_Lock : Boolean := False)
is
Result : Interfaces.C.int;
-
begin
if not Single_Lock or else Global_Lock then
pragma Assert (Check_Lock (To_Lock_Ptr (RTS_Lock_Ptr (L))));
procedure Write_Lock (T : Task_Id) is
Result : Interfaces.C.int;
-
begin
if not Single_Lock then
pragma Assert (Check_Lock (To_Lock_Ptr (T.Common.LL.L'Access)));
-- Read_Lock --
---------------
- procedure Read_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
+ procedure Read_Lock
+ (L : not null access Lock;
+ Ceiling_Violation : out Boolean) is
begin
Write_Lock (L, Ceiling_Violation);
end Read_Lock;
-- Unlock --
------------
- procedure Unlock (L : access Lock) is
- Result : Interfaces.C.int;
+ procedure Unlock (L : not null access Lock) is
+ Result : Interfaces.C.int;
begin
pragma Assert (Check_Unlock (Lock_Ptr (L)));
end if;
end Unlock;
- procedure Unlock (L : access RTS_Lock; Global_Lock : Boolean := False) is
+ procedure Unlock
+ (L : not null access RTS_Lock;
+ Global_Lock : Boolean := False)
+ is
Result : Interfaces.C.int;
-
begin
if not Single_Lock or else Global_Lock then
pragma Assert (Check_Unlock (To_Lock_Ptr (RTS_Lock_Ptr (L))));
procedure Unlock (T : Task_Id) is
Result : Interfaces.C.int;
-
begin
if not Single_Lock then
pragma Assert (Check_Unlock (To_Lock_Ptr (T.Common.LL.L'Access)));
end if;
end Unlock;
+ -----------------
+ -- Set_Ceiling --
+ -----------------
+
+ -- Dynamic priority ceilings are not supported by the underlying system
+
+ procedure Set_Ceiling
+ (L : not null access Lock;
+ Prio : System.Any_Priority)
+ is
+ pragma Unreferenced (L, Prio);
+ begin
+ null;
+ end Set_Ceiling;
+
-- For the time delay implementation, we need to make sure we
-- achieve following criteria:
Result : Interfaces.C.int;
pragma Unreferenced (Result);
- Param : aliased struct_pcparms;
+ Param : aliased struct_pcparms;
use Task_Info;
thr_setprio (T.Common.LL.Thread, Interfaces.C.int (Prio));
else
-
-- The task is bound to a LWP, use priocntl
-- ??? TBD
if Self_ID.Common.Task_Info.CPU = ANY_CPU then
Result := 0;
Proc := 0;
-
while Proc < Last_Proc loop
Result := p_online (Proc, PR_STATUS);
exit when Result = PR_ONLINE;
raise Invalid_CPU_Number;
end if;
- Result := processor_bind
- (P_LWPID, P_MYID, Self_ID.Common.Task_Info.CPU, null);
+ Result :=
+ processor_bind
+ (P_LWPID, P_MYID, Self_ID.Common.Task_Info.CPU, null);
pragma Assert (Result = 0);
end if;
end if;
Result : Interfaces.C.int := 0;
begin
- -- Give the task a unique serial number.
+ -- Give the task a unique serial number
Self_ID.Serial_Number := Next_Serial_Number;
Next_Serial_Number := Next_Serial_Number + 1;
Self_ID.Common.LL.Thread := To_thread_t (-1);
if not Single_Lock then
- Result := mutex_init
- (Self_ID.Common.LL.L.L'Access, USYNC_THREAD, System.Null_Address);
+ Result :=
+ mutex_init
+ (Self_ID.Common.LL.L.L'Access, USYNC_THREAD, System.Null_Address);
Self_ID.Common.LL.L.Level :=
Private_Task_Serial_Number (Self_ID.Serial_Number);
pragma Assert (Result = 0 or else Result = ENOMEM);
Opts := THR_DETACHED + THR_BOUND;
end if;
- Result := thr_create
- (System.Null_Address,
- Adjusted_Stack_Size,
- Thread_Body_Access (Wrapper),
- To_Address (T),
- Opts,
- T.Common.LL.Thread'Access);
+ Result :=
+ thr_create
+ (System.Null_Address,
+ Adjusted_Stack_Size,
+ Thread_Body_Access (Wrapper),
+ To_Address (T),
+ Opts,
+ T.Common.LL.Thread'Access);
Succeeded := Result = 0;
pragma Assert
------------------
procedure Finalize_TCB (T : Task_Id) is
- Result : Interfaces.C.int;
- Tmp : Task_Id := T;
+ Result : Interfaces.C.int;
+ Tmp : Task_Id := T;
Is_Self : constant Boolean := T = Self;
procedure Free is new
- Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
+ Ada.Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
begin
T.Common.LL.Thread := To_thread_t (0);
-- Exit_Task --
---------------
- -- This procedure must be called with abort deferred.
- -- It can no longer call Self or access
- -- the current task's ATCB, since the ATCB has been deallocated.
+ -- This procedure must be called with abort deferred. It can no longer
+ -- call Self or access the current task's ATCB, since the ATCB has been
+ -- deallocated.
procedure Exit_Task is
begin
Result : Interfaces.C.int;
begin
pragma Assert (T /= Self);
-
- Result := thr_kill (T.Common.LL.Thread,
- Signal (System.Interrupt_Management.Abort_Task_Interrupt));
+ Result :=
+ thr_kill
+ (T.Common.LL.Thread,
+ Signal (System.Interrupt_Management.Abort_Task_Interrupt));
pragma Assert (Result = 0);
end Abort_Task;
begin
pragma Assert (Check_Sleep (Reason));
- if Dynamic_Priority_Support
- and then Self_ID.Pending_Priority_Change
- then
- Self_ID.Pending_Priority_Change := False;
- Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
- Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
- end if;
-
if Single_Lock then
- Result := cond_wait
- (Self_ID.Common.LL.CV'Access, Single_RTS_Lock.L'Access);
+ Result :=
+ cond_wait
+ (Self_ID.Common.LL.CV'Access, Single_RTS_Lock.L'Access);
else
- Result := cond_wait
- (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L.L'Access);
+ Result :=
+ cond_wait
+ (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L.L'Access);
end if;
- pragma Assert (Record_Wakeup
- (To_Lock_Ptr (Self_ID.Common.LL.L'Access), Reason));
+ pragma Assert
+ (Record_Wakeup (To_Lock_Ptr (Self_ID.Common.LL.L'Access), Reason));
pragma Assert (Result = 0 or else Result = EINTR);
end Sleep;
- -- Note that we are relying heaviliy here on the GNAT feature
- -- that Calendar.Time, System.Real_Time.Time, Duration, and
- -- System.Real_Time.Time_Span are all represented in the same
- -- way, i.e., as a 64-bit count of nanoseconds.
+ -- Note that we are relying heavily here on GNAT representing
+ -- Calendar.Time, System.Real_Time.Time, Duration,
+ -- System.Real_Time.Time_Span in the same way, i.e., as a 64-bit count of
+ -- nanoseconds.
-- This allows us to always pass the timeout value as a Duration.
-- ???
- -- We are taking liberties here with the semantics of the delays.
- -- That is, we make no distinction between delays on the Calendar clock
- -- and delays on the Real_Time clock. That is technically incorrect, if
- -- the Calendar clock happens to be reset or adjusted.
- -- To solve this defect will require modification to the compiler
- -- interface, so that it can pass through more information, to tell
- -- us here which clock to use!
+ -- We are taking liberties here with the semantics of the delays. That is,
+ -- we make no distinction between delays on the Calendar clock and delays
+ -- on the Real_Time clock. That is technically incorrect, if the Calendar
+ -- clock happens to be reset or adjusted. To solve this defect will require
+ -- modification to the compiler interface, so that it can pass through more
+ -- information, to tell us here which clock to use!
-- cond_timedwait will return if any of the following happens:
-- 1) some other task did cond_signal on this condition variable
-- UNIX calls this an "interrupted" system call.
-- In this case, the return value is EINTR
- -- If the cond_timedwait returns 0 or EINTR, it is still
- -- possible that the time has actually expired, and by chance
- -- a signal or cond_signal occurred at around the same time.
-
- -- We have also observed that on some OS's the value ETIME
- -- will be returned, but the clock will show that the full delay
- -- has not yet expired.
-
- -- For these reasons, we need to check the clock after return
- -- from cond_timedwait. If the time has expired, we will set
- -- Timedout = True.
-
- -- This check might be omitted for systems on which the
- -- cond_timedwait() never returns early or wakes up spuriously.
-
- -- Annex D requires that completion of a delay cause the task
- -- to go to the end of its priority queue, regardless of whether
- -- the task actually was suspended by the delay. Since
- -- cond_timedwait does not do this on Solaris, we add a call
- -- to thr_yield at the end. We might do this at the beginning,
- -- instead, but then the round-robin effect would not be the
- -- same; the delayed task would be ahead of other tasks of the
- -- same priority that awoke while it was sleeping.
-
- -- For Timed_Sleep, we are expecting possible cond_signals
- -- to indicate other events (e.g., completion of a RV or
- -- completion of the abortable part of an async. select),
- -- we want to always return if interrupted. The caller will
- -- be responsible for checking the task state to see whether
- -- the wakeup was spurious, and to go back to sleep again
- -- in that case. We don't need to check for pending abort
- -- or priority change on the way in our out; that is the
- -- caller's responsibility.
-
- -- For Timed_Delay, we are not expecting any cond_signals or
- -- other interruptions, except for priority changes and aborts.
- -- Therefore, we don't want to return unless the delay has
- -- actually expired, or the call has been aborted. In this
- -- case, since we want to implement the entire delay statement
- -- semantics, we do need to check for pending abort and priority
- -- changes. We can quietly handle priority changes inside the
+ -- If the cond_timedwait returns 0 or EINTR, it is still possible that the
+ -- time has actually expired, and by chance a signal or cond_signal
+ -- occurred at around the same time.
+
+ -- We have also observed that on some OS's the value ETIME will be
+ -- returned, but the clock will show that the full delay has not yet
+ -- expired.
+
+ -- For these reasons, we need to check the clock after return from
+ -- cond_timedwait. If the time has expired, we will set Timedout = True.
+
+ -- This check might be omitted for systems on which the cond_timedwait()
+ -- never returns early or wakes up spuriously.
+
+ -- Annex D requires that completion of a delay cause the task to go to the
+ -- end of its priority queue, regardless of whether the task actually was
+ -- suspended by the delay. Since cond_timedwait does not do this on
+ -- Solaris, we add a call to thr_yield at the end. We might do this at the
+ -- beginning, instead, but then the round-robin effect would not be the
+ -- same; the delayed task would be ahead of other tasks of the same
+ -- priority that awoke while it was sleeping.
+
+ -- For Timed_Sleep, we are expecting possible cond_signals to indicate
+ -- other events (e.g., completion of a RV or completion of the abortable
+ -- part of an async. select), we want to always return if interrupted. The
+ -- caller will be responsible for checking the task state to see whether
+ -- the wakeup was spurious, and to go back to sleep again in that case. We
+ -- don't need to check for pending abort or priority change on the way in
+ -- our out; that is the caller's responsibility.
+
+ -- For Timed_Delay, we are not expecting any cond_signals or other
+ -- interruptions, except for priority changes and aborts. Therefore, we
+ -- don't want to return unless the delay has actually expired, or the call
+ -- has been aborted. In this case, since we want to implement the entire
+ -- delay statement semantics, we do need to check for pending abort and
+ -- priority changes. We can quietly handle priority changes inside the
-- procedure, since there is no entry-queue reordering involved.
-----------------
Timedout : out Boolean;
Yielded : out Boolean)
is
- Check_Time : constant Duration := Monotonic_Clock;
+ Base_Time : constant Duration := Monotonic_Clock;
+ Check_Time : Duration := Base_Time;
Abs_Time : Duration;
Request : aliased timespec;
Result : Interfaces.C.int;
Request := To_Timespec (Abs_Time);
loop
- exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
- or else (Dynamic_Priority_Support and then
- Self_ID.Pending_Priority_Change);
+ exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
if Single_Lock then
- Result := cond_timedwait (Self_ID.Common.LL.CV'Access,
- Single_RTS_Lock.L'Access, Request'Access);
+ Result :=
+ cond_timedwait
+ (Self_ID.Common.LL.CV'Access,
+ Single_RTS_Lock.L'Access, Request'Access);
else
- Result := cond_timedwait (Self_ID.Common.LL.CV'Access,
- Self_ID.Common.LL.L.L'Access, Request'Access);
+ Result :=
+ cond_timedwait
+ (Self_ID.Common.LL.CV'Access,
+ Self_ID.Common.LL.L.L'Access, Request'Access);
end if;
Yielded := True;
- exit when Abs_Time <= Monotonic_Clock;
+ Check_Time := Monotonic_Clock;
+ exit when Abs_Time <= Check_Time or else Check_Time < Base_Time;
if Result = 0 or Result = EINTR then
end loop;
end if;
- pragma Assert (Record_Wakeup
- (To_Lock_Ptr (Self_ID.Common.LL.L'Access), Reason));
+ pragma Assert
+ (Record_Wakeup (To_Lock_Ptr (Self_ID.Common.LL.L'Access), Reason));
end Timed_Sleep;
-----------------
-----------------
procedure Timed_Delay
- (Self_ID : Task_Id;
- Time : Duration;
- Mode : ST.Delay_Modes)
+ (Self_ID : Task_Id;
+ Time : Duration;
+ Mode : ST.Delay_Modes)
is
- Check_Time : constant Duration := Monotonic_Clock;
+ Base_Time : constant Duration := Monotonic_Clock;
+ Check_Time : Duration := Base_Time;
Abs_Time : Duration;
Request : aliased timespec;
Result : Interfaces.C.int;
pragma Assert (Check_Sleep (Delay_Sleep));
loop
- if Dynamic_Priority_Support and then
- Self_ID.Pending_Priority_Change then
- Self_ID.Pending_Priority_Change := False;
- Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
- Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
- end if;
-
exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
if Single_Lock then
- Result := cond_timedwait (Self_ID.Common.LL.CV'Access,
- Single_RTS_Lock.L'Access, Request'Access);
+ Result :=
+ cond_timedwait
+ (Self_ID.Common.LL.CV'Access,
+ Single_RTS_Lock.L'Access,
+ Request'Access);
else
- Result := cond_timedwait (Self_ID.Common.LL.CV'Access,
- Self_ID.Common.LL.L.L'Access, Request'Access);
+ Result :=
+ cond_timedwait
+ (Self_ID.Common.LL.CV'Access,
+ Self_ID.Common.LL.L.L'Access,
+ Request'Access);
end if;
Yielded := True;
- exit when Abs_Time <= Monotonic_Clock;
+ Check_Time := Monotonic_Clock;
+ exit when Abs_Time <= Check_Time or else Check_Time < Base_Time;
- pragma Assert (Result = 0 or else
- Result = ETIME or else
- Result = EINTR);
+ pragma Assert
+ (Result = 0 or else
+ Result = ETIME or else
+ Result = EINTR);
end loop;
- pragma Assert (Record_Wakeup
- (To_Lock_Ptr (Self_ID.Common.LL.L'Access), Delay_Sleep));
+ pragma Assert
+ (Record_Wakeup
+ (To_Lock_Ptr (Self_ID.Common.LL.L'Access), Delay_Sleep));
Self_ID.Common.State := Runnable;
end if;
Reason : Task_States)
is
Result : Interfaces.C.int;
-
begin
pragma Assert (Check_Wakeup (T, Reason));
Result := cond_signal (T.Common.LL.CV'Access);
-- Check_Initialize_Lock --
---------------------------
- -- The following code is intended to check some of the invariant
- -- assertions related to lock usage, on which we depend.
+ -- The following code is intended to check some of the invariant assertions
+ -- related to lock usage, on which we depend.
function Check_Initialize_Lock
(L : Lock_Ptr;
return False;
end if;
+ -- Magic constant 4???
+
if L.Level = 4 then
Check_Count := Unlock_Count;
end if;
+ -- Magic constant 1000???
+
if Unlock_Count - Check_Count > 1000 then
Check_Count := Unlock_Count;
end if;
procedure Initialize (S : in out Suspension_Object) is
Result : Interfaces.C.int;
+
begin
- -- Initialize internal state. It is always initialized to False (ARM
- -- D.10 par. 6).
+ -- Initialize internal state (always to zero (RM D.10(6)))
S.State := False;
S.Waiting := False;
procedure Finalize (S : in out Suspension_Object) is
Result : Interfaces.C.int;
+
begin
-- Destroy internal mutex
procedure Set_False (S : in out Suspension_Object) is
Result : Interfaces.C.int;
+
begin
SSL.Abort_Defer.all;
procedure Set_True (S : in out Suspension_Object) is
Result : Interfaces.C.int;
+
begin
SSL.Abort_Defer.all;
Result := cond_signal (S.CV'Access);
pragma Assert (Result = 0);
+
else
S.State := True;
end if;
procedure Suspend_Until_True (S : in out Suspension_Object) is
Result : Interfaces.C.int;
+
begin
SSL.Abort_Defer.all;
pragma Assert (Result = 0);
if S.Waiting then
+
-- Program_Error must be raised upon calling Suspend_Until_True
-- if another task is already waiting on that suspension object
- -- (ARM D.10 par. 10).
+ -- (RM D.10(10)).
Result := mutex_unlock (S.L'Access);
pragma Assert (Result = 0);
SSL.Abort_Undefer.all;
raise Program_Error;
+
else
-- Suspend the task if the state is False. Otherwise, the task
-- continues its execution, and the state of the suspension object
function Check_Exit (Self_ID : Task_Id) return Boolean is
begin
- -- Check that caller is just holding Global_Task_Lock
- -- and no other locks
+ -- Check that caller is just holding Global_Task_Lock and no other locks
if Self_ID.Common.LL.Locks = null then
return False;
end if;
end Resume_Task;
+ --------------------
+ -- Stop_All_Tasks --
+ --------------------
+
+ procedure Stop_All_Tasks is
+ begin
+ null;
+ end Stop_All_Tasks;
+
+ ---------------
+ -- Stop_Task --
+ ---------------
+
+ function Stop_Task (T : ST.Task_Id) return Boolean is
+ pragma Unreferenced (T);
+ begin
+ return False;
+ end Stop_Task;
+
+ -------------------
+ -- Continue_Task --
+ -------------------
+
+ function Continue_Task (T : ST.Task_Id) return Boolean is
+ pragma Unreferenced (T);
+ begin
+ return False;
+ end Continue_Task;
+
end System.Task_Primitives.Operations;