OSDN Git Service

2011-08-05 Yannick Moy <moy@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-2011, 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 3,  or (at your option) any later ver- --
14 -- sion.  GNAT 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.                                     --
17 --                                                                          --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception,   --
20 -- version 3.1, as published by the Free Software Foundation.               --
21 --                                                                          --
22 -- You should have received a copy of the GNU General Public License and    --
23 -- a copy of the GCC Runtime Library Exception along with this program;     --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
25 -- <http://www.gnu.org/licenses/>.                                          --
26 --                                                                          --
27 -- GNARL was developed by the GNARL team at Florida State University.       --
28 -- Extensive contributions were provided by Ada Core Technologies, Inc.     --
29 --                                                                          --
30 ------------------------------------------------------------------------------
31
32 --  This is a GNU/Linux (GNU/LinuxThreads) version of this package
33
34 --  This package contains all the GNULL primitives that interface directly with
35 --  the underlying OS.
36
37 pragma Polling (Off);
38 --  Turn off polling, we do not want ATC polling to take place during tasking
39 --  operations. It causes infinite loops and other problems.
40
41 with Ada.Unchecked_Conversion;
42 with Ada.Unchecked_Deallocation;
43
44 with Interfaces.C;
45
46 with System.Task_Info;
47 with System.Tasking.Debug;
48 with System.Interrupt_Management;
49 with System.OS_Primitives;
50 with System.Stack_Checking.Operations;
51 with System.Multiprocessors;
52
53 with System.Soft_Links;
54 --  We use System.Soft_Links instead of System.Tasking.Initialization
55 --  because the later is a higher level package that we shouldn't depend on.
56 --  For example when using the restricted run time, it is replaced by
57 --  System.Tasking.Restricted.Stages.
58
59 package body System.Task_Primitives.Operations is
60
61    package SSL renames System.Soft_Links;
62    package SC renames System.Stack_Checking.Operations;
63
64    use System.Tasking.Debug;
65    use System.Tasking;
66    use Interfaces.C;
67    use System.OS_Interface;
68    use System.Parameters;
69    use System.OS_Primitives;
70    use System.Task_Info;
71
72    ----------------
73    -- Local Data --
74    ----------------
75
76    --  The followings are logically constants, but need to be initialized
77    --  at run time.
78
79    Single_RTS_Lock : aliased RTS_Lock;
80    --  This is a lock to allow only one thread of control in the RTS at
81    --  a time; it is used to execute in mutual exclusion from all other tasks.
82    --  Used mainly in Single_Lock mode, but also to protect All_Tasks_List
83
84    Environment_Task_Id : Task_Id;
85    --  A variable to hold Task_Id for the environment task
86
87    Unblocked_Signal_Mask : aliased sigset_t;
88    --  The set of signals that should be unblocked in all tasks
89
90    --  The followings are internal configuration constants needed
91
92    Next_Serial_Number : Task_Serial_Number := 100;
93    --  We start at 100 (reserve some special values for using in error checks)
94
95    Time_Slice_Val : Integer;
96    pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
97
98    Dispatching_Policy : Character;
99    pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
100
101    --  The following are effectively constants, but they need to be initialized
102    --  by calling a pthread_ function.
103
104    Mutex_Attr   : aliased pthread_mutexattr_t;
105    Cond_Attr    : aliased pthread_condattr_t;
106
107    Foreign_Task_Elaborated : aliased Boolean := True;
108    --  Used to identified fake tasks (i.e., non-Ada Threads)
109
110    Use_Alternate_Stack : constant Boolean := Alternate_Stack_Size /= 0;
111    --  Whether to use an alternate signal stack for stack overflows
112
113    Abort_Handler_Installed : Boolean := False;
114    --  True if a handler for the abort signal is installed
115
116    --------------------
117    -- Local Packages --
118    --------------------
119
120    package Specific is
121
122       procedure Initialize (Environment_Task : Task_Id);
123       pragma Inline (Initialize);
124       --  Initialize various data needed by this package
125
126       function Is_Valid_Task return Boolean;
127       pragma Inline (Is_Valid_Task);
128       --  Does executing thread have a TCB?
129
130       procedure Set (Self_Id : Task_Id);
131       pragma Inline (Set);
132       --  Set the self id for the current task
133
134       function Self return Task_Id;
135       pragma Inline (Self);
136       --  Return a pointer to the Ada Task Control Block of the calling task
137
138    end Specific;
139
140    package body Specific is separate;
141    --  The body of this package is target specific
142
143    ---------------------------------
144    -- Support for foreign threads --
145    ---------------------------------
146
147    function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
148    --  Allocate and Initialize a new ATCB for the current Thread
149
150    function Register_Foreign_Thread
151      (Thread : Thread_Id) return Task_Id is separate;
152
153    -----------------------
154    -- Local Subprograms --
155    -----------------------
156
157    subtype unsigned_long is Interfaces.C.unsigned_long;
158
159    procedure Abort_Handler (signo : Signal);
160
161    function To_pthread_t is new Ada.Unchecked_Conversion
162      (unsigned_long, System.OS_Interface.pthread_t);
163
164    -------------------
165    -- Abort_Handler --
166    -------------------
167
168    procedure Abort_Handler (signo : Signal) is
169       pragma Unreferenced (signo);
170
171       Self_Id : constant Task_Id := Self;
172       Result  : Interfaces.C.int;
173       Old_Set : aliased sigset_t;
174
175    begin
176       --  It's not safe to raise an exception when using GCC ZCX mechanism.
177       --  Note that we still need to install a signal handler, since in some
178       --  cases (e.g. shutdown of the Server_Task in System.Interrupts) we
179       --  need to send the Abort signal to a task.
180
181       if ZCX_By_Default and then GCC_ZCX_Support then
182          return;
183       end if;
184
185       if Self_Id.Deferral_Level = 0
186         and then Self_Id.Pending_ATC_Level < Self_Id.ATC_Nesting_Level
187         and then not Self_Id.Aborting
188       then
189          Self_Id.Aborting := True;
190
191          --  Make sure signals used for RTS internal purpose are unmasked
192
193          Result :=
194            pthread_sigmask
195              (SIG_UNBLOCK,
196               Unblocked_Signal_Mask'Access,
197               Old_Set'Access);
198          pragma Assert (Result = 0);
199
200          raise Standard'Abort_Signal;
201       end if;
202    end Abort_Handler;
203
204    --------------
205    -- Lock_RTS --
206    --------------
207
208    procedure Lock_RTS is
209    begin
210       Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
211    end Lock_RTS;
212
213    ----------------
214    -- Unlock_RTS --
215    ----------------
216
217    procedure Unlock_RTS is
218    begin
219       Unlock (Single_RTS_Lock'Access, Global_Lock => True);
220    end Unlock_RTS;
221
222    -----------------
223    -- Stack_Guard --
224    -----------------
225
226    --  The underlying thread system extends the memory (up to 2MB) when needed
227
228    procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is
229       pragma Unreferenced (T);
230       pragma Unreferenced (On);
231    begin
232       null;
233    end Stack_Guard;
234
235    --------------------
236    -- Get_Thread_Id  --
237    --------------------
238
239    function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is
240    begin
241       return T.Common.LL.Thread;
242    end Get_Thread_Id;
243
244    ----------
245    -- Self --
246    ----------
247
248    function Self return Task_Id renames Specific.Self;
249
250    ---------------------
251    -- Initialize_Lock --
252    ---------------------
253
254    --  Note: mutexes and cond_variables needed per-task basis are initialized
255    --  in Initialize_TCB and the Storage_Error is handled. Other mutexes (such
256    --  as RTS_Lock, Memory_Lock...) used in RTS is initialized before any
257    --  status change of RTS. Therefore raising Storage_Error in the following
258    --  routines should be able to be handled safely.
259
260    procedure Initialize_Lock
261      (Prio : System.Any_Priority;
262       L    : not null access Lock)
263    is
264       pragma Unreferenced (Prio);
265
266       Result : Interfaces.C.int;
267
268    begin
269       Result := pthread_mutex_init (L, Mutex_Attr'Access);
270
271       pragma Assert (Result = 0 or else Result = ENOMEM);
272
273       if Result = ENOMEM then
274          raise Storage_Error with "Failed to allocate a lock";
275       end if;
276    end Initialize_Lock;
277
278    procedure Initialize_Lock
279      (L     : not null access RTS_Lock;
280       Level : Lock_Level)
281    is
282       pragma Unreferenced (Level);
283
284       Result : Interfaces.C.int;
285
286    begin
287       Result := pthread_mutex_init (L, Mutex_Attr'Access);
288
289       pragma Assert (Result = 0 or else Result = ENOMEM);
290
291       if Result = ENOMEM then
292          raise Storage_Error;
293       end if;
294    end Initialize_Lock;
295
296    -------------------
297    -- Finalize_Lock --
298    -------------------
299
300    procedure Finalize_Lock (L : not null access Lock) is
301       Result : Interfaces.C.int;
302    begin
303       Result := pthread_mutex_destroy (L);
304       pragma Assert (Result = 0);
305    end Finalize_Lock;
306
307    procedure Finalize_Lock (L : not null access RTS_Lock) is
308       Result : Interfaces.C.int;
309    begin
310       Result := pthread_mutex_destroy (L);
311       pragma Assert (Result = 0);
312    end Finalize_Lock;
313
314    ----------------
315    -- Write_Lock --
316    ----------------
317
318    procedure Write_Lock
319      (L                 : not null access Lock;
320       Ceiling_Violation : out Boolean)
321    is
322       Result : Interfaces.C.int;
323    begin
324       Result := pthread_mutex_lock (L);
325       Ceiling_Violation := Result = EINVAL;
326
327       --  Assume the cause of EINVAL is a priority ceiling violation
328
329       pragma Assert (Result = 0 or else Result = EINVAL);
330    end Write_Lock;
331
332    procedure Write_Lock
333      (L           : not null access RTS_Lock;
334       Global_Lock : Boolean := False)
335    is
336       Result : Interfaces.C.int;
337    begin
338       if not Single_Lock or else Global_Lock then
339          Result := pthread_mutex_lock (L);
340          pragma Assert (Result = 0);
341       end if;
342    end Write_Lock;
343
344    procedure Write_Lock (T : Task_Id) is
345       Result : Interfaces.C.int;
346    begin
347       if not Single_Lock then
348          Result := pthread_mutex_lock (T.Common.LL.L'Access);
349          pragma Assert (Result = 0);
350       end if;
351    end Write_Lock;
352
353    ---------------
354    -- Read_Lock --
355    ---------------
356
357    procedure Read_Lock
358      (L                 : not null access Lock;
359       Ceiling_Violation : out Boolean)
360    is
361    begin
362       Write_Lock (L, Ceiling_Violation);
363    end Read_Lock;
364
365    ------------
366    -- Unlock --
367    ------------
368
369    procedure Unlock (L : not null access Lock) is
370       Result : Interfaces.C.int;
371    begin
372       Result := pthread_mutex_unlock (L);
373       pragma Assert (Result = 0);
374    end Unlock;
375
376    procedure Unlock
377      (L           : not null access RTS_Lock;
378       Global_Lock : Boolean := False)
379    is
380       Result : Interfaces.C.int;
381    begin
382       if not Single_Lock or else Global_Lock then
383          Result := pthread_mutex_unlock (L);
384          pragma Assert (Result = 0);
385       end if;
386    end Unlock;
387
388    procedure Unlock (T : Task_Id) is
389       Result : Interfaces.C.int;
390    begin
391       if not Single_Lock then
392          Result := pthread_mutex_unlock (T.Common.LL.L'Access);
393          pragma Assert (Result = 0);
394       end if;
395    end Unlock;
396
397    -----------------
398    -- Set_Ceiling --
399    -----------------
400
401    --  Dynamic priority ceilings are not supported by the underlying system
402
403    procedure Set_Ceiling
404      (L    : not null access Lock;
405       Prio : System.Any_Priority)
406    is
407       pragma Unreferenced (L, Prio);
408    begin
409       null;
410    end Set_Ceiling;
411
412    -----------
413    -- Sleep --
414    -----------
415
416    procedure Sleep
417      (Self_ID  : Task_Id;
418       Reason   : System.Tasking.Task_States)
419    is
420       pragma Unreferenced (Reason);
421
422       Result : Interfaces.C.int;
423
424    begin
425       pragma Assert (Self_ID = Self);
426
427       Result :=
428         pthread_cond_wait
429           (cond  => Self_ID.Common.LL.CV'Access,
430            mutex => (if Single_Lock
431                      then Single_RTS_Lock'Access
432                      else Self_ID.Common.LL.L'Access));
433
434       --  EINTR is not considered a failure
435
436       pragma Assert (Result = 0 or else Result = EINTR);
437    end Sleep;
438
439    -----------------
440    -- Timed_Sleep --
441    -----------------
442
443    --  This is for use within the run-time system, so abort is
444    --  assumed to be already deferred, and the caller should be
445    --  holding its own ATCB lock.
446
447    procedure Timed_Sleep
448      (Self_ID  : Task_Id;
449       Time     : Duration;
450       Mode     : ST.Delay_Modes;
451       Reason   : System.Tasking.Task_States;
452       Timedout : out Boolean;
453       Yielded  : out Boolean)
454    is
455       pragma Unreferenced (Reason);
456
457       Base_Time  : constant Duration := Monotonic_Clock;
458       Check_Time : Duration := Base_Time;
459       Abs_Time   : Duration;
460       Request    : aliased timespec;
461       Result     : Interfaces.C.int;
462
463    begin
464       Timedout := True;
465       Yielded := False;
466
467       Abs_Time :=
468         (if Mode = Relative
469          then Duration'Min (Time, Max_Sensible_Delay) + Check_Time
470          else Duration'Min (Check_Time + Max_Sensible_Delay, Time));
471
472       if Abs_Time > Check_Time then
473          Request := To_Timespec (Abs_Time);
474
475          loop
476             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
477
478             Result :=
479               pthread_cond_timedwait
480                 (cond    => Self_ID.Common.LL.CV'Access,
481                  mutex   => (if Single_Lock
482                              then Single_RTS_Lock'Access
483                              else Self_ID.Common.LL.L'Access),
484                  abstime => Request'Access);
485
486             Check_Time := Monotonic_Clock;
487             exit when Abs_Time <= Check_Time or else Check_Time < Base_Time;
488
489             if Result = 0 or else Result = EINTR then
490
491                --  Somebody may have called Wakeup for us
492
493                Timedout := False;
494                exit;
495             end if;
496
497             pragma Assert (Result = ETIMEDOUT);
498          end loop;
499       end if;
500    end Timed_Sleep;
501
502    -----------------
503    -- Timed_Delay --
504    -----------------
505
506    --  This is for use in implementing delay statements, so we assume the
507    --  caller is abort-deferred but is holding no locks.
508
509    procedure Timed_Delay
510      (Self_ID : Task_Id;
511       Time    : Duration;
512       Mode    : ST.Delay_Modes)
513    is
514       Base_Time  : constant Duration := Monotonic_Clock;
515       Check_Time : Duration := Base_Time;
516       Abs_Time   : Duration;
517       Request    : aliased timespec;
518
519       Result : Interfaces.C.int;
520       pragma Warnings (Off, Result);
521
522    begin
523       if Single_Lock then
524          Lock_RTS;
525       end if;
526
527       Write_Lock (Self_ID);
528
529       Abs_Time :=
530         (if Mode = Relative
531          then Time + Check_Time
532          else Duration'Min (Check_Time + Max_Sensible_Delay, Time));
533
534       if Abs_Time > Check_Time then
535          Request := To_Timespec (Abs_Time);
536          Self_ID.Common.State := Delay_Sleep;
537
538          loop
539             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
540
541             Result :=
542               pthread_cond_timedwait
543                 (cond    => Self_ID.Common.LL.CV'Access,
544                  mutex   => (if Single_Lock
545                              then Single_RTS_Lock'Access
546                              else Self_ID.Common.LL.L'Access),
547                  abstime => Request'Access);
548
549             Check_Time := Monotonic_Clock;
550             exit when Abs_Time <= Check_Time or else Check_Time < Base_Time;
551
552             pragma Assert (Result = 0 or else
553               Result = ETIMEDOUT or else
554               Result = EINTR);
555          end loop;
556
557          Self_ID.Common.State := Runnable;
558       end if;
559
560       Unlock (Self_ID);
561
562       if Single_Lock then
563          Unlock_RTS;
564       end if;
565
566       Result := sched_yield;
567    end Timed_Delay;
568
569    ---------------------
570    -- Monotonic_Clock --
571    ---------------------
572
573    function Monotonic_Clock return Duration is
574       use Interfaces;
575
576       type timeval is array (1 .. 2) of C.long;
577
578       procedure timeval_to_duration
579         (T    : not null access timeval;
580          sec  : not null access C.long;
581          usec : not null access C.long);
582       pragma Import (C, timeval_to_duration, "__gnat_timeval_to_duration");
583
584       Micro  : constant := 10**6;
585       sec    : aliased C.long;
586       usec   : aliased C.long;
587       TV     : aliased timeval;
588       Result : int;
589
590       function gettimeofday
591         (Tv : access timeval;
592          Tz : System.Address := System.Null_Address) return int;
593       pragma Import (C, gettimeofday, "gettimeofday");
594
595    begin
596       Result := gettimeofday (TV'Access, System.Null_Address);
597       pragma Assert (Result = 0);
598       timeval_to_duration (TV'Access, sec'Access, usec'Access);
599       return Duration (sec) + Duration (usec) / Micro;
600    end Monotonic_Clock;
601
602    -------------------
603    -- RT_Resolution --
604    -------------------
605
606    function RT_Resolution return Duration is
607    begin
608       return 10#1.0#E-6;
609    end RT_Resolution;
610
611    ------------
612    -- Wakeup --
613    ------------
614
615    procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
616       pragma Unreferenced (Reason);
617       Result : Interfaces.C.int;
618    begin
619       Result := pthread_cond_signal (T.Common.LL.CV'Access);
620       pragma Assert (Result = 0);
621    end Wakeup;
622
623    -----------
624    -- Yield --
625    -----------
626
627    procedure Yield (Do_Yield : Boolean := True) is
628       Result : Interfaces.C.int;
629       pragma Unreferenced (Result);
630    begin
631       if Do_Yield then
632          Result := sched_yield;
633       end if;
634    end Yield;
635
636    ------------------
637    -- Set_Priority --
638    ------------------
639
640    procedure Set_Priority
641      (T                   : Task_Id;
642       Prio                : System.Any_Priority;
643       Loss_Of_Inheritance : Boolean := False)
644    is
645       pragma Unreferenced (Loss_Of_Inheritance);
646
647       Result : Interfaces.C.int;
648       Param  : aliased struct_sched_param;
649
650       function Get_Policy (Prio : System.Any_Priority) return Character;
651       pragma Import (C, Get_Policy, "__gnat_get_specific_dispatching");
652       --  Get priority specific dispatching policy
653
654       Priority_Specific_Policy : constant Character := Get_Policy (Prio);
655       --  Upper case first character of the policy name corresponding to the
656       --  task as set by a Priority_Specific_Dispatching pragma.
657
658    begin
659       T.Common.Current_Priority := Prio;
660
661       --  Priorities are 1 .. 99 on GNU/Linux, so we map 0 .. 98 to 1 .. 99
662
663       Param.sched_priority := Interfaces.C.int (Prio) + 1;
664
665       if Dispatching_Policy = 'R'
666         or else Priority_Specific_Policy = 'R'
667         or else Time_Slice_Val > 0
668       then
669          Result :=
670            pthread_setschedparam
671              (T.Common.LL.Thread, SCHED_RR, Param'Access);
672
673       elsif Dispatching_Policy = 'F'
674         or else Priority_Specific_Policy = 'F'
675         or else Time_Slice_Val = 0
676       then
677          Result :=
678            pthread_setschedparam
679              (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
680
681       else
682          Param.sched_priority := 0;
683          Result :=
684            pthread_setschedparam
685              (T.Common.LL.Thread,
686               SCHED_OTHER, Param'Access);
687       end if;
688
689       pragma Assert (Result = 0 or else Result = EPERM);
690    end Set_Priority;
691
692    ------------------
693    -- Get_Priority --
694    ------------------
695
696    function Get_Priority (T : Task_Id) return System.Any_Priority is
697    begin
698       return T.Common.Current_Priority;
699    end Get_Priority;
700
701    ----------------
702    -- Enter_Task --
703    ----------------
704
705    procedure Enter_Task (Self_ID : Task_Id) is
706    begin
707       if Self_ID.Common.Task_Info /= null
708         and then Self_ID.Common.Task_Info.CPU_Affinity = No_CPU
709       then
710          raise Invalid_CPU_Number;
711       end if;
712
713       Self_ID.Common.LL.Thread := pthread_self;
714       Self_ID.Common.LL.LWP := lwp_self;
715
716       Specific.Set (Self_ID);
717
718       if Use_Alternate_Stack
719         and then Self_ID.Common.Task_Alternate_Stack /= Null_Address
720       then
721          declare
722             Stack  : aliased stack_t;
723             Result : Interfaces.C.int;
724          begin
725             Stack.ss_sp    := Self_ID.Common.Task_Alternate_Stack;
726             Stack.ss_size  := Alternate_Stack_Size;
727             Stack.ss_flags := 0;
728             Result := sigaltstack (Stack'Access, null);
729             pragma Assert (Result = 0);
730          end;
731       end if;
732    end Enter_Task;
733
734    --------------
735    -- New_ATCB --
736    --------------
737
738    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
739    begin
740       return new Ada_Task_Control_Block (Entry_Num);
741    end New_ATCB;
742
743    -------------------
744    -- Is_Valid_Task --
745    -------------------
746
747    function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
748
749    -----------------------------
750    -- Register_Foreign_Thread --
751    -----------------------------
752
753    function Register_Foreign_Thread return Task_Id is
754    begin
755       if Is_Valid_Task then
756          return Self;
757       else
758          return Register_Foreign_Thread (pthread_self);
759       end if;
760    end Register_Foreign_Thread;
761
762    --------------------
763    -- Initialize_TCB --
764    --------------------
765
766    procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
767       Result : Interfaces.C.int;
768
769    begin
770       --  Give the task a unique serial number
771
772       Self_ID.Serial_Number := Next_Serial_Number;
773       Next_Serial_Number := Next_Serial_Number + 1;
774       pragma Assert (Next_Serial_Number /= 0);
775
776       Self_ID.Common.LL.Thread := To_pthread_t (-1);
777
778       if not Single_Lock then
779          Result := pthread_mutex_init (Self_ID.Common.LL.L'Access,
780            Mutex_Attr'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       end if;
788
789       Result := pthread_cond_init (Self_ID.Common.LL.CV'Access,
790         Cond_Attr'Access);
791       pragma Assert (Result = 0 or else Result = ENOMEM);
792
793       if Result = 0 then
794          Succeeded := True;
795       else
796          if not Single_Lock then
797             Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
798             pragma Assert (Result = 0);
799          end if;
800
801          Succeeded := False;
802       end if;
803    end Initialize_TCB;
804
805    -----------------
806    -- Create_Task --
807    -----------------
808
809    procedure Create_Task
810      (T          : Task_Id;
811       Wrapper    : System.Address;
812       Stack_Size : System.Parameters.Size_Type;
813       Priority   : System.Any_Priority;
814       Succeeded  : out Boolean)
815    is
816       Attributes          : aliased pthread_attr_t;
817       Adjusted_Stack_Size : Interfaces.C.size_t;
818       Result              : Interfaces.C.int;
819
820       use type System.Multiprocessors.CPU_Range;
821
822    begin
823       Adjusted_Stack_Size :=
824          Interfaces.C.size_t (Stack_Size + Alternate_Stack_Size);
825
826       Result := pthread_attr_init (Attributes'Access);
827       pragma Assert (Result = 0 or else Result = ENOMEM);
828
829       if Result /= 0 then
830          Succeeded := False;
831          return;
832       end if;
833
834       Result :=
835         pthread_attr_setstacksize
836           (Attributes'Access, Adjusted_Stack_Size);
837       pragma Assert (Result = 0);
838
839       Result :=
840         pthread_attr_setdetachstate
841           (Attributes'Access, PTHREAD_CREATE_DETACHED);
842       pragma Assert (Result = 0);
843
844       --  Set the required attributes for the creation of the thread
845
846       --  Note: Previously, we called pthread_setaffinity_np (after thread
847       --  creation but before thread activation) to set the affinity but it was
848       --  not behaving as expected. Setting the required attributes for the
849       --  creation of the thread works correctly and it is more appropriate.
850
851       --  Do nothing if required support not provided by the operating system
852
853       if pthread_attr_setaffinity_np'Address = System.Null_Address then
854          null;
855
856       --  Support is available
857
858       elsif T.Common.Base_CPU /= System.Multiprocessors.Not_A_Specific_CPU then
859          declare
860             CPU_Set : aliased cpu_set_t := (bits => (others => False));
861          begin
862             CPU_Set.bits (Integer (T.Common.Base_CPU)) := True;
863             Result :=
864               pthread_attr_setaffinity_np
865                 (Attributes'Access,
866                  CPU_SETSIZE / 8,
867                  CPU_Set'Access);
868             pragma Assert (Result = 0);
869          end;
870
871       --  Handle Task_Info
872
873       elsif T.Common.Task_Info /= null
874         and then T.Common.Task_Info.CPU_Affinity /= Task_Info.Any_CPU
875       then
876          Result :=
877            pthread_attr_setaffinity_np
878              (Attributes'Access,
879               CPU_SETSIZE / 8,
880               T.Common.Task_Info.CPU_Affinity'Access);
881          pragma Assert (Result = 0);
882       end if;
883
884       --  Since the initial signal mask of a thread is inherited from the
885       --  creator, and the Environment task has all its signals masked, we
886       --  do not need to manipulate caller's signal mask at this point.
887       --  All tasks in RTS will have All_Tasks_Mask initially.
888
889       Result := pthread_create
890         (T.Common.LL.Thread'Access,
891          Attributes'Access,
892          Thread_Body_Access (Wrapper),
893          To_Address (T));
894       pragma Assert
895         (Result = 0 or else Result = EAGAIN or else Result = ENOMEM);
896
897       if Result /= 0 then
898          Succeeded := False;
899          Result := pthread_attr_destroy (Attributes'Access);
900          pragma Assert (Result = 0);
901          return;
902       end if;
903
904       Succeeded := True;
905
906       Result := pthread_attr_destroy (Attributes'Access);
907       pragma Assert (Result = 0);
908
909       Set_Priority (T, Priority);
910    end Create_Task;
911
912    ------------------
913    -- Finalize_TCB --
914    ------------------
915
916    procedure Finalize_TCB (T : Task_Id) is
917       Result  : Interfaces.C.int;
918       Tmp     : Task_Id := T;
919       Is_Self : constant Boolean := T = Self;
920
921       procedure Free is new
922         Ada.Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
923
924    begin
925       if not Single_Lock then
926          Result := pthread_mutex_destroy (T.Common.LL.L'Access);
927          pragma Assert (Result = 0);
928       end if;
929
930       Result := pthread_cond_destroy (T.Common.LL.CV'Access);
931       pragma Assert (Result = 0);
932
933       if T.Known_Tasks_Index /= -1 then
934          Known_Tasks (T.Known_Tasks_Index) := null;
935       end if;
936       SC.Invalidate_Stack_Cache (T.Common.Compiler_Data.Pri_Stack_Info'Access);
937       Free (Tmp);
938
939       if Is_Self then
940          Specific.Set (null);
941       end if;
942    end Finalize_TCB;
943
944    ---------------
945    -- Exit_Task --
946    ---------------
947
948    procedure Exit_Task is
949    begin
950       Specific.Set (null);
951    end Exit_Task;
952
953    ----------------
954    -- Abort_Task --
955    ----------------
956
957    procedure Abort_Task (T : Task_Id) is
958       Result : Interfaces.C.int;
959    begin
960       if Abort_Handler_Installed then
961          Result :=
962            pthread_kill
963              (T.Common.LL.Thread,
964               Signal (System.Interrupt_Management.Abort_Task_Interrupt));
965          pragma Assert (Result = 0);
966       end if;
967    end Abort_Task;
968
969    ----------------
970    -- Initialize --
971    ----------------
972
973    procedure Initialize (S : in out Suspension_Object) is
974       Result : Interfaces.C.int;
975
976    begin
977       --  Initialize internal state (always to False (RM D.10(6)))
978
979       S.State := False;
980       S.Waiting := False;
981
982       --  Initialize internal mutex
983
984       Result := pthread_mutex_init (S.L'Access, Mutex_Attr'Access);
985
986       pragma Assert (Result = 0 or else Result = ENOMEM);
987
988       if Result = ENOMEM then
989          raise Storage_Error;
990       end if;
991
992       --  Initialize internal condition variable
993
994       Result := pthread_cond_init (S.CV'Access, Cond_Attr'Access);
995
996       pragma Assert (Result = 0 or else Result = ENOMEM);
997
998       if Result /= 0 then
999          Result := pthread_mutex_destroy (S.L'Access);
1000          pragma Assert (Result = 0);
1001
1002          if Result = ENOMEM then
1003             raise Storage_Error;
1004          end if;
1005       end if;
1006    end Initialize;
1007
1008    --------------
1009    -- Finalize --
1010    --------------
1011
1012    procedure Finalize (S : in out Suspension_Object) is
1013       Result : Interfaces.C.int;
1014
1015    begin
1016       --  Destroy internal mutex
1017
1018       Result := pthread_mutex_destroy (S.L'Access);
1019       pragma Assert (Result = 0);
1020
1021       --  Destroy internal condition variable
1022
1023       Result := pthread_cond_destroy (S.CV'Access);
1024       pragma Assert (Result = 0);
1025    end Finalize;
1026
1027    -------------------
1028    -- Current_State --
1029    -------------------
1030
1031    function Current_State (S : Suspension_Object) return Boolean is
1032    begin
1033       --  We do not want to use lock on this read operation. State is marked
1034       --  as Atomic so that we ensure that the value retrieved is correct.
1035
1036       return S.State;
1037    end Current_State;
1038
1039    ---------------
1040    -- Set_False --
1041    ---------------
1042
1043    procedure Set_False (S : in out Suspension_Object) is
1044       Result : Interfaces.C.int;
1045
1046    begin
1047       SSL.Abort_Defer.all;
1048
1049       Result := pthread_mutex_lock (S.L'Access);
1050       pragma Assert (Result = 0);
1051
1052       S.State := False;
1053
1054       Result := pthread_mutex_unlock (S.L'Access);
1055       pragma Assert (Result = 0);
1056
1057       SSL.Abort_Undefer.all;
1058    end Set_False;
1059
1060    --------------
1061    -- Set_True --
1062    --------------
1063
1064    procedure Set_True (S : in out Suspension_Object) is
1065       Result : Interfaces.C.int;
1066
1067    begin
1068       SSL.Abort_Defer.all;
1069
1070       Result := pthread_mutex_lock (S.L'Access);
1071       pragma Assert (Result = 0);
1072
1073       --  If there is already a task waiting on this suspension object then
1074       --  we resume it, leaving the state of the suspension object to False,
1075       --  as it is specified in ARM D.10 par. 9. Otherwise, it just leaves
1076       --  the state to True.
1077
1078       if S.Waiting then
1079          S.Waiting := False;
1080          S.State := False;
1081
1082          Result := pthread_cond_signal (S.CV'Access);
1083          pragma Assert (Result = 0);
1084
1085       else
1086          S.State := True;
1087       end if;
1088
1089       Result := pthread_mutex_unlock (S.L'Access);
1090       pragma Assert (Result = 0);
1091
1092       SSL.Abort_Undefer.all;
1093    end Set_True;
1094
1095    ------------------------
1096    -- Suspend_Until_True --
1097    ------------------------
1098
1099    procedure Suspend_Until_True (S : in out Suspension_Object) is
1100       Result : Interfaces.C.int;
1101
1102    begin
1103       SSL.Abort_Defer.all;
1104
1105       Result := pthread_mutex_lock (S.L'Access);
1106       pragma Assert (Result = 0);
1107
1108       if S.Waiting then
1109
1110          --  Program_Error must be raised upon calling Suspend_Until_True
1111          --  if another task is already waiting on that suspension object
1112          --  (RM D.10(10)).
1113
1114          Result := pthread_mutex_unlock (S.L'Access);
1115          pragma Assert (Result = 0);
1116
1117          SSL.Abort_Undefer.all;
1118
1119          raise Program_Error;
1120
1121       else
1122          --  Suspend the task if the state is False. Otherwise, the task
1123          --  continues its execution, and the state of the suspension object
1124          --  is set to False (ARM D.10 par. 9).
1125
1126          if S.State then
1127             S.State := False;
1128          else
1129             S.Waiting := True;
1130
1131             loop
1132                --  Loop in case pthread_cond_wait returns earlier than expected
1133                --  (e.g. in case of EINTR caused by a signal). This should not
1134                --  happen with the current Linux implementation of pthread, but
1135                --  POSIX does not guarantee it so this may change in future.
1136
1137                Result := pthread_cond_wait (S.CV'Access, S.L'Access);
1138                pragma Assert (Result = 0 or else Result = EINTR);
1139
1140                exit when not S.Waiting;
1141             end loop;
1142          end if;
1143
1144          Result := pthread_mutex_unlock (S.L'Access);
1145          pragma Assert (Result = 0);
1146
1147          SSL.Abort_Undefer.all;
1148       end if;
1149    end Suspend_Until_True;
1150
1151    ----------------
1152    -- Check_Exit --
1153    ----------------
1154
1155    --  Dummy version
1156
1157    function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1158       pragma Unreferenced (Self_ID);
1159    begin
1160       return True;
1161    end Check_Exit;
1162
1163    --------------------
1164    -- Check_No_Locks --
1165    --------------------
1166
1167    function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1168       pragma Unreferenced (Self_ID);
1169    begin
1170       return True;
1171    end Check_No_Locks;
1172
1173    ----------------------
1174    -- Environment_Task --
1175    ----------------------
1176
1177    function Environment_Task return Task_Id is
1178    begin
1179       return Environment_Task_Id;
1180    end Environment_Task;
1181
1182    ------------------
1183    -- Suspend_Task --
1184    ------------------
1185
1186    function Suspend_Task
1187      (T           : ST.Task_Id;
1188       Thread_Self : Thread_Id) return Boolean
1189    is
1190    begin
1191       if T.Common.LL.Thread /= Thread_Self then
1192          return pthread_kill (T.Common.LL.Thread, SIGSTOP) = 0;
1193       else
1194          return True;
1195       end if;
1196    end Suspend_Task;
1197
1198    -----------------
1199    -- Resume_Task --
1200    -----------------
1201
1202    function Resume_Task
1203      (T           : ST.Task_Id;
1204       Thread_Self : Thread_Id) return Boolean
1205    is
1206    begin
1207       if T.Common.LL.Thread /= Thread_Self then
1208          return pthread_kill (T.Common.LL.Thread, SIGCONT) = 0;
1209       else
1210          return True;
1211       end if;
1212    end Resume_Task;
1213
1214    --------------------
1215    -- Stop_All_Tasks --
1216    --------------------
1217
1218    procedure Stop_All_Tasks is
1219    begin
1220       null;
1221    end Stop_All_Tasks;
1222
1223    ---------------
1224    -- Stop_Task --
1225    ---------------
1226
1227    function Stop_Task (T : ST.Task_Id) return Boolean is
1228       pragma Unreferenced (T);
1229    begin
1230       return False;
1231    end Stop_Task;
1232
1233    -------------------
1234    -- Continue_Task --
1235    -------------------
1236
1237    function Continue_Task (T : ST.Task_Id) return Boolean is
1238       pragma Unreferenced (T);
1239    begin
1240       return False;
1241    end Continue_Task;
1242
1243    ----------------
1244    -- Initialize --
1245    ----------------
1246
1247    procedure Initialize (Environment_Task : Task_Id) is
1248       act     : aliased struct_sigaction;
1249       old_act : aliased struct_sigaction;
1250       Tmp_Set : aliased sigset_t;
1251       Result  : Interfaces.C.int;
1252       --  Whether to use an alternate signal stack for stack overflows
1253
1254       function State
1255         (Int : System.Interrupt_Management.Interrupt_ID) return Character;
1256       pragma Import (C, State, "__gnat_get_interrupt_state");
1257       --  Get interrupt state.  Defined in a-init.c
1258       --  The input argument is the interrupt number,
1259       --  and the result is one of the following:
1260
1261       Default : constant Character := 's';
1262       --    'n'   this interrupt not set by any Interrupt_State pragma
1263       --    'u'   Interrupt_State pragma set state to User
1264       --    'r'   Interrupt_State pragma set state to Runtime
1265       --    's'   Interrupt_State pragma set state to System (use "default"
1266       --           system handler)
1267
1268       use type System.Multiprocessors.CPU_Range;
1269
1270    begin
1271       Environment_Task_Id := Environment_Task;
1272
1273       Interrupt_Management.Initialize;
1274
1275       --  Prepare the set of signals that should be unblocked in all tasks
1276
1277       Result := sigemptyset (Unblocked_Signal_Mask'Access);
1278       pragma Assert (Result = 0);
1279
1280       for J in Interrupt_Management.Interrupt_ID loop
1281          if System.Interrupt_Management.Keep_Unmasked (J) then
1282             Result := sigaddset (Unblocked_Signal_Mask'Access, Signal (J));
1283             pragma Assert (Result = 0);
1284          end if;
1285       end loop;
1286
1287       Result := pthread_mutexattr_init (Mutex_Attr'Access);
1288       pragma Assert (Result = 0);
1289
1290       Result := pthread_condattr_init (Cond_Attr'Access);
1291       pragma Assert (Result = 0);
1292
1293       Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1294
1295       --  Initialize the global RTS lock
1296
1297       Specific.Initialize (Environment_Task);
1298
1299       if Use_Alternate_Stack then
1300          Environment_Task.Common.Task_Alternate_Stack :=
1301            Alternate_Stack'Address;
1302       end if;
1303
1304       --  Make environment task known here because it doesn't go through
1305       --  Activate_Tasks, which does it for all other tasks.
1306
1307       Known_Tasks (Known_Tasks'First) := Environment_Task;
1308       Environment_Task.Known_Tasks_Index := Known_Tasks'First;
1309
1310       Enter_Task (Environment_Task);
1311
1312       if State
1313           (System.Interrupt_Management.Abort_Task_Interrupt) /= Default
1314       then
1315          act.sa_flags := 0;
1316          act.sa_handler := Abort_Handler'Address;
1317
1318          Result := sigemptyset (Tmp_Set'Access);
1319          pragma Assert (Result = 0);
1320          act.sa_mask := Tmp_Set;
1321
1322          Result :=
1323            sigaction
1324            (Signal (Interrupt_Management.Abort_Task_Interrupt),
1325             act'Unchecked_Access,
1326             old_act'Unchecked_Access);
1327          pragma Assert (Result = 0);
1328          Abort_Handler_Installed := True;
1329       end if;
1330
1331       --  pragma CPU for the environment task
1332
1333       if pthread_setaffinity_np'Address /= System.Null_Address
1334         and then Environment_Task.Common.Base_CPU /=
1335                    System.Multiprocessors.Not_A_Specific_CPU
1336       then
1337          declare
1338             CPU_Set : aliased cpu_set_t := (bits => (others => False));
1339          begin
1340             CPU_Set.bits (Integer (Environment_Task.Common.Base_CPU)) := True;
1341             Result :=
1342               pthread_setaffinity_np
1343                 (Environment_Task.Common.LL.Thread,
1344                  CPU_SETSIZE / 8,
1345                  CPU_Set'Access);
1346             pragma Assert (Result = 0);
1347          end;
1348       end if;
1349    end Initialize;
1350
1351 end System.Task_Primitives.Operations;