OSDN Git Service

2003-12-11 Ed Falis <falis@gnat.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-tarest.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                GNU ADA 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-2002, 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,  59 Temple Place - Suite 330,  Boston, --
20 -- MA 02111-1307, 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 System.Parameters;
49 --  used for Size_Type
50 --           Single_Lock
51
52 with System.Task_Info;
53 --  used for Task_Info_Type
54
55 with System.Task_Primitives.Operations;
56 --  used for Enter_Task
57 --           Write_Lock
58 --           Unlock
59 --           Wakeup
60 --           Get_Priority
61
62 with System.Soft_Links;
63 --  used for the non-tasking routines (*_NT) that refer to global data.
64 --  They are needed here before the tasking run time has been elaborated.
65 --  used for Create_TSD
66 --  This package also provides initialization routines for task specific data.
67 --  The GNARL must call these to be sure that all non-tasking
68 --  Ada constructs will work.
69
70 with System.Secondary_Stack;
71 --  used for SS_Init;
72
73 with System.Storage_Elements;
74 --  used for Storage_Array;
75
76 package body System.Tasking.Restricted.Stages is
77
78    package STPO renames System.Task_Primitives.Operations;
79    package SSL  renames System.Soft_Links;
80    package SSE  renames System.Storage_Elements;
81    package SST  renames System.Secondary_Stack;
82
83    use Parameters;
84    use Task_Primitives.Operations;
85    use Task_Info;
86
87    Global_Task_Lock : aliased System.Task_Primitives.RTS_Lock;
88    --  This is a global lock; it is used to execute in mutual exclusion
89    --  from all other tasks. It is only used by Task_Lock and Task_Unlock.
90
91    -----------------------------------------------------------------
92    -- Tasking versions of services needed by non-tasking programs --
93    -----------------------------------------------------------------
94
95    procedure Task_Lock;
96    --  Locks out other tasks. Preceding a section of code by Task_Lock and
97    --  following it by Task_Unlock creates a critical region. This is used
98    --  for ensuring that a region of non-tasking code (such as code used to
99    --  allocate memory) is tasking safe. Note that it is valid for calls to
100    --  Task_Lock/Task_Unlock to be nested, and this must work properly, i.e.
101    --  only the corresponding outer level Task_Unlock will actually unlock.
102
103    procedure Task_Unlock;
104    --  Releases lock previously set by call to Task_Lock. In the nested case,
105    --  all nested locks must be released before other tasks competing for the
106    --  tasking lock are released.
107
108    --  See s-tasini.adb for more information on the following functions.
109
110    function Get_Jmpbuf_Address return Address;
111    procedure Set_Jmpbuf_Address (Addr : Address);
112
113    function Get_Sec_Stack_Addr return Address;
114    procedure Set_Sec_Stack_Addr (Addr : Address);
115
116    function  Get_Machine_State_Addr return Address;
117    procedure Set_Machine_State_Addr (Addr : Address);
118
119    function Get_Current_Excep return SSL.EOA;
120
121    procedure Timed_Delay_T (Time : Duration; Mode : Integer);
122
123    ------------------------
124    --  Local Subprograms --
125    ------------------------
126
127    procedure Task_Wrapper (Self_ID : Task_ID);
128    --  This is the procedure that is called by the GNULL from the
129    --  new context when a task is created. It waits for activation
130    --  and then calls the task body procedure. When the task body
131    --  procedure completes, it terminates the task.
132
133    procedure Terminate_Task (Self_ID : Task_ID);
134    --  Terminate the calling task.
135    --  This should only be called by the Task_Wrapper procedure.
136
137    procedure Init_RTS;
138    --  This procedure performs the initialization of the GNARL.
139    --  It consists of initializing the environment task, global locks, and
140    --  installing tasking versions of certain operations used by the compiler.
141    --  Init_RTS is called during elaboration.
142
143    ---------------
144    -- Task_Lock --
145    ---------------
146
147    procedure Task_Lock is
148    begin
149       STPO.Write_Lock (Global_Task_Lock'Access, Global_Lock => True);
150    end Task_Lock;
151
152    -----------------
153    -- Task_Unlock --
154    -----------------
155
156    procedure Task_Unlock is
157    begin
158       STPO.Unlock (Global_Task_Lock'Access, Global_Lock => True);
159    end Task_Unlock;
160
161    ----------------------
162    -- Soft-Link Bodies --
163    ----------------------
164
165    function Get_Current_Excep return SSL.EOA is
166    begin
167       return STPO.Self.Common.Compiler_Data.Current_Excep'Access;
168    end Get_Current_Excep;
169
170    function Get_Jmpbuf_Address return  Address is
171    begin
172       return STPO.Self.Common.Compiler_Data.Jmpbuf_Address;
173    end Get_Jmpbuf_Address;
174
175    function Get_Machine_State_Addr return Address is
176    begin
177       return STPO.Self.Common.Compiler_Data.Machine_State_Addr;
178    end Get_Machine_State_Addr;
179
180    function Get_Sec_Stack_Addr return  Address is
181    begin
182       return STPO.Self.Common.Compiler_Data.Sec_Stack_Addr;
183    end Get_Sec_Stack_Addr;
184
185    procedure Set_Jmpbuf_Address (Addr : Address) is
186    begin
187       STPO.Self.Common.Compiler_Data.Jmpbuf_Address := Addr;
188    end Set_Jmpbuf_Address;
189
190    procedure Set_Machine_State_Addr (Addr : Address) is
191    begin
192       STPO.Self.Common.Compiler_Data.Machine_State_Addr := Addr;
193    end Set_Machine_State_Addr;
194
195    procedure Set_Sec_Stack_Addr (Addr : Address) is
196    begin
197       STPO.Self.Common.Compiler_Data.Sec_Stack_Addr := Addr;
198    end Set_Sec_Stack_Addr;
199
200    ------------------
201    -- Task_Wrapper --
202    ------------------
203
204    --  The task wrapper is a procedure that is called first for each task
205    --  task body, and which in turn calls the compiler-generated task body
206    --  procedure. The wrapper's main job is to do initialization for the task.
207
208    --  The variable ID in the task wrapper is used to implement the Self
209    --  function on targets where there is a fast way to find the stack base
210    --  of the current thread, since it should be at a fixed offset from the
211    --  stack base.
212
213    procedure Task_Wrapper (Self_ID : Task_ID) is
214       ID : Task_ID := Self_ID;
215       pragma Volatile (ID);
216
217       pragma Warnings (Off, ID);
218       --  Turn off warnings (stand alone volatile constant has to be
219       --  imported, so we cannot just make ID constant).
220
221       --  Do not delete this variable.
222       --  In some targets, we need this variable to implement a fast Self.
223
224       use type System.Parameters.Size_Type;
225       use type SSE.Storage_Offset;
226
227       Secondary_Stack : aliased SSE.Storage_Array
228         (1 .. Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size *
229            SSE.Storage_Offset (Parameters.Sec_Stack_Ratio) / 100);
230       Secondary_Stack_Address : System.Address := Secondary_Stack'Address;
231
232    begin
233       if not Parameters.Sec_Stack_Dynamic then
234          Self_ID.Common.Compiler_Data.Sec_Stack_Addr :=
235            Secondary_Stack'Address;
236          SST.SS_Init (Secondary_Stack_Address, Integer (Secondary_Stack'Last));
237       end if;
238
239       --  Initialize low-level TCB components, that
240       --  cannot be initialized by the creator.
241
242       Enter_Task (Self_ID);
243
244       --  Call the task body procedure.
245
246       begin
247          --  We are separating the following portion of the code in order to
248          --  place the exception handlers in a different block.
249          --  In this way we do not call Set_Jmpbuf_Address (which needs
250          --  Self) before we set Self in Enter_Task.
251          --  Note that in the case of Ravenscar HI-E where there are no
252          --  exception handlers, the exception handler is suppressed.
253
254          --  Call the task body procedure.
255
256          Self_ID.Common.Task_Entry_Point (Self_ID.Common.Task_Arg);
257          Terminate_Task (Self_ID);
258
259       exception
260          when others =>
261             Terminate_Task (Self_ID);
262       end;
263    end Task_Wrapper;
264
265    -------------------
266    -- Timed_Delay_T --
267    -------------------
268
269    procedure Timed_Delay_T (Time : Duration; Mode : Integer) is
270    begin
271       STPO.Timed_Delay (STPO.Self, Time, Mode);
272    end Timed_Delay_T;
273
274    -----------------------
275    -- Restricted GNARLI --
276    -----------------------
277
278    -------------------------------
279    -- Activate_Restricted_Tasks --
280    -------------------------------
281
282    --  Note that locks of activator and activated task are both locked
283    --  here. This is necessary because C.State and Self.Wait_Count
284    --  have to be synchronized. This is safe from deadlock because
285    --  the activator is always created before the activated task.
286    --  That satisfies our in-order-of-creation ATCB locking policy.
287
288    procedure Activate_Restricted_Tasks
289      (Chain_Access : Activation_Chain_Access)
290    is
291       Self_ID       : constant Task_ID := STPO.Self;
292       C             : Task_ID;
293       Activate_Prio : System.Any_Priority;
294       Success       : Boolean;
295
296    begin
297       pragma Assert (Self_ID = Environment_Task);
298       pragma Assert (Self_ID.Common.Wait_Count = 0);
299
300       if Single_Lock then
301          Lock_RTS;
302       end if;
303
304       --  Lock self, to prevent activated tasks
305       --  from racing ahead before we finish activating the chain.
306
307       Write_Lock (Self_ID);
308
309       --  Activate all the tasks in the chain.
310       --  Creation of the thread of control was deferred until
311       --  activation. So create it now.
312
313       C := Chain_Access.T_ID;
314
315       while C /= null loop
316          if C.Common.State /= Terminated then
317             pragma Assert (C.Common.State = Unactivated);
318
319             Write_Lock (C);
320
321             if C.Common.Base_Priority < Get_Priority (Self_ID) then
322                Activate_Prio := Get_Priority (Self_ID);
323             else
324                Activate_Prio := C.Common.Base_Priority;
325             end if;
326
327             STPO.Create_Task
328               (C, Task_Wrapper'Address,
329                Parameters.Size_Type
330                  (C.Common.Compiler_Data.Pri_Stack_Info.Size),
331                Activate_Prio, Success);
332
333             Self_ID.Common.Wait_Count := Self_ID.Common.Wait_Count + 1;
334
335             if Success then
336                C.Common.State := Runnable;
337             else
338                raise Program_Error;
339             end if;
340
341             Unlock (C);
342          end if;
343
344          C := C.Common.Activation_Link;
345       end loop;
346
347       Self_ID.Common.State := Activator_Sleep;
348
349       --  Wait for the activated tasks to complete activation.
350       --  It is unsafe to abort any of these tasks until the count goes to
351       --  zero.
352
353       loop
354          exit when Self_ID.Common.Wait_Count = 0;
355          Sleep (Self_ID, Activator_Sleep);
356       end loop;
357
358       Self_ID.Common.State := Runnable;
359       Unlock (Self_ID);
360
361       if Single_Lock then
362          Unlock_RTS;
363       end if;
364
365       --  Remove the tasks from the chain.
366
367       Chain_Access.T_ID := null;
368    end Activate_Restricted_Tasks;
369
370    ------------------------------------
371    -- Complete_Restricted_Activation --
372    ------------------------------------
373
374    --  As in several other places, the locks of the activator and activated
375    --  task are both locked here. This follows our deadlock prevention lock
376    --  ordering policy, since the activated task must be created after the
377    --  activator.
378
379    procedure Complete_Restricted_Activation is
380       Self_ID   : constant Task_ID := STPO.Self;
381       Activator : constant Task_ID := Self_ID.Common.Activator;
382
383    begin
384       if Single_Lock then
385          Lock_RTS;
386       end if;
387
388       Write_Lock (Activator);
389       Write_Lock (Self_ID);
390
391       --  Remove dangling reference to Activator,
392       --  since a task may outlive its activator.
393
394       Self_ID.Common.Activator := null;
395
396       --  Wake up the activator, if it is waiting for a chain
397       --  of tasks to activate, and we are the last in the chain
398       --  to complete activation
399
400       if Activator.Common.State = Activator_Sleep then
401          Activator.Common.Wait_Count := Activator.Common.Wait_Count - 1;
402
403          if Activator.Common.Wait_Count = 0 then
404             Wakeup (Activator, Activator_Sleep);
405          end if;
406       end if;
407
408       Unlock (Self_ID);
409       Unlock (Activator);
410
411       if Single_Lock then
412          Unlock_RTS;
413       end if;
414
415       --  After the activation, active priority should be the same
416       --  as base priority. We must unlock the Activator first,
417       --  though, since it should not wait if we have lower priority.
418
419       if Get_Priority (Self_ID) /= Self_ID.Common.Base_Priority then
420          Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
421       end if;
422    end Complete_Restricted_Activation;
423
424    ------------------------------
425    -- Complete_Restricted_Task --
426    ------------------------------
427
428    procedure Complete_Restricted_Task is
429    begin
430       STPO.Self.Common.State := Terminated;
431    end Complete_Restricted_Task;
432
433    ----------------------------
434    -- Create_Restricted_Task --
435    ----------------------------
436
437    procedure Create_Restricted_Task
438      (Priority      : Integer;
439       Size          : System.Parameters.Size_Type;
440       Task_Info     : System.Task_Info.Task_Info_Type;
441       State         : Task_Procedure_Access;
442       Discriminants : System.Address;
443       Elaborated    : Access_Boolean;
444       Chain         : in out Activation_Chain;
445       Task_Image    : String;
446       Created_Task  : out Task_ID)
447    is
448       T             : Task_ID;
449       Self_ID       : constant Task_ID := STPO.Self;
450       Base_Priority : System.Any_Priority;
451       Success       : Boolean;
452
453    begin
454       if Priority = Unspecified_Priority then
455          Base_Priority := Self_ID.Common.Base_Priority;
456       else
457          Base_Priority := System.Any_Priority (Priority);
458       end if;
459
460       T := New_ATCB (0);
461
462       if Single_Lock then
463          Lock_RTS;
464       end if;
465
466       Write_Lock (Self_ID);
467
468       --  With no task hierarchy, the parent of all non-Environment tasks that
469       --  are created must be the Environment task
470
471       Initialize_ATCB
472         (Self_ID, State, Discriminants, Self_ID, Elaborated, Base_Priority,
473          Task_Info, Size, T, Success);
474
475       --  If we do our job right then there should never be any failures,
476       --  which was probably said about the Titanic; so just to be safe,
477       --  let's retain this code for now
478
479       if not Success then
480          Unlock (Self_ID);
481
482          if Single_Lock then
483             Unlock_RTS;
484          end if;
485
486          raise Program_Error;
487       end if;
488
489       T.Entry_Calls (1).Self := T;
490
491       T.Common.Task_Image_Len :=
492         Integer'Min (T.Common.Task_Image'Length, Task_Image'Length);
493       T.Common.Task_Image (1 .. T.Common.Task_Image_Len) := Task_Image;
494
495       Unlock (Self_ID);
496
497       if Single_Lock then
498          Unlock_RTS;
499       end if;
500
501       --  Create TSD as early as possible in the creation of a task, since it
502       --  may be used by the operation of Ada code within the task.
503
504       SSL.Create_TSD (T.Common.Compiler_Data);
505       T.Common.Activation_Link := Chain.T_ID;
506       Chain.T_ID   := T;
507       Created_Task := T;
508    end Create_Restricted_Task;
509
510    ---------------------------
511    -- Finalize_Global_Tasks --
512    ---------------------------
513
514    --  This is needed to support the compiler interface; it will only be called
515    --  by the Environment task. Instead, it will cause the Environment to block
516    --  forever, since none of the dependent tasks are expected to terminate
517
518    procedure Finalize_Global_Tasks is
519       Self_ID : constant Task_ID := STPO.Self;
520
521    begin
522       pragma Assert (Self_ID = STPO.Environment_Task);
523
524       if Single_Lock then
525          Lock_RTS;
526       end if;
527
528       Write_Lock (Self_ID);
529       Sleep (Self_ID, Master_Completion_Sleep);
530       Unlock (Self_ID);
531
532       if Single_Lock then
533          Unlock_RTS;
534       end if;
535
536       --  Should never return from Master Completion Sleep
537
538       raise Program_Error;
539    end Finalize_Global_Tasks;
540
541    ---------------------------
542    -- Restricted_Terminated --
543    ---------------------------
544
545    function Restricted_Terminated (T : Task_ID) return Boolean is
546    begin
547       return T.Common.State = Terminated;
548    end Restricted_Terminated;
549
550    --------------------
551    -- Terminate_Task --
552    --------------------
553
554    procedure Terminate_Task (Self_ID : Task_ID) is
555    begin
556       Self_ID.Common.State := Terminated;
557    end Terminate_Task;
558
559    --------------
560    -- Init_RTS --
561    --------------
562
563    procedure Init_RTS is
564    begin
565       --  Initialize lock used to implement mutual exclusion between all tasks
566
567       STPO.Initialize_Lock (Global_Task_Lock'Access, STPO.Global_Task_Level);
568
569       --  Notify that the tasking run time has been elaborated so that
570       --  the tasking version of the soft links can be used.
571
572       SSL.Lock_Task              := Task_Lock'Access;
573       SSL.Unlock_Task            := Task_Unlock'Access;
574
575       SSL.Get_Jmpbuf_Address     := Get_Jmpbuf_Address'Access;
576       SSL.Set_Jmpbuf_Address     := Set_Jmpbuf_Address'Access;
577       SSL.Get_Machine_State_Addr := Get_Machine_State_Addr'Access;
578       SSL.Set_Machine_State_Addr := Set_Machine_State_Addr'Access;
579       SSL.Get_Current_Excep      := Get_Current_Excep'Access;
580       SSL.Set_Jmpbuf_Address     (SSL.Get_Jmpbuf_Address_NT);
581       SSL.Set_Machine_State_Addr (SSL.Get_Machine_State_Addr_NT);
582
583       SSL.Get_Sec_Stack_Addr     := Get_Sec_Stack_Addr'Access;
584       SSL.Set_Sec_Stack_Addr     := Set_Sec_Stack_Addr'Access;
585
586       --  No need to create a new Secondary Stack, since we will use the
587       --  default one created in s-secsta.adb
588
589       Set_Sec_Stack_Addr (SSL.Get_Sec_Stack_Addr_NT);
590
591       SSL.Timed_Delay            := Timed_Delay_T'Access;
592       SSL.Adafinal               := Finalize_Global_Tasks'Access;
593    end Init_RTS;
594
595 begin
596    Init_RTS;
597 end System.Tasking.Restricted.Stages;