OSDN Git Service

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