OSDN Git Service

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