OSDN Git Service

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