OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [gcc/] [ada/] [s-tassta.adb] - Blame information for rev 826

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 281 jeremybenn
------------------------------------------------------------------------------
2
--                                                                          --
3
--                 GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS                 --
4
--                                                                          --
5
--                 S Y S T E M . T A S K I N G . S T A G E S                --
6
--                                                                          --
7
--                                  B o d y                                 --
8
--                                                                          --
9
--         Copyright (C) 1992-2009, 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
 
32
pragma Polling (Off);
33
--  Turn off polling, we do not want ATC polling to take place during tasking
34
--  operations. It causes infinite loops and other problems.
35
 
36
with Ada.Exceptions;
37
with Ada.Unchecked_Deallocation;
38
 
39
with System.Interrupt_Management;
40
with System.Tasking.Debug;
41
with System.Address_Image;
42
with System.Task_Primitives;
43
with System.Task_Primitives.Operations;
44
with System.Tasking.Utilities;
45
with System.Tasking.Queuing;
46
with System.Tasking.Rendezvous;
47
with System.OS_Primitives;
48
with System.Secondary_Stack;
49
with System.Storage_Elements;
50
with System.Restrictions;
51
with System.Standard_Library;
52
with System.Traces.Tasking;
53
with System.Stack_Usage;
54
 
55
with System.Soft_Links;
56
--  These are procedure pointers to non-tasking routines that use task
57
--  specific data. In the absence of tasking, these routines refer to global
58
--  data. In the presence of tasking, they must be replaced with pointers to
59
--  task-specific versions. Also used for Create_TSD, Destroy_TSD,
60
--  Get_Current_Excep, Finalize_Global_List, Task_Termination, Handler.
61
 
62
with System.Tasking.Initialization;
63
pragma Elaborate_All (System.Tasking.Initialization);
64
--  This insures that tasking is initialized if any tasks are created
65
 
66
package body System.Tasking.Stages is
67
 
68
   package STPO renames System.Task_Primitives.Operations;
69
   package SSL  renames System.Soft_Links;
70
   package SSE  renames System.Storage_Elements;
71
   package SST  renames System.Secondary_Stack;
72
 
73
   use Ada.Exceptions;
74
 
75
   use Parameters;
76
   use Task_Primitives;
77
   use Task_Primitives.Operations;
78
   use Task_Info;
79
 
80
   use System.Traces;
81
   use System.Traces.Tasking;
82
 
83
   -----------------------
84
   -- Local Subprograms --
85
   -----------------------
86
 
87
   procedure Free is new
88
     Ada.Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
89
 
90
   procedure Free_Entry_Names (T : Task_Id);
91
   --  Deallocate all string names associated with task entries
92
 
93
   procedure Trace_Unhandled_Exception_In_Task (Self_Id : Task_Id);
94
   --  This procedure outputs the task specific message for exception
95
   --  tracing purposes.
96
 
97
   procedure Task_Wrapper (Self_ID : Task_Id);
98
   pragma Convention (C, Task_Wrapper);
99
   --  This is the procedure that is called by the GNULL from the new context
100
   --  when a task is created. It waits for activation and then calls the task
101
   --  body procedure. When the task body procedure completes, it terminates
102
   --  the task.
103
   --
104
   --  The Task_Wrapper's address will be provided to the underlying threads
105
   --  library as the task entry point. Convention C is what makes most sense
106
   --  for that purpose (Export C would make the function globally visible,
107
   --  and affect the link name on which GDB depends). This will in addition
108
   --  trigger an automatic stack alignment suitable for GCC's assumptions if
109
   --  need be.
110
 
111
   --  "Vulnerable_..." in the procedure names below means they must be called
112
   --  with abort deferred.
113
 
114
   procedure Vulnerable_Complete_Task (Self_ID : Task_Id);
115
   --  Complete the calling task. This procedure must be called with
116
   --  abort deferred. It should only be called by Complete_Task and
117
   --  Finalize_Global_Tasks (for the environment task).
118
 
119
   procedure Vulnerable_Complete_Master (Self_ID : Task_Id);
120
   --  Complete the current master of the calling task. This procedure
121
   --  must be called with abort deferred. It should only be called by
122
   --  Vulnerable_Complete_Task and Complete_Master.
123
 
124
   procedure Vulnerable_Complete_Activation (Self_ID : Task_Id);
125
   --  Signal to Self_ID's activator that Self_ID has completed activation.
126
   --  This procedure must be called with abort deferred.
127
 
128
   procedure Abort_Dependents (Self_ID : Task_Id);
129
   --  Abort all the direct dependents of Self at its current master nesting
130
   --  level, plus all of their dependents, transitively. RTS_Lock should be
131
   --  locked by the caller.
132
 
133
   procedure Vulnerable_Free_Task (T : Task_Id);
134
   --  Recover all runtime system storage associated with the task T. This
135
   --  should only be called after T has terminated and will no longer be
136
   --  referenced.
137
   --
138
   --  For tasks created by an allocator that fails, due to an exception, it is
139
   --  called from Expunge_Unactivated_Tasks.
140
   --
141
   --  Different code is used at master completion, in Terminate_Dependents,
142
   --  due to a need for tighter synchronization with the master.
143
 
144
   ----------------------
145
   -- Abort_Dependents --
146
   ----------------------
147
 
148
   procedure Abort_Dependents (Self_ID : Task_Id) is
149
      C : Task_Id;
150
      P : Task_Id;
151
 
152
   begin
153
      C := All_Tasks_List;
154
      while C /= null loop
155
         P := C.Common.Parent;
156
         while P /= null loop
157
            if P = Self_ID then
158
 
159
               --  ??? C is supposed to take care of its own dependents, so
160
               --  there should be no need to worry about them. Need to double
161
               --  check this.
162
 
163
               if C.Master_of_Task = Self_ID.Master_Within then
164
                  Utilities.Abort_One_Task (Self_ID, C);
165
                  C.Dependents_Aborted := True;
166
               end if;
167
 
168
               exit;
169
            end if;
170
 
171
            P := P.Common.Parent;
172
         end loop;
173
 
174
         C := C.Common.All_Tasks_Link;
175
      end loop;
176
 
177
      Self_ID.Dependents_Aborted := True;
178
   end Abort_Dependents;
179
 
180
   -----------------
181
   -- Abort_Tasks --
182
   -----------------
183
 
184
   procedure Abort_Tasks (Tasks : Task_List) is
185
   begin
186
      Utilities.Abort_Tasks (Tasks);
187
   end Abort_Tasks;
188
 
189
   --------------------
190
   -- Activate_Tasks --
191
   --------------------
192
 
193
   --  Note that locks of activator and activated task are both locked here.
194
   --  This is necessary because C.Common.State and Self.Common.Wait_Count have
195
   --  to be synchronized. This is safe from deadlock because the activator is
196
   --  always created before the activated task. That satisfies our
197
   --  in-order-of-creation ATCB locking policy.
198
 
199
   --  At one point, we may also lock the parent, if the parent is different
200
   --  from the activator. That is also consistent with the lock ordering
201
   --  policy, since the activator cannot be created before the parent.
202
 
203
   --  Since we are holding both the activator's lock, and Task_Wrapper locks
204
   --  that before it does anything more than initialize the low-level ATCB
205
   --  components, it should be safe to wait to update the counts until we see
206
   --  that the thread creation is successful.
207
 
208
   --  If the thread creation fails, we do need to close the entries of the
209
   --  task. The first phase, of dequeuing calls, only requires locking the
210
   --  acceptor's ATCB, but the waking up of the callers requires locking the
211
   --  caller's ATCB. We cannot safely do this while we are holding other
212
   --  locks. Therefore, the queue-clearing operation is done in a separate
213
   --  pass over the activation chain.
214
 
215
   procedure Activate_Tasks (Chain_Access : Activation_Chain_Access) is
216
      Self_ID        : constant Task_Id := STPO.Self;
217
      P              : Task_Id;
218
      C              : Task_Id;
219
      Next_C, Last_C : Task_Id;
220
      Activate_Prio  : System.Any_Priority;
221
      Success        : Boolean;
222
      All_Elaborated : Boolean := True;
223
 
224
   begin
225
      --  If pragma Detect_Blocking is active, then we must check whether this
226
      --  potentially blocking operation is called from a protected action.
227
 
228
      if System.Tasking.Detect_Blocking
229
        and then Self_ID.Common.Protected_Action_Nesting > 0
230
      then
231
         raise Program_Error with "potentially blocking operation";
232
      end if;
233
 
234
      pragma Debug
235
        (Debug.Trace (Self_ID, "Activate_Tasks", 'C'));
236
 
237
      Initialization.Defer_Abort_Nestable (Self_ID);
238
 
239
      pragma Assert (Self_ID.Common.Wait_Count = 0);
240
 
241
      --  Lock RTS_Lock, to prevent activated tasks from racing ahead before
242
      --  we finish activating the chain.
243
 
244
      Lock_RTS;
245
 
246
      --  Check that all task bodies have been elaborated
247
 
248
      C := Chain_Access.T_ID;
249
      Last_C := null;
250
      while C /= null loop
251
         if C.Common.Elaborated /= null
252
           and then not C.Common.Elaborated.all
253
         then
254
            All_Elaborated := False;
255
         end if;
256
 
257
         --  Reverse the activation chain so that tasks are activated in the
258
         --  same order they're declared.
259
 
260
         Next_C := C.Common.Activation_Link;
261
         C.Common.Activation_Link := Last_C;
262
         Last_C := C;
263
         C := Next_C;
264
      end loop;
265
 
266
      Chain_Access.T_ID := Last_C;
267
 
268
      if not All_Elaborated then
269
         Unlock_RTS;
