OSDN Git Service

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