OSDN Git Service

2007-10-15 Hristian Kirtchev <kirtchev@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-tarest.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                 GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS                 --
4 --                                                                          --
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      --
6 --                                                                          --
7 --                                  B o d y                                 --
8 --                                                                          --
9 --         Copyright (C) 1999-2007, 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 2,  or (at your option) any later ver- --
14 -- sion. GNARL 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.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNARL; see file COPYING.  If not, write --
19 -- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
20 -- Boston, MA 02110-1301, USA.                                              --
21 --                                                                          --
22 -- As a special exception,  if other files  instantiate  generics from this --
23 -- unit, or you link  this unit with other files  to produce an executable, --
24 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
25 -- covered  by the  GNU  General  Public  License.  This exception does not --
26 -- however invalidate  any other reasons why  the executable file  might be --
27 -- covered by the  GNU Public License.                                      --
28 --                                                                          --
29 -- GNARL was developed by the GNARL team at Florida State University.       --
30 -- Extensive contributions were provided by Ada Core Technologies, Inc.     --
31 --                                                                          --
32 ------------------------------------------------------------------------------
33
34 pragma Style_Checks (All_Checks);
35 --  Turn off subprogram alpha order check, since we group soft link
36 --  bodies and also separate off subprograms for restricted GNARLI.
37
38 --  This is a simplified version of the System.Tasking.Stages package,
39 --  intended to be used in a restricted run time.
40
41 --  This package represents the high level tasking interface used by the
42 --  compiler to expand Ada 95 tasking constructs into simpler run time calls.
43
44 pragma Polling (Off);
45 --  Turn off polling, we do not want ATC polling to take place during
46 --  tasking operations. It causes infinite loops and other problems.
47
48 with Ada.Exceptions;
49 --  used for Exception_Occurrence
50
51 with System.Task_Primitives.Operations;
52 --  used for Enter_Task
53 --           Write_Lock
54 --           Unlock
55 --           Wakeup
56 --           Get_Priority
57
58 with System.Soft_Links;
59 --  used for the non-tasking routines (*_NT) that refer to global data.
60 --  They are needed here before the tasking run time has been elaborated.
61 --  used for Create_TSD
62 --  This package also provides initialization routines for task specific data.
63 --  The GNARL must call these to be sure that all non-tasking
64 --  Ada constructs will work.
65
66 with System.Soft_Links.Tasking;
67 --  Used for Init_Tasking_Soft_Links
68
69 with System.Secondary_Stack;
70 --  used for SS_Init;
71
72 with System.Storage_Elements;
73 --  used for Storage_Array;
74
75 package body System.Tasking.Restricted.Stages is
76
77    package STPO renames System.Task_Primitives.Operations;
78    package SSL  renames System.Soft_Links;
79    package SSE  renames System.Storage_Elements;
80    package SST  renames System.Secondary_Stack;
81
82    use Ada.Exceptions;
83
84    use Parameters;
85    use Task_Primitives.Operations;
86    use Task_Info;
87
88    Global_Task_Lock : aliased System.Task_Primitives.RTS_Lock;
89    --  This is a global lock; it is used to execute in mutual exclusion
90    --  from all other tasks. It is only used by Task_Lock and Task_Unlock.
91
92    -----------------------------------------------------------------
93    -- Tasking versions of services needed by non-tasking programs --
94    -----------------------------------------------------------------
95
96    function Get_Current_Excep return SSL.EOA;
97    --  Task-safe version of SSL.Get_Current_Excep
98
99    procedure Task_Lock;
100    --  Locks out other tasks. Preceding a section of code by Task_Lock and
101    --  following it by Task_Unlock creates a critical region. This is used
102    --  for ensuring that a region of non-tasking code (such as code used to
103    --  allocate memory) is tasking safe. Note that it is valid for calls to
104    --  Task_Lock/Task_Unlock to be nested, and this must work properly, i.e.
105    --  only the corresponding outer level Task_Unlock will actually unlock.
106
107    procedure Task_Unlock;
108    --  Releases lock previously set by call to Task_Lock. In the nested case,
109    --  all nested locks must be released before other tasks competing for the
110    --  tasking lock are released.
111
112    -----------------------
113    -- Local Subprograms --
114    -----------------------
115
116    procedure Task_Wrapper (Self_ID : Task_Id);
117    --  This is the procedure that is called by the GNULL from the
118    --  new context when a task is created. It waits for activation
119    --  and then calls the task body procedure. When the task body
120    --  procedure completes, it terminates the task.
121
122    procedure Terminate_Task (Self_ID : Task_Id);
123    --  Terminate the calling task.
124    --  This should only be called by the Task_Wrapper procedure.
125
126    procedure Init_RTS;
127    --  This procedure performs the initialization of the GNARL.
128    --  It consists of initializing the environment task, global locks, and
129    --  installing tasking versions of certain operations used by the compiler.
130    --  Init_RTS is called during elaboration.
131
132    -----------------------
133    -- Get_Current_Excep --
134    -----------------------
135
136    function Get_Current_Excep return SSL.EOA is
137    begin
138       return STPO.Self.Common.Compiler_Data.Current_Excep'Access;
139    end Get_Current_Excep;
140
141    ---------------
142    -- Task_Lock --
143    ---------------
144
145    procedure Task_Lock is
146       Self_ID : constant Task_Id := STPO.Self;
147
148    begin
149       Self_ID.Common.Global_Task_Lock_Nesting :=
150         Self_ID.Common.Global_Task_Lock_Nesting + 1;
151
152       if Self_ID.Common.Global_Task_Lock_Nesting = 1 then
153          STPO.Write_Lock (Global_Task_Lock'Access, Global_Lock => True);
154       end if;
155    end Task_Lock;
156
157    -----------------
158    -- Task_Unlock --
159    -----------------
160
161    procedure Task_Unlock is
162       Self_ID : constant Task_Id := STPO.Self;
163
164    begin
165       pragma Assert (Self_ID.Common.Global_Task_Lock_Nesting > 0);
166       Self_ID.Common.Global_Task_Lock_Nesting :=
167         Self_ID.Common.Global_Task_Lock_Nesting - 1;
168
169       if Self_ID.Common.Global_Task_Lock_Nesting = 0 then
170          STPO.Unlock (Global_Task_Lock'Access, Global_Lock => True);
171       end if;
172    end Task_Unlock;
173
174    ------------------
175    -- Task_Wrapper --
176    ------------------
177
178    --  The task wrapper is a procedure that is called first for each task
179    --  task body, and which in turn calls the compiler-generated task body
180    --  procedure. The wrapper's main job is to do initialization for the task.
181
182    --  The variable ID in the task wrapper is used to implement the Self
183    --  function on targets where there is a fast way to find the stack base
184    --  of the current thread, since it should be at a fixed offset from the
185    --  stack base.
186
187    procedure Task_Wrapper (Self_ID : Task_Id) is
188       ID : Task_Id := Self_ID;
189       pragma Volatile (ID);
190       pragma Warnings (Off, ID);
191       --  Variable used on some targets to implement a fast self. We turn off
192       --  warnings because a stand alone volatile constant has to be imported,
193       --  so we don't want warnings about ID not being referenced, and volatile
194       --  having no effect.
195       --
196       --  DO NOT delete ID. As noted, it is needed on some targets.
197
198       use type SSE.Storage_Offset;
199
200       Secondary_Stack : aliased SSE.Storage_Array
201         (1 .. Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size *
202                 SSE.Storage_Offset (Parameters.Sec_Stack_Ratio) / 100);
203
204       pragma Warnings (Off);
205       Secondary_Stack_Address : System.Address := Secondary_Stack'Address;
206       pragma Warnings (On);
207       --  Address of secondary stack. In the fixed secondary stack case, this
208       --  value is not modified, causing a warning, hence the bracketing with
209       --  Warnings (Off/On).
210
211       Cause : Cause_Of_Termination := Normal;
212       --  Indicates the reason why this task terminates. Normal corresponds to
213       --  a task terminating due to completing the last statement of its body.
214       --  If the task terminates because of an exception raised by the
215       --  execution of its task body, then Cause is set to Unhandled_Exception.
216       --  Aborts are not allowed in the restriced profile to which this file
217       --  belongs.
218
219       EO : Exception_Occurrence;
220       --  If the task terminates because of an exception raised by the
221       --  execution of its task body, then EO will contain the associated
222       --  exception occurrence. Otherwise, it will contain Null_Occurrence.
223
224    begin
225       if not Parameters.Sec_Stack_Dynamic then
226          Self_ID.Common.Compiler_Data.Sec_Stack_Addr :=
227            Secondary_Stack'Address;
228          SST.SS_Init (Secondary_Stack_Address, Integer (Secondary_Stack'Last));
229       end if;
230
231       --  Initialize low-level TCB components, that
232       --  cannot be initialized by the creator.
233
234       Enter_Task (Self_ID);
235
236       --  Call the task body procedure
237
238       begin
239          --  We are separating the following portion of the code in order to
240          --  place the exception handlers in a different block. In this way we
241          --  do not call Set_Jmpbuf_Address (which needs Self) before we set
242          --  Self in Enter_Task.
243
244          --  Note that in the case of Ravenscar HI-E where there are no
245          --  exception handlers, the exception handler is suppressed.
246
247          --  Call the task body procedure
248
249          Self_ID.Common.Task_Entry_Point (Self_ID.Common.Task_Arg);
250
251          --  Normal task termination
252
253          Cause := Normal;
254          Save_Occurrence (EO, Ada.Exceptions.Null_Occurrence);
255
256       exception
257          when E : others =>
258
259             --  Task terminating because of an unhandled exception
260
261             Cause := Unhandled_Exception;
262             Save_Occurrence (EO, E);
263       end;
264
265       --  Look for a fall-back handler. It can be either in the task itself
266       --  or in the environment task. Note that this code is always executed
267       --  by a task whose master is the environment task. The task termination
268       --  code for the environment task is executed by
269       --  SSL.Task_Termination_Handler.
270
271       --  This package is part of the restricted run time which supports
272       --  neither task hierarchies (No_Task_Hierarchy) nor specific task
273       --  termination handlers (No_Specific_Termination_Handlers).
274
275       --  There is no need for explicit protection against race conditions
276       --  for Self_ID.Common.Fall_Back_Handler because this procedure can
277       --  only be executed by Self, and the Fall_Back_Handler can only be
278       --  modified by Self.
279
280       if Self_ID.Common.Fall_Back_Handler /= null then
281          Self_ID.Common.Fall_Back_Handler (Cause, Self_ID, EO);
282       else
283          declare
284             TH : Termination_Handler := null;
285
286          begin
287             if Single_Lock then
288                Lock_RTS;
289             end if;
290
291             Write_Lock (Self_ID.Common.Parent);
292
293             TH := Self_ID.Common.Parent.Common.Fall_Back_Handler;
294
295             Unlock (Self_ID.Common.Parent);
296
297             if Single_Lock then
298                Unlock_RTS;
299             end if;
300
301             --  Execute the task termination handler if we found it
302
303             if TH /= null then
304                TH.all (Cause, Self_ID, EO);
305             end if;
306          end;
307       end if;
308
309       Terminate_Task (Self_ID);
310    end Task_Wrapper;
311
312    -----------------------
313    -- Restricted GNARLI --
314    -----------------------
315
316    -------------------------------
317    -- Activate_Restricted_Tasks --
318    -------------------------------
319
320    --  Note that locks of activator and activated task are both locked here.
321    --  This is necessary because C.State and Self.Wait_Count have to be
322    --  synchronized. This is safe from deadlock because the activator is always
323    --  created before the activated task. That satisfies our
324    --  in-order-of-creation ATCB locking policy.
325
326    procedure Activate_Restricted_Tasks
327      (Chain_Access : Activation_Chain_Access)
328    is
329       Self_ID       : constant Task_Id := STPO.Self;
330       C             : Task_Id;
331       Activate_Prio : System.Any_Priority;
332       Success       : Boolean;
333
334    begin
335       pragma Assert (Self_ID = Environment_Task);
336       pragma Assert (Self_ID.Common.Wait_Count = 0);
337
338       if Single_Lock then
339          Lock_RTS;
340       end if;
341
342       --  Lock self, to prevent activated tasks from racing ahead before we
343       --  finish activating the chain.
344
345       Write_Lock (Self_ID);
346
347       --  Activate all the tasks in the chain. Creation of the thread of
348       --  control was deferred until activation. So create it now.
349
350       C := Chain_Access.T_ID;
351
352       while C /= null loop
353          if C.Common.State /= Terminated then
354             pragma Assert (C.Common.State = Unactivated);
355
356             Write_Lock (C);
357
358             if C.Common.Base_Priority < Get_Priority (Self_ID) then
359                Activate_Prio := Get_Priority (Self_ID);
360             else
361                Activate_Prio := C.Common.Base_Priority;
362             end if;
363
364             STPO.Create_Task
365               (C, Task_Wrapper'Address,
366                Parameters.Size_Type
367                  (C.Common.Compiler_Data.Pri_Stack_Info.Size),
368                Activate_Prio, Success);
369
370             Self_ID.Common.Wait_Count := Self_ID.Common.Wait_Count + 1;
371
372             if Success then
373                C.Common.State := Runnable;
374             else
375                raise Program_Error;
376             end if;
377
378             Unlock (C);
379          end if;
380
381          C := C.Common.Activation_Link;
382       end loop;
383
384       Self_ID.Common.State := Activator_Sleep;
385
386       --  Wait for the activated tasks to complete activation. It is unsafe to
387       --  abort any of these tasks until the count goes to zero.
388
389       loop
390          exit when Self_ID.Common.Wait_Count = 0;
391          Sleep (Self_ID, Activator_Sleep);
392       end loop;
393
394       Self_ID.Common.State := Runnable;
395       Unlock (Self_ID);
396
397       if Single_Lock then
398          Unlock_RTS;
399       end if;
400
401       --  Remove the tasks from the chain
402
403       Chain_Access.T_ID := null;
404    end Activate_Restricted_Tasks;
405
406    ------------------------------------
407    -- Complete_Restricted_Activation --
408    ------------------------------------
409
410    --  As in several other places, the locks of the activator and activated
411    --  task are both locked here. This follows our deadlock prevention lock
412    --  ordering policy, since the activated task must be created after the
413    --  activator.
414
415    procedure Complete_Restricted_Activation is
416       Self_ID   : constant Task_Id := STPO.Self;
417       Activator : constant Task_Id := Self_ID.Common.Activator;
418
419    begin
420       if Single_Lock then
421          Lock_RTS;
422       end if;
423
424       Write_Lock (Activator);
425       Write_Lock (Self_ID);
426
427       --  Remove dangling reference to Activator, since a task may outlive its
428       --  activator.
429
430       Self_ID.Common.Activator := null;
431
432       --  Wake up the activator, if it is waiting for a chain of tasks to
433       --  activate, and we are the last in the chain to complete activation
434
435       if Activator.Common.State = Activator_Sleep then
436          Activator.Common.Wait_Count := Activator.Common.Wait_Count - 1;
437
438          if Activator.Common.Wait_Count = 0 then
439             Wakeup (Activator, Activator_Sleep);
440          end if;
441       end if;
442
443       Unlock (Self_ID);
444       Unlock (Activator);
445
446       if Single_Lock then
447          Unlock_RTS;
448       end if;
449
450       --  After the activation, active priority should be the same as base
451       --  priority. We must unlock the Activator first, though, since it should
452       --  not wait if we have lower priority.
453
454       if Get_Priority (Self_ID) /= Self_ID.Common.Base_Priority then
455          Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
456       end if;
457    end Complete_Restricted_Activation;
458
459    ------------------------------
460    -- Complete_Restricted_Task --
461    ------------------------------
462
463    procedure Complete_Restricted_Task is
464    begin
465       STPO.Self.Common.State := Terminated;
466    end Complete_Restricted_Task;
467
468    ----------------------------
469    -- Create_Restricted_Task --
470    ----------------------------
471
472    procedure Create_Restricted_Task
473      (Priority      : Integer;
474       Stack_Address : System.Address;
475       Size          : System.Parameters.Size_Type;
476       Task_Info     : System.Task_Info.Task_Info_Type;
477       State         : Task_Procedure_Access;
478       Discriminants : System.Address;
479       Elaborated    : Access_Boolean;
480       Chain         : in out Activation_Chain;
481       Task_Image    : String;
482       Created_Task  : Task_Id)
483    is
484       Self_ID       : constant Task_Id := STPO.Self;
485       Base_Priority : System.Any_Priority;
486       Success       : Boolean;
487       Len           : Integer;
488
489    begin
490       --  Stack is not preallocated on this target, so that Stack_Address must
491       --  be null.
492
493       pragma Assert (Stack_Address = Null_Address);
494
495       if Priority = Unspecified_Priority then
496          Base_Priority := Self_ID.Common.Base_Priority;
497       else
498          Base_Priority := System.Any_Priority (Priority);
499       end if;
500
501       if Single_Lock then
502          Lock_RTS;
503       end if;
504
505       Write_Lock (Self_ID);
506
507       --  With no task hierarchy, the parent of all non-Environment tasks that
508       --  are created must be the Environment task
509
510       Initialize_ATCB
511         (Self_ID, State, Discriminants, Self_ID, Elaborated, Base_Priority,
512          Task_Info, Size, Created_Task, Success);
513
514       --  If we do our job right then there should never be any failures, which
515       --  was probably said about the Titanic; so just to be safe, let's retain
516       --  this code for now
517
518       if not Success then
519          Unlock (Self_ID);
520
521          if Single_Lock then
522             Unlock_RTS;
523          end if;
524
525          raise Program_Error;
526       end if;
527
528       Created_Task.Entry_Calls (1).Self := Created_Task;
529
530       Len :=
531         Integer'Min (Created_Task.Common.Task_Image'Length, Task_Image'Length);
532       Created_Task.Common.Task_Image_Len := Len;
533       Created_Task.Common.Task_Image (1 .. Len) :=
534         Task_Image (Task_Image'First .. Task_Image'First + Len - 1);
535
536       Unlock (Self_ID);
537
538       if Single_Lock then
539          Unlock_RTS;
540       end if;
541
542       --  Create TSD as early as possible in the creation of a task, since it
543       --  may be used by the operation of Ada code within the task.
544
545       SSL.Create_TSD (Created_Task.Common.Compiler_Data);
546       Created_Task.Common.Activation_Link := Chain.T_ID;
547       Chain.T_ID := Created_Task;
548    end Create_Restricted_Task;
549
550    ---------------------------
551    -- Finalize_Global_Tasks --
552    ---------------------------
553
554    --  This is needed to support the compiler interface; it will only be called
555    --  by the Environment task. Instead, it will cause the Environment to block
556    --  forever, since none of the dependent tasks are expected to terminate
557
558    procedure Finalize_Global_Tasks is
559       Self_ID : constant Task_Id := STPO.Self;
560
561    begin
562       pragma Assert (Self_ID = STPO.Environment_Task);
563
564       if Single_Lock then
565          Lock_RTS;
566       end if;
567
568       --  Handle normal task termination by the environment task, but only for
569       --  the normal task termination. In the case of Abnormal and
570       --  Unhandled_Exception they must have been handled before, and the task
571       --  termination soft link must have been changed so the task termination
572       --  routine is not executed twice.
573
574       --  Note that in the "normal" implementation in s-tassta.adb the task
575       --  termination procedure for the environment task should be executed
576       --  after termination of library-level tasks. However, this
577       --  implementation is to be used when the Ravenscar restrictions are in
578       --  effect, and AI-394 says that if there is a fall-back handler set for
579       --  the partition it should be called when the first task (including the
580       --  environment task) attempts to terminate.
581
582       SSL.Task_Termination_Handler.all (Ada.Exceptions.Null_Occurrence);
583
584       Write_Lock (Self_ID);
585       Sleep (Self_ID, Master_Completion_Sleep);
586       Unlock (Self_ID);
587
588       if Single_Lock then
589          Unlock_RTS;
590       end if;
591
592       --  Should never return from Master Completion Sleep
593
594       raise Program_Error;
595    end Finalize_Global_Tasks;
596
597    ---------------------------
598    -- Restricted_Terminated --
599    ---------------------------
600
601    function Restricted_Terminated (T : Task_Id) return Boolean is
602    begin
603       return T.Common.State = Terminated;
604    end Restricted_Terminated;
605
606    --------------------
607    -- Terminate_Task --
608    --------------------
609
610    procedure Terminate_Task (Self_ID : Task_Id) is
611    begin
612       Self_ID.Common.State := Terminated;
613    end Terminate_Task;
614
615    --------------
616    -- Init_RTS --
617    --------------
618
619    procedure Init_RTS is
620    begin
621       Tasking.Initialize;
622
623       --  Initialize lock used to implement mutual exclusion between all tasks
624
625       STPO.Initialize_Lock (Global_Task_Lock'Access, STPO.Global_Task_Level);
626
627       --  Notify that the tasking run time has been elaborated so that
628       --  the tasking version of the soft links can be used.
629
630       SSL.Lock_Task         := Task_Lock'Access;
631       SSL.Unlock_Task       := Task_Unlock'Access;
632       SSL.Adafinal          := Finalize_Global_Tasks'Access;
633       SSL.Get_Current_Excep := Get_Current_Excep'Access;
634
635       --  Initialize the tasking soft links (if not done yet) that are common
636       --  to the full and the restricted run times.
637
638       SSL.Tasking.Init_Tasking_Soft_Links;
639    end Init_RTS;
640
641 begin
642    Init_RTS;
643 end System.Tasking.Restricted.Stages;