270
         Initialization.Undefer_Abort_Nestable (Self_ID);
271
         raise Program_Error with "Some tasks have not been elaborated";
272
      end if;
273
 
274
      --  Activate all the tasks in the chain. Creation of the thread of
275
      --  control was deferred until activation. So create it now.
276
 
277
      C := Chain_Access.T_ID;
278
      while C /= null loop
279
         if C.Common.State /= Terminated then
280
            pragma Assert (C.Common.State = Unactivated);
281
 
282
            P := C.Common.Parent;
283
            Write_Lock (P);
284
            Write_Lock (C);
285
 
286
            Activate_Prio :=
287
              (if C.Common.Base_Priority < Get_Priority (Self_ID)
288
               then Get_Priority (Self_ID)
289
               else C.Common.Base_Priority);
290
 
291
            System.Task_Primitives.Operations.Create_Task
292
              (C, Task_Wrapper'Address,
293
               Parameters.Size_Type
294
                 (C.Common.Compiler_Data.Pri_Stack_Info.Size),
295
               Activate_Prio, Success);
296
 
297
            --  There would be a race between the created task and the creator
298
            --  to do the following initialization, if we did not have a
299
            --  Lock/Unlock_RTS pair in the task wrapper to prevent it from
300
            --  racing ahead.
301
 
302
            if Success then
303
               C.Common.State := Activating;
304
               C.Awake_Count := 1;
305
               C.Alive_Count := 1;
306
               P.Awake_Count := P.Awake_Count + 1;
307
               P.Alive_Count := P.Alive_Count + 1;
308
 
309
               if P.Common.State = Master_Completion_Sleep and then
310
                 C.Master_of_Task = P.Master_Within
311
               then
312
                  pragma Assert (Self_ID /= P);
313
                  P.Common.Wait_Count := P.Common.Wait_Count + 1;
314
               end if;
315
 
316
               for J in System.Tasking.Debug.Known_Tasks'Range loop
317
                  if System.Tasking.Debug.Known_Tasks (J) = null then
318
                     System.Tasking.Debug.Known_Tasks (J) := C;
319
                     C.Known_Tasks_Index := J;
320
                     exit;
321
                  end if;
322
               end loop;
323
 
324
               if Global_Task_Debug_Event_Set then
325
                  Debug.Signal_Debug_Event
326
                   (Debug.Debug_Event_Activating, C);
327
               end if;
328
 
329
               C.Common.State := Runnable;
330
 
331
               Unlock (C);
332
               Unlock (P);
333
 
334
            else
335
               --  No need to set Awake_Count, State, etc. here since the loop
336
               --  below will do that for any Unactivated tasks.
337
 
338
               Unlock (C);
339
               Unlock (P);
340
               Self_ID.Common.Activation_Failed := True;
341
            end if;
342
         end if;
343
 
344
         C := C.Common.Activation_Link;
345
      end loop;
346
 
347
      if not Single_Lock then
348
         Unlock_RTS;
349
      end if;
350
 
351
      --  Close the entries of any tasks that failed thread creation, and count
352
      --  those that have not finished activation.
353
 
354
      Write_Lock (Self_ID);
355
      Self_ID.Common.State := Activator_Sleep;
356
 
357
      C := Chain_Access.T_ID;
358
      while C /= null loop
359
         Write_Lock (C);
360
 
361
         if C.Common.State = Unactivated then
362
            C.Common.Activator := null;
363
            C.Common.State := Terminated;
364
            C.Callable := False;
365
            Utilities.Cancel_Queued_Entry_Calls (C);
366
 
367
         elsif C.Common.Activator /= null then
368
            Self_ID.Common.Wait_Count := Self_ID.Common.Wait_Count + 1;
369
         end if;
370
 
371
         Unlock (C);
372
         P := C.Common.Activation_Link;
373
         C.Common.Activation_Link := null;
374
         C := P;
375
      end loop;
376
 
377
      --  Wait for the activated tasks to complete activation. It is
378
      --  unsafe to abort any of these tasks until the count goes to zero.
379
 
380
      loop
381
         exit when Self_ID.Common.Wait_Count = 0;
382
         Sleep (Self_ID, Activator_Sleep);
383
      end loop;
384
 
385
      Self_ID.Common.State := Runnable;
386
      Unlock (Self_ID);
387
 
388
      if Single_Lock then
389
         Unlock_RTS;
390
      end if;
391
 
392
      --  Remove the tasks from the chain
393
 
394
      Chain_Access.T_ID := null;
395
      Initialization.Undefer_Abort_Nestable (Self_ID);
396
 
397
      if Self_ID.Common.Activation_Failed then
398
         Self_ID.Common.Activation_Failed := False;
399
         raise Tasking_Error with "Failure during activation";
400
      end if;
401
   end Activate_Tasks;
402
 
403
   -------------------------
404
   -- Complete_Activation --
405
   -------------------------
406
 
407
   procedure Complete_Activation is
408
      Self_ID : constant Task_Id := STPO.Self;
409
 
410
   begin
411
      Initialization.Defer_Abort_Nestable (Self_ID);
412
 
413
      if Single_Lock then
414
         Lock_RTS;
415
      end if;
416
 
417
      Vulnerable_Complete_Activation (Self_ID);
418
 
419
      if Single_Lock then
420
         Unlock_RTS;
421
      end if;
422
 
423
      Initialization.Undefer_Abort_Nestable (Self_ID);
424
 
425
      --  ??? Why do we need to allow for nested deferral here?
426
 
427
      if Runtime_Traces then
428
         Send_Trace_Info (T_Activate);
429
      end if;
430
   end Complete_Activation;
431
 
432
   ---------------------
433
   -- Complete_Master --
434
   ---------------------
435
 
436
   procedure Complete_Master is
437
      Self_ID : constant Task_Id := STPO.Self;
438
   begin
439
      pragma Assert
440
        (Self_ID.Deferral_Level > 0
441
          or else not System.Restrictions.Abort_Allowed);
442
      Vulnerable_Complete_Master (Self_ID);
443
   end Complete_Master;
444
 
445
   -------------------
446
   -- Complete_Task --
447
   -------------------
448
 
449
   --  See comments on Vulnerable_Complete_Task for details
450
 
451
   procedure Complete_Task is
452
      Self_ID  : constant Task_Id := STPO.Self;
453
 
454
   begin
455
      pragma Assert
456
        (Self_ID.Deferral_Level > 0
457
          or else not System.Restrictions.Abort_Allowed);
458
 
459
      Vulnerable_Complete_Task (Self_ID);
460
 
461
      --  All of our dependents have terminated. Never undefer abort again!
462
 
463
   end Complete_Task;
464
 
465
   -----------------
466
   -- Create_Task --
467
   -----------------
468
 
469
   --  Compiler interface only. Do not call from within the RTS. This must be
470
   --  called to create a new task.
471
 
472
   procedure Create_Task
473
     (Priority          : Integer;
474
      Size              : System.Parameters.Size_Type;
475
      Task_Info         : System.Task_Info.Task_Info_Type;
476
      Relative_Deadline : Ada.Real_Time.Time_Span;
477
      Num_Entries       : Task_Entry_Index;
478
      Master            : Master_Level;
479
      State             : Task_Procedure_Access;
480
      Discriminants     : System.Address;
481
      Elaborated        : Access_Boolean;
482
      Chain             : in out Activation_Chain;
483
      Task_Image        : String;
484
      Created_Task      : out Task_Id;
485
      Build_Entry_Names : Boolean)
486
   is
487
      T, P          : Task_Id;
488
      Self_ID       : constant Task_Id := STPO.Self;
489
      Success       : Boolean;
490
      Base_Priority : System.Any_Priority;
491
      Len           : Natural;
492
 
493
      pragma Unreferenced (Relative_Deadline);
494
      --  EDF scheduling is not supported by any of the target platforms so
495
      --  this parameter is not passed any further.
496
 
497
   begin
498
      --  If Master is greater than the current master, it means that Master
499
      --  has already awaited its dependent tasks. This raises Program_Error,
500
      --  by 4.8(10.3/2). See AI-280. Ignore this check for foreign threads.
501
 
502
      if Self_ID.Master_of_Task /= Foreign_Task_Level
503
        and then Master > Self_ID.Master_Within
504
      then
505
         raise Program_Error with
506
           "create task after awaiting termination";
507
      end if;
508
 
509
      --  If pragma Detect_Blocking is active must be checked whether this
510
      --  potentially blocking operation is called from a protected action.
511
 
512
      if System.Tasking.Detect_Blocking
513
        and then Self_ID.Common.Protected_Action_Nesting > 0
514
      then
515
         raise Program_Error with "potentially blocking operation";
516
      end if;
517
 
518
      pragma Debug (Debug.Trace (Self_ID, "Create_Task", 'C'));
519
 
520
      Base_Priority :=
521
        (if Priority = Unspecified_Priority
522
         then Self_ID.Common.Base_Priority
523
         else System.Any_Priority (Priority));
524
 
525
      --  Find parent P of new Task, via master level number
526
 
527
      P := Self_ID;
528
 
529
      if P /= null then
530
         while P.Master_of_Task >= Master loop
531
            P := P.Common.Parent;
532
            exit when P = null;
533
         end loop;
534
      end if;
535
 
536
      Initialization.Defer_Abort_Nestable (Self_ID);
537
 
538
      begin
539
         T := New_ATCB (Num_Entries);
540
      exception
541
         when others =>
542
            Initialization.Undefer_Abort_Nestable (Self_ID);
543
            raise Storage_Error with "Cannot allocate task";
544
      end;
545
 
546
      --  RTS_Lock is used by Abort_Dependents and Abort_Tasks. Up to this
547
      --  point, it is possible that we may be part of a family of tasks that
