OSDN Git Service

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