OSDN Git Service

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