OSDN Git Service

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