OSDN Git Service

Update FSF address
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-taprop-hpux-dce.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                 GNAT 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-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 --  This is a HP-UX DCE threads (HPUX 10) 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.Stages.
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    Single_RTS_Lock : aliased RTS_Lock;
104    --  This is a lock to allow only one thread of control in the RTS at
105    --  a time; it is used to execute in mutual exclusion from all other tasks.
106    --  Used mainly in Single_Lock mode, but also to protect All_Tasks_List
107
108    ATCB_Key : aliased pthread_key_t;
109    --  Key used to find the Ada Task_Id associated with a thread
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    Dispatching_Policy : Character;
121    pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
122
123    --  Note: the reason that Locking_Policy is not needed is that this
124    --  is not implemented for DCE threads. The HPUX 10 port is at this
125    --  stage considered dead, and no further work is planned on it.
126
127    FIFO_Within_Priorities : constant Boolean := Dispatching_Policy = 'F';
128    --  Indicates whether FIFO_Within_Priorities is set
129
130    Foreign_Task_Elaborated : aliased Boolean := True;
131    --  Used to identified fake tasks (i.e., non-Ada Threads)
132
133    --------------------
134    -- Local Packages --
135    --------------------
136
137    package Specific is
138
139       procedure Initialize (Environment_Task : Task_Id);
140       pragma Inline (Initialize);
141       --  Initialize various data needed by this package
142
143       function Is_Valid_Task return Boolean;
144       pragma Inline (Is_Valid_Task);
145       --  Does the executing thread have a TCB?
146
147       procedure Set (Self_Id : Task_Id);
148       pragma Inline (Set);
149       --  Set the self id for the current task
150
151       function Self return Task_Id;
152       pragma Inline (Self);
153       --  Return a pointer to the Ada Task Control Block of the calling task
154
155    end Specific;
156
157    package body Specific is separate;
158    --  The body of this package is target specific
159
160    ---------------------------------
161    -- Support for foreign threads --
162    ---------------------------------
163
164    function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
165    --  Allocate and Initialize a new ATCB for the current Thread
166
167    function Register_Foreign_Thread
168      (Thread : Thread_Id) return Task_Id is separate;
169
170    -----------------------
171    -- Local Subprograms --
172    -----------------------
173
174    procedure Abort_Handler (Sig : Signal);
175
176    function To_Address is new Unchecked_Conversion (Task_Id, System.Address);
177
178    -------------------
179    -- Abort_Handler --
180    -------------------
181
182    procedure Abort_Handler (Sig : Signal) is
183       pragma Unreferenced (Sig);
184
185       Self_Id : constant Task_Id := Self;
186       Result  : Interfaces.C.int;
187       Old_Set : aliased sigset_t;
188
189    begin
190       if Self_Id.Deferral_Level = 0
191         and then Self_Id.Pending_ATC_Level < Self_Id.ATC_Nesting_Level and then
192         not Self_Id.Aborting
193       then
194          Self_Id.Aborting := True;
195
196          --  Make sure signals used for RTS internal purpose are unmasked
197
198          Result := pthread_sigmask (SIG_UNBLOCK,
199            Unblocked_Signal_Mask'Unchecked_Access, Old_Set'Unchecked_Access);
200          pragma Assert (Result = 0);
201
202          raise Standard'Abort_Signal;
203       end if;
204    end Abort_Handler;
205
206    -----------------
207    -- Stack_Guard --
208    -----------------
209
210    --  The underlying thread system sets a guard page at the
211    --  bottom of a thread stack, so nothing is needed.
212    --  ??? Check the comment above
213
214    procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is
215       pragma Unreferenced (T, On);
216    begin
217       null;
218    end Stack_Guard;
219
220    -------------------
221    -- Get_Thread_Id --
222    -------------------
223
224    function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is
225    begin
226       return T.Common.LL.Thread;
227    end Get_Thread_Id;
228
229    ----------
230    -- Self --
231    ----------
232
233    function Self return Task_Id renames Specific.Self;
234
235    ---------------------
236    -- Initialize_Lock --
237    ---------------------
238
239    --  Note: mutexes and cond_variables needed per-task basis are
240    --        initialized in Initialize_TCB and the Storage_Error is
241    --        handled. Other mutexes (such as RTS_Lock, Memory_Lock...)
242    --        used in RTS is initialized before any status change of RTS.
243    --        Therefore rasing Storage_Error in the following routines
244    --        should be able to be handled safely.
245
246    procedure Initialize_Lock
247      (Prio : System.Any_Priority;
248       L    : access Lock)
249    is
250       Attributes : aliased pthread_mutexattr_t;
251       Result     : Interfaces.C.int;
252
253    begin
254       Result := pthread_mutexattr_init (Attributes'Access);
255       pragma Assert (Result = 0 or else Result = ENOMEM);
256
257       if Result = ENOMEM then
258          raise Storage_Error;
259       end if;
260
261       L.Priority := Prio;
262
263       Result := pthread_mutex_init (L.L'Access, Attributes'Access);
264       pragma Assert (Result = 0 or else Result = ENOMEM);
265
266       if Result = ENOMEM then
267          raise Storage_Error;
268       end if;
269
270       Result := pthread_mutexattr_destroy (Attributes'Access);
271       pragma Assert (Result = 0);
272    end Initialize_Lock;
273
274    procedure Initialize_Lock (L : access RTS_Lock; Level : Lock_Level) is
275       pragma Unreferenced (Level);
276
277       Attributes : aliased pthread_mutexattr_t;
278       Result     : Interfaces.C.int;
279
280    begin
281       Result := pthread_mutexattr_init (Attributes'Access);
282       pragma Assert (Result = 0 or else Result = ENOMEM);
283
284       if Result = ENOMEM then
285          raise Storage_Error;
286       end if;
287
288       Result := pthread_mutex_init (L, Attributes'Access);
289
290       pragma Assert (Result = 0 or else Result = ENOMEM);
291
292       if Result = ENOMEM then
293          raise Storage_Error;
294       end if;
295
296       Result := pthread_mutexattr_destroy (Attributes'Access);
297       pragma Assert (Result = 0);
298    end Initialize_Lock;
299
300    -------------------
301    -- Finalize_Lock --
302    -------------------
303
304    procedure Finalize_Lock (L : access Lock) is
305       Result : Interfaces.C.int;
306    begin
307       Result := pthread_mutex_destroy (L.L'Access);
308       pragma Assert (Result = 0);
309    end Finalize_Lock;
310
311    procedure Finalize_Lock (L : access RTS_Lock) is
312       Result : Interfaces.C.int;
313    begin
314       Result := pthread_mutex_destroy (L);
315       pragma Assert (Result = 0);
316    end Finalize_Lock;
317
318    ----------------
319    -- Write_Lock --
320    ----------------
321
322    procedure Write_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
323       Result : Interfaces.C.int;
324
325    begin
326       L.Owner_Priority := Get_Priority (Self);
327
328       if L.Priority < L.Owner_Priority then
329          Ceiling_Violation := True;
330          return;
331       end if;
332
333       Result := pthread_mutex_lock (L.L'Access);
334       pragma Assert (Result = 0);
335       Ceiling_Violation := False;
336    end Write_Lock;
337
338    procedure Write_Lock
339      (L : access RTS_Lock; Global_Lock : Boolean := False)
340    is
341       Result : Interfaces.C.int;
342    begin
343       if not Single_Lock or else Global_Lock then
344          Result := pthread_mutex_lock (L);
345          pragma Assert (Result = 0);
346       end if;
347    end Write_Lock;
348
349    procedure Write_Lock (T : Task_Id) is
350       Result : Interfaces.C.int;
351    begin
352       if not Single_Lock then
353          Result := pthread_mutex_lock (T.Common.LL.L'Access);
354          pragma Assert (Result = 0);
355       end if;
356    end Write_Lock;
357
358    ---------------
359    -- Read_Lock --
360    ---------------
361
362    procedure Read_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
363    begin
364       Write_Lock (L, Ceiling_Violation);
365    end Read_Lock;
366
367    ------------
368    -- Unlock --
369    ------------
370
371    procedure Unlock (L : access Lock) is
372       Result : Interfaces.C.int;
373    begin
374       Result := pthread_mutex_unlock (L.L'Access);
375       pragma Assert (Result = 0);
376    end Unlock;
377
378    procedure Unlock (L : access RTS_Lock; Global_Lock : Boolean := False) is
379       Result : Interfaces.C.int;
380    begin
381       if not Single_Lock or else Global_Lock then
382          Result := pthread_mutex_unlock (L);
383          pragma Assert (Result = 0);
384       end if;
385    end Unlock;
386
387    procedure Unlock (T : Task_Id) is
388       Result : Interfaces.C.int;
389    begin
390       if not Single_Lock then
391          Result := pthread_mutex_unlock (T.Common.LL.L'Access);
392          pragma Assert (Result = 0);
393       end if;
394    end Unlock;
395
396    -----------
397    -- Sleep --
398    -----------
399
400    procedure Sleep
401      (Self_ID : Task_Id;
402       Reason  : System.Tasking.Task_States)
403    is
404       pragma Unreferenced (Reason);
405
406       Result : Interfaces.C.int;
407    begin
408       if Single_Lock then
409          Result := pthread_cond_wait
410            (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access);
411       else
412          Result := pthread_cond_wait
413            (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
414       end if;
415
416       --  EINTR is not considered a failure
417
418       pragma Assert (Result = 0 or else Result = EINTR);
419    end Sleep;
420
421    -----------------
422    -- Timed_Sleep --
423    -----------------
424
425    procedure Timed_Sleep
426      (Self_ID  : Task_Id;
427       Time     : Duration;
428       Mode     : ST.Delay_Modes;
429       Reason   : System.Tasking.Task_States;
430       Timedout : out Boolean;
431       Yielded  : out Boolean)
432    is
433       pragma Unreferenced (Reason);
434
435       Check_Time : constant Duration := Monotonic_Clock;
436       Abs_Time   : Duration;
437       Request    : aliased timespec;
438       Result     : Interfaces.C.int;
439
440    begin
441       Timedout := True;
442       Yielded := False;
443
444       if Mode = Relative then
445          Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
446       else
447          Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
448       end if;
449
450       if Abs_Time > Check_Time then
451          Request := To_Timespec (Abs_Time);
452
453          loop
454             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
455               or else Self_ID.Pending_Priority_Change;
456
457             if Single_Lock then
458                Result := pthread_cond_timedwait
459                  (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access,
460                   Request'Access);
461
462             else
463                Result := pthread_cond_timedwait
464                  (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access,
465                   Request'Access);
466             end if;
467
468             exit when Abs_Time <= Monotonic_Clock;
469
470             if Result = 0 or Result = EINTR then
471
472                --  Somebody may have called Wakeup for us
473
474                Timedout := False;
475                exit;
476             end if;
477
478             pragma Assert (Result = ETIMEDOUT);
479          end loop;
480       end if;
481    end Timed_Sleep;
482
483    -----------------
484    -- Timed_Delay --
485    -----------------
486
487    procedure Timed_Delay
488      (Self_ID  : Task_Id;
489       Time     : Duration;
490       Mode     : ST.Delay_Modes)
491    is
492       Check_Time : constant Duration := Monotonic_Clock;
493       Abs_Time   : Duration;
494       Request    : aliased timespec;
495       Result     : Interfaces.C.int;
496
497    begin
498       --  The little window between deferring abort and locking Self_ID is the
499       --  only reason to check for pending abort and priority change below!
500
501       SSL.Abort_Defer.all;
502
503       if Single_Lock then
504          Lock_RTS;
505       end if;
506
507       Write_Lock (Self_ID);
508
509       if Mode = Relative then
510          Abs_Time := Time + Check_Time;
511       else
512          Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
513       end if;
514
515       if Abs_Time > Check_Time then
516          Request := To_Timespec (Abs_Time);
517          Self_ID.Common.State := Delay_Sleep;
518
519          loop
520             if Self_ID.Pending_Priority_Change then
521                Self_ID.Pending_Priority_Change := False;
522                Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
523                Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
524             end if;
525
526             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
527
528             if Single_Lock then
529                Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
530                  Single_RTS_Lock'Access, Request'Access);
531             else
532                Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
533                  Self_ID.Common.LL.L'Access, Request'Access);
534             end if;
535
536             exit when Abs_Time <= Monotonic_Clock;
537
538             pragma Assert (Result = 0 or else
539               Result = ETIMEDOUT or else
540               Result = EINTR);
541          end loop;
542
543          Self_ID.Common.State := Runnable;
544       end if;
545
546       Unlock (Self_ID);
547
548       if Single_Lock then
549          Unlock_RTS;
550       end if;
551
552       Result := sched_yield;
553       SSL.Abort_Undefer.all;
554    end Timed_Delay;
555
556    ---------------------
557    -- Monotonic_Clock --
558    ---------------------
559
560    function Monotonic_Clock return Duration is
561       TS     : aliased timespec;
562       Result : Interfaces.C.int;
563    begin
564       Result := Clock_Gettime (CLOCK_REALTIME, TS'Unchecked_Access);
565       pragma Assert (Result = 0);
566       return To_Duration (TS);
567    end Monotonic_Clock;
568
569    -------------------
570    -- RT_Resolution --
571    -------------------
572
573    function RT_Resolution return Duration is
574    begin
575       return 10#1.0#E-6;
576    end RT_Resolution;
577
578    ------------
579    -- Wakeup --
580    ------------
581
582    procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
583       pragma Unreferenced (Reason);
584
585       Result : Interfaces.C.int;
586
587    begin
588       Result := pthread_cond_signal (T.Common.LL.CV'Access);
589       pragma Assert (Result = 0);
590    end Wakeup;
591
592    -----------
593    -- Yield --
594    -----------
595
596    procedure Yield (Do_Yield : Boolean := True) is
597       Result : Interfaces.C.int;
598       pragma Unreferenced (Result);
599    begin
600       if Do_Yield then
601          Result := sched_yield;
602       end if;
603    end Yield;
604
605    ------------------
606    -- Set_Priority --
607    ------------------
608
609    type Prio_Array_Type is array (System.Any_Priority) of Integer;
610    pragma Atomic_Components (Prio_Array_Type);
611
612    Prio_Array : Prio_Array_Type;
613    --  Global array containing the id of the currently running task for
614    --  each priority.
615    --
616    --  Note: we assume that we are on a single processor with run-til-blocked
617    --  scheduling.
618
619    procedure Set_Priority
620      (T                   : Task_Id;
621       Prio                : System.Any_Priority;
622       Loss_Of_Inheritance : Boolean := False)
623    is
624       Result     : Interfaces.C.int;
625       Array_Item : Integer;
626       Param      : aliased struct_sched_param;
627
628    begin
629       Param.sched_priority  := Interfaces.C.int (Underlying_Priorities (Prio));
630
631       if Time_Slice_Val > 0 then
632          Result := pthread_setschedparam
633            (T.Common.LL.Thread, SCHED_RR, Param'Access);
634
635       elsif FIFO_Within_Priorities or else Time_Slice_Val = 0 then
636          Result := pthread_setschedparam
637            (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
638
639       else
640          Result := pthread_setschedparam
641            (T.Common.LL.Thread, SCHED_OTHER, Param'Access);
642       end if;
643
644       pragma Assert (Result = 0);
645
646       if FIFO_Within_Priorities then
647
648          --  Annex D requirement [RM D.2.2 par. 9]:
649          --    If the task drops its priority due to the loss of inherited
650          --    priority, it is added at the head of the ready queue for its
651          --    new active priority.
652
653          if Loss_Of_Inheritance
654            and then Prio < T.Common.Current_Priority
655          then
656             Array_Item := Prio_Array (T.Common.Base_Priority) + 1;
657             Prio_Array (T.Common.Base_Priority) := Array_Item;
658
659             loop
660                --  Let some processes a chance to arrive
661
662                Yield;
663
664                --  Then wait for our turn to proceed
665
666                exit when Array_Item = Prio_Array (T.Common.Base_Priority)
667                  or else Prio_Array (T.Common.Base_Priority) = 1;
668             end loop;
669
670             Prio_Array (T.Common.Base_Priority) :=
671               Prio_Array (T.Common.Base_Priority) - 1;
672          end if;
673       end if;
674
675       T.Common.Current_Priority := Prio;
676    end Set_Priority;
677
678    ------------------
679    -- Get_Priority --
680    ------------------
681
682    function Get_Priority (T : Task_Id) return System.Any_Priority is
683    begin
684       return T.Common.Current_Priority;
685    end Get_Priority;
686
687    ----------------
688    -- Enter_Task --
689    ----------------
690
691    procedure Enter_Task (Self_ID : Task_Id) is
692    begin
693       Self_ID.Common.LL.Thread := pthread_self;
694       Specific.Set (Self_ID);
695
696       Lock_RTS;
697
698       for J in Known_Tasks'Range loop
699          if Known_Tasks (J) = null then
700             Known_Tasks (J) := Self_ID;
701             Self_ID.Known_Tasks_Index := J;
702             exit;
703          end if;
704       end loop;
705
706       Unlock_RTS;
707    end Enter_Task;
708
709    --------------
710    -- New_ATCB --
711    --------------
712
713    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
714    begin
715       return new Ada_Task_Control_Block (Entry_Num);
716    end New_ATCB;
717
718    -------------------
719    -- Is_Valid_Task --
720    -------------------
721
722    function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
723
724    -----------------------------
725    -- Register_Foreign_Thread --
726    -----------------------------
727
728    function Register_Foreign_Thread return Task_Id is
729    begin
730       if Is_Valid_Task then
731          return Self;
732       else
733          return Register_Foreign_Thread (pthread_self);
734       end if;
735    end Register_Foreign_Thread;
736
737    --------------------
738    -- Initialize_TCB --
739    --------------------
740
741    procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
742       Mutex_Attr : aliased pthread_mutexattr_t;
743       Result     : Interfaces.C.int;
744       Cond_Attr  : aliased pthread_condattr_t;
745
746    begin
747       if not Single_Lock then
748          Result := pthread_mutexattr_init (Mutex_Attr'Access);
749          pragma Assert (Result = 0 or else Result = ENOMEM);
750
751          if Result = 0 then
752             Result := pthread_mutex_init (Self_ID.Common.LL.L'Access,
753               Mutex_Attr'Access);
754             pragma Assert (Result = 0 or else Result = ENOMEM);
755          end if;
756
757          if Result /= 0 then
758             Succeeded := False;
759             return;
760          end if;
761
762          Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
763          pragma Assert (Result = 0);
764       end if;
765
766       Result := pthread_condattr_init (Cond_Attr'Access);
767       pragma Assert (Result = 0 or else Result = ENOMEM);
768
769       if Result = 0 then
770          Result := pthread_cond_init (Self_ID.Common.LL.CV'Access,
771            Cond_Attr'Access);
772          pragma Assert (Result = 0 or else Result = ENOMEM);
773       end if;
774
775       if Result = 0 then
776          Succeeded := True;
777       else
778          if not Single_Lock then
779             Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
780             pragma Assert (Result = 0);
781          end if;
782
783          Succeeded := False;
784       end if;
785
786       Result := pthread_condattr_destroy (Cond_Attr'Access);
787       pragma Assert (Result = 0);
788    end Initialize_TCB;
789
790    -----------------
791    -- Create_Task --
792    -----------------
793
794    procedure Create_Task
795      (T          : Task_Id;
796       Wrapper    : System.Address;
797       Stack_Size : System.Parameters.Size_Type;
798       Priority   : System.Any_Priority;
799       Succeeded  : out Boolean)
800    is
801       Attributes          : aliased pthread_attr_t;
802       Adjusted_Stack_Size : Interfaces.C.size_t;
803       Result              : Interfaces.C.int;
804
805       function Thread_Body_Access is new
806         Unchecked_Conversion (System.Address, Thread_Body);
807
808    begin
809       if Stack_Size = Unspecified_Size then
810          Adjusted_Stack_Size := Interfaces.C.size_t (Default_Stack_Size);
811
812       elsif Stack_Size < Minimum_Stack_Size then
813          Adjusted_Stack_Size := Interfaces.C.size_t (Minimum_Stack_Size);
814
815       else
816          Adjusted_Stack_Size := Interfaces.C.size_t (Stack_Size);
817       end if;
818
819       Result := pthread_attr_init (Attributes'Access);
820       pragma Assert (Result = 0 or else Result = ENOMEM);
821
822       if Result /= 0 then
823          Succeeded := False;
824          return;
825       end if;
826
827       Result := pthread_attr_setstacksize
828         (Attributes'Access, Adjusted_Stack_Size);
829       pragma Assert (Result = 0);
830
831       --  Since the initial signal mask of a thread is inherited from the
832       --  creator, and the Environment task has all its signals masked, we
833       --  do not need to manipulate caller's signal mask at this point.
834       --  All tasks in RTS will have All_Tasks_Mask initially.
835
836       Result := pthread_create
837         (T.Common.LL.Thread'Access,
838          Attributes'Access,
839          Thread_Body_Access (Wrapper),
840          To_Address (T));
841       pragma Assert (Result = 0 or else Result = EAGAIN);
842
843       Succeeded := Result = 0;
844
845       pthread_detach (T.Common.LL.Thread'Access);
846       --  Detach the thread using pthread_detach, sinc DCE threads do not have
847       --  pthread_attr_set_detachstate.
848
849       Result := pthread_attr_destroy (Attributes'Access);
850       pragma Assert (Result = 0);
851
852       Set_Priority (T, Priority);
853    end Create_Task;
854
855    ------------------
856    -- Finalize_TCB --
857    ------------------
858
859    procedure Finalize_TCB (T : Task_Id) is
860       Result  : Interfaces.C.int;
861       Tmp     : Task_Id := T;
862       Is_Self : constant Boolean := T = Self;
863
864       procedure Free is new
865         Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
866
867    begin
868       if not Single_Lock then
869          Result := pthread_mutex_destroy (T.Common.LL.L'Access);
870          pragma Assert (Result = 0);
871       end if;
872
873       Result := pthread_cond_destroy (T.Common.LL.CV'Access);
874       pragma Assert (Result = 0);
875
876       if T.Known_Tasks_Index /= -1 then
877          Known_Tasks (T.Known_Tasks_Index) := null;
878       end if;
879
880       Free (Tmp);
881
882       if Is_Self then
883          Specific.Set (null);
884       end if;
885    end Finalize_TCB;
886
887    ---------------
888    -- Exit_Task --
889    ---------------
890
891    procedure Exit_Task is
892    begin
893       Specific.Set (null);
894    end Exit_Task;
895
896    ----------------
897    -- Abort_Task --
898    ----------------
899
900    procedure Abort_Task (T : Task_Id) is
901    begin
902       --
903       --  Interrupt Server_Tasks may be waiting on an "event" flag (signal)
904       --
905       if T.Common.State = Interrupt_Server_Blocked_On_Event_Flag then
906          System.Interrupt_Management.Operations.Interrupt_Self_Process
907            (System.Interrupt_Management.Interrupt_ID
908              (PIO.Get_Interrupt_ID (T)));
909       end if;
910    end Abort_Task;
911
912    ----------------
913    -- Initialize --
914    ----------------
915
916    procedure Initialize (S : in out Suspension_Object) is
917       Mutex_Attr : aliased pthread_mutexattr_t;
918       Cond_Attr  : aliased pthread_condattr_t;
919       Result     : Interfaces.C.int;
920    begin
921       --  Initialize internal state. It is always initialized to False (ARM
922       --  D.10 par. 6).
923
924       S.State := False;
925       S.Waiting := False;
926
927       --  Initialize internal mutex
928
929       Result := pthread_mutex_init (S.L'Access, Mutex_Attr'Access);
930       pragma Assert (Result = 0 or else Result = ENOMEM);
931
932       if Result = ENOMEM then
933          raise Storage_Error;
934       end if;
935
936       --  Initialize internal condition variable
937
938       Result := pthread_cond_init (S.CV'Access, Cond_Attr'Access);
939       pragma Assert (Result = 0 or else Result = ENOMEM);
940
941       if Result /= 0 then
942          Result := pthread_mutex_destroy (S.L'Access);
943          pragma Assert (Result = 0);
944
945          if Result = ENOMEM then
946             raise Storage_Error;
947          end if;
948       end if;
949    end Initialize;
950
951    --------------
952    -- Finalize --
953    --------------
954
955    procedure Finalize (S : in out Suspension_Object) is
956       Result  : Interfaces.C.int;
957    begin
958       --  Destroy internal mutex
959
960       Result := pthread_mutex_destroy (S.L'Access);
961       pragma Assert (Result = 0);
962
963       --  Destroy internal condition variable
964
965       Result := pthread_cond_destroy (S.CV'Access);
966       pragma Assert (Result = 0);
967    end Finalize;
968
969    -------------------
970    -- Current_State --
971    -------------------
972
973    function Current_State (S : Suspension_Object) return Boolean is
974    begin
975       --  We do not want to use lock on this read operation. State is marked
976       --  as Atomic so that we ensure that the value retrieved is correct.
977
978       return S.State;
979    end Current_State;
980
981    ---------------
982    -- Set_False --
983    ---------------
984
985    procedure Set_False (S : in out Suspension_Object) is
986       Result  : Interfaces.C.int;
987    begin
988       Result := pthread_mutex_lock (S.L'Access);
989       pragma Assert (Result = 0);
990
991       S.State := False;
992
993       Result := pthread_mutex_unlock (S.L'Access);
994       pragma Assert (Result = 0);
995    end Set_False;
996
997    --------------
998    -- Set_True --
999    --------------
1000
1001    procedure Set_True (S : in out Suspension_Object) is
1002       Result : Interfaces.C.int;
1003    begin
1004       Result := pthread_mutex_lock (S.L'Access);
1005       pragma Assert (Result = 0);
1006
1007       --  If there is already a task waiting on this suspension object then
1008       --  we resume it, leaving the state of the suspension object to False,
1009       --  as it is specified in ARM D.10 par. 9. Otherwise, it just leaves
1010       --  the state to True.
1011
1012       if S.Waiting then
1013          S.Waiting := False;
1014          S.State := False;
1015
1016          Result := pthread_cond_signal (S.CV'Access);
1017          pragma Assert (Result = 0);
1018       else
1019          S.State := True;
1020       end if;
1021
1022       Result := pthread_mutex_unlock (S.L'Access);
1023       pragma Assert (Result = 0);
1024    end Set_True;
1025
1026    ------------------------
1027    -- Suspend_Until_True --
1028    ------------------------
1029
1030    procedure Suspend_Until_True (S : in out Suspension_Object) is
1031       Result : Interfaces.C.int;
1032    begin
1033       Result := pthread_mutex_lock (S.L'Access);
1034       pragma Assert (Result = 0);
1035
1036       if S.Waiting then
1037          --  Program_Error must be raised upon calling Suspend_Until_True
1038          --  if another task is already waiting on that suspension object
1039          --  (ARM D.10 par. 10).
1040
1041          Result := pthread_mutex_unlock (S.L'Access);
1042          pragma Assert (Result = 0);
1043
1044          raise Program_Error;
1045       else
1046          --  Suspend the task if the state is False. Otherwise, the task
1047          --  continues its execution, and the state of the suspension object
1048          --  is set to False (ARM D.10 par. 9).
1049
1050          if S.State then
1051             S.State := False;
1052          else
1053             S.Waiting := True;
1054             Result := pthread_cond_wait (S.CV'Access, S.L'Access);
1055          end if;
1056       end if;
1057
1058       Result := pthread_mutex_unlock (S.L'Access);
1059       pragma Assert (Result = 0);
1060    end Suspend_Until_True;
1061
1062    ----------------
1063    -- Check_Exit --
1064    ----------------
1065
1066    --  Dummy version
1067
1068    function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1069       pragma Unreferenced (Self_ID);
1070    begin
1071       return True;
1072    end Check_Exit;
1073
1074    --------------------
1075    -- Check_No_Locks --
1076    --------------------
1077
1078    function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1079       pragma Unreferenced (Self_ID);
1080    begin
1081       return True;
1082    end Check_No_Locks;
1083
1084    ----------------------
1085    -- Environment_Task --
1086    ----------------------
1087
1088    function Environment_Task return Task_Id is
1089    begin
1090       return Environment_Task_Id;
1091    end Environment_Task;
1092
1093    --------------
1094    -- Lock_RTS --
1095    --------------
1096
1097    procedure Lock_RTS is
1098    begin
1099       Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
1100    end Lock_RTS;
1101
1102    ----------------
1103    -- Unlock_RTS --
1104    ----------------
1105
1106    procedure Unlock_RTS is
1107    begin
1108       Unlock (Single_RTS_Lock'Access, Global_Lock => True);
1109    end Unlock_RTS;
1110
1111    ------------------
1112    -- Suspend_Task --
1113    ------------------
1114
1115    function Suspend_Task
1116      (T           : ST.Task_Id;
1117       Thread_Self : Thread_Id) return Boolean
1118    is
1119       pragma Unreferenced (T);
1120       pragma Unreferenced (Thread_Self);
1121    begin
1122       return False;
1123    end Suspend_Task;
1124
1125    -----------------
1126    -- Resume_Task --
1127    -----------------
1128
1129    function Resume_Task
1130      (T           : ST.Task_Id;
1131       Thread_Self : Thread_Id) return Boolean
1132    is
1133       pragma Unreferenced (T);
1134       pragma Unreferenced (Thread_Self);
1135    begin
1136       return False;
1137    end Resume_Task;
1138
1139    ----------------
1140    -- Initialize --
1141    ----------------
1142
1143    procedure Initialize (Environment_Task : Task_Id) is
1144       act       : aliased struct_sigaction;
1145       old_act   : aliased struct_sigaction;
1146       Tmp_Set   : aliased sigset_t;
1147       Result    : Interfaces.C.int;
1148
1149       function State
1150         (Int : System.Interrupt_Management.Interrupt_ID) return Character;
1151       pragma Import (C, State, "__gnat_get_interrupt_state");
1152       --  Get interrupt state. Defined in a-init.c. The input argument is
1153       --  the interrupt number, and the result is one of the following:
1154
1155       Default : constant Character := 's';
1156       --    'n'   this interrupt not set by any Interrupt_State pragma
1157       --    'u'   Interrupt_State pragma set state to User
1158       --    'r'   Interrupt_State pragma set state to Runtime
1159       --    's'   Interrupt_State pragma set state to System (use "default"
1160       --           system handler)
1161
1162    begin
1163       Environment_Task_Id := Environment_Task;
1164
1165       --  Initialize the lock used to synchronize chain of all ATCBs
1166
1167       Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1168
1169       Specific.Initialize (Environment_Task);
1170
1171       Enter_Task (Environment_Task);
1172
1173       --  Install the abort-signal handler
1174
1175       if State (System.Interrupt_Management.Abort_Task_Interrupt)
1176                                                      /= Default
1177       then
1178          act.sa_flags := 0;
1179          act.sa_handler := Abort_Handler'Address;
1180
1181          Result := sigemptyset (Tmp_Set'Access);
1182          pragma Assert (Result = 0);
1183          act.sa_mask := Tmp_Set;
1184
1185          Result :=
1186            sigaction (
1187              Signal (System.Interrupt_Management.Abort_Task_Interrupt),
1188              act'Unchecked_Access,
1189              old_act'Unchecked_Access);
1190          pragma Assert (Result = 0);
1191       end if;
1192    end Initialize;
1193
1194    --  NOTE: Unlike other pthread implementations, we do *not* mask all
1195    --  signals here since we handle signals using the process-wide primitive
1196    --  signal, rather than using sigthreadmask and sigwait. The reason of
1197    --  this difference is that sigwait doesn't work when some critical
1198    --  signals (SIGABRT, SIGPIPE) are masked.
1199
1200 end System.Task_Primitives.Operations;