1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
5 -- S Y S T E M . T A S K _ P R I M I T I V E S . O P E R A T I O N S --
9 -- Copyright (C) 1992-2011, Free Software Foundation, Inc. --
11 -- GNARL is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- GNARL was developed by the GNARL team at Florida State University. --
28 -- Extensive contributions were provided by Ada Core Technologies, Inc. --
30 ------------------------------------------------------------------------------
32 -- This is the VxWorks version of this package
34 -- This package contains all the GNULL primitives that interface directly with
38 -- Turn off polling, we do not want ATC polling to take place during tasking
39 -- operations. It causes infinite loops and other problems.
41 with Ada.Unchecked_Conversion;
42 with Ada.Unchecked_Deallocation;
46 with System.Multiprocessors;
47 with System.Tasking.Debug;
48 with System.Interrupt_Management;
50 with System.Soft_Links;
51 -- We use System.Soft_Links instead of System.Tasking.Initialization
52 -- because the later is a higher level package that we shouldn't depend
53 -- on. For example when using the restricted run time, it is replaced by
54 -- System.Tasking.Restricted.Stages.
56 with System.Task_Info;
57 with System.VxWorks.Ext;
59 package body System.Task_Primitives.Operations is
61 package SSL renames System.Soft_Links;
63 use System.Tasking.Debug;
65 use System.OS_Interface;
66 use System.Parameters;
67 use type System.VxWorks.Ext.t_id;
68 use type Interfaces.C.int;
70 subtype int is System.OS_Interface.int;
72 Relative : constant := 0;
78 -- The followings are logically constants, but need to be initialized at
81 Environment_Task_Id : Task_Id;
82 -- A variable to hold Task_Id for the environment task
84 -- The followings are internal configuration constants needed
86 Dispatching_Policy : Character;
87 pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
89 Foreign_Task_Elaborated : aliased Boolean := True;
90 -- Used to identified fake tasks (i.e., non-Ada Threads)
92 Locking_Policy : Character;
93 pragma Import (C, Locking_Policy, "__gl_locking_policy");
95 Mutex_Protocol : Priority_Type;
97 Single_RTS_Lock : aliased RTS_Lock;
98 -- This is a lock to allow only one thread of control in the RTS at a
99 -- time; it is used to execute in mutual exclusion from all other tasks.
100 -- Used mainly in Single_Lock mode, but also to protect All_Tasks_List
102 Time_Slice_Val : Integer;
103 pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
111 procedure Initialize;
112 pragma Inline (Initialize);
113 -- Initialize task specific data
115 function Is_Valid_Task return Boolean;
116 pragma Inline (Is_Valid_Task);
117 -- Does executing thread have a TCB?
119 procedure Set (Self_Id : Task_Id);
121 -- Set the self id for the current task
124 pragma Inline (Delete);
125 -- Delete the task specific data associated with the current task
127 function Self return Task_Id;
128 pragma Inline (Self);
129 -- Return a pointer to the Ada Task Control Block of the calling task
133 package body Specific is separate;
134 -- The body of this package is target specific
136 ---------------------------------
137 -- Support for foreign threads --
138 ---------------------------------
140 function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
141 -- Allocate and Initialize a new ATCB for the current Thread
143 function Register_Foreign_Thread
144 (Thread : Thread_Id) return Task_Id is separate;
146 -----------------------
147 -- Local Subprograms --
148 -----------------------
150 procedure Abort_Handler (signo : Signal);
151 -- Handler for the abort (SIGABRT) signal to handle asynchronous abort
153 procedure Install_Signal_Handlers;
154 -- Install the default signal handlers for the current task
156 function Is_Task_Context return Boolean;
157 -- This function returns True if the current execution is in the context
158 -- of a task, and False if it is an interrupt context.
160 type Set_Stack_Limit_Proc_Acc is access procedure;
161 pragma Convention (C, Set_Stack_Limit_Proc_Acc);
163 Set_Stack_Limit_Hook : Set_Stack_Limit_Proc_Acc;
164 pragma Import (C, Set_Stack_Limit_Hook, "__gnat_set_stack_limit_hook");
165 -- Procedure to be called when a task is created to set stack
166 -- limit. Used only for VxWorks 5 and VxWorks MILS guest OS.
168 function To_Address is
169 new Ada.Unchecked_Conversion (Task_Id, System.Address);
175 procedure Abort_Handler (signo : Signal) is
176 pragma Unreferenced (signo);
178 Self_ID : constant Task_Id := Self;
179 Old_Set : aliased sigset_t;
180 Unblocked_Mask : aliased sigset_t;
182 pragma Warnings (Off, Result);
184 use System.Interrupt_Management;
187 -- It is not safe to raise an exception when using ZCX and the GCC
188 -- exception handling mechanism.
190 if ZCX_By_Default and then GCC_ZCX_Support then
194 if Self_ID.Deferral_Level = 0
195 and then Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
196 and then not Self_ID.Aborting
198 Self_ID.Aborting := True;
200 -- Make sure signals used for RTS internal purposes are unmasked
202 Result := sigemptyset (Unblocked_Mask'Access);
203 pragma Assert (Result = 0);
206 (Unblocked_Mask'Access,
207 Signal (Abort_Task_Interrupt));
208 pragma Assert (Result = 0);
209 Result := sigaddset (Unblocked_Mask'Access, SIGBUS);
210 pragma Assert (Result = 0);
211 Result := sigaddset (Unblocked_Mask'Access, SIGFPE);
212 pragma Assert (Result = 0);
213 Result := sigaddset (Unblocked_Mask'Access, SIGILL);
214 pragma Assert (Result = 0);
215 Result := sigaddset (Unblocked_Mask'Access, SIGSEGV);
216 pragma Assert (Result = 0);
221 Unblocked_Mask'Access,
223 pragma Assert (Result = 0);
225 raise Standard'Abort_Signal;
233 procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is
234 pragma Unreferenced (T);
235 pragma Unreferenced (On);
238 -- Nothing needed (why not???)
247 function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is
249 return T.Common.LL.Thread;
256 function Self return Task_Id renames Specific.Self;
258 -----------------------------
259 -- Install_Signal_Handlers --
260 -----------------------------
262 procedure Install_Signal_Handlers is
263 act : aliased struct_sigaction;
264 old_act : aliased struct_sigaction;
265 Tmp_Set : aliased sigset_t;
270 act.sa_handler := Abort_Handler'Address;
272 Result := sigemptyset (Tmp_Set'Access);
273 pragma Assert (Result = 0);
274 act.sa_mask := Tmp_Set;
278 (Signal (Interrupt_Management.Abort_Task_Interrupt),
279 act'Unchecked_Access,
280 old_act'Unchecked_Access);
281 pragma Assert (Result = 0);
283 Interrupt_Management.Initialize_Interrupts;
284 end Install_Signal_Handlers;
286 ---------------------
287 -- Initialize_Lock --
288 ---------------------
290 procedure Initialize_Lock
291 (Prio : System.Any_Priority;
292 L : not null access Lock)
295 L.Mutex := semMCreate (SEM_Q_PRIORITY + SEM_INVERSION_SAFE);
296 L.Prio_Ceiling := int (Prio);
297 L.Protocol := Mutex_Protocol;
298 pragma Assert (L.Mutex /= 0);
301 procedure Initialize_Lock
302 (L : not null access RTS_Lock;
305 pragma Unreferenced (Level);
307 L.Mutex := semMCreate (SEM_Q_PRIORITY + SEM_INVERSION_SAFE);
308 L.Prio_Ceiling := int (System.Any_Priority'Last);
309 L.Protocol := Mutex_Protocol;
310 pragma Assert (L.Mutex /= 0);
317 procedure Finalize_Lock (L : not null access Lock) is
320 Result := semDelete (L.Mutex);
321 pragma Assert (Result = 0);
324 procedure Finalize_Lock (L : not null access RTS_Lock) is
327 Result := semDelete (L.Mutex);
328 pragma Assert (Result = 0);
336 (L : not null access Lock;
337 Ceiling_Violation : out Boolean)
342 if L.Protocol = Prio_Protect
343 and then int (Self.Common.Current_Priority) > L.Prio_Ceiling
345 Ceiling_Violation := True;
348 Ceiling_Violation := False;
351 Result := semTake (L.Mutex, WAIT_FOREVER);
352 pragma Assert (Result = 0);
356 (L : not null access RTS_Lock;
357 Global_Lock : Boolean := False)
361 if not Single_Lock or else Global_Lock then
362 Result := semTake (L.Mutex, WAIT_FOREVER);
363 pragma Assert (Result = 0);
367 procedure Write_Lock (T : Task_Id) is
370 if not Single_Lock then
371 Result := semTake (T.Common.LL.L.Mutex, WAIT_FOREVER);
372 pragma Assert (Result = 0);
381 (L : not null access Lock;
382 Ceiling_Violation : out Boolean)
385 Write_Lock (L, Ceiling_Violation);
392 procedure Unlock (L : not null access Lock) is
395 Result := semGive (L.Mutex);
396 pragma Assert (Result = 0);
400 (L : not null access RTS_Lock;
401 Global_Lock : Boolean := False)
405 if not Single_Lock or else Global_Lock then
406 Result := semGive (L.Mutex);
407 pragma Assert (Result = 0);
411 procedure Unlock (T : Task_Id) is
414 if not Single_Lock then
415 Result := semGive (T.Common.LL.L.Mutex);
416 pragma Assert (Result = 0);
424 -- Dynamic priority ceilings are not supported by the underlying system
426 procedure Set_Ceiling
427 (L : not null access Lock;
428 Prio : System.Any_Priority)
430 pragma Unreferenced (L, Prio);
439 procedure Sleep (Self_ID : Task_Id; Reason : System.Tasking.Task_States) is
440 pragma Unreferenced (Reason);
445 pragma Assert (Self_ID = Self);
447 -- Release the mutex before sleeping
450 semGive (if Single_Lock
451 then Single_RTS_Lock.Mutex
452 else Self_ID.Common.LL.L.Mutex);
453 pragma Assert (Result = 0);
455 -- Perform a blocking operation to take the CV semaphore. Note that a
456 -- blocking operation in VxWorks will reenable task scheduling. When we
457 -- are no longer blocked and control is returned, task scheduling will
458 -- again be disabled.
460 Result := semTake (Self_ID.Common.LL.CV, WAIT_FOREVER);
461 pragma Assert (Result = 0);
463 -- Take the mutex back
466 semTake ((if Single_Lock
467 then Single_RTS_Lock.Mutex
468 else Self_ID.Common.LL.L.Mutex), WAIT_FOREVER);
469 pragma Assert (Result = 0);
476 -- This is for use within the run-time system, so abort is assumed to be
477 -- already deferred, and the caller should be holding its own ATCB lock.
479 procedure Timed_Sleep
482 Mode : ST.Delay_Modes;
483 Reason : System.Tasking.Task_States;
484 Timedout : out Boolean;
485 Yielded : out Boolean)
487 pragma Unreferenced (Reason);
489 Orig : constant Duration := Monotonic_Clock;
493 Wakeup : Boolean := False;
499 if Mode = Relative then
500 Absolute := Orig + Time;
502 -- Systematically add one since the first tick will delay *at most*
503 -- 1 / Rate_Duration seconds, so we need to add one to be on the
506 Ticks := To_Clock_Ticks (Time);
508 if Ticks > 0 and then Ticks < int'Last then
514 Ticks := To_Clock_Ticks (Time - Monotonic_Clock);
519 -- Release the mutex before sleeping
522 semGive (if Single_Lock
523 then Single_RTS_Lock.Mutex
524 else Self_ID.Common.LL.L.Mutex);
525 pragma Assert (Result = 0);
527 -- Perform a blocking operation to take the CV semaphore. Note
528 -- that a blocking operation in VxWorks will reenable task
529 -- scheduling. When we are no longer blocked and control is
530 -- returned, task scheduling will again be disabled.
532 Result := semTake (Self_ID.Common.LL.CV, Ticks);
536 -- Somebody may have called Wakeup for us
541 if errno /= S_objLib_OBJ_TIMEOUT then
545 -- If Ticks = int'last, it was most probably truncated so
546 -- let's make another round after recomputing Ticks from
547 -- the absolute time.
549 if Ticks /= int'Last then
553 Ticks := To_Clock_Ticks (Absolute - Monotonic_Clock);
562 -- Take the mutex back
565 semTake ((if Single_Lock
566 then Single_RTS_Lock.Mutex
567 else Self_ID.Common.LL.L.Mutex), WAIT_FOREVER);
568 pragma Assert (Result = 0);
570 exit when Timedout or Wakeup;
576 -- Should never hold a lock while yielding
579 Result := semGive (Single_RTS_Lock.Mutex);
581 Result := semTake (Single_RTS_Lock.Mutex, WAIT_FOREVER);
584 Result := semGive (Self_ID.Common.LL.L.Mutex);
586 Result := semTake (Self_ID.Common.LL.L.Mutex, WAIT_FOREVER);
595 -- This is for use in implementing delay statements, so we assume the
596 -- caller is holding no locks.
598 procedure Timed_Delay
601 Mode : ST.Delay_Modes)
603 Orig : constant Duration := Monotonic_Clock;
607 Aborted : Boolean := False;
610 pragma Warnings (Off, Result);
613 if Mode = Relative then
614 Absolute := Orig + Time;
615 Ticks := To_Clock_Ticks (Time);
617 if Ticks > 0 and then Ticks < int'Last then
619 -- First tick will delay anytime between 0 and 1 / sysClkRateGet
620 -- seconds, so we need to add one to be on the safe side.
627 Ticks := To_Clock_Ticks (Time - Orig);
632 -- Modifying State, locking the TCB
635 semTake ((if Single_Lock
636 then Single_RTS_Lock.Mutex
637 else Self_ID.Common.LL.L.Mutex), WAIT_FOREVER);
639 pragma Assert (Result = 0);
641 Self_ID.Common.State := Delay_Sleep;
645 Aborted := Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
647 -- Release the TCB before sleeping
650 semGive (if Single_Lock
651 then Single_RTS_Lock.Mutex
652 else Self_ID.Common.LL.L.Mutex);
653 pragma Assert (Result = 0);
657 Result := semTake (Self_ID.Common.LL.CV, Ticks);
661 -- If Ticks = int'last, it was most probably truncated
662 -- so let's make another round after recomputing Ticks
663 -- from the absolute time.
665 if errno = S_objLib_OBJ_TIMEOUT and then Ticks /= int'Last then
668 Ticks := To_Clock_Ticks (Absolute - Monotonic_Clock);
676 -- Take back the lock after having slept, to protect further
677 -- access to Self_ID.
682 then Single_RTS_Lock.Mutex
683 else Self_ID.Common.LL.L.Mutex), WAIT_FOREVER);
685 pragma Assert (Result = 0);
690 Self_ID.Common.State := Runnable;
695 then Single_RTS_Lock.Mutex
696 else Self_ID.Common.LL.L.Mutex);
703 ---------------------
704 -- Monotonic_Clock --
705 ---------------------
707 function Monotonic_Clock return Duration is
708 TS : aliased timespec;
711 Result := clock_gettime (CLOCK_REALTIME, TS'Unchecked_Access);
712 pragma Assert (Result = 0);
713 return To_Duration (TS);
720 function RT_Resolution return Duration is
722 return 1.0 / Duration (sysClkRateGet);
729 procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
730 pragma Unreferenced (Reason);
733 Result := semGive (T.Common.LL.CV);
734 pragma Assert (Result = 0);
741 procedure Yield (Do_Yield : Boolean := True) is
742 pragma Unreferenced (Do_Yield);
744 pragma Unreferenced (Result);
746 Result := taskDelay (0);
753 procedure Set_Priority
755 Prio : System.Any_Priority;
756 Loss_Of_Inheritance : Boolean := False)
758 pragma Unreferenced (Loss_Of_Inheritance);
765 (T.Common.LL.Thread, To_VxWorks_Priority (int (Prio)));
766 pragma Assert (Result = 0);
768 -- Note: in VxWorks 6.6 (or earlier), the task is placed at the end of
769 -- the priority queue instead of the head. This is not the behavior
770 -- required by Annex D (RM D.2.3(5/2)), but we consider it an acceptable
771 -- variation (RM 1.1.3(6)), given this is the built-in behavior of the
772 -- operating system. VxWorks versions starting from 6.7 implement the
773 -- required Annex D semantics.
775 -- In older versions we attempted to better approximate the Annex D
776 -- required behavior, but this simulation was not entirely accurate,
777 -- and it seems better to live with the standard VxWorks semantics.
779 T.Common.Current_Priority := Prio;
786 function Get_Priority (T : Task_Id) return System.Any_Priority is
788 return T.Common.Current_Priority;
795 procedure Enter_Task (Self_ID : Task_Id) is
796 procedure Init_Float;
797 pragma Import (C, Init_Float, "__gnat_init_float");
798 -- Properly initializes the FPU for PPC/MIPS systems
801 -- Store the user-level task id in the Thread field (to be used
802 -- internally by the run-time system) and the kernel-level task id in
803 -- the LWP field (to be used by the debugger).
805 Self_ID.Common.LL.Thread := taskIdSelf;
806 Self_ID.Common.LL.LWP := getpid;
808 Specific.Set (Self_ID);
812 -- Install the signal handlers
814 -- This is called for each task since there is no signal inheritance
815 -- between VxWorks tasks.
817 Install_Signal_Handlers;
819 -- If stack checking is enabled, set the stack limit for this task
821 if Set_Stack_Limit_Hook /= null then
822 Set_Stack_Limit_Hook.all;
830 function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
832 return new Ada_Task_Control_Block (Entry_Num);
839 function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
841 -----------------------------
842 -- Register_Foreign_Thread --
843 -----------------------------
845 function Register_Foreign_Thread return Task_Id is
847 if Is_Valid_Task then
850 return Register_Foreign_Thread (taskIdSelf);
852 end Register_Foreign_Thread;
858 procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
860 Self_ID.Common.LL.CV := semBCreate (SEM_Q_PRIORITY, SEM_EMPTY);
861 Self_ID.Common.LL.Thread := 0;
863 if Self_ID.Common.LL.CV = 0 then
869 if not Single_Lock then
870 Initialize_Lock (Self_ID.Common.LL.L'Access, ATCB_Level);
879 procedure Create_Task
881 Wrapper : System.Address;
882 Stack_Size : System.Parameters.Size_Type;
883 Priority : System.Any_Priority;
884 Succeeded : out Boolean)
886 Adjusted_Stack_Size : size_t;
889 use System.Task_Info;
890 use type System.Multiprocessors.CPU_Range;
893 -- Ask for four extra bytes of stack space so that the ATCB pointer can
894 -- be stored below the stack limit, plus extra space for the frame of
895 -- Task_Wrapper. This is so the user gets the amount of stack requested
896 -- exclusive of the needs.
898 -- We also have to allocate n more bytes for the task name storage and
899 -- enough space for the Wind Task Control Block which is around 0x778
900 -- bytes. VxWorks also seems to carve out additional space, so use 2048
901 -- as a nice round number. We might want to increment to the nearest
902 -- page size in case we ever support VxVMI.
904 -- ??? - we should come back and visit this so we can set the task name
905 -- to something appropriate.
907 Adjusted_Stack_Size := size_t (Stack_Size) + 2048;
909 -- Since the initial signal mask of a thread is inherited from the
910 -- creator, and the Environment task has all its signals masked, we do
911 -- not need to manipulate caller's signal mask at this point. All tasks
912 -- in RTS will have All_Tasks_Mask initially.
914 -- We now compute the VxWorks task name and options, then spawn ...
917 Name : aliased String (1 .. T.Common.Task_Image_Len + 1);
918 Name_Address : System.Address;
919 -- Task name we are going to hand down to VxWorks
921 function Get_Task_Options return int;
922 pragma Import (C, Get_Task_Options, "__gnat_get_task_options");
923 -- Function that returns the options to be set for the task that we
924 -- are creating. We fetch the options assigned to the current task,
925 -- so offering some user level control over the options for a task
926 -- hierarchy, and force VX_FP_TASK because it is almost always
930 -- If there is no Ada task name handy, let VxWorks choose one.
931 -- Otherwise, tell VxWorks what the Ada task name is.
933 if T.Common.Task_Image_Len = 0 then
934 Name_Address := System.Null_Address;
936 Name (1 .. Name'Last - 1) :=
937 T.Common.Task_Image (1 .. T.Common.Task_Image_Len);
938 Name (Name'Last) := ASCII.NUL;
939 Name_Address := Name'Address;
942 -- Now spawn the VxWorks task for real
944 T.Common.LL.Thread :=
947 To_VxWorks_Priority (int (Priority)),
954 -- Set processor affinity
956 if T.Common.Base_CPU /= System.Multiprocessors.Not_A_Specific_CPU then
957 -- Ada 2012 pragma CPU uses CPU numbers starting from 1, while
958 -- on VxWorks the first CPU is identified by a 0, so we need to
963 (T.Common.LL.Thread, int (T.Common.Base_CPU) - 1);
965 elsif T.Common.Task_Info /= Unspecified_Task_Info then
967 taskCpuAffinitySet (T.Common.LL.Thread, T.Common.Task_Info);
971 taskDelete (T.Common.LL.Thread);
972 T.Common.LL.Thread := -1;
975 if T.Common.LL.Thread = -1 then
979 Task_Creation_Hook (T.Common.LL.Thread);
980 Set_Priority (T, Priority);
988 procedure Finalize_TCB (T : Task_Id) is
991 Is_Self : constant Boolean := (T = Self);
993 procedure Free is new
994 Ada.Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
997 if not Single_Lock then
998 Result := semDelete (T.Common.LL.L.Mutex);
999 pragma Assert (Result = 0);
1002 T.Common.LL.Thread := 0;
1004 Result := semDelete (T.Common.LL.CV);
1005 pragma Assert (Result = 0);
1007 if T.Known_Tasks_Index /= -1 then
1008 Known_Tasks (T.Known_Tasks_Index) := null;
1022 procedure Exit_Task is
1024 Specific.Set (null);
1031 procedure Abort_Task (T : Task_Id) is
1036 (T.Common.LL.Thread,
1037 Signal (Interrupt_Management.Abort_Task_Interrupt));
1038 pragma Assert (Result = 0);
1045 procedure Initialize (S : in out Suspension_Object) is
1047 -- Initialize internal state (always to False (RM D.10(6)))
1052 -- Initialize internal mutex
1054 -- Use simpler binary semaphore instead of VxWorks
1055 -- mutual exclusion semaphore, because we don't need
1056 -- the fancier semantics and their overhead.
1058 S.L := semBCreate (SEM_Q_FIFO, SEM_FULL);
1060 -- Initialize internal condition variable
1062 S.CV := semBCreate (SEM_Q_FIFO, SEM_EMPTY);
1069 procedure Finalize (S : in out Suspension_Object) is
1070 pragma Unmodified (S);
1071 -- S may be modified on other targets, but not on VxWorks
1076 -- Destroy internal mutex
1078 Result := semDelete (S.L);
1079 pragma Assert (Result = OK);
1081 -- Destroy internal condition variable
1083 Result := semDelete (S.CV);
1084 pragma Assert (Result = OK);
1091 function Current_State (S : Suspension_Object) return Boolean is
1093 -- We do not want to use lock on this read operation. State is marked
1094 -- as Atomic so that we ensure that the value retrieved is correct.
1103 procedure Set_False (S : in out Suspension_Object) is
1107 SSL.Abort_Defer.all;
1109 Result := semTake (S.L, WAIT_FOREVER);
1110 pragma Assert (Result = OK);
1114 Result := semGive (S.L);
1115 pragma Assert (Result = OK);
1117 SSL.Abort_Undefer.all;
1124 procedure Set_True (S : in out Suspension_Object) is
1128 -- Set_True can be called from an interrupt context, in which case
1129 -- Abort_Defer is undefined.
1131 if Is_Task_Context then
1132 SSL.Abort_Defer.all;
1135 Result := semTake (S.L, WAIT_FOREVER);
1136 pragma Assert (Result = OK);
1138 -- If there is already a task waiting on this suspension object then
1139 -- we resume it, leaving the state of the suspension object to False,
1140 -- as it is specified in ARM D.10 par. 9. Otherwise, it just leaves
1141 -- the state to True.
1147 Result := semGive (S.CV);
1148 pragma Assert (Result = OK);
1153 Result := semGive (S.L);
1154 pragma Assert (Result = OK);
1156 -- Set_True can be called from an interrupt context, in which case
1157 -- Abort_Undefer is undefined.
1159 if Is_Task_Context then
1160 SSL.Abort_Undefer.all;
1165 ------------------------
1166 -- Suspend_Until_True --
1167 ------------------------
1169 procedure Suspend_Until_True (S : in out Suspension_Object) is
1173 SSL.Abort_Defer.all;
1175 Result := semTake (S.L, WAIT_FOREVER);
1179 -- Program_Error must be raised upon calling Suspend_Until_True
1180 -- if another task is already waiting on that suspension object
1181 -- (ARM D.10 par. 10).
1183 Result := semGive (S.L);
1184 pragma Assert (Result = OK);
1186 SSL.Abort_Undefer.all;
1188 raise Program_Error;
1191 -- Suspend the task if the state is False. Otherwise, the task
1192 -- continues its execution, and the state of the suspension object
1193 -- is set to False (ARM D.10 par. 9).
1198 Result := semGive (S.L);
1199 pragma Assert (Result = 0);
1201 SSL.Abort_Undefer.all;
1206 -- Release the mutex before sleeping
1208 Result := semGive (S.L);
1209 pragma Assert (Result = OK);
1211 SSL.Abort_Undefer.all;
1213 Result := semTake (S.CV, WAIT_FOREVER);
1214 pragma Assert (Result = 0);
1217 end Suspend_Until_True;
1225 function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1226 pragma Unreferenced (Self_ID);
1231 --------------------
1232 -- Check_No_Locks --
1233 --------------------
1235 function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1236 pragma Unreferenced (Self_ID);
1241 ----------------------
1242 -- Environment_Task --
1243 ----------------------
1245 function Environment_Task return Task_Id is
1247 return Environment_Task_Id;
1248 end Environment_Task;
1254 procedure Lock_RTS is
1256 Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
1263 procedure Unlock_RTS is
1265 Unlock (Single_RTS_Lock'Access, Global_Lock => True);
1272 function Suspend_Task
1274 Thread_Self : Thread_Id) return Boolean
1277 if T.Common.LL.Thread /= 0
1278 and then T.Common.LL.Thread /= Thread_Self
1280 return taskSuspend (T.Common.LL.Thread) = 0;
1290 function Resume_Task
1292 Thread_Self : Thread_Id) return Boolean
1295 if T.Common.LL.Thread /= 0
1296 and then T.Common.LL.Thread /= Thread_Self
1298 return taskResume (T.Common.LL.Thread) = 0;
1304 --------------------
1305 -- Stop_All_Tasks --
1306 --------------------
1308 procedure Stop_All_Tasks
1310 Thread_Self : constant Thread_Id := taskIdSelf;
1314 pragma Unreferenced (Dummy);
1319 C := All_Tasks_List;
1320 while C /= null loop
1321 if C.Common.LL.Thread /= 0
1322 and then C.Common.LL.Thread /= Thread_Self
1324 Dummy := Task_Stop (C.Common.LL.Thread);
1327 C := C.Common.All_Tasks_Link;
1330 Dummy := Int_Unlock;
1337 function Stop_Task (T : ST.Task_Id) return Boolean is
1339 if T.Common.LL.Thread /= 0 then
1340 return Task_Stop (T.Common.LL.Thread) = 0;
1350 function Continue_Task (T : ST.Task_Id) return Boolean
1353 if T.Common.LL.Thread /= 0 then
1354 return Task_Cont (T.Common.LL.Thread) = 0;
1360 ---------------------
1361 -- Is_Task_Context --
1362 ---------------------
1364 function Is_Task_Context return Boolean is
1366 return System.OS_Interface.Interrupt_Context /= 1;
1367 end Is_Task_Context;
1373 procedure Initialize (Environment_Task : Task_Id) is
1376 use type System.Multiprocessors.CPU_Range;
1379 Environment_Task_Id := Environment_Task;
1381 Interrupt_Management.Initialize;
1382 Specific.Initialize;
1384 if Locking_Policy = 'C' then
1385 Mutex_Protocol := Prio_Protect;
1386 elsif Locking_Policy = 'I' then
1387 Mutex_Protocol := Prio_Inherit;
1389 Mutex_Protocol := Prio_None;
1392 if Time_Slice_Val > 0 then
1396 (Duration (Time_Slice_Val) / Duration (1_000_000.0)));
1398 elsif Dispatching_Policy = 'R' then
1399 Result := Set_Time_Slice (To_Clock_Ticks (0.01));
1403 -- Initialize the lock used to synchronize chain of all ATCBs
1405 Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1407 -- Make environment task known here because it doesn't go through
1408 -- Activate_Tasks, which does it for all other tasks.
1410 Known_Tasks (Known_Tasks'First) := Environment_Task;
1411 Environment_Task.Known_Tasks_Index := Known_Tasks'First;
1413 Enter_Task (Environment_Task);
1415 -- Set processor affinity
1417 if Environment_Task.Common.Base_CPU /=
1418 System.Multiprocessors.Not_A_Specific_CPU
1420 -- Ada 2012 pragma CPU uses CPU numbers starting from 1, while
1421 -- on VxWorks the first CPU is identified by a 0, so we need to
1426 (Environment_Task.Common.LL.Thread,
1427 int (Environment_Task.Common.Base_CPU) - 1);
1428 pragma Assert (Result /= -1);
1432 end System.Task_Primitives.Operations;