1------------------------------------------------------------------------------ 2-- -- 3-- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS -- 4-- -- 5-- S Y S T E M . T A S K I N G -- 6-- -- 7-- B o d y -- 8-- -- 9-- Copyright (C) 1992-2019, Free Software Foundation, Inc. -- 10-- -- 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. -- 17-- -- 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. -- 21-- -- 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/>. -- 26-- -- 27-- GNARL was developed by the GNARL team at Florida State University. -- 28-- Extensive contributions were provided by Ada Core Technologies, Inc. -- 29-- -- 30------------------------------------------------------------------------------ 31 32pragma Polling (Off); 33-- Turn off polling, we do not want ATC polling to take place during tasking 34-- operations. It causes infinite loops and other problems. 35 36with System.Task_Primitives.Operations; 37with System.Storage_Elements; 38 39package body System.Tasking is 40 41 package STPO renames System.Task_Primitives.Operations; 42 43 --------------------- 44 -- Detect_Blocking -- 45 --------------------- 46 47 function Detect_Blocking return Boolean is 48 GL_Detect_Blocking : Integer; 49 pragma Import (C, GL_Detect_Blocking, "__gl_detect_blocking"); 50 -- Global variable exported by the binder generated file. A value equal 51 -- to 1 indicates that pragma Detect_Blocking is active, while 0 is used 52 -- for the pragma not being present. 53 54 begin 55 return GL_Detect_Blocking = 1; 56 end Detect_Blocking; 57 58 ----------------------- 59 -- Number_Of_Entries -- 60 ----------------------- 61 62 function Number_Of_Entries (Self_Id : Task_Id) return Entry_Index is 63 begin 64 return Entry_Index (Self_Id.Entry_Num); 65 end Number_Of_Entries; 66 67 ---------- 68 -- Self -- 69 ---------- 70 71 function Self return Task_Id renames STPO.Self; 72 73 ------------------ 74 -- Storage_Size -- 75 ------------------ 76 77 function Storage_Size (T : Task_Id) return System.Parameters.Size_Type is 78 begin 79 return 80 System.Parameters.Size_Type 81 (T.Common.Compiler_Data.Pri_Stack_Info.Size); 82 end Storage_Size; 83 84 --------------------- 85 -- Initialize_ATCB -- 86 --------------------- 87 88 procedure Initialize_ATCB 89 (Self_ID : Task_Id; 90 Task_Entry_Point : Task_Procedure_Access; 91 Task_Arg : System.Address; 92 Parent : Task_Id; 93 Elaborated : Access_Boolean; 94 Base_Priority : System.Any_Priority; 95 Base_CPU : System.Multiprocessors.CPU_Range; 96 Domain : Dispatching_Domain_Access; 97 Task_Info : System.Task_Info.Task_Info_Type; 98 Stack_Size : System.Parameters.Size_Type; 99 T : Task_Id; 100 Success : out Boolean) 101 is 102 begin 103 T.Common.State := Unactivated; 104 105 -- Initialize T.Common.LL 106 107 STPO.Initialize_TCB (T, Success); 108 109 if not Success then 110 return; 111 end if; 112 113 -- Note that use of an aggregate here for this assignment 114 -- would be illegal, because Common_ATCB is limited because 115 -- Task_Primitives.Private_Data is limited. 116 117 T.Common.Parent := Parent; 118 T.Common.Base_Priority := Base_Priority; 119 T.Common.Base_CPU := Base_CPU; 120 121 -- The Domain defaults to that of the activator. But that can be null in 122 -- the case of foreign threads (see Register_Foreign_Thread), in which 123 -- case we default to the System_Domain. 124 125 if Domain /= null then 126 T.Common.Domain := Domain; 127 elsif Self_ID.Common.Domain /= null then 128 T.Common.Domain := Self_ID.Common.Domain; 129 else 130 T.Common.Domain := System_Domain; 131 end if; 132 pragma Assert (T.Common.Domain /= null); 133 134 T.Common.Current_Priority := 0; 135 T.Common.Protected_Action_Nesting := 0; 136 T.Common.Call := null; 137 T.Common.Task_Arg := Task_Arg; 138 T.Common.Task_Entry_Point := Task_Entry_Point; 139 T.Common.Activator := Self_ID; 140 T.Common.Wait_Count := 0; 141 T.Common.Elaborated := Elaborated; 142 T.Common.Activation_Failed := False; 143 T.Common.Task_Info := Task_Info; 144 T.Common.Global_Task_Lock_Nesting := 0; 145 T.Common.Fall_Back_Handler := null; 146 T.Common.Specific_Handler := null; 147 T.Common.Debug_Events := (others => False); 148 T.Common.Task_Image_Len := 0; 149 150 if T.Common.Parent = null then 151 152 -- For the environment task, the adjusted stack size is meaningless. 153 -- For example, an unspecified Stack_Size means that the stack size 154 -- is determined by the environment, or can grow dynamically. The 155 -- Stack_Checking algorithm therefore needs to use the requested 156 -- size, or 0 in case of an unknown size. 157 158 T.Common.Compiler_Data.Pri_Stack_Info.Size := 159 Storage_Elements.Storage_Offset (Stack_Size); 160 161 else 162 T.Common.Compiler_Data.Pri_Stack_Info.Size := 163 Storage_Elements.Storage_Offset 164 (Parameters.Adjust_Storage_Size (Stack_Size)); 165 end if; 166 167 -- Link the task into the list of all tasks 168 169 T.Common.All_Tasks_Link := All_Tasks_List; 170 All_Tasks_List := T; 171 end Initialize_ATCB; 172 173 ---------------- 174 -- Initialize -- 175 ---------------- 176 177 Main_Task_Image : constant String := "main_task"; 178 -- Image of environment task 179 180 Main_Priority : Integer; 181 pragma Import (C, Main_Priority, "__gl_main_priority"); 182 -- Priority for main task. Note that this is of type Integer, not Priority, 183 -- because we use the value -1 to indicate the default main priority, and 184 -- that is of course not in Priority'range. 185 186 Main_CPU : Integer; 187 pragma Import (C, Main_CPU, "__gl_main_cpu"); 188 -- Affinity for main task. Note that this is of type Integer, not 189 -- CPU_Range, because we use the value -1 to indicate the unassigned 190 -- affinity, and that is of course not in CPU_Range'Range. 191 192 Initialized : Boolean := False; 193 -- Used to prevent multiple calls to Initialize 194 195 procedure Initialize is 196 T : Task_Id; 197 Base_Priority : Any_Priority; 198 Base_CPU : System.Multiprocessors.CPU_Range; 199 Success : Boolean; 200 201 use type System.Multiprocessors.CPU_Range; 202 203 begin 204 if Initialized then 205 return; 206 end if; 207 208 Initialized := True; 209 210 -- Initialize Environment Task 211 212 Base_Priority := 213 (if Main_Priority = Unspecified_Priority 214 then Default_Priority 215 else Priority (Main_Priority)); 216 217 Base_CPU := 218 (if Main_CPU = Unspecified_CPU 219 then System.Multiprocessors.Not_A_Specific_CPU 220 else System.Multiprocessors.CPU_Range (Main_CPU)); 221 222 -- At program start-up the environment task is allocated to the default 223 -- system dispatching domain. 224 -- Make sure that the processors which are not available are not taken 225 -- into account. Use Number_Of_CPUs to know the exact number of 226 -- processors in the system at execution time. 227 228 System_Domain := 229 new Dispatching_Domain' 230 (Multiprocessors.CPU'First .. Multiprocessors.Number_Of_CPUs => 231 True); 232 233 T := STPO.New_ATCB (0); 234 Initialize_ATCB 235 (Self_ID => null, 236 Task_Entry_Point => null, 237 Task_Arg => Null_Address, 238 Parent => Null_Task, 239 Elaborated => null, 240 Base_Priority => Base_Priority, 241 Base_CPU => Base_CPU, 242 Domain => System_Domain, 243 Task_Info => Task_Info.Unspecified_Task_Info, 244 Stack_Size => 0, 245 T => T, 246 Success => Success); 247 pragma Assert (Success); 248 249 STPO.Initialize (T); 250 STPO.Set_Priority (T, T.Common.Base_Priority); 251 T.Common.State := Runnable; 252 T.Common.Task_Image_Len := Main_Task_Image'Length; 253 T.Common.Task_Image (Main_Task_Image'Range) := Main_Task_Image; 254 255 Dispatching_Domain_Tasks := 256 new Array_Allocated_Tasks' 257 (Multiprocessors.CPU'First .. Multiprocessors.Number_Of_CPUs => 0); 258 259 -- Signal that this task is being allocated to a processor 260 261 if Base_CPU /= System.Multiprocessors.Not_A_Specific_CPU then 262 263 -- Increase the number of tasks attached to the CPU to which this 264 -- task is allocated. 265 266 Dispatching_Domain_Tasks (Base_CPU) := 267 Dispatching_Domain_Tasks (Base_CPU) + 1; 268 end if; 269 270 -- The full initialization of the environment task's Entry_Calls array 271 -- is deferred to Init_RTS because only the first element of the array 272 -- is used by the restricted Ravenscar runtime. 273 274 T.Entry_Calls (T.Entry_Calls'First).Self := T; 275 T.Entry_Calls (T.Entry_Calls'First).Level := T.Entry_Calls'First; 276 277 end Initialize; 278end System.Tasking; 279