OSDN Git Service

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