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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [gcc/] [ada/] [s-tassta.adb] - Blame information for rev 12

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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