OSDN Git Service

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