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