548
      --  is being aborted.
549
 
550
      Lock_RTS;
551
      Write_Lock (Self_ID);
552
 
553
      --  Now, we must check that we have not been aborted. If so, we should
554
      --  give up on creating this task, and simply return.
555
 
556
      if not Self_ID.Callable then
557
         pragma Assert (Self_ID.Pending_ATC_Level = 0);
558
         pragma Assert (Self_ID.Pending_Action);
559
         pragma Assert
560
           (Chain.T_ID = null or else Chain.T_ID.Common.State = Unactivated);
561
 
562
         Unlock (Self_ID);
563
         Unlock_RTS;
564
         Initialization.Undefer_Abort_Nestable (Self_ID);
565
 
566
         --  ??? Should never get here
567
 
568
         pragma Assert (False);
569
         raise Standard'Abort_Signal;
570
      end if;
571
 
572
      Initialize_ATCB (Self_ID, State, Discriminants, P, Elaborated,
573
        Base_Priority, Task_Info, Size, T, Success);
574
 
575
      if not Success then
576
         Free (T);
577
         Unlock (Self_ID);
578
         Unlock_RTS;
579
         Initialization.Undefer_Abort_Nestable (Self_ID);
580
         raise Storage_Error with "Failed to initialize task";
581
      end if;
582
 
583
      if Master = Foreign_Task_Level + 2 then
584
 
585
         --  This should not happen, except when a foreign task creates non
586
         --  library-level Ada tasks. In this case, we pretend the master is
587
         --  a regular library level task, otherwise the run-time will get
588
         --  confused when waiting for these tasks to terminate.
589
 
590
         T.Master_of_Task := Library_Task_Level;
591
 
592
      else
593
         T.Master_of_Task := Master;
594
      end if;
595
 
596
      T.Master_Within := T.Master_of_Task + 1;
597
 
598
      for L in T.Entry_Calls'Range loop
599
         T.Entry_Calls (L).Self := T;
600
         T.Entry_Calls (L).Level := L;
601
      end loop;
602
 
603
      if Task_Image'Length = 0 then
604
         T.Common.Task_Image_Len := 0;
605
      else
606
         Len := 1;
