OSDN Git Service

2011-08-31 Jose Ruiz <ruiz@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 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
883       --  Handle dispatching domains
884
885       elsif T.Common.Domain /= null then
886          declare
887             CPU_Set : aliased cpu_set_t := (bits => (others => False));
888
889          begin
890             --  Set the affinity to all the processors belonging to the
891             --  dispatching domain.
892
893             for Proc in T.Common.Domain'Range loop
894                CPU_Set.bits (Integer (Proc)) := T.Common.Domain (Proc);
895             end loop;
896
897             Result :=
898               pthread_attr_setaffinity_np
899                 (Attributes'Access,
900                  CPU_SETSIZE / 8,
901                  CPU_Set'Access);
902             pragma Assert (Result = 0);
903          end;
904       end if;
905
906       --  Since the initial signal mask of a thread is inherited from the
907       --  creator, and the Environment task has all its signals masked, we
908       --  do not need to manipulate caller's signal mask at this point.
909       --  All tasks in RTS will have All_Tasks_Mask initially.
910
911       Result := pthread_create
912         (T.Common.LL.Thread'Access,
913          Attributes'Access,
914          Thread_Body_Access (Wrapper),
915          To_Address (T));
916       pragma Assert
917         (Result = 0 or else Result = EAGAIN or else Result = ENOMEM);
918
919       if Result /= 0 then
920          Succeeded := False;
921          Result := pthread_attr_destroy (Attributes'Access);
922          pragma Assert (Result = 0);
923          return;
924       end if;
925
926       Succeeded := True;
927
928       Result := pthread_attr_destroy (Attributes'Access);
929       pragma Assert (Result = 0);
930
931       Set_Priority (T, Priority);
932    end Create_Task;
933
934    ------------------
935    -- Finalize_TCB --
936    ------------------
937
938    procedure Finalize_TCB (T : Task_Id) is
939       Result  : Interfaces.C.int;
940       Tmp     : Task_Id := T;
941       Is_Self : constant Boolean := T = Self;
942
943       procedure Free is new
944         Ada.Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
945
946    begin
947       if not Single_Lock then
948          Result := pthread_mutex_destroy (T.Common.LL.L'Access);
949          pragma Assert (Result = 0);
950       end if;
951
952       Result := pthread_cond_destroy (T.Common.LL.CV'Access);
953       pragma Assert (Result = 0);
954
955       if T.Known_Tasks_Index /= -1 then
956          Known_Tasks (T.Known_Tasks_Index) := null;
957       end if;
958       SC.Invalidate_Stack_Cache (T.Common.Compiler_Data.Pri_Stack_Info'Access);
959       Free (Tmp);
960
961       if Is_Self then
962          Specific.Set (null);
963       end if;
964    end Finalize_TCB;
965
966    ---------------
967    -- Exit_Task --
968    ---------------
969
970    procedure Exit_Task is
971    begin
972       Specific.Set (null);
973    end Exit_Task;
974
975    ----------------
976    -- Abort_Task --
977    ----------------
978
979    procedure Abort_Task (T : Task_Id) is
980       Result : Interfaces.C.int;
981    begin
982       if Abort_Handler_Installed then
983          Result :=
984            pthread_kill
985              (T.Common.LL.Thread,
986               Signal (System.Interrupt_Management.Abort_Task_Interrupt));
987          pragma Assert (Result = 0);
988       end if;
989    end Abort_Task;
990
991    ----------------
992    -- Initialize --
993    ----------------
994
995    procedure Initialize (S : in out Suspension_Object) is
996       Result : Interfaces.C.int;
997
998    begin
999       --  Initialize internal state (always to False (RM D.10(6)))
1000
1001       S.State := False;
1002       S.Waiting := False;
1003
1004       --  Initialize internal mutex
1005
1006       Result := pthread_mutex_init (S.L'Access, Mutex_Attr'Access);
1007
1008       pragma Assert (Result = 0 or else Result = ENOMEM);
1009
1010       if Result = ENOMEM then
1011          raise Storage_Error;
1012       end if;
1013
1014       --  Initialize internal condition variable
1015
1016       Result := pthread_cond_init (S.CV'Access, Cond_Attr'Access);
1017
1018       pragma Assert (Result = 0 or else Result = ENOMEM);
1019
1020       if Result /= 0 then
1021          Result := pthread_mutex_destroy (S.L'Access);
1022          pragma Assert (Result = 0);
1023
1024          if Result = ENOMEM then
1025             raise Storage_Error;
1026          end if;
1027       end if;
1028    end Initialize;
1029
1030    --------------
1031    -- Finalize --
1032    --------------
1033
1034    procedure Finalize (S : in out Suspension_Object) is
1035       Result : Interfaces.C.int;
1036
1037    begin
1038       --  Destroy internal mutex
1039
1040       Result := pthread_mutex_destroy (S.L'Access);
1041       pragma Assert (Result = 0);
1042
1043       --  Destroy internal condition variable
1044
1045       Result := pthread_cond_destroy (S.CV'Access);
1046       pragma Assert (Result = 0);
1047    end Finalize;
1048
1049    -------------------
1050    -- Current_State --
1051    -------------------
1052
1053    function Current_State (S : Suspension_Object) return Boolean is
1054    begin
1055       --  We do not want to use lock on this read operation. State is marked
1056       --  as Atomic so that we ensure that the value retrieved is correct.
1057
1058       return S.State;
1059    end Current_State;
1060
1061    ---------------
1062    -- Set_False --
1063    ---------------
1064
1065    procedure Set_False (S : in out Suspension_Object) is
1066       Result : Interfaces.C.int;
1067
1068    begin
1069       SSL.Abort_Defer.all;
1070
1071       Result := pthread_mutex_lock (S.L'Access);
1072       pragma Assert (Result = 0);
1073
1074       S.State := False;
1075
1076       Result := pthread_mutex_unlock (S.L'Access);
1077       pragma Assert (Result = 0);
1078
1079       SSL.Abort_Undefer.all;
1080    end Set_False;
1081
1082    --------------
1083    -- Set_True --
1084    --------------
1085
1086    procedure Set_True (S : in out Suspension_Object) is
1087       Result : Interfaces.C.int;
1088
1089    begin
1090       SSL.Abort_Defer.all;
1091
1092       Result := pthread_mutex_lock (S.L'Access);
1093       pragma Assert (Result = 0);
1094
1095       --  If there is already a task waiting on this suspension object then
1096       --  we resume it, leaving the state of the suspension object to False,
1097       --  as it is specified in ARM D.10 par. 9. Otherwise, it just leaves
1098       --  the state to True.
1099
1100       if S.Waiting then
1101          S.Waiting := False;
1102          S.State := False;
1103
1104          Result := pthread_cond_signal (S.CV'Access);
1105          pragma Assert (Result = 0);
1106
1107       else
1108          S.State := True;
1109       end if;
1110
1111       Result := pthread_mutex_unlock (S.L'Access);
1112       pragma Assert (Result = 0);
1113
1114       SSL.Abort_Undefer.all;
1115    end Set_True;
1116
1117    ------------------------
1118    -- Suspend_Until_True --
1119    ------------------------
1120
1121    procedure Suspend_Until_True (S : in out Suspension_Object) is
1122       Result : Interfaces.C.int;
1123
1124    begin
1125       SSL.Abort_Defer.all;
1126
1127       Result := pthread_mutex_lock (S.L'Access);
1128       pragma Assert (Result = 0);
1129
1130       if S.Waiting then
1131
1132          --  Program_Error must be raised upon calling Suspend_Until_True
1133          --  if another task is already waiting on that suspension object
1134          --  (RM D.10(10)).
1135
1136          Result := pthread_mutex_unlock (S.L'Access);
1137          pragma Assert (Result = 0);
1138
1139          SSL.Abort_Undefer.all;
1140
1141          raise Program_Error;
1142
1143       else
1144          --  Suspend the task if the state is False. Otherwise, the task
1145          --  continues its execution, and the state of the suspension object
1146          --  is set to False (ARM D.10 par. 9).
1147
1148          if S.State then
1149             S.State := False;
1150          else
1151             S.Waiting := True;
1152
1153             loop
1154                --  Loop in case pthread_cond_wait returns earlier than expected
1155                --  (e.g. in case of EINTR caused by a signal). This should not
1156                --  happen with the current Linux implementation of pthread, but
1157                --  POSIX does not guarantee it so this may change in future.
1158
1159                Result := pthread_cond_wait (S.CV'Access, S.L'Access);
1160                pragma Assert (Result = 0 or else Result = EINTR);
1161
1162                exit when not S.Waiting;
1163             end loop;
1164          end if;
1165
1166          Result := pthread_mutex_unlock (S.L'Access);
1167          pragma Assert (Result = 0);
1168
1169          SSL.Abort_Undefer.all;
1170       end if;
1171    end Suspend_Until_True;
1172
1173    ----------------
1174    -- Check_Exit --
1175    ----------------
1176
1177    --  Dummy version
1178
1179    function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1180       pragma Unreferenced (Self_ID);
1181    begin
1182       return True;
1183    end Check_Exit;
1184
1185    --------------------
1186    -- Check_No_Locks --
1187    --------------------
1188
1189    function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1190       pragma Unreferenced (Self_ID);
1191    begin
1192       return True;
1193    end Check_No_Locks;
1194
1195    ----------------------
1196    -- Environment_Task --
1197    ----------------------
1198
1199    function Environment_Task return Task_Id is
1200    begin
1201       return Environment_Task_Id;
1202    end Environment_Task;
1203
1204    ------------------
1205    -- Suspend_Task --
1206    ------------------
1207
1208    function Suspend_Task
1209      (T           : ST.Task_Id;
1210       Thread_Self : Thread_Id) return Boolean
1211    is
1212    begin
1213       if T.Common.LL.Thread /= Thread_Self then
1214          return pthread_kill (T.Common.LL.Thread, SIGSTOP) = 0;
1215       else
1216          return True;
1217       end if;
1218    end Suspend_Task;
1219
1220    -----------------
1221    -- Resume_Task --
1222    -----------------
1223
1224    function Resume_Task
1225      (T           : ST.Task_Id;
1226       Thread_Self : Thread_Id) return Boolean
1227    is
1228    begin
1229       if T.Common.LL.Thread /= Thread_Self then
1230          return pthread_kill (T.Common.LL.Thread, SIGCONT) = 0;
1231       else
1232          return True;
1233       end if;
1234    end Resume_Task;
1235
1236    --------------------
1237    -- Stop_All_Tasks --
1238    --------------------
1239
1240    procedure Stop_All_Tasks is
1241    begin
1242       null;
1243    end Stop_All_Tasks;
1244
1245    ---------------
1246    -- Stop_Task --
1247    ---------------
1248
1249    function Stop_Task (T : ST.Task_Id) return Boolean is
1250       pragma Unreferenced (T);
1251    begin
1252       return False;
1253    end Stop_Task;
1254
1255    -------------------
1256    -- Continue_Task --
1257    -------------------
1258
1259    function Continue_Task (T : ST.Task_Id) return Boolean is
1260       pragma Unreferenced (T);
1261    begin
1262       return False;
1263    end Continue_Task;
1264
1265    ----------------
1266    -- Initialize --
1267    ----------------
1268
1269    procedure Initialize (Environment_Task : Task_Id) is
1270       act     : aliased struct_sigaction;
1271       old_act : aliased struct_sigaction;
1272       Tmp_Set : aliased sigset_t;
1273       Result  : Interfaces.C.int;
1274       --  Whether to use an alternate signal stack for stack overflows
1275
1276       function State
1277         (Int : System.Interrupt_Management.Interrupt_ID) return Character;
1278       pragma Import (C, State, "__gnat_get_interrupt_state");
1279       --  Get interrupt state.  Defined in a-init.c
1280       --  The input argument is the interrupt number,
1281       --  and the result is one of the following:
1282
1283       Default : constant Character := 's';
1284       --    'n'   this interrupt not set by any Interrupt_State pragma
1285       --    'u'   Interrupt_State pragma set state to User
1286       --    'r'   Interrupt_State pragma set state to Runtime
1287       --    's'   Interrupt_State pragma set state to System (use "default"
1288       --           system handler)
1289
1290       use type System.Multiprocessors.CPU_Range;
1291
1292    begin
1293       Environment_Task_Id := Environment_Task;
1294
1295       Interrupt_Management.Initialize;
1296
1297       --  Prepare the set of signals that should be unblocked in all tasks
1298
1299       Result := sigemptyset (Unblocked_Signal_Mask'Access);
1300       pragma Assert (Result = 0);
1301
1302       for J in Interrupt_Management.Interrupt_ID loop
1303          if System.Interrupt_Management.Keep_Unmasked (J) then
1304             Result := sigaddset (Unblocked_Signal_Mask'Access, Signal (J));
1305             pragma Assert (Result = 0);
1306          end if;
1307       end loop;
1308
1309       Result := pthread_mutexattr_init (Mutex_Attr'Access);
1310       pragma Assert (Result = 0);
1311
1312       Result := pthread_condattr_init (Cond_Attr'Access);
1313       pragma Assert (Result = 0);
1314
1315       Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1316
1317       --  Initialize the global RTS lock
1318
1319       Specific.Initialize (Environment_Task);
1320
1321       if Use_Alternate_Stack then
1322          Environment_Task.Common.Task_Alternate_Stack :=
1323            Alternate_Stack'Address;
1324       end if;
1325
1326       --  Make environment task known here because it doesn't go through
1327       --  Activate_Tasks, which does it for all other tasks.
1328
1329       Known_Tasks (Known_Tasks'First) := Environment_Task;
1330       Environment_Task.Known_Tasks_Index := Known_Tasks'First;
1331
1332       Enter_Task (Environment_Task);
1333
1334       if State
1335           (System.Interrupt_Management.Abort_Task_Interrupt) /= Default
1336       then
1337          act.sa_flags := 0;
1338          act.sa_handler := Abort_Handler'Address;
1339
1340          Result := sigemptyset (Tmp_Set'Access);
1341          pragma Assert (Result = 0);
1342          act.sa_mask := Tmp_Set;
1343
1344          Result :=
1345            sigaction
1346            (Signal (Interrupt_Management.Abort_Task_Interrupt),
1347             act'Unchecked_Access,
1348             old_act'Unchecked_Access);
1349          pragma Assert (Result = 0);
1350          Abort_Handler_Installed := True;
1351       end if;
1352
1353       --  pragma CPU and dispatching domains for the environment task
1354
1355       Set_Task_Affinity (Environment_Task);
1356    end Initialize;
1357
1358    -----------------------
1359    -- Set_Task_Affinity --
1360    -----------------------
1361
1362    procedure Set_Task_Affinity (T : ST.Task_Id) is
1363       use type System.Multiprocessors.CPU_Range;
1364
1365    begin
1366       if pthread_setaffinity_np'Address /= System.Null_Address then
1367          declare
1368             type cpu_set_t_ptr is access all cpu_set_t;
1369
1370             CPU_Set : cpu_set_t_ptr := null;
1371             Result  : Interfaces.C.int;
1372
1373          begin
1374             --  We look at the specific CPU (Base_CPU) first, then at the
1375             --  Task_Info field, and finally at the assigned dispatching
1376             --  domain, if any.
1377
1378             if T.Common.Base_CPU /= Multiprocessors.Not_A_Specific_CPU then
1379
1380                --  Set the affinity to an unique CPU
1381
1382                CPU_Set := new cpu_set_t'(bits => (others => False));
1383                CPU_Set.bits (Integer (T.Common.Base_CPU)) := True;
1384
1385             --  Handle Task_Info
1386
1387             elsif T.Common.Task_Info /= null
1388               and then T.Common.Task_Info.CPU_Affinity /= Task_Info.Any_CPU
1389             then
1390                CPU_Set := T.Common.Task_Info.CPU_Affinity'Access;
1391
1392             --  Handle dispatching domains
1393
1394             elsif T.Common.Domain /= null and then
1395               (T.Common.Domain /= ST.System_Domain
1396                 or else T.Common.Domain.all /=
1397                           (Multiprocessors.CPU'First ..
1398                            Multiprocessors.Number_Of_CPUs => True))
1399             then
1400                --  Set the affinity to all the processors belonging to the
1401                --  dispatching domain. To avoid changing CPU affinities when
1402                --  not needed, we set the affinity only when assigning to a
1403                --  domain other than the default one, or when the default one
1404                --  has been modified.
1405
1406                CPU_Set := new cpu_set_t'(bits => (others => False));
1407
1408                for Proc in T.Common.Domain'Range loop
1409                   CPU_Set.bits (Integer (Proc)) := T.Common.Domain (Proc);
1410                end loop;
1411             end if;
1412
1413             --  We set the new affinity if needed. Otherwise, the new task
1414             --  will inherit its creator's CPU affinity mask (according to
1415             --  the documentation of pthread_setaffinity_np), which is
1416             --  consistent with Ada's required semantics.
1417
1418             if CPU_Set /= null then
1419                Result :=
1420                  pthread_setaffinity_np
1421                    (T.Common.LL.Thread, CPU_SETSIZE / 8, CPU_Set);
1422                pragma Assert (Result = 0);
1423             end if;
1424          end;
1425       end if;
1426    end Set_Task_Affinity;
1427
1428 end System.Task_Primitives.Operations;