OSDN Git Service

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