607
         T.Common.Task_Image (1) := Task_Image (Task_Image'First);
608
 
609
         --  Remove unwanted blank space generated by 'Image
610
 
611
         for J in Task_Image'First + 1 .. Task_Image'Last loop
612
            if Task_Image (J) /= ' '
613
              or else Task_Image (J - 1) /= '('
614
            then
615
               Len := Len + 1;
616
               T.Common.Task_Image (Len) := Task_Image (J);
617
               exit when Len = T.Common.Task_Image'Last;
618
            end if;
619
         end loop;
620
 
621
         T.Common.Task_Image_Len := Len;
622
      end if;
623
 
624
      Unlock (Self_ID);
625
      Unlock_RTS;
626
 
627
      --  Note: we should not call 'new' while holding locks since new
628
      --  may use locks (e.g. RTS_Lock under Windows) itself and cause a
629
      --  deadlock.
630
 
631
      if Build_Entry_Names then
632
         T.Entry_Names :=
633
           new Entry_Names_Array (1 .. Entry_Index (Num_Entries));
634
      end if;
635
 
636
      --  Create TSD as early as possible in the creation of a task, since it
637
      --  may be used by the operation of Ada code within the task.
638
 
639
      SSL.Create_TSD (T.Common.Compiler_Data);
640
      T.Common.Activation_Link := Chain.T_ID;
641
      Chain.T_ID := T;
642
      Initialization.Initialize_Attributes_Link.all (T);
643
      Created_Task := T;
644
      Initialization.Undefer_Abort_Nestable (Self_ID);
645
 
646
      if Runtime_Traces then
647
         Send_Trace_Info (T_Create, T);
648
      end if;
649
   end Create_Task;
650
 
651
   --------------------
652
   -- Current_Master --
653
   --------------------
654
 
655
   function Current_Master return Master_Level is
656
   begin
657
      return STPO.Self.Master_Within;
658
   end Current_Master;
659
 
660
   ------------------
661
   -- Enter_Master --
662
   ------------------
663
 
664
   procedure Enter_Master is
665
      Self_ID : constant Task_Id := STPO.Self;
666
   begin
667
      Self_ID.Master_Within := Self_ID.Master_Within + 1;
668
   end Enter_Master;
669
 
670
   -------------------------------
671
   -- Expunge_Unactivated_Tasks --
672
   -------------------------------
673
 
674
   --  See procedure Close_Entries for the general case
675
 
676
   procedure Expunge_Unactivated_Tasks (Chain : in out Activation_Chain) is
677
      Self_ID : constant Task_Id := STPO.Self;
678
      C       : Task_Id;
679
      Call    : Entry_Call_Link;
680
      Temp    : Task_Id;
681
 
682
   begin
683
      pragma Debug
684
        (Debug.Trace (Self_ID, "Expunge_Unactivated_Tasks", 'C'));
685
 
686
      Initialization.Defer_Abort_Nestable (Self_ID);
687
 
688
      --  ???
689
      --  Experimentation has shown that abort is sometimes (but not always)
690
      --  already deferred when this is called.
691
 
692
      --  That may indicate an error. Find out what is going on
693
 
694
      C := Chain.T_ID;
695
      while C /= null loop
696
         pragma Assert (C.Common.State = Unactivated);
697
 
698
         Temp := C.Common.Activation_Link;
699
 
700
         if C.Common.State = Unactivated then
701
            Lock_RTS;
702
            Write_Lock (C);
703
 
704
            for J in 1 .. C.Entry_Num loop
705
               Queuing.Dequeue_Head (C.Entry_Queues (J), Call);
706
               pragma Assert (Call = null);
707
            end loop;
708
 
709
            Unlock (C);
710
 
711
            Initialization.Remove_From_All_Tasks_List (C);
712
            Unlock_RTS;
713
 
714
            Vulnerable_Free_Task (C);
715
            C := Temp;
716
         end if;
717
      end loop;
718
 
719
      Chain.T_ID := null;
720
      Initialization.Undefer_Abort_Nestable (Self_ID);
721
   end Expunge_Unactivated_Tasks;
722
 
723
   ---------------------------
724
   -- Finalize_Global_Tasks --
725
   ---------------------------
726
 
727
   --  ???
728
   --  We have a potential problem here if finalization of global objects does
729
   --  anything with signals or the timer server, since by that time those
730
   --  servers have terminated.
731
 
732
   --  It is hard to see how that would occur
733
 
734
   --  However, a better solution might be to do all this finalization
735
   --  using the global finalization chain.
736
 
737
   procedure Finalize_Global_Tasks is
738
      Self_ID : constant Task_Id := STPO.Self;
739
 
740
      Ignore  : Boolean;
741
      pragma Unreferenced (Ignore);
742
 
743
      function State
744
        (Int : System.Interrupt_Management.Interrupt_ID) return Character;
745
      pragma Import (C, State, "__gnat_get_interrupt_state");
746
      --  Get interrupt state for interrupt number Int. Defined in init.c
747
 
748
      Default : constant Character := 's';
749
      --    's'   Interrupt_State pragma set state to System (use "default"
750
      --           system handler)
751
 
752
   begin
753
      if Self_ID.Deferral_Level = 0 then
754
         --  ???
755
         --  In principle, we should be able to predict whether abort is
756
         --  already deferred here (and it should not be deferred yet but in
757
         --  practice it seems Finalize_Global_Tasks is being called sometimes,
758
         --  from RTS code for exceptions, with abort already deferred.
759
 
760
         Initialization.Defer_Abort_Nestable (Self_ID);
761
 
762
         --  Never undefer again!!!
763
      end if;
764
 
765
      --  This code is only executed by the environment task
766
 
767
      pragma Assert (Self_ID = Environment_Task);
768
 
769
      --  Set Environment_Task'Callable to false to notify library-level tasks
770
      --  that it is waiting for them.
771
 
772
      Self_ID.Callable := False;
773
 
774
      --  Exit level 2 master, for normal tasks in library-level packages
775
 
776
      Complete_Master;
777
 
778
      --  Force termination of "independent" library-level server tasks
779
 
780
      Lock_RTS;
781
 
782
      Abort_Dependents (Self_ID);
783
 
784
      if not Single_Lock then
785
         Unlock_RTS;
786
      end if;
787
 
788
      --  We need to explicitly wait for the task to be terminated here
789
      --  because on true concurrent system, we may end this procedure before
790
      --  the tasks are really terminated.
791
 
792
      Write_Lock (Self_ID);
793
 
794
      --  If the Abort_Task signal is set to system, it means that we may not
795
      --  have been able to abort all independent tasks (in particular
796
      --  Server_Task may be blocked, waiting for a signal), in which case,
797
      --  do not wait for Independent_Task_Count to go down to 0.
798
 
799
      if State
800
          (System.Interrupt_Management.Abort_Task_Interrupt) /= Default
801
      then
802
         loop
803
            exit when Utilities.Independent_Task_Count = 0;
804
 
805
            --  We used to yield here, but this did not take into account low
806
            --  priority tasks that would cause dead lock in some cases (true
807
            --  FIFO scheduling).
808
 
809
            Timed_Sleep
810
              (Self_ID, 0.01, System.OS_Primitives.Relative,
811
               Self_ID.Common.State, Ignore, Ignore);
812
         end loop;
813
      end if;
814
 
815
      --  ??? On multi-processor environments, it seems that the above loop
816
      --  isn't sufficient, so we need to add an additional delay.
817
 
818
      Timed_Sleep
819
        (Self_ID, 0.01, System.OS_Primitives.Relative,
820
         Self_ID.Common.State, Ignore, Ignore);
821
 
822
      Unlock (Self_ID);
823
 
824
      if Single_Lock then
825
         Unlock_RTS;
826
      end if;
827
 
828
      --  Complete the environment task
829
 
830
      Vulnerable_Complete_Task (Self_ID);
831
 
832
      --  Handle normal task termination by the environment task, but only
833
      --  for the normal task termination. In the case of Abnormal and
834
      --  Unhandled_Exception they must have been handled before, and the
835
      --  task termination soft link must have been changed so the task
836
      --  termination routine is not executed twice.
837
 
838
      SSL.Task_Termination_Handler.all (Ada.Exceptions.Null_Occurrence);
839
 
840
      --  Finalize the global list for controlled objects if needed
841
 
842
      SSL.Finalize_Global_List.all;
843
 
844
      --  Reset the soft links to non-tasking
845
 
846
      SSL.Abort_Defer        := SSL.Abort_Defer_NT'Access;
847
      SSL.Abort_Undefer      := SSL.Abort_Undefer_NT'Access;
848
      SSL.Lock_Task          := SSL.Task_Lock_NT'Access;
849
      SSL.Unlock_Task        := SSL.Task_Unlock_NT'Access;
850
      SSL.Get_Jmpbuf_Address := SSL.Get_Jmpbuf_Address_NT'Access;
851
      SSL.Set_Jmpbuf_Address := SSL.Set_Jmpbuf_Address_NT'Access;
852
      SSL.Get_Sec_Stack_Addr := SSL.Get_Sec_Stack_Addr_NT'Access;
853
      SSL.Set_Sec_Stack_Addr := SSL.Set_Sec_Stack_Addr_NT'Access;
854
      SSL.Check_Abort_Status := SSL.Check_Abort_Status_NT'Access;
855
      SSL.Get_Stack_Info     := SSL.Get_Stack_Info_NT'Access;
856
 
857
      --  Don't bother trying to finalize Initialization.Global_Task_Lock
858
      --  and System.Task_Primitives.RTS_Lock.
859
 
860
   end Finalize_Global_Tasks;
861
 
862
   ----------------------
863
   -- Free_Entry_Names --
864
   ----------------------
865
 
866
   procedure Free_Entry_Names (T : Task_Id) is
867
      Names : Entry_Names_Array_Access := T.Entry_Names;
868
 
869
      procedure Free_Entry_Names_Array_Access is new
870
        Ada.Unchecked_Deallocation
871
          (Entry_Names_Array, Entry_Names_Array_Access);
872
 
873
   begin
874
      if Names = null then
875
         return;
876
      end if;
877
 
878
      Free_Entry_Names_Array (Names.all);
879
      Free_Entry_Names_Array_Access (Names);
880
   end Free_Entry_Names;
881
 
882
   ---------------
883
   -- Free_Task --
884
   ---------------
885
 
886
   procedure Free_Task (T : Task_Id) is
887
      Self_Id : constant Task_Id := Self;
888
 
889
   begin
890
      if T.Common.State = Terminated then
891
 
892
         --  It is not safe to call Abort_Defer or Write_Lock at this stage
893
 
894
         Initialization.Task_Lock (Self_Id);
895
 
896
         Lock_RTS;
897
         Initialization.Finalize_Attributes_Link.all (T);
898
         Initialization.Remove_From_All_Tasks_List (T);
899
         Unlock_RTS;
900
 
901
         Initialization.Task_Unlock (Self_Id);
902
 
903
         Free_Entry_Names (T);
904
         System.Task_Primitives.Operations.Finalize_TCB (T);
905
 
906
      --  If the task is not terminated, then we simply ignore the call. This
907
      --  happens when a user program attempts an unchecked deallocation on
908
      --  a non-terminated task.
909
 
910
      else
911
         null;
912
      end if;
913
   end Free_Task;
914
 
915
   ---------------------------
916
   -- Move_Activation_Chain --
917
   ---------------------------
918
 
919
   procedure Move_Activation_Chain
920
     (From, To   : Activation_Chain_Access;
921
      New_Master : Master_ID)
922
   is
923
      Self_ID : constant Task_Id := STPO.Self;
924
      C       : Task_Id;
925
 
926
   begin
927
      pragma Debug
928
        (Debug.Trace (Self_ID, "Move_Activation_Chain", 'C'));
929
 
930
      --  Nothing to do if From is empty, and we can check that without
931
      --  deferring aborts.
932
 
933
      C := From.all.T_ID;
934
 
935
      if C = null then
936
         return;
937
      end if;
938
 
939
      Initialization.Defer_Abort (Self_ID);
940
 
941
      --  Loop through the From chain, changing their Master_of_Task
942
      --  fields, and to find the end of the chain.
943
 
944
      loop
945
         C.Master_of_Task := New_Master;
946
         exit when C.Common.Activation_Link = null;
947
         C := C.Common.Activation_Link;
948
      end loop;
949
 
950
      --  Hook From in at the start of To
951
 
952
      C.Common.Activation_Link := To.all.T_ID;
953
      To.all.T_ID := From.all.T_ID;
954
 
955
      --  Set From to empty
956
 
957
      From.all.T_ID := null;
958
 
959
      Initialization.Undefer_Abort (Self_ID);
960
   end Move_Activation_Chain;
961
 
962
   --  Compiler interface only. Do not call from within the RTS
963
 
964
   --------------------
965
   -- Set_Entry_Name --
966
   --------------------
967
 
968
   procedure Set_Entry_Name
969
     (T   : Task_Id;
970
      Pos : Task_Entry_Index;
971
      Val : String_Access)
972
   is
973
   begin
974
      pragma Assert (T.Entry_Names /= null);
975
 
976
      T.Entry_Names (Entry_Index (Pos)) := Val;
977
   end Set_Entry_Name;
978
 
979
   ------------------
980
   -- Task_Wrapper --
981
   ------------------
982
 
983
   --  The task wrapper is a procedure that is called first for each task body
984
   --  and which in turn calls the compiler-generated task body procedure.
985
   --  The wrapper's main job is to do initialization for the task. It also
986
   --  has some locally declared objects that serve as per-task local data.
987
   --  Task finalization is done by Complete_Task, which is called from an
988
   --  at-end handler that the compiler generates.
989
 
990
   procedure Task_Wrapper (Self_ID : Task_Id) is
991
      use type SSE.Storage_Offset;
992
      use System.Standard_Library;
993
      use System.Stack_Usage;
994
 
995
      Bottom_Of_Stack : aliased Integer;
996
 
997
      Task_Alternate_Stack :
998
        aliased SSE.Storage_Array (1 .. Alternate_Stack_Size);
999
      --  The alternate signal stack for this task, if any
1000
 
1001
      Use_Alternate_Stack : constant Boolean := Alternate_Stack_Size /= 0;
1002
      --  Whether to use above alternate signal stack for stack overflows
1003
 
1004
      Secondary_Stack_Size :
1005
        constant SSE.Storage_Offset :=
1006
          Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size *
1007
          SSE.Storage_Offset (Parameters.Sec_Stack_Ratio) / 100;
1008
 
1009
      Secondary_Stack : aliased SSE.Storage_Array (1 .. Secondary_Stack_Size);
1010
 
1011
      pragma Warnings (Off);
1012
      --  Why are warnings being turned off here???
1013
 
1014
      Secondary_Stack_Address : System.Address := Secondary_Stack'Address;
1015
      --  Address of secondary stack. In the fixed secondary stack case, this
1016
      --  value is not modified, causing a warning, hence the bracketing with
1017
      --  Warnings (Off/On). But why is so much *more* bracketed???
1018
 
1019
      Small_Overflow_Guard : constant := 12 * 1024;
1020
      --  Note: this used to be 4K, but was changed to 12K, since smaller
1021
      --  values resulted in segmentation faults from dynamic stack analysis.
1022
 
1023
      Big_Overflow_Guard   : constant := 16 * 1024;
1024
      Small_Stack_Limit    : constant := 64 * 1024;
1025
      --  ??? These three values are experimental, and seems to work on most
1026
      --  platforms. They still need to be analyzed further. They also need
1027
      --  documentation, what are they???
1028
 
1029
      Size : Natural :=
1030
               Natural (Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size);
1031
 
1032
      Overflow_Guard : Natural;
1033
      --  Size of the overflow guard, used by dynamic stack usage analysis
1034
 
1035
      pragma Warnings (On);
1036
 
1037
      SEH_Table : aliased SSE.Storage_Array (1 .. 8);
1038
      --  Structured Exception Registration table (2 words)
1039
 
1040
      procedure Install_SEH_Handler (Addr : System.Address);
1041
      pragma Import (C, Install_SEH_Handler, "__gnat_install_SEH_handler");
1042
      --  Install the SEH (Structured Exception Handling) handler
1043
 
1044
      Cause : Cause_Of_Termination := Normal;
1045
      --  Indicates the reason why this task terminates. Normal corresponds to
1046
      --  a task terminating due to completing the last statement of its body,
1047
      --  or as a result of waiting on a terminate alternative. If the task
1048
      --  terminates because it is being aborted then Cause will be set to
1049
      --  Abnormal. If the task terminates because of an exception raised by
1050
      --  the execution of its task body, then Cause is set to
1051
      --  Unhandled_Exception.
1052
 
1053
      EO : Exception_Occurrence;
1054
      --  If the task terminates because of an exception raised by the
1055
      --  execution of its task body, then EO will contain the associated
1056
      --  exception occurrence. Otherwise, it will contain Null_Occurrence.
1057
 
1058
      TH : Termination_Handler := null;
1059
      --  Pointer to the protected procedure to be executed upon task
1060
      --  termination.
1061
 
1062
      procedure Search_Fall_Back_Handler (ID : Task_Id);
1063
      --  Procedure that searches recursively a fall-back handler through the
1064
      --  master relationship. If the handler is found, its pointer is stored
1065
      --  in TH.
1066
 
1067
      ------------------------------
1068
      -- Search_Fall_Back_Handler --
1069
      ------------------------------
1070
 
1071
      procedure Search_Fall_Back_Handler (ID : Task_Id) is
1072
      begin
1073
         --  If there is a fall back handler, store its pointer for later
1074
         --  execution.
1075
 
1076
         if ID.Common.Fall_Back_Handler /= null then
1077
            TH := ID.Common.Fall_Back_Handler;
1078
 
1079
         --  Otherwise look for a fall back handler in the parent
1080
 
1081
         elsif ID.Common.Parent /= null then
1082
            Search_Fall_Back_Handler (ID.Common.Parent);
1083
 
1084
         --  Otherwise, do nothing
1085
 
1086
         else
1087
            return;
1088
         end if;
1089
      end Search_Fall_Back_Handler;
1090
 
1091
   begin
1092
      pragma Assert (Self_ID.Deferral_Level = 1);
1093
 
1094
      --  Assume a size of the stack taken at this stage
1095
 
1096
      Overflow_Guard :=
1097
        (if Size < Small_Stack_Limit
1098
         then Small_Overflow_Guard
1099
         else Big_Overflow_Guard);
1100
 
1101
      if not Parameters.Sec_Stack_Dynamic then
1102
         Self_ID.Common.Compiler_Data.Sec_Stack_Addr :=
1103
           Secondary_Stack'Address;
1104
         SST.SS_Init (Secondary_Stack_Address, Integer (Secondary_Stack'Last));
1105
         Size := Size - Natural (Secondary_Stack_Size);
1106
      end if;
1107
 
1108
      if Use_Alternate_Stack then
1109
         Self_ID.Common.Task_Alternate_Stack := Task_Alternate_Stack'Address;
1110
      end if;
1111
 
1112
      Size := Size - Overflow_Guard;
1113
 
1114
      if System.Stack_Usage.Is_Enabled then
1115
         STPO.Lock_RTS;
1116
         Initialize_Analyzer
1117
           (Self_ID.Common.Analyzer,
1118
            Self_ID.Common.Task_Image
1119
              (1 .. Self_ID.Common.Task_Image_Len),
1120
            Natural
1121
              (Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size),
1122
            Size,
1123
            SSE.To_Integer (Bottom_Of_Stack'Address));
1124
         STPO.Unlock_RTS;
1125
         Fill_Stack (Self_ID.Common.Analyzer);
1126
      end if;
1127
 
1128
      --  Set the guard page at the bottom of the stack. The call to unprotect
1129
      --  the page is done in Terminate_Task
1130
 
1131
      Stack_Guard (Self_ID, True);
1132
 
1133
      --  Initialize low-level TCB components, that cannot be initialized by
1134
      --  the creator. Enter_Task sets Self_ID.LL.Thread
1135
 
1136
      Enter_Task (Self_ID);
1137
 
1138
      --  We setup the SEH (Structured Exception Handling) handler if supported
1139
      --  on the target.
1140
 
1141
      Install_SEH_Handler (SEH_Table'Address);
1142
 
1143
      --  Initialize exception occurrence
1144
 
1145
      Save_Occurrence (EO, Ada.Exceptions.Null_Occurrence);
1146
 
1147
      --  We lock RTS_Lock to wait for activator to finish activating the rest
1148
      --  of the chain, so that everyone in the chain comes out in priority
1149
      --  order.
1150
 
1151
      --  This also protects the value of
1152
      --    Self_ID.Common.Activator.Common.Wait_Count.
1153
 
1154
      Lock_RTS;
1155
      Unlock_RTS;
1156
 
1157
      if not System.Restrictions.Abort_Allowed then
1158
 
1159
         --  If Abort is not allowed, reset the deferral level since it will
1160
         --  not get changed by the generated code. Keeping a default value
1161
         --  of one would prevent some operations (e.g. select or delay) to
1162
         --  proceed successfully.
1163
 
1164
         Self_ID.Deferral_Level := 0;
1165
      end if;
1166
 
1167
      if Global_Task_Debug_Event_Set then
1168
         Debug.Signal_Debug_Event
1169
          (Debug.Debug_Event_Run, Self_ID);
1170
      end if;
1171
 
1172
      begin
1173
         --  We are separating the following portion of the code in order to
1174
         --  place the exception handlers in a different block. In this way,
1175
         --  we do not call Set_Jmpbuf_Address (which needs Self) before we
1176
         --  set Self in Enter_Task
1177
 
1178
         --  Call the task body procedure
1179
 
1180
         --  The task body is called with abort still deferred. That
1181
         --  eliminates a dangerous window, for which we had to patch-up in
1182
         --  Terminate_Task.
1183
 
1184
         --  During the expansion of the task body, we insert an RTS-call
1185
         --  to Abort_Undefer, at the first point where abort should be
1186
         --  allowed.
1187
 
1188
         Self_ID.Common.Task_Entry_Point (Self_ID.Common.Task_Arg);
1189
         Initialization.Defer_Abort_Nestable (Self_ID);
1190
 
1191
      exception
1192
         --  We can't call Terminate_Task in the exception handlers below,
1193
         --  since there may be (e.g. in the case of GCC exception handling)
1194
         --  clean ups associated with the exception handler that need to
1195
         --  access task specific data.
1196
 
1197
         --  Defer abort so that this task can't be aborted while exiting
1198
 
1199
         when Standard'Abort_Signal =>
1200
            Initialization.Defer_Abort_Nestable (Self_ID);
1201
 
1202
            --  Update the cause that motivated the task termination so that
1203
            --  the appropriate information is passed to the task termination
1204
            --  procedure. Task termination as a result of waiting on a
1205
            --  terminate alternative is a normal termination, although it is
1206
            --  implemented using the abort mechanisms.
1207
 
1208
            if Self_ID.Terminate_Alternative then
1209
               Cause := Normal;
1210
 
1211
               if Global_Task_Debug_Event_Set then
1212
                  Debug.Signal_Debug_Event
1213
                   (Debug.Debug_Event_Terminated, Self_ID);
1214
               end if;
1215
            else
1216
               Cause := Abnormal;
1217
 
1218
               if Global_Task_Debug_Event_Set then
1219
                  Debug.Signal_Debug_Event
1220
                   (Debug.Debug_Event_Abort_Terminated, Self_ID);
1221
               end if;
1222
            end if;
1223
         when others =>
1224
            --  ??? Using an E : others here causes CD2C11A to fail on Tru64
1225
 
1226
            Initialization.Defer_Abort_Nestable (Self_ID);
1227
 
1228
            --  Perform the task specific exception tracing duty.  We handle
1229
            --  these outputs here and not in the common notification routine
1230
            --  because we need access to tasking related data and we don't
1231
            --  want to drag dependencies against tasking related units in the
1232
            --  the common notification units. Additionally, no trace is ever
1233
            --  triggered from the common routine for the Unhandled_Raise case
1234
            --  in tasks, since an exception never appears unhandled in this
1235
            --  context because of this handler.
1236
 
1237
            if Exception_Trace = Unhandled_Raise then
1238
               Trace_Unhandled_Exception_In_Task (Self_ID);
1239
            end if;
1240
 
1241
            --  Update the cause that motivated the task termination so that
1242
            --  the appropriate information is passed to the task termination
1243
            --  procedure, as well as the associated Exception_Occurrence.
1244
 
1245
            Cause := Unhandled_Exception;
1246
 
1247
            Save_Occurrence (EO, SSL.Get_Current_Excep.all.all);
1248
 
1249
            if Global_Task_Debug_Event_Set then
1250
               Debug.Signal_Debug_Event
1251
                 (Debug.Debug_Event_Exception_Terminated, Self_ID);
1252
            end if;
1253
      end;
1254
 
1255
      --  Look for a task termination handler. This code is for all tasks but
1256
      --  the environment task. The task termination code for the environment
1257
      --  task is executed by SSL.Task_Termination_Handler.
1258
 
1259
      if Single_Lock then
1260
         Lock_RTS;
1261
      end if;
1262
 
1263
      Write_Lock (Self_ID);
1264
 
1265
      if Self_ID.Common.Specific_Handler /= null then
1266
         TH := Self_ID.Common.Specific_Handler;
1267
      else
1268
         --  Look for a fall-back handler following the master relationship
1269
         --  for the task.
1270
 
1271
         Search_Fall_Back_Handler (Self_ID);
1272
      end if;
1273
 
1274
      Unlock (Self_ID);
1275
 
1276
      if Single_Lock then
1277
         Unlock_RTS;
1278
      end if;
1279
 
1280
      --  Execute the task termination handler if we found it
1281
 
1282
      if TH /= null then
1283
         TH.all (Cause, Self_ID, EO);
1284
      end if;
1285
 
1286
      if System.Stack_Usage.Is_Enabled then
1287
         Compute_Result (Self_ID.Common.Analyzer);
1288
         Report_Result (Self_ID.Common.Analyzer);
1289
      end if;
1290
 
1291
      Terminate_Task (Self_ID);
1292
   end Task_Wrapper;
1293
 
1294
   --------------------
1295
   -- Terminate_Task --
1296
   --------------------
1297
 
1298
   --  Before we allow the thread to exit, we must clean up. This is a
1299
   --  delicate job. We must wake up the task's master, who may immediately try
1300
   --  to deallocate the ATCB out from under the current task WHILE IT IS STILL
1301
   --  EXECUTING.
1302
 
1303
   --  To avoid this, the parent task must be blocked up to the latest
1304
   --  statement executed. The trouble is that we have another step that we
1305
   --  also want to postpone to the very end, i.e., calling SSL.Destroy_TSD.
1306
   --  We have to postpone that until the end because compiler-generated code
1307
   --  is likely to try to access that data at just about any point.
1308
 
1309
   --  We can't call Destroy_TSD while we are holding any other locks, because
1310
   --  it locks Global_Task_Lock, and our deadlock prevention rules require
1311
   --  that to be the outermost lock. Our first "solution" was to just lock
1312
   --  Global_Task_Lock in addition to the other locks, and force the parent to
1313
   --  also lock this lock between its wakeup and its freeing of the ATCB. See
1314
   --  Complete_Task for the parent-side of the code that has the matching
1315
   --  calls to Task_Lock and Task_Unlock. That was not really a solution,
1316
   --  since the operation Task_Unlock continued to access the ATCB after
1317
   --  unlocking, after which the parent was observed to race ahead, deallocate
1318
   --  the ATCB, and then reallocate it to another task. The call to
1319
   --  Undefer_Abort in Task_Unlock by the "terminated" task was overwriting
1320
   --  the data of the new task that reused the ATCB! To solve this problem, we
1321
   --  introduced the new operation Final_Task_Unlock.
1322
 
1323
   procedure Terminate_Task (Self_ID : Task_Id) is
1324
      Environment_Task : constant Task_Id := STPO.Environment_Task;
1325
      Master_of_Task   : Integer;
1326
 
1327
   begin
1328
      Debug.Task_Termination_Hook;
1329
 
1330
      if Runtime_Traces then
1331
         Send_Trace_Info (T_Terminate);
1332
      end if;
1333
 
1334
      --  Since GCC cannot allocate stack chunks efficiently without reordering
1335
      --  some of the allocations, we have to handle this unexpected situation
1336
      --  here. We should normally never have to call Vulnerable_Complete_Task
1337
      --  here.
1338
 
1339
      if Self_ID.Common.Activator /= null then
1340
         Vulnerable_Complete_Task (Self_ID);
1341
      end if;
1342
 
1343
      Initialization.Task_Lock (Self_ID);
1344
 
1345
      if Single_Lock then
1346
         Lock_RTS;
1347
      end if;
1348
 
1349
      Master_of_Task := Self_ID.Master_of_Task;
1350
 
1351
      --  Check if the current task is an independent task If so, decrement
1352
      --  the Independent_Task_Count value.
1353
 
1354
      if Master_of_Task = Independent_Task_Level then
1355
         if Single_Lock then
1356
            Utilities.Independent_Task_Count :=
1357
              Utilities.Independent_Task_Count - 1;
1358
         else
1359
            Write_Lock (Environment_Task);
1360
            Utilities.Independent_Task_Count :=
1361
              Utilities.Independent_Task_Count - 1;
1362
            Unlock (Environment_Task);
1363
         end if;
1364
      end if;
1365
 
1366
      --  Unprotect the guard page if needed
1367
 
1368
      Stack_Guard (Self_ID, False);
1369
 
1370
      Utilities.Make_Passive (Self_ID, Task_Completed => True);
1371
 
1372
      if Single_Lock then
1373
         Unlock_RTS;
1374
      end if;
1375
 
1376
      pragma Assert (Check_Exit (Self_ID));
1377
 
1378
      SSL.Destroy_TSD (Self_ID.Common.Compiler_Data);
1379
      Initialization.Final_Task_Unlock (Self_ID);
1380
 
1381
      --  WARNING: past this point, this thread must assume that the ATCB has
1382
      --  been deallocated. It should not be accessed again.
1383
 
1384
      if Master_of_Task > 0 then
1385
         STPO.Exit_Task;
1386
      end if;
1387
   end Terminate_Task;
1388
 
1389
   ----------------
1390
   -- Terminated --
1391
   ----------------
1392
 
1393
   function Terminated (T : Task_Id) return Boolean is
1394
      Self_ID : constant Task_Id := STPO.Self;
1395
      Result  : Boolean;
1396
 
1397
   begin
1398
      Initialization.Defer_Abort_Nestable (Self_ID);
1399
 
1400
      if Single_Lock then
1401
         Lock_RTS;
1402
      end if;
1403
 
1404
      Write_Lock (T);
1405
      Result := T.Common.State = Terminated;
1406
      Unlock (T);
1407
 
1408
      if Single_Lock then
1409
         Unlock_RTS;
1410
      end if;
1411
 
1412
      Initialization.Undefer_Abort_Nestable (Self_ID);
1413
      return Result;
1414
   end Terminated;
1415
 
1416
   ----------------------------------------
1417
   -- Trace_Unhandled_Exception_In_Task --
1418
   ----------------------------------------
1419
 
1420
   procedure Trace_Unhandled_Exception_In_Task (Self_Id : Task_Id) is
1421
      procedure To_Stderr (S : String);
1422
      pragma Import (Ada, To_Stderr, "__gnat_to_stderr");
1423
 
1424
      use System.Soft_Links;
1425
      use System.Standard_Library;
1426
 
1427
      function To_Address is new
1428
        Ada.Unchecked_Conversion
1429
         (Task_Id, System.Task_Primitives.Task_Address);
1430
 
1431
      function Tailored_Exception_Information
1432
        (E : Exception_Occurrence) return String;
1433
      pragma Import
1434
        (Ada, Tailored_Exception_Information,
1435
         "__gnat_tailored_exception_information");
1436
 
1437
      Excep : constant Exception_Occurrence_Access :=
1438
                SSL.Get_Current_Excep.all;
1439
 
1440
   begin
1441
      --  This procedure is called by the task outermost handler in
1442
      --  Task_Wrapper below, so only once the task stack has been fully
1443
      --  unwound. The common notification routine has been called at the
1444
      --  raise point already.
1445
 
1446
      --  Lock to prevent unsynchronized output
1447
 
1448
      Initialization.Task_Lock (Self_Id);
1449
      To_Stderr ("task ");
1450
 
1451
      if Self_Id.Common.Task_Image_Len /= 0 then
1452
         To_Stderr
1453
           (Self_Id.Common.Task_Image (1 .. Self_Id.Common.Task_Image_Len));
1454
         To_Stderr ("_");
1455
      end if;
1456
 
1457
      To_Stderr (System.Address_Image (To_Address (Self_Id)));
1458
      To_Stderr (" terminated by unhandled exception");
1459
      To_Stderr ((1 => ASCII.LF));
1460
      To_Stderr (Tailored_Exception_Information (Excep.all));
1461
      Initialization.Task_Unlock (Self_Id);
1462
   end Trace_Unhandled_Exception_In_Task;
1463
 
1464
   ------------------------------------
1465
   -- Vulnerable_Complete_Activation --
1466
   ------------------------------------
1467
 
1468
   --  As in several other places, the locks of the activator and activated
1469
   --  task are both locked here. This follows our deadlock prevention lock
1470
   --  ordering policy, since the activated task must be created after the
1471
   --  activator.
1472
 
1473
   procedure Vulnerable_Complete_Activation (Self_ID : Task_Id) is
1474
      Activator : constant Task_Id := Self_ID.Common.Activator;
1475
 
1476
   begin
1477
      pragma Debug (Debug.Trace (Self_ID, "V_Complete_Activation", 'C'));
1478
 
1479
      Write_Lock (Activator);
1480
      Write_Lock (Self_ID);
1481
 
1482
      pragma Assert (Self_ID.Common.Activator /= null);
1483
 
1484
      --  Remove dangling reference to Activator, since a task may
1485
      --  outlive its activator.
1486
 
1487
      Self_ID.Common.Activator := null;
1488
 
1489
      --  Wake up the activator, if it is waiting for a chain of tasks to
1490
      --  activate, and we are the last in the chain to complete activation.
1491
 
1492
      if Activator.Common.State = Activator_Sleep then
1493
         Activator.Common.Wait_Count := Activator.Common.Wait_Count - 1;
1494
 
1495
         if Activator.Common.Wait_Count = 0 then
1496
            Wakeup (Activator, Activator_Sleep);
1497
         end if;
1498
      end if;
1499
 
1500
      --  The activator raises a Tasking_Error if any task it is activating
1501
      --  is completed before the activation is done. However, if the reason
1502
      --  for the task completion is an abort, we do not raise an exception.
1503
      --  See RM 9.2(5).
1504
 
1505
      if not Self_ID.Callable and then Self_ID.Pending_ATC_Level /= 0 then
1506
         Activator.Common.Activation_Failed := True;
1507
      end if;
1508
 
1509
      Unlock (Self_ID);
1510
      Unlock (Activator);
1511
 
1512
      --  After the activation, active priority should be the same as base
1513
      --  priority. We must unlock the Activator first, though, since it
1514
      --  should not wait if we have lower priority.
1515
 
1516
      if Get_Priority (Self_ID) /= Self_ID.Common.Base_Priority then
1517
         Write_Lock (Self_ID);
1518
         Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
1519
         Unlock (Self_ID);
1520
      end if;
1521
   end Vulnerable_Complete_Activation;
1522
 
1523
   --------------------------------
1524
   -- Vulnerable_Complete_Master --
1525
   --------------------------------
1526
 
1527
   procedure Vulnerable_Complete_Master (Self_ID : Task_Id) is
1528
      C  : Task_Id;
1529
      P  : Task_Id;
1530
      CM : constant Master_Level := Self_ID.Master_Within;
1531
      T  : aliased Task_Id;
1532
 
1533
      To_Be_Freed : Task_Id;
1534
      --  This is a list of ATCBs to be freed, after we have released all RTS
1535
      --  locks. This is necessary because of the locking order rules, since
1536
      --  the storage manager uses Global_Task_Lock.
1537
 
1538
      pragma Warnings (Off);
1539
      function Check_Unactivated_Tasks return Boolean;
1540
      pragma Warnings (On);
1541
      --  Temporary error-checking code below. This is part of the checks
1542
      --  added in the new run time. Call it only inside a pragma Assert.
1543
 
1544
      -----------------------------
1545
      -- Check_Unactivated_Tasks --
1546
      -----------------------------
1547
 
1548
      function Check_Unactivated_Tasks return Boolean is
1549
      begin
1550
         if not Single_Lock then
1551
            Lock_RTS;
1552
         end if;
1553
 
1554
         Write_Lock (Self_ID);
1555
 
1556
         C := All_Tasks_List;
1557
         while C /= null loop
1558
            if C.Common.Activator = Self_ID and then C.Master_of_Task = CM then
1559
               return False;
1560
            end if;
1561
 
1562
            if C.Common.Parent = Self_ID and then C.Master_of_Task = CM then
1563
               Write_Lock (C);
1564
 
1565
               if C.Common.State = Unactivated then
1566
                  return False;
1567
               end if;
1568
 
1569
               Unlock (C);
1570
            end if;
1571
 
1572
            C := C.Common.All_Tasks_Link;
1573
         end loop;
1574
 
1575
         Unlock (Self_ID);
1576
 
1577
         if not Single_Lock then
1578
            Unlock_RTS;
1579
         end if;
1580
 
1581
         return True;
1582
      end Check_Unactivated_Tasks;
1583
 
1584
   --  Start of processing for Vulnerable_Complete_Master
1585
 
1586
   begin
1587
      pragma Debug
1588
        (Debug.Trace (Self_ID, "V_Complete_Master", 'C'));
1589
 
1590
      pragma Assert (Self_ID.Common.Wait_Count = 0);
1591
      pragma Assert
1592
        (Self_ID.Deferral_Level > 0
1593
          or else not System.Restrictions.Abort_Allowed);
1594
 
1595
      --  Count how many active dependent tasks this master currently has, and
1596
      --  record this in Wait_Count.
1597
 
1598
      --  This count should start at zero, since it is initialized to zero for
1599
      --  new tasks, and the task should not exit the sleep-loops that use this
1600
      --  count until the count reaches zero.
1601
 
1602
      --  While we're counting, if we run across any unactivated tasks that
1603
      --  belong to this master, we summarily terminate them as required by
1604
      --  RM-9.2(6).
1605
 
1606
      Lock_RTS;
1607
      Write_Lock (Self_ID);
1608
 
1609
      C := All_Tasks_List;
1610
      while C /= null loop
1611
 
1612
         --  Terminate unactivated (never-to-be activated) tasks
1613
 
1614
         if C.Common.Activator = Self_ID and then C.Master_of_Task = CM then
1615
 
1616
            pragma Assert (C.Common.State = Unactivated);
1617
            --  Usually, C.Common.Activator = Self_ID implies C.Master_of_Task
1618
            --  = CM. The only case where C is pending activation by this
1619
            --  task, but the master of C is not CM is in Ada 2005, when C is
1620
            --  part of a return object of a build-in-place function.
1621
 
1622
            Write_Lock (C);
1623
            C.Common.Activator := null;
1624
            C.Common.State := Terminated;
1625
            C.Callable := False;
1626
            Utilities.Cancel_Queued_Entry_Calls (C);
1627
            Unlock (C);
1628
         end if;
1629
 
1630
         --  Count it if dependent on this master
1631
 
1632
         if C.Common.Parent = Self_ID and then C.Master_of_Task = CM then
1633
            Write_Lock (C);
1634
 
1635
            if C.Awake_Count /= 0 then
1636
               Self_ID.Common.Wait_Count := Self_ID.Common.Wait_Count + 1;
1637
            end if;
1638
 
1639
            Unlock (C);
1640
         end if;
1641
 
1642
         C := C.Common.All_Tasks_Link;
1643
      end loop;
1644
 
1645
      Self_ID.Common.State := Master_Completion_Sleep;
1646
      Unlock (Self_ID);
1647
 
1648
      if not Single_Lock then
1649
         Unlock_RTS;
1650
      end if;
1651
 
1652
      --  Wait until dependent tasks are all terminated or ready to terminate.
1653
      --  While waiting, the task may be awakened if the task's priority needs
1654
      --  changing, or this master is aborted. In the latter case, we abort the
1655
      --  dependents, and resume waiting until Wait_Count goes to zero.
1656
 
1657
      Write_Lock (Self_ID);
1658
 
1659
      loop
1660
         exit when Self_ID.Common.Wait_Count = 0;
1661
 
1662
         --  Here is a difference as compared to Complete_Master
1663
 
1664
         if Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
1665
           and then not Self_ID.Dependents_Aborted
1666
         then
1667
            if Single_Lock then
1668
               Abort_Dependents (Self_ID);
1669
            else
1670
               Unlock (Self_ID);
1671
               Lock_RTS;
1672
               Abort_Dependents (Self_ID);
1673
               Unlock_RTS;
1674
               Write_Lock (Self_ID);
1675
            end if;
1676
         else
1677
            Sleep (Self_ID, Master_Completion_Sleep);
1678
         end if;
1679
      end loop;
1680
 
1681
      Self_ID.Common.State := Runnable;
1682
      Unlock (Self_ID);
1683
 
1684
      --  Dependents are all terminated or on terminate alternatives. Now,
1685
      --  force those on terminate alternatives to terminate, by aborting them.
1686
 
1687
      pragma Assert (Check_Unactivated_Tasks);
1688
 
1689
      if Self_ID.Alive_Count > 1 then
1690
         --  ???
1691
         --  Consider finding a way to skip the following extra steps if there
1692
         --  are no dependents with terminate alternatives. This could be done
1693
         --  by adding another count to the ATCB, similar to Awake_Count, but
1694
         --  keeping track of tasks that are on terminate alternatives.
1695
 
1696
         pragma Assert (Self_ID.Common.Wait_Count = 0);
1697
 
1698
         --  Force any remaining dependents to terminate by aborting them
1699
 
1700
         if not Single_Lock then
1701
            Lock_RTS;
1702
         end if;
1703
 
1704
         Abort_Dependents (Self_ID);
1705
 
1706
         --  Above, when we "abort" the dependents we are simply using this
1707
         --  operation for convenience. We are not required to support the full
1708
         --  abort-statement semantics; in particular, we are not required to
1709
         --  immediately cancel any queued or in-service entry calls. That is
1710
         --  good, because if we tried to cancel a call we would need to lock
1711
         --  the caller, in order to wake the caller up. Our anti-deadlock
1712
         --  rules prevent us from doing that without releasing the locks on C
1713
         --  and Self_ID. Releasing and retaking those locks would be wasteful
1714
         --  at best, and should not be considered further without more
1715
         --  detailed analysis of potential concurrent accesses to the ATCBs
1716
         --  of C and Self_ID.
1717
 
1718
         --  Count how many "alive" dependent tasks this master currently has,
1719
         --  and record this in Wait_Count. This count should start at zero,
1720
         --  since it is initialized to zero for new tasks, and the task should
1721
         --  not exit the sleep-loops that use this count until the count
1722
         --  reaches zero.
1723
 
1724
         pragma Assert (Self_ID.Common.Wait_Count = 0);
1725
 
1726
         Write_Lock (Self_ID);
1727
 
1728
         C := All_Tasks_List;
1729
         while C /= null loop
1730
            if C.Common.Parent = Self_ID and then C.Master_of_Task = CM then
1731
               Write_Lock (C);
1732
 
1733
               pragma Assert (C.Awake_Count = 0);
1734
 
1735
               if C.Alive_Count > 0 then
1736
                  pragma Assert (C.Terminate_Alternative);
1737
                  Self_ID.Common.Wait_Count := Self_ID.Common.Wait_Count + 1;
1738
               end if;
1739
 
1740
               Unlock (C);
1741
            end if;
1742
 
1743
            C := C.Common.All_Tasks_Link;
1744
         end loop;
1745
 
1746
         Self_ID.Common.State := Master_Phase_2_Sleep;
1747
         Unlock (Self_ID);
1748
 
1749
         if not Single_Lock then
1750
            Unlock_RTS;
1751
         end if;
1752
 
1753
         --  Wait for all counted tasks to finish terminating themselves
1754
 
1755
         Write_Lock (Self_ID);
1756
 
1757
         loop
1758
            exit when Self_ID.Common.Wait_Count = 0;
1759
            Sleep (Self_ID, Master_Phase_2_Sleep);
1760
         end loop;
1761
 
1762
         Self_ID.Common.State := Runnable;
1763
         Unlock (Self_ID);
1764
      end if;
1765
 
1766
      --  We don't wake up for abort here. We are already terminating just as
1767
      --  fast as we can, so there is no point.
1768
 
1769
      --  Remove terminated tasks from the list of Self_ID's dependents, but
1770
      --  don't free their ATCBs yet, because of lock order restrictions, which
1771
      --  don't allow us to call "free" or "malloc" while holding any other
1772
      --  locks. Instead, we put those ATCBs to be freed onto a temporary list,
1773
      --  called To_Be_Freed.
1774
 
1775
      if not Single_Lock then
1776
         Lock_RTS;
1777
      end if;
1778
 
1779
      C := All_Tasks_List;
1780
      P := null;
1781
      while C /= null loop
1782
         if C.Common.Parent = Self_ID and then C.Master_of_Task >= CM then
1783
            if P /= null then
1784
               P.Common.All_Tasks_Link := C.Common.All_Tasks_Link;
1785
            else
1786
               All_Tasks_List := C.Common.All_Tasks_Link;
1787
            end if;
1788
 
1789
            T := C.Common.All_Tasks_Link;
1790
            C.Common.All_Tasks_Link := To_Be_Freed;
1791
            To_Be_Freed := C;
1792
            C := T;
1793
 
1794
         else
1795
            P := C;
1796
            C := C.Common.All_Tasks_Link;
1797
         end if;
1798
      end loop;
1799
 
1800
      Unlock_RTS;
1801
 
1802
      --  Free all the ATCBs on the list To_Be_Freed
1803
 
1804
      --  The ATCBs in the list are no longer in All_Tasks_List, and after
1805
      --  any interrupt entries are detached from them they should no longer
1806
      --  be referenced.
1807
 
1808
      --  Global_Task_Lock (Task_Lock/Unlock) is locked in the loop below to
1809
      --  avoid a race between a terminating task and its parent. The parent
1810
      --  might try to deallocate the ACTB out from underneath the exiting
1811
      --  task. Note that Free will also lock Global_Task_Lock, but that is
1812
      --  OK, since this is the *one* lock for which we have a mechanism to
1813
      --  support nested locking. See Task_Wrapper and its finalizer for more
1814
      --  explanation.
1815
 
1816
      --  ???
1817
      --  The check "T.Common.Parent /= null ..." below is to prevent dangling
1818
      --  references to terminated library-level tasks, which could otherwise
1819
      --  occur during finalization of library-level objects. A better solution
1820
      --  might be to hook task objects into the finalization chain and
1821
      --  deallocate the ATCB when the task object is deallocated. However,
1822
      --  this change is not likely to gain anything significant, since all
1823
      --  this storage should be recovered en-masse when the process exits.
1824
 
1825
      while To_Be_Freed /= null loop
1826
         T := To_Be_Freed;
1827
         To_Be_Freed := T.Common.All_Tasks_Link;
1828
 
1829
         --  ??? On SGI there is currently no Interrupt_Manager, that's why we
1830
         --  need to check if the Interrupt_Manager_ID is null.
1831
 
1832
         if T.Interrupt_Entry and then Interrupt_Manager_ID /= null then
1833
            declare
1834
               Detach_Interrupt_Entries_Index : constant Task_Entry_Index := 1;
1835
               --  Corresponds to the entry index of System.Interrupts.
1836
               --  Interrupt_Manager.Detach_Interrupt_Entries.
1837
               --  Be sure to update this value when changing
1838
               --  Interrupt_Manager specs.
1839
 
1840
               type Param_Type is access all Task_Id;
1841
 
1842
               Param : aliased Param_Type := T'Access;
1843
 
1844
            begin
1845
               System.Tasking.Rendezvous.Call_Simple
1846
                 (Interrupt_Manager_ID, Detach_Interrupt_Entries_Index,
1847
                  Param'Address);
1848
            end;
1849
         end if;
1850
 
1851
         if (T.Common.Parent /= null
1852
              and then T.Common.Parent.Common.Parent /= null)
1853
           or else T.Master_of_Task > Library_Task_Level
1854
         then
1855
            Initialization.Task_Lock (Self_ID);
1856
 
1857
            --  If Sec_Stack_Addr is not null, it means that Destroy_TSD
1858
            --  has not been called yet (case of an unactivated task).
1859
 
1860
            if T.Common.Compiler_Data.Sec_Stack_Addr /= Null_Address then
1861
               SSL.Destroy_TSD (T.Common.Compiler_Data);
1862
            end if;
1863
 
1864
            Vulnerable_Free_Task (T);
1865
            Initialization.Task_Unlock (Self_ID);
1866
         end if;
1867
      end loop;
1868
 
1869
      --  It might seem nice to let the terminated task deallocate its own
1870
      --  ATCB. That would not cover the case of unactivated tasks. It also
1871
      --  would force us to keep the underlying thread around past termination,
1872
      --  since references to the ATCB are possible past termination.
1873
 
1874
      --  Currently, we get rid of the thread as soon as the task terminates,
1875
      --  and let the parent recover the ATCB later.
1876
 
1877
      --  Some day, if we want to recover the ATCB earlier, at task
1878
      --  termination, we could consider using "fat task IDs", that include the
1879
      --  serial number with the ATCB pointer, to catch references to tasks
1880
      --  that no longer have ATCBs. It is not clear how much this would gain,
1881
      --  since the user-level task object would still be occupying storage.
1882
 
1883
      --  Make next master level up active. We don't need to lock the ATCB,
1884
      --  since the value is only updated by each task for itself.
1885
 
1886
      Self_ID.Master_Within := CM - 1;
1887
   end Vulnerable_Complete_Master;
1888
 
1889
   ------------------------------
1890
   -- Vulnerable_Complete_Task --
1891
   ------------------------------
1892
 
1893
   --  Complete the calling task
1894
 
1895
   --  This procedure must be called with abort deferred. It should only be
1896
   --  called by Complete_Task and Finalize_Global_Tasks (for the environment
1897
   --  task).
1898
 
1899
   --  The effect is similar to that of Complete_Master. Differences include
1900
   --  the closing of entries here, and computation of the number of active
1901
   --  dependent tasks in Complete_Master.
1902
 
1903
   --  We don't lock Self_ID before the call to Vulnerable_Complete_Activation,
1904
   --  because that does its own locking, and because we do not need the lock
1905
   --  to test Self_ID.Common.Activator. That value should only be read and
1906
   --  modified by Self.
1907
 
1908
   procedure Vulnerable_Complete_Task (Self_ID : Task_Id) is
1909
   begin
1910
      pragma Assert
1911
        (Self_ID.Deferral_Level > 0
1912
          or else not System.Restrictions.Abort_Allowed);
1913
      pragma Assert (Self_ID = Self);
1914
      pragma Assert (Self_ID.Master_Within = Self_ID.Master_of_Task + 1
1915
                       or else
1916
                     Self_ID.Master_Within = Self_ID.Master_of_Task + 2);
1917
      pragma Assert (Self_ID.Common.Wait_Count = 0);
1918
      pragma Assert (Self_ID.Open_Accepts = null);
1919
      pragma Assert (Self_ID.ATC_Nesting_Level = 1);
1920
 
1921
      pragma Debug (Debug.Trace (Self_ID, "V_Complete_Task", 'C'));
1922
 
1923
      if Single_Lock then
1924
         Lock_RTS;
1925
      end if;
1926
 
1927
      Write_Lock (Self_ID);
1928
      Self_ID.Callable := False;
1929
 
1930
      --  In theory, Self should have no pending entry calls left on its
1931
      --  call-stack. Each async. select statement should clean its own call,
1932
      --  and blocking entry calls should defer abort until the calls are
1933
      --  cancelled, then clean up.
1934
 
1935
      Utilities.Cancel_Queued_Entry_Calls (Self_ID);
1936
      Unlock (Self_ID);
1937
 
1938
      if Self_ID.Common.Activator /= null then
1939
         Vulnerable_Complete_Activation (Self_ID);
1940
      end if;
1941
 
1942
      if Single_Lock then
1943
         Unlock_RTS;
1944
      end if;
1945
 
1946
      --  If Self_ID.Master_Within = Self_ID.Master_of_Task + 2 we may have
1947
      --  dependent tasks for which we need to wait. Otherwise we just exit.
1948
 
1949
      if Self_ID.Master_Within = Self_ID.Master_of_Task + 2 then
1950
         Vulnerable_Complete_Master (Self_ID);
1951
      end if;
1952
   end Vulnerable_Complete_Task;
1953
 
1954
   --------------------------
1955
   -- Vulnerable_Free_Task --
1956
   --------------------------
1957
 
1958
   --  Recover all runtime system storage associated with the task T. This
1959
   --  should only be called after T has terminated and will no longer be
1960
   --  referenced.
1961
 
1962
   --  For tasks created by an allocator that fails, due to an exception, it
1963
   --  is called from Expunge_Unactivated_Tasks.
1964
 
1965
   --  For tasks created by elaboration of task object declarations it is
1966
   --  called from the finalization code of the Task_Wrapper procedure. It is
1967
   --  also called from Ada.Unchecked_Deallocation, for objects that are or
1968
   --  contain tasks.
1969
 
1970
   procedure Vulnerable_Free_Task (T : Task_Id) is
1971
   begin
1972
      pragma Debug (Debug.Trace (Self, "Vulnerable_Free_Task", 'C', T));
1973
 
1974
      if Single_Lock then
1975
         Lock_RTS;
1976
      end if;
1977
 
1978
      Write_Lock (T);
1979
      Initialization.Finalize_Attributes_Link.all (T);
1980
      Unlock (T);
1981
 
1982
      if Single_Lock then
1983
         Unlock_RTS;
1984
      end if;
1985
 
1986
      Free_Entry_Names (T);
1987
      System.Task_Primitives.Operations.Finalize_TCB (T);
1988
   end Vulnerable_Free_Task;
1989
 
1990
--  Package elaboration code
1991
 
1992
begin
1993
   --  Establish the Adafinal oftlink
1994
 
1995
   --  This is not done inside the central RTS initialization routine
1996
   --  to avoid with-ing this package from System.Tasking.Initialization.
1997
 
1998
   SSL.Adafinal := Finalize_Global_Tasks'Access;
1999
 
2000
   --  Establish soft links for subprograms that manipulate master_id's.
2001
   --  This cannot be done when the RTS is initialized, because of various
2002
   --  elaboration constraints.
2003
 
2004
   SSL.Current_Master  := Stages.Current_Master'Access;
2005
   SSL.Enter_Master    := Stages.Enter_Master'Access;
2006
   SSL.Complete_Master := Stages.Complete_Master'Access;
2007
end System.Tasking.Stages;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.