1 ------------------------------------------------------------------------------
3 -- GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS --
5 -- S Y S T E M . T A S K I N G . R E S T R I C T E D . S T A G E S --
11 -- Copyright (C) 1999-2001 Ada Core Technologies --
13 -- GNARL is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 2, or (at your option) any later ver- --
16 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
19 -- for more details. You should have received a copy of the GNU General --
20 -- Public License distributed with GNARL; see file COPYING. If not, write --
21 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
22 -- MA 02111-1307, USA. --
24 -- As a special exception, if other files instantiate generics from this --
25 -- unit, or you link this unit with other files to produce an executable, --
26 -- this unit does not by itself cause the resulting executable to be --
27 -- covered by the GNU General Public License. This exception does not --
28 -- however invalidate any other reasons why the executable file might be --
29 -- covered by the GNU Public License. --
31 -- GNARL was developed by the GNARL team at Florida State University. It is --
32 -- now maintained by Ada Core Technologies Inc. in cooperation with Florida --
33 -- State University (http://www.gnat.com). --
35 ------------------------------------------------------------------------------
37 pragma Style_Checks (All_Checks);
38 -- Turn off subprogram alpha order check, since we group soft link
39 -- bodies and also separate off subprograms for restricted GNARLI.
41 -- This is a simplified version of the System.Tasking.Stages package,
42 -- intended to be used in a restricted run time.
44 -- This package represents the high level tasking interface used by the
45 -- compiler to expand Ada 95 tasking constructs into simpler run time calls.
48 -- Turn off polling, we do not want ATC polling to take place during
49 -- tasking operations. It causes infinite loops and other problems.
51 with System.Parameters;
54 with System.Task_Info;
55 -- used for Task_Info_Type
58 with System.Task_Primitives.Operations;
59 -- used for Enter_Task
65 with System.Soft_Links;
66 -- used for the non-tasking routines (*_NT) that refer to global data.
67 -- They are needed here before the tasking run time has been elaborated.
68 -- used for Create_TSD
69 -- This package also provides initialization routines for task specific data.
70 -- The GNARL must call these to be sure that all non-tasking
71 -- Ada constructs will work.
73 with System.Secondary_Stack;
76 with System.Storage_Elements;
77 -- used for Storage_Array;
79 package body System.Tasking.Restricted.Stages is
81 package STPO renames System.Task_Primitives.Operations;
82 package SSL renames System.Soft_Links;
83 package SSE renames System.Storage_Elements;
84 package SST renames System.Secondary_Stack;
86 use System.Task_Primitives;
87 use System.Task_Primitives.Operations;
90 Global_Task_Lock : aliased System.Task_Primitives.RTS_Lock;
91 -- This is a global lock; it is used to execute in mutual exclusion
92 -- from all other tasks. It is only used by Task_Lock and Task_Unlock.
94 -----------------------------------------------------------------
95 -- Tasking versions of services needed by non-tasking programs --
96 -----------------------------------------------------------------
99 -- Locks out other tasks. Preceding a section of code by Task_Lock and
100 -- following it by Task_Unlock creates a critical region. This is used
101 -- for ensuring that a region of non-tasking code (such as code used to
102 -- allocate memory) is tasking safe. Note that it is valid for calls to
103 -- Task_Lock/Task_Unlock to be nested, and this must work properly, i.e.
104 -- only the corresponding outer level Task_Unlock will actually unlock.
106 procedure Task_Unlock;
107 -- Releases lock previously set by call to Task_Lock. In the nested case,
108 -- all nested locks must be released before other tasks competing for the
109 -- tasking lock are released.
111 function Get_Jmpbuf_Address return Address;
112 procedure Set_Jmpbuf_Address (Addr : Address);
114 function Get_Sec_Stack_Addr return Address;
115 procedure Set_Sec_Stack_Addr (Addr : Address);
117 function Get_Machine_State_Addr return Address;
118 procedure Set_Machine_State_Addr (Addr : Address);
120 function Get_Current_Excep return SSL.EOA;
122 procedure Timed_Delay_T (Time : Duration; Mode : Integer);
124 ------------------------
125 -- Local Subprograms --
126 ------------------------
128 procedure Task_Wrapper (Self_ID : Task_ID);
129 -- This is the procedure that is called by the GNULL from the
130 -- new context when a task is created. It waits for activation
131 -- and then calls the task body procedure. When the task body
132 -- procedure completes, it terminates the task.
134 procedure Terminate_Task (Self_ID : Task_ID);
135 -- Terminate the calling task.
136 -- This should only be called by the Task_Wrapper procedure.
139 -- This procedure performs the initialization of the GNARL.
140 -- It consists of initializing the environment task, global locks, and
141 -- installing tasking versions of certain operations used by the compiler.
142 -- Init_RTS is called during elaboration.
148 procedure Task_Lock is
150 STPO.Write_Lock (Global_Task_Lock'Access);
157 procedure Task_Unlock is
159 STPO.Unlock (Global_Task_Lock'Access);
162 ----------------------
163 -- Soft-Link Bodies --
164 ----------------------
166 function Get_Current_Excep return SSL.EOA is
168 return STPO.Self.Common.Compiler_Data.Current_Excep'Access;
169 end Get_Current_Excep;
171 function Get_Jmpbuf_Address return Address is
173 return STPO.Self.Common.Compiler_Data.Jmpbuf_Address;
174 end Get_Jmpbuf_Address;
176 function Get_Machine_State_Addr return Address is
178 return STPO.Self.Common.Compiler_Data.Machine_State_Addr;
179 end Get_Machine_State_Addr;
181 function Get_Sec_Stack_Addr return Address is
183 return STPO.Self.Common.Compiler_Data.Sec_Stack_Addr;
184 end Get_Sec_Stack_Addr;
186 procedure Set_Jmpbuf_Address (Addr : Address) is
188 STPO.Self.Common.Compiler_Data.Jmpbuf_Address := Addr;
189 end Set_Jmpbuf_Address;
191 procedure Set_Machine_State_Addr (Addr : Address) is
193 STPO.Self.Common.Compiler_Data.Machine_State_Addr := Addr;
194 end Set_Machine_State_Addr;
196 procedure Set_Sec_Stack_Addr (Addr : Address) is
198 STPO.Self.Common.Compiler_Data.Sec_Stack_Addr := Addr;
199 end Set_Sec_Stack_Addr;
205 -- The task wrapper is a procedure that is called first for each task
206 -- task body, and which in turn calls the compiler-generated task body
207 -- procedure. The wrapper's main job is to do initialization for the task.
209 -- The variable ID in the task wrapper is used to implement the Self
210 -- function on targets where there is a fast way to find the stack base
211 -- of the current thread, since it should be at a fixed offset from the
214 procedure Task_Wrapper (Self_ID : Task_ID) is
215 ID : Task_ID := Self_ID;
216 pragma Volatile (ID);
218 -- Do not delete this variable.
219 -- In some targets, we need this variable to implement a fast Self.
221 use type System.Parameters.Size_Type;
222 use type SSE.Storage_Offset;
224 Secondary_Stack : aliased SSE.Storage_Array
225 (1 .. Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size *
226 SSE.Storage_Offset (Parameters.Sec_Stack_Ratio) / 100);
227 Secondary_Stack_Address : System.Address := Secondary_Stack'Address;
230 if not Parameters.Sec_Stack_Dynamic then
231 Self_ID.Common.Compiler_Data.Sec_Stack_Addr :=
232 Secondary_Stack'Address;
233 SST.SS_Init (Secondary_Stack_Address, Integer (Secondary_Stack'Last));
236 -- Initialize low-level TCB components, that
237 -- cannot be initialized by the creator.
239 Enter_Task (Self_ID);
241 -- Call the task body procedure.
244 -- We are separating the following portion of the code in order to
245 -- place the exception handlers in a different block.
246 -- In this way we do not call Set_Jmpbuf_Address (which needs
247 -- Self) before we set Self in Enter_Task.
248 -- Note that in the case of Ravenscar HI-E where there are no
249 -- exception handlers, the exception handler is suppressed.
251 -- Call the task body procedure.
253 Self_ID.Common.Task_Entry_Point (Self_ID.Common.Task_Arg);
254 Terminate_Task (Self_ID);
256 exception -- not needed in no exc mode
257 when others => -- not needed in no exc mode
258 Terminate_Task (Self_ID); -- not needed in no exc mode
266 procedure Timed_Delay_T (Time : Duration; Mode : Integer) is
268 STPO.Timed_Delay (STPO.Self, Time, Mode);
271 -----------------------
272 -- Restricted GNARLI --
273 -----------------------
275 -------------------------------
276 -- Activate_Restricted_Tasks --
277 -------------------------------
279 -- Note that locks of activator and activated task are both locked
280 -- here. This is necessary because C.State and Self.Wait_Count
281 -- have to be synchronized. This is safe from deadlock because
282 -- the activator is always created before the activated task.
283 -- That satisfies our in-order-of-creation ATCB locking policy.
285 procedure Activate_Restricted_Tasks
286 (Chain_Access : Activation_Chain_Access)
288 Self_ID : constant Task_ID := STPO.Self;
290 Activate_Prio : System.Any_Priority;
294 pragma Assert (Self_ID = Environment_Task);
295 pragma Assert (Self_ID.Common.Wait_Count = 0);
297 -- Lock self, to prevent activated tasks
298 -- from racing ahead before we finish activating the chain.
300 Write_Lock (Self_ID);
302 -- Activate all the tasks in the chain.
303 -- Creation of the thread of control was deferred until
304 -- activation. So create it now.
306 C := Chain_Access.T_ID;
309 if C.Common.State /= Terminated then
310 pragma Assert (C.Common.State = Unactivated);
314 if C.Common.Base_Priority < Get_Priority (Self_ID) then
315 Activate_Prio := Get_Priority (Self_ID);
317 Activate_Prio := C.Common.Base_Priority;
321 (C, Task_Wrapper'Address,
323 (C.Common.Compiler_Data.Pri_Stack_Info.Size),
324 Activate_Prio, Success);
326 Self_ID.Common.Wait_Count := Self_ID.Common.Wait_Count + 1;
329 C.Common.State := Runnable;
337 C := C.Common.Activation_Link;
340 Self_ID.Common.State := Activator_Sleep;
342 -- Wait for the activated tasks to complete activation.
343 -- It is unsafe to abort any of these tasks until the count goes to
347 exit when Self_ID.Common.Wait_Count = 0;
348 Sleep (Self_ID, Activator_Sleep);
351 Self_ID.Common.State := Runnable;
354 -- Remove the tasks from the chain.
356 Chain_Access.T_ID := null;
357 end Activate_Restricted_Tasks;
359 ------------------------------------
360 -- Complete_Restricted_Activation --
361 ------------------------------------
363 -- As in several other places, the locks of the activator and activated
364 -- task are both locked here. This follows our deadlock prevention lock
365 -- ordering policy, since the activated task must be created after the
368 procedure Complete_Restricted_Activation is
369 Self_ID : constant Task_ID := STPO.Self;
370 Activator : constant Task_ID := Self_ID.Common.Activator;
373 Write_Lock (Activator);
374 Write_Lock (Self_ID);
376 -- Remove dangling reference to Activator,
377 -- since a task may outlive its activator.
379 Self_ID.Common.Activator := null;
381 -- Wake up the activator, if it is waiting for a chain
382 -- of tasks to activate, and we are the last in the chain
383 -- to complete activation
385 if Activator.Common.State = Activator_Sleep then
386 Activator.Common.Wait_Count := Activator.Common.Wait_Count - 1;
388 if Activator.Common.Wait_Count = 0 then
389 Wakeup (Activator, Activator_Sleep);
396 -- After the activation, active priority should be the same
397 -- as base priority. We must unlock the Activator first,
398 -- though, since it should not wait if we have lower priority.
400 if Get_Priority (Self_ID) /= Self_ID.Common.Base_Priority then
401 Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
403 end Complete_Restricted_Activation;
405 ------------------------------
406 -- Complete_Restricted_Task --
407 ------------------------------
409 procedure Complete_Restricted_Task is
411 STPO.Self.Common.State := Terminated;
412 end Complete_Restricted_Task;
414 ----------------------------
415 -- Create_Restricted_Task --
416 ----------------------------
418 procedure Create_Restricted_Task
420 Size : System.Parameters.Size_Type;
421 Task_Info : System.Task_Info.Task_Info_Type;
422 State : Task_Procedure_Access;
423 Discriminants : System.Address;
424 Elaborated : Access_Boolean;
425 Chain : in out Activation_Chain;
426 Task_Image : System.Task_Info.Task_Image_Type;
427 Created_Task : out Task_ID)
430 Self_ID : constant Task_ID := STPO.Self;
431 Base_Priority : System.Any_Priority;
435 if Priority = Unspecified_Priority then
436 Base_Priority := Self_ID.Common.Base_Priority;
438 Base_Priority := System.Any_Priority (Priority);
442 Write_Lock (Self_ID);
444 -- With no task hierarchy, the parent of all non-Environment tasks that
445 -- are created must be the Environment task
448 (Self_ID, State, Discriminants, Self_ID, Elaborated, Base_Priority,
449 Task_Info, Size, T, Success);
451 -- If we do our job right then there should never be any failures,
452 -- which was probably said about the Titanic; so just to be safe,
453 -- let's retain this code for now
460 T.Entry_Calls (1).Self := T;
461 T.Common.Task_Image := Task_Image;
464 -- Create TSD as early as possible in the creation of a task, since it
465 -- may be used by the operation of Ada code within the task.
467 SSL.Create_TSD (T.Common.Compiler_Data);
468 T.Common.Activation_Link := Chain.T_ID;
471 end Create_Restricted_Task;
473 ---------------------------
474 -- Finalize_Global_Tasks --
475 ---------------------------
477 -- This is needed to support the compiler interface; it will only be called
478 -- by the Environment task. Instead, it will cause the Environment to block
479 -- forever, since none of the dependent tasks are expected to terminate
481 procedure Finalize_Global_Tasks is
482 Self_ID : constant Task_ID := STPO.Self;
484 pragma Assert (Self_ID = STPO.Environment_Task);
486 Write_Lock (Self_ID);
487 Sleep (Self_ID, Master_Completion_Sleep);
490 -- Should never return from Master Completion Sleep
493 end Finalize_Global_Tasks;
495 ---------------------------
496 -- Restricted_Terminated --
497 ---------------------------
499 function Restricted_Terminated (T : Task_ID) return Boolean is
501 return T.Common.State = Terminated;
502 end Restricted_Terminated;
508 procedure Terminate_Task (Self_ID : Task_ID) is
510 Self_ID.Common.State := Terminated;
517 procedure Init_RTS is
519 -- Initialize lock used to implement mutual exclusion between all tasks
521 STPO.Initialize_Lock (Global_Task_Lock'Access, STPO.Global_Task_Level);
523 -- Notify that the tasking run time has been elaborated so that
524 -- the tasking version of the soft links can be used.
526 SSL.Lock_Task := Task_Lock'Access;
527 SSL.Unlock_Task := Task_Unlock'Access;
528 SSL.Get_Jmpbuf_Address := Get_Jmpbuf_Address'Access;
529 SSL.Set_Jmpbuf_Address := Set_Jmpbuf_Address'Access;
530 SSL.Get_Sec_Stack_Addr := Get_Sec_Stack_Addr'Access;
531 SSL.Set_Sec_Stack_Addr := Set_Sec_Stack_Addr'Access;
532 SSL.Get_Machine_State_Addr := Get_Machine_State_Addr'Access;
533 SSL.Set_Machine_State_Addr := Set_Machine_State_Addr'Access;
534 SSL.Get_Current_Excep := Get_Current_Excep'Access;
535 SSL.Timed_Delay := Timed_Delay_T'Access;
536 SSL.Adafinal := Finalize_Global_Tasks'Access;
538 -- No need to create a new Secondary Stack, since we will use the
539 -- default one created in s-secsta.adb
541 SSL.Set_Sec_Stack_Addr (SSL.Get_Sec_Stack_Addr_NT);
542 SSL.Set_Jmpbuf_Address (SSL.Get_Jmpbuf_Address_NT);
543 SSL.Set_Machine_State_Addr (SSL.Get_Machine_State_Addr_NT);
548 end System.Tasking.Restricted.Stages;