OSDN Git Service

* 1aexcept.adb, 1aexcept.ads, 1ic.ads, 1ssecsta.adb,
[pf3gnuchains/gcc-fork.git] / gcc / ada / 5htaprop.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                GNU ADA RUN-TIME LIBRARY (GNARL) COMPONENTS               --
4 --                                                                          --
5 --     S Y S T E M . T A S K _ P R I M I T I V E S . O P E R A T I O N S    --
6 --                                                                          --
7 --                                  B o d y                                 --
8 --                                                                          --
9 --         Copyright (C) 1992-2001, Free Software Foundation, Inc.          --
10 --                                                                          --
11 -- GNARL is free software; you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
14 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNARL; see file COPYING.  If not, write --
19 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
20 -- MA 02111-1307, USA.                                                      --
21 --                                                                          --
22 -- As a special exception,  if other files  instantiate  generics from this --
23 -- unit, or you link  this unit with other files  to produce an executable, --
24 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
25 -- covered  by the  GNU  General  Public  License.  This exception does not --
26 -- however invalidate  any other reasons why  the executable file  might be --
27 -- covered by the  GNU Public License.                                      --
28 --                                                                          --
29 -- GNARL was developed by the GNARL team at Florida State University.       --
30 -- Extensive contributions were provided by Ada Core Technologies, Inc.     --
31 --                                                                          --
32 ------------------------------------------------------------------------------
33
34 --  This is a HP-UX DCE threads version of this package
35
36 --  This package contains all the GNULL primitives that interface directly
37 --  with the underlying OS.
38
39 pragma Polling (Off);
40 --  Turn off polling, we do not want ATC polling to take place during
41 --  tasking operations. It causes infinite loops and other problems.
42
43 with System.Tasking.Debug;
44 --  used for Known_Tasks
45
46 with Interfaces.C;
47 --  used for int
48 --           size_t
49
50 with System.Interrupt_Management;
51 --  used for Keep_Unmasked
52 --           Abort_Task_Interrupt
53 --           Interrupt_ID
54
55 with System.Interrupt_Management.Operations;
56 --  used for Set_Interrupt_Mask
57 --           All_Tasks_Mask
58 pragma Elaborate_All (System.Interrupt_Management.Operations);
59
60 with System.Parameters;
61 --  used for Size_Type
62
63 with System.Task_Primitives.Interrupt_Operations;
64 --  used for Get_Interrupt_ID
65
66 with System.Tasking;
67 --  used for Ada_Task_Control_Block
68 --           Task_ID
69
70 with System.Soft_Links;
71 --  used for Defer/Undefer_Abort
72
73 --  Note that we do not use System.Tasking.Initialization directly since
74 --  this is a higher level package that we shouldn't depend on. For example
75 --  when using the restricted run time, it is replaced by
76 --  System.Tasking.Restricted.Initialization
77
78 with System.OS_Primitives;
79 --  used for Delay_Modes
80
81 with Unchecked_Conversion;
82 with Unchecked_Deallocation;
83
84 package body System.Task_Primitives.Operations is
85
86    use System.Tasking.Debug;
87    use System.Tasking;
88    use Interfaces.C;
89    use System.OS_Interface;
90    use System.Parameters;
91    use System.OS_Primitives;
92
93    package PIO renames System.Task_Primitives.Interrupt_Operations;
94    package SSL renames System.Soft_Links;
95
96    ------------------
97    --  Local Data  --
98    ------------------
99
100    --  The followings are logically constants, but need to be initialized
101    --  at run time.
102
103    ATCB_Key : aliased pthread_key_t;
104    --  Key used to find the Ada Task_ID associated with a thread
105
106    Single_RTS_Lock : aliased RTS_Lock;
107    --  This is a lock to allow only one thread of control in the RTS at
108    --  a time; it is used to execute in mutual exclusion from all other tasks.
109    --  Used mainly in Single_Lock mode, but also to protect All_Tasks_List
110
111    Environment_Task_ID : Task_ID;
112    --  A variable to hold Task_ID for the environment task.
113
114    Unblocked_Signal_Mask : aliased sigset_t;
115    --  The set of signals that should unblocked in all tasks
116
117    Time_Slice_Val : Integer;
118    pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
119
120    Locking_Policy : Character;
121    pragma Import (C, Locking_Policy, "__gl_locking_policy");
122
123    Dispatching_Policy : Character;
124    pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
125
126    FIFO_Within_Priorities : constant Boolean := Dispatching_Policy = 'F';
127    --  Indicates whether FIFO_Within_Priorities is set.
128
129    --  The followings are internal configuration constants needed.
130
131    -----------------------
132    -- Local Subprograms --
133    -----------------------
134
135    procedure Abort_Handler (Sig : Signal);
136
137    function To_Task_ID is new Unchecked_Conversion (System.Address, Task_ID);
138
139    function To_Address is new Unchecked_Conversion (Task_ID, System.Address);
140
141    -------------------
142    -- Abort_Handler --
143    -------------------
144
145    procedure Abort_Handler (Sig : Signal) is
146       Self_Id : constant Task_ID := Self;
147       Result  : Interfaces.C.int;
148       Old_Set : aliased sigset_t;
149
150    begin
151       if Self_Id.Deferral_Level = 0
152         and then Self_Id.Pending_ATC_Level < Self_Id.ATC_Nesting_Level and then
153         not Self_Id.Aborting
154       then
155          Self_Id.Aborting := True;
156
157          --  Make sure signals used for RTS internal purpose are unmasked
158
159          Result := pthread_sigmask (SIG_UNBLOCK,
160            Unblocked_Signal_Mask'Unchecked_Access, Old_Set'Unchecked_Access);
161          pragma Assert (Result = 0);
162
163          raise Standard'Abort_Signal;
164       end if;
165    end Abort_Handler;
166
167    -----------------
168    -- Stack_Guard --
169    -----------------
170
171    --  The underlying thread system sets a guard page at the
172    --  bottom of a thread stack, so nothing is needed.
173    --  ??? Check the comment above
174
175    procedure Stack_Guard (T : ST.Task_ID; On : Boolean) is
176    begin
177       null;
178    end Stack_Guard;
179
180    -------------------
181    -- Get_Thread_Id --
182    -------------------
183
184    function Get_Thread_Id (T : ST.Task_ID) return OSI.Thread_Id is
185    begin
186       return T.Common.LL.Thread;
187    end Get_Thread_Id;
188
189    ----------
190    -- Self --
191    ----------
192
193    function Self return Task_ID is
194       Result : System.Address;
195    begin
196       Result := pthread_getspecific (ATCB_Key);
197       pragma Assert (Result /= System.Null_Address);
198       return To_Task_ID (Result);
199    end Self;
200
201    ---------------------
202    -- Initialize_Lock --
203    ---------------------
204
205    --  Note: mutexes and cond_variables needed per-task basis are
206    --        initialized in Initialize_TCB and the Storage_Error is
207    --        handled. Other mutexes (such as RTS_Lock, Memory_Lock...)
208    --        used in RTS is initialized before any status change of RTS.
209    --        Therefore rasing Storage_Error in the following routines
210    --        should be able to be handled safely.
211
212    procedure Initialize_Lock
213      (Prio : System.Any_Priority;
214       L    : access Lock)
215    is
216       Attributes : aliased pthread_mutexattr_t;
217       Result     : Interfaces.C.int;
218
219    begin
220       Result := pthread_mutexattr_init (Attributes'Access);
221       pragma Assert (Result = 0 or else Result = ENOMEM);
222
223       if Result = ENOMEM then
224          raise Storage_Error;
225       end if;
226
227       L.Priority := Prio;
228
229       Result := pthread_mutex_init (L.L'Access, Attributes'Access);
230       pragma Assert (Result = 0 or else Result = ENOMEM);
231
232       if Result = ENOMEM then
233          raise Storage_Error;
234       end if;
235
236       Result := pthread_mutexattr_destroy (Attributes'Access);
237       pragma Assert (Result = 0);
238    end Initialize_Lock;
239
240    procedure Initialize_Lock (L : access RTS_Lock; Level : Lock_Level) is
241       Attributes : aliased pthread_mutexattr_t;
242       Result     : Interfaces.C.int;
243
244    begin
245       Result := pthread_mutexattr_init (Attributes'Access);
246       pragma Assert (Result = 0 or else Result = ENOMEM);
247
248       if Result = ENOMEM then
249          raise Storage_Error;
250       end if;
251
252       Result := pthread_mutex_init (L, Attributes'Access);
253
254       pragma Assert (Result = 0 or else Result = ENOMEM);
255
256       if Result = ENOMEM then
257          raise Storage_Error;
258       end if;
259
260       Result := pthread_mutexattr_destroy (Attributes'Access);
261       pragma Assert (Result = 0);
262    end Initialize_Lock;
263
264    -------------------
265    -- Finalize_Lock --
266    -------------------
267
268    procedure Finalize_Lock (L : access Lock) is
269       Result : Interfaces.C.int;
270    begin
271       Result := pthread_mutex_destroy (L.L'Access);
272       pragma Assert (Result = 0);
273    end Finalize_Lock;
274
275    procedure Finalize_Lock (L : access RTS_Lock) is
276       Result : Interfaces.C.int;
277    begin
278       Result := pthread_mutex_destroy (L);
279       pragma Assert (Result = 0);
280    end Finalize_Lock;
281
282    ----------------
283    -- Write_Lock --
284    ----------------
285
286    procedure Write_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
287       Result : Interfaces.C.int;
288    begin
289       L.Owner_Priority := Get_Priority (Self);
290
291       if L.Priority < L.Owner_Priority then
292          Ceiling_Violation := True;
293          return;
294       end if;
295
296       Result := pthread_mutex_lock (L.L'Access);
297       pragma Assert (Result = 0);
298       Ceiling_Violation := False;
299    end Write_Lock;
300
301    procedure Write_Lock
302      (L : access RTS_Lock; Global_Lock : Boolean := False)
303    is
304       Result : Interfaces.C.int;
305    begin
306       if not Single_Lock or else Global_Lock then
307          Result := pthread_mutex_lock (L);
308          pragma Assert (Result = 0);
309       end if;
310    end Write_Lock;
311
312    procedure Write_Lock (T : Task_ID) is
313       Result : Interfaces.C.int;
314    begin
315       if not Single_Lock then
316          Result := pthread_mutex_lock (T.Common.LL.L'Access);
317          pragma Assert (Result = 0);
318       end if;
319    end Write_Lock;
320
321    ---------------
322    -- Read_Lock --
323    ---------------
324
325    procedure Read_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
326    begin
327       Write_Lock (L, Ceiling_Violation);
328    end Read_Lock;
329
330    ------------
331    -- Unlock --
332    ------------
333
334    procedure Unlock (L : access Lock) is
335       Result : Interfaces.C.int;
336    begin
337       Result := pthread_mutex_unlock (L.L'Access);
338       pragma Assert (Result = 0);
339    end Unlock;
340
341    procedure Unlock (L : access RTS_Lock; Global_Lock : Boolean := False) is
342       Result : Interfaces.C.int;
343    begin
344       if not Single_Lock or else Global_Lock then
345          Result := pthread_mutex_unlock (L);
346          pragma Assert (Result = 0);
347       end if;
348    end Unlock;
349
350    procedure Unlock (T : Task_ID) is
351       Result : Interfaces.C.int;
352    begin
353       if not Single_Lock then
354          Result := pthread_mutex_unlock (T.Common.LL.L'Access);
355          pragma Assert (Result = 0);
356       end if;
357    end Unlock;
358
359    -----------
360    -- Sleep --
361    -----------
362
363    procedure Sleep
364      (Self_ID : Task_ID;
365       Reason  : System.Tasking.Task_States)
366    is
367       Result : Interfaces.C.int;
368    begin
369       if Single_Lock then
370          Result := pthread_cond_wait
371            (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access);
372       else
373          Result := pthread_cond_wait
374            (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
375       end if;
376
377       --  EINTR is not considered a failure.
378       pragma Assert (Result = 0 or else Result = EINTR);
379    end Sleep;
380
381    -----------------
382    -- Timed_Sleep --
383    -----------------
384
385    procedure Timed_Sleep
386      (Self_ID  : Task_ID;
387       Time     : Duration;
388       Mode     : ST.Delay_Modes;
389       Reason   : System.Tasking.Task_States;
390       Timedout : out Boolean;
391       Yielded  : out Boolean)
392    is
393       Check_Time : constant Duration := Monotonic_Clock;
394       Abs_Time   : Duration;
395       Request    : aliased timespec;
396       Result     : Interfaces.C.int;
397
398    begin
399       Timedout := True;
400       Yielded := False;
401
402       if Mode = Relative then
403          Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
404       else
405          Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
406       end if;
407
408       if Abs_Time > Check_Time then
409          Request := To_Timespec (Abs_Time);
410
411          loop
412             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
413               or else Self_ID.Pending_Priority_Change;
414
415             if Single_Lock then
416                Result := pthread_cond_timedwait
417                  (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access,
418                   Request'Access);
419
420             else
421                Result := pthread_cond_timedwait
422                  (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access,
423                   Request'Access);
424             end if;
425
426             exit when Abs_Time <= Monotonic_Clock;
427
428             if Result = 0 or Result = EINTR then
429                --  somebody may have called Wakeup for us
430                Timedout := False;
431                exit;
432             end if;
433
434             pragma Assert (Result = ETIMEDOUT);
435          end loop;
436       end if;
437    end Timed_Sleep;
438
439    -----------------
440    -- Timed_Delay --
441    -----------------
442
443    procedure Timed_Delay
444      (Self_ID  : Task_ID;
445       Time     : Duration;
446       Mode     : ST.Delay_Modes)
447    is
448       Check_Time : constant Duration := Monotonic_Clock;
449       Abs_Time   : Duration;
450       Request    : aliased timespec;
451       Result     : Interfaces.C.int;
452
453    begin
454       --  Only the little window between deferring abort and
455       --  locking Self_ID is the reason we need to
456       --  check for pending abort and priority change below! :(
457
458       SSL.Abort_Defer.all;
459
460       if Single_Lock then
461          Lock_RTS;
462       end if;
463
464       Write_Lock (Self_ID);
465
466       if Mode = Relative then
467          Abs_Time := Time + Check_Time;
468       else
469          Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
470       end if;
471
472       if Abs_Time > Check_Time then
473          Request := To_Timespec (Abs_Time);
474          Self_ID.Common.State := Delay_Sleep;
475
476          loop
477             if Self_ID.Pending_Priority_Change then
478                Self_ID.Pending_Priority_Change := False;
479                Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
480                Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
481             end if;
482
483             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
484
485             if Single_Lock then
486                Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
487                  Single_RTS_Lock'Access, Request'Access);
488             else
489                Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
490                  Self_ID.Common.LL.L'Access, Request'Access);
491             end if;
492
493             exit when Abs_Time <= Monotonic_Clock;
494
495             pragma Assert (Result = 0 or else
496               Result = ETIMEDOUT or else
497               Result = EINTR);
498          end loop;
499
500          Self_ID.Common.State := Runnable;
501       end if;
502
503       Unlock (Self_ID);
504
505       if Single_Lock then
506          Unlock_RTS;
507       end if;
508
509       Result := sched_yield;
510       SSL.Abort_Undefer.all;
511    end Timed_Delay;
512
513    ---------------------
514    -- Monotonic_Clock --
515    ---------------------
516
517    function Monotonic_Clock return Duration is
518       TS     : aliased timespec;
519       Result : Interfaces.C.int;
520
521    begin
522       Result := Clock_Gettime (CLOCK_REALTIME, TS'Unchecked_Access);
523       pragma Assert (Result = 0);
524       return To_Duration (TS);
525    end Monotonic_Clock;
526
527    -------------------
528    -- RT_Resolution --
529    -------------------
530
531    function RT_Resolution return Duration is
532    begin
533       return 10#1.0#E-6;
534    end RT_Resolution;
535
536    ------------
537    -- Wakeup --
538    ------------
539
540    procedure Wakeup (T : Task_ID; Reason : System.Tasking.Task_States) is
541       Result : Interfaces.C.int;
542    begin
543       Result := pthread_cond_signal (T.Common.LL.CV'Access);
544       pragma Assert (Result = 0);
545    end Wakeup;
546
547    -----------
548    -- Yield --
549    -----------
550
551    procedure Yield (Do_Yield : Boolean := True) is
552       Result : Interfaces.C.int;
553    begin
554       if Do_Yield then
555          Result := sched_yield;
556       end if;
557    end Yield;
558
559    ------------------
560    -- Set_Priority --
561    ------------------
562
563    type Prio_Array_Type is array (System.Any_Priority) of Integer;
564    pragma Atomic_Components (Prio_Array_Type);
565
566    Prio_Array : Prio_Array_Type;
567    --  Global array containing the id of the currently running task for
568    --  each priority.
569    --
570    --  Note: we assume that we are on a single processor with run-til-blocked
571    --  scheduling.
572
573    procedure Set_Priority
574      (T : Task_ID;
575       Prio : System.Any_Priority;
576       Loss_Of_Inheritance : Boolean := False)
577    is
578       Result     : Interfaces.C.int;
579       Array_Item : Integer;
580       Param      : aliased struct_sched_param;
581
582    begin
583       Param.sched_priority  := Interfaces.C.int (Underlying_Priorities (Prio));
584
585       if Time_Slice_Val > 0 then
586          Result := pthread_setschedparam
587            (T.Common.LL.Thread, SCHED_RR, Param'Access);
588
589       elsif FIFO_Within_Priorities or else Time_Slice_Val = 0 then
590          Result := pthread_setschedparam
591            (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
592
593       else
594          Result := pthread_setschedparam
595            (T.Common.LL.Thread, SCHED_OTHER, Param'Access);
596       end if;
597
598       pragma Assert (Result = 0);
599
600       if FIFO_Within_Priorities then
601
602          --  Annex D requirement [RM D.2.2 par. 9]:
603          --    If the task drops its priority due to the loss of inherited
604          --    priority, it is added at the head of the ready queue for its
605          --    new active priority.
606
607          if Loss_Of_Inheritance
608            and then Prio < T.Common.Current_Priority
609          then
610             Array_Item := Prio_Array (T.Common.Base_Priority) + 1;
611             Prio_Array (T.Common.Base_Priority) := Array_Item;
612
613             loop
614                --  Let some processes a chance to arrive
615
616                Yield;
617
618                --  Then wait for our turn to proceed
619
620                exit when Array_Item = Prio_Array (T.Common.Base_Priority)
621                  or else Prio_Array (T.Common.Base_Priority) = 1;
622             end loop;
623
624             Prio_Array (T.Common.Base_Priority) :=
625               Prio_Array (T.Common.Base_Priority) - 1;
626          end if;
627       end if;
628
629       T.Common.Current_Priority := Prio;
630    end Set_Priority;
631
632    ------------------
633    -- Get_Priority --
634    ------------------
635
636    function Get_Priority (T : Task_ID) return System.Any_Priority is
637    begin
638       return T.Common.Current_Priority;
639    end Get_Priority;
640
641    ----------------
642    -- Enter_Task --
643    ----------------
644
645    procedure Enter_Task (Self_ID : Task_ID) is
646       Result  : Interfaces.C.int;
647
648    begin
649       Self_ID.Common.LL.Thread := pthread_self;
650
651       Result := pthread_setspecific (ATCB_Key, To_Address (Self_ID));
652       pragma Assert (Result = 0);
653
654       Lock_RTS;
655
656       for J in Known_Tasks'Range loop
657          if Known_Tasks (J) = null then
658             Known_Tasks (J) := Self_ID;
659             Self_ID.Known_Tasks_Index := J;
660             exit;
661          end if;
662       end loop;
663
664       Unlock_RTS;
665    end Enter_Task;
666
667    --------------
668    -- New_ATCB --
669    --------------
670
671    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_ID is
672    begin
673       return new Ada_Task_Control_Block (Entry_Num);
674    end New_ATCB;
675
676    --------------------
677    -- Initialize_TCB --
678    --------------------
679
680    procedure Initialize_TCB (Self_ID : Task_ID; Succeeded : out Boolean) is
681       Mutex_Attr : aliased pthread_mutexattr_t;
682       Result     : Interfaces.C.int;
683       Cond_Attr  : aliased pthread_condattr_t;
684
685    begin
686       if not Single_Lock then
687          Result := pthread_mutexattr_init (Mutex_Attr'Access);
688          pragma Assert (Result = 0 or else Result = ENOMEM);
689
690          if Result = 0 then
691             Result := pthread_mutex_init (Self_ID.Common.LL.L'Access,
692               Mutex_Attr'Access);
693             pragma Assert (Result = 0 or else Result = ENOMEM);
694          end if;
695
696          if Result /= 0 then
697             Succeeded := False;
698             return;
699          end if;
700
701          Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
702          pragma Assert (Result = 0);
703       end if;
704
705       Result := pthread_condattr_init (Cond_Attr'Access);
706       pragma Assert (Result = 0 or else Result = ENOMEM);
707
708       if Result = 0 then
709          Result := pthread_cond_init (Self_ID.Common.LL.CV'Access,
710            Cond_Attr'Access);
711          pragma Assert (Result = 0 or else Result = ENOMEM);
712       end if;
713
714       if Result = 0 then
715          Succeeded := True;
716       else
717          if not Single_Lock then
718             Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
719             pragma Assert (Result = 0);
720          end if;
721
722          Succeeded := False;
723       end if;
724
725       Result := pthread_condattr_destroy (Cond_Attr'Access);
726       pragma Assert (Result = 0);
727    end Initialize_TCB;
728
729    -----------------
730    -- Create_Task --
731    -----------------
732
733    procedure Create_Task
734      (T          : Task_ID;
735       Wrapper    : System.Address;
736       Stack_Size : System.Parameters.Size_Type;
737       Priority   : System.Any_Priority;
738       Succeeded  : out Boolean)
739    is
740       Attributes          : aliased pthread_attr_t;
741       Adjusted_Stack_Size : Interfaces.C.size_t;
742       Result              : Interfaces.C.int;
743
744       function Thread_Body_Access is new
745         Unchecked_Conversion (System.Address, Thread_Body);
746
747    begin
748       if Stack_Size = Unspecified_Size then
749          Adjusted_Stack_Size := Interfaces.C.size_t (Default_Stack_Size);
750
751       elsif Stack_Size < Minimum_Stack_Size then
752          Adjusted_Stack_Size := Interfaces.C.size_t (Minimum_Stack_Size);
753
754       else
755          Adjusted_Stack_Size := Interfaces.C.size_t (Stack_Size);
756       end if;
757
758       Result := pthread_attr_init (Attributes'Access);
759       pragma Assert (Result = 0 or else Result = ENOMEM);
760
761       if Result /= 0 then
762          Succeeded := False;
763          return;
764       end if;
765
766       Result := pthread_attr_setstacksize
767         (Attributes'Access, Adjusted_Stack_Size);
768       pragma Assert (Result = 0);
769
770       --  Since the initial signal mask of a thread is inherited from the
771       --  creator, and the Environment task has all its signals masked, we
772       --  do not need to manipulate caller's signal mask at this point.
773       --  All tasks in RTS will have All_Tasks_Mask initially.
774
775       Result := pthread_create
776         (T.Common.LL.Thread'Access,
777          Attributes'Access,
778          Thread_Body_Access (Wrapper),
779          To_Address (T));
780       pragma Assert (Result = 0 or else Result = EAGAIN);
781
782       Succeeded := Result = 0;
783
784       pthread_detach (T.Common.LL.Thread'Access);
785       --  Detach the thread using pthread_detach, sinc DCE threads do not have
786       --  pthread_attr_set_detachstate.
787
788       Result := pthread_attr_destroy (Attributes'Access);
789       pragma Assert (Result = 0);
790
791       Set_Priority (T, Priority);
792    end Create_Task;
793
794    ------------------
795    -- Finalize_TCB --
796    ------------------
797
798    procedure Finalize_TCB (T : Task_ID) is
799       Result : Interfaces.C.int;
800       Tmp    : Task_ID := T;
801
802       procedure Free is new
803         Unchecked_Deallocation (Ada_Task_Control_Block, Task_ID);
804
805    begin
806       if not Single_Lock then
807          Result := pthread_mutex_destroy (T.Common.LL.L'Access);
808          pragma Assert (Result = 0);
809       end if;
810
811       Result := pthread_cond_destroy (T.Common.LL.CV'Access);
812       pragma Assert (Result = 0);
813
814       if T.Known_Tasks_Index /= -1 then
815          Known_Tasks (T.Known_Tasks_Index) := null;
816       end if;
817
818       Free (Tmp);
819    end Finalize_TCB;
820
821    ---------------
822    -- Exit_Task --
823    ---------------
824
825    procedure Exit_Task is
826    begin
827       pthread_exit (System.Null_Address);
828    end Exit_Task;
829
830    ----------------
831    -- Abort_Task --
832    ----------------
833
834    procedure Abort_Task (T : Task_ID) is
835    begin
836       --
837       --  Interrupt Server_Tasks may be waiting on an "event" flag (signal)
838       --
839       if T.Common.State = Interrupt_Server_Blocked_On_Event_Flag then
840          System.Interrupt_Management.Operations.Interrupt_Self_Process
841            (System.Interrupt_Management.Interrupt_ID
842              (PIO.Get_Interrupt_ID (T)));
843       end if;
844    end Abort_Task;
845
846    ----------------
847    -- Check_Exit --
848    ----------------
849
850    --  Dummy versions.  The only currently working versions is for solaris
851    --  (native).
852
853    function Check_Exit (Self_ID : ST.Task_ID) return Boolean is
854    begin
855       return True;
856    end Check_Exit;
857
858    --------------------
859    -- Check_No_Locks --
860    --------------------
861
862    function Check_No_Locks (Self_ID : ST.Task_ID) return Boolean is
863    begin
864       return True;
865    end Check_No_Locks;
866
867    ----------------------
868    -- Environment_Task --
869    ----------------------
870
871    function Environment_Task return Task_ID is
872    begin
873       return Environment_Task_ID;
874    end Environment_Task;
875
876    --------------
877    -- Lock_RTS --
878    --------------
879
880    procedure Lock_RTS is
881    begin
882       Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
883    end Lock_RTS;
884
885    ----------------
886    -- Unlock_RTS --
887    ----------------
888
889    procedure Unlock_RTS is
890    begin
891       Unlock (Single_RTS_Lock'Access, Global_Lock => True);
892    end Unlock_RTS;
893
894    ------------------
895    -- Suspend_Task --
896    ------------------
897
898    function Suspend_Task
899      (T           : ST.Task_ID;
900       Thread_Self : Thread_Id) return Boolean is
901    begin
902       return False;
903    end Suspend_Task;
904
905    -----------------
906    -- Resume_Task --
907    -----------------
908
909    function Resume_Task
910      (T           : ST.Task_ID;
911       Thread_Self : Thread_Id) return Boolean is
912    begin
913       return False;
914    end Resume_Task;
915
916    ----------------
917    -- Initialize --
918    ----------------
919
920    procedure Initialize (Environment_Task : Task_ID) is
921       act       : aliased struct_sigaction;
922       old_act   : aliased struct_sigaction;
923       Tmp_Set   : aliased sigset_t;
924       Result    : Interfaces.C.int;
925
926    begin
927
928       Environment_Task_ID := Environment_Task;
929
930       Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
931       --  Initialize the lock used to synchronize chain of all ATCBs.
932
933       Enter_Task (Environment_Task);
934
935       --  Install the abort-signal handler
936
937       act.sa_flags := 0;
938       act.sa_handler := Abort_Handler'Address;
939
940       Result := sigemptyset (Tmp_Set'Access);
941       pragma Assert (Result = 0);
942       act.sa_mask := Tmp_Set;
943
944       Result :=
945         sigaction (
946           Signal (System.Interrupt_Management.Abort_Task_Interrupt),
947           act'Unchecked_Access,
948           old_act'Unchecked_Access);
949       pragma Assert (Result = 0);
950    end Initialize;
951
952    procedure do_nothing (arg : System.Address);
953
954    procedure do_nothing (arg : System.Address) is
955    begin
956       null;
957    end do_nothing;
958
959 begin
960    declare
961       Result : Interfaces.C.int;
962    begin
963       --  NOTE: Unlike other pthread implementations, we do *not* mask all
964       --  signals here since we handle signals using the process-wide primitive
965       --  signal, rather than using sigthreadmask and sigwait. The reason of
966       --  this difference is that sigwait doesn't work when some critical
967       --  signals (SIGABRT, SIGPIPE) are masked.
968
969       Result := pthread_key_create (ATCB_Key'Access, do_nothing'Access);
970       pragma Assert (Result = 0);
971    end;
972 end System.Task_Primitives.Operations;