OSDN Git Service

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