OSDN Git Service

2006-06-07 Paolo Bonzini <bonzini@gnu.org>
[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
582    --  we assume the caller is abort-deferred but is holding
583    --  no locks.
584
585    procedure Timed_Delay
586      (Self_ID  : Task_Id;
587       Time     : Duration;
588       Mode     : ST.Delay_Modes)
589    is
590       Check_Time : constant Duration := Monotonic_Clock;
591       Abs_Time   : Duration;
592       Rel_Time   : Duration;
593       Request    : aliased timespec;
594       Result     : Interfaces.C.int;
595
596    begin
597       if Single_Lock then
598          Lock_RTS;
599       end if;
600
601       Write_Lock (Self_ID);
602
603       if Mode = Relative then
604          Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
605
606          if Relative_Timed_Wait then
607             Rel_Time := Duration'Min (Max_Sensible_Delay, Time);
608          end if;
609
610       else
611          Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
612
613          if Relative_Timed_Wait then
614             Rel_Time := Duration'Min (Max_Sensible_Delay, Time - Check_Time);
615          end if;
616       end if;
617
618       if Abs_Time > Check_Time then
619          if Relative_Timed_Wait then
620             Request := To_Timespec (Rel_Time);
621          else
622             Request := To_Timespec (Abs_Time);
623          end if;
624
625          Self_ID.Common.State := Delay_Sleep;
626
627          loop
628             if Self_ID.Pending_Priority_Change then
629                Self_ID.Pending_Priority_Change := False;
630                Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
631                Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
632             end if;
633
634             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
635
636             if Single_Lock then
637                Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
638                  Single_RTS_Lock'Access, Request'Access);
639             else
640                Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
641                  Self_ID.Common.LL.L'Access, Request'Access);
642             end if;
643
644             exit when Abs_Time <= Monotonic_Clock;
645
646             pragma Assert (Result = 0
647                              or else Result = ETIMEDOUT
648                              or else Result = EINTR);
649          end loop;
650
651          Self_ID.Common.State := Runnable;
652       end if;
653
654       Unlock (Self_ID);
655
656       if Single_Lock then
657          Unlock_RTS;
658       end if;
659
660       Result := sched_yield;
661    end Timed_Delay;
662
663    ---------------------
664    -- Monotonic_Clock --
665    ---------------------
666
667    function Monotonic_Clock return Duration is
668       TS     : aliased timespec;
669       Result : Interfaces.C.int;
670    begin
671       Result := clock_gettime
672         (clock_id => CLOCK_REALTIME, tp => TS'Unchecked_Access);
673       pragma Assert (Result = 0);
674       return To_Duration (TS);
675    end Monotonic_Clock;
676
677    -------------------
678    -- RT_Resolution --
679    -------------------
680
681    function RT_Resolution return Duration is
682    begin
683       return 10#1.0#E-6;
684    end RT_Resolution;
685
686    ------------
687    -- Wakeup --
688    ------------
689
690    procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
691       pragma Warnings (Off, Reason);
692       Result : Interfaces.C.int;
693    begin
694       Result := pthread_cond_signal (T.Common.LL.CV'Access);
695       pragma Assert (Result = 0);
696    end Wakeup;
697
698    -----------
699    -- Yield --
700    -----------
701
702    procedure Yield (Do_Yield : Boolean := True) is
703       Result : Interfaces.C.int;
704       pragma Unreferenced (Result);
705    begin
706       if Do_Yield then
707          Result := sched_yield;
708       end if;
709    end Yield;
710
711    ------------------
712    -- Set_Priority --
713    ------------------
714
715    procedure Set_Priority
716      (T                   : Task_Id;
717       Prio                : System.Any_Priority;
718       Loss_Of_Inheritance : Boolean := False)
719    is
720       pragma Warnings (Off, Loss_Of_Inheritance);
721
722       Result : Interfaces.C.int;
723       Param  : aliased struct_sched_param;
724
725    begin
726       T.Common.Current_Priority := Prio;
727       Param.sched_priority := Interfaces.C.int (Prio);
728
729       if Time_Slice_Supported and then Time_Slice_Val > 0 then
730          Result := pthread_setschedparam
731            (T.Common.LL.Thread, SCHED_RR, Param'Access);
732
733       elsif Dispatching_Policy = 'F' or else Time_Slice_Val = 0 then
734          Result := pthread_setschedparam
735            (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
736
737       else
738          Result := pthread_setschedparam
739            (T.Common.LL.Thread, SCHED_OTHER, Param'Access);
740       end if;
741
742       pragma Assert (Result = 0);
743    end Set_Priority;
744
745    ------------------
746    -- Get_Priority --
747    ------------------
748
749    function Get_Priority (T : Task_Id) return System.Any_Priority is
750    begin
751       return T.Common.Current_Priority;
752    end Get_Priority;
753
754    ----------------
755    -- Enter_Task --
756    ----------------
757
758    procedure Enter_Task (Self_ID : Task_Id) is
759    begin
760       Self_ID.Common.LL.Thread := pthread_self;
761       Self_ID.Common.LL.LWP := lwp_self;
762
763       Specific.Set (Self_ID);
764
765       Lock_RTS;
766
767       for J in Known_Tasks'Range loop
768          if Known_Tasks (J) = null then
769             Known_Tasks (J) := Self_ID;
770             Self_ID.Known_Tasks_Index := J;
771             exit;
772          end if;
773       end loop;
774
775       Unlock_RTS;
776    end Enter_Task;
777
778    --------------
779    -- New_ATCB --
780    --------------
781
782    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
783    begin
784       return new Ada_Task_Control_Block (Entry_Num);
785    end New_ATCB;
786
787    -------------------
788    -- Is_Valid_Task --
789    -------------------
790
791    function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
792
793    -----------------------------
794    -- Register_Foreign_Thread --
795    -----------------------------
796
797    function Register_Foreign_Thread return Task_Id is
798    begin
799       if Is_Valid_Task then
800          return Self;
801       else
802          return Register_Foreign_Thread (pthread_self);
803       end if;
804    end Register_Foreign_Thread;
805
806    --------------------
807    -- Initialize_TCB --
808    --------------------
809
810    procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
811       Mutex_Attr : aliased pthread_mutexattr_t;
812       Result     : Interfaces.C.int;
813       Cond_Attr  : aliased pthread_condattr_t;
814
815    begin
816       --  Give the task a unique serial number.
817
818       Self_ID.Serial_Number := Next_Serial_Number;
819       Next_Serial_Number := Next_Serial_Number + 1;
820       pragma Assert (Next_Serial_Number /= 0);
821
822       if not Single_Lock then
823          Result := pthread_mutexattr_init (Mutex_Attr'Access);
824          pragma Assert (Result = 0 or else Result = ENOMEM);
825
826          if Result = 0 then
827             if Locking_Policy = 'C' then
828                Result := pthread_mutexattr_setprotocol
829                  (Mutex_Attr'Access, PTHREAD_PRIO_PROTECT);
830                pragma Assert (Result = 0);
831
832                Result := pthread_mutexattr_setprioceiling
833                   (Mutex_Attr'Access,
834                    Interfaces.C.int (System.Any_Priority'Last));
835                pragma Assert (Result = 0);
836
837             elsif Locking_Policy = 'I' then
838                Result := pthread_mutexattr_setprotocol
839                  (Mutex_Attr'Access, PTHREAD_PRIO_INHERIT);
840                pragma Assert (Result = 0);
841             end if;
842
843             Result := pthread_mutex_init (Self_ID.Common.LL.L'Access,
844               Mutex_Attr'Access);
845             pragma Assert (Result = 0 or else Result = ENOMEM);
846          end if;
847
848          if Result /= 0 then
849             Succeeded := False;
850             return;
851          end if;
852
853          Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
854          pragma Assert (Result = 0);
855       end if;
856
857       Result := pthread_condattr_init (Cond_Attr'Access);
858       pragma Assert (Result = 0 or else Result = ENOMEM);
859
860       if Result = 0 then
861          Result := pthread_cond_init (Self_ID.Common.LL.CV'Access,
862            Cond_Attr'Access);
863          pragma Assert (Result = 0 or else Result = ENOMEM);
864       end if;
865
866       if Result = 0 then
867          Succeeded := True;
868       else
869          if not Single_Lock then
870             Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
871             pragma Assert (Result = 0);
872          end if;
873
874          Succeeded := False;
875       end if;
876
877       Result := pthread_condattr_destroy (Cond_Attr'Access);
878       pragma Assert (Result = 0);
879    end Initialize_TCB;
880
881    -----------------
882    -- Create_Task --
883    -----------------
884
885    procedure Create_Task
886      (T          : Task_Id;
887       Wrapper    : System.Address;
888       Stack_Size : System.Parameters.Size_Type;
889       Priority   : System.Any_Priority;
890       Succeeded  : out Boolean)
891    is
892       Attributes          : aliased pthread_attr_t;
893       Adjusted_Stack_Size : Interfaces.C.size_t;
894       Result              : Interfaces.C.int;
895
896       function Thread_Body_Access is new
897         Unchecked_Conversion (System.Address, Thread_Body);
898
899       use System.Task_Info;
900
901    begin
902       Adjusted_Stack_Size := Interfaces.C.size_t (Stack_Size);
903
904       if Stack_Base_Available then
905          --  If Stack Checking is supported then allocate 2 additional pages:
906          --
907          --  In the worst case, stack is allocated at something like
908          --  N * Get_Page_Size - epsilon, we need to add the size for 2 pages
909          --  to be sure the effective stack size is greater than what
910          --  has been asked.
911
912          Adjusted_Stack_Size := Adjusted_Stack_Size + 2 * Get_Page_Size;
913       end if;
914
915       Result := pthread_attr_init (Attributes'Access);
916       pragma Assert (Result = 0 or else Result = ENOMEM);
917
918       if Result /= 0 then
919          Succeeded := False;
920          return;
921       end if;
922
923       Result := pthread_attr_setdetachstate
924         (Attributes'Access, PTHREAD_CREATE_DETACHED);
925       pragma Assert (Result = 0);
926
927       Result := pthread_attr_setstacksize
928         (Attributes'Access, Adjusted_Stack_Size);
929       pragma Assert (Result = 0);
930
931       if T.Common.Task_Info /= Default_Scope then
932
933          --  We are assuming that Scope_Type has the same values than the
934          --  corresponding C macros
935
936          Result := pthread_attr_setscope
937            (Attributes'Access, Task_Info_Type'Pos (T.Common.Task_Info));
938          pragma Assert (Result = 0);
939       end if;
940
941       --  Since the initial signal mask of a thread is inherited from the
942       --  creator, and the Environment task has all its signals masked, we
943       --  do not need to manipulate caller's signal mask at this point.
944       --  All tasks in RTS will have All_Tasks_Mask initially.
945
946       Result := pthread_create
947         (T.Common.LL.Thread'Access,
948          Attributes'Access,
949          Thread_Body_Access (Wrapper),
950          To_Address (T));
951       pragma Assert (Result = 0 or else Result = EAGAIN);
952
953       Succeeded := Result = 0;
954
955       Result := pthread_attr_destroy (Attributes'Access);
956       pragma Assert (Result = 0);
957
958       Set_Priority (T, Priority);
959    end Create_Task;
960
961    ------------------
962    -- Finalize_TCB --
963    ------------------
964
965    procedure Finalize_TCB (T : Task_Id) is
966       Result  : Interfaces.C.int;
967       Tmp     : Task_Id := T;
968       Is_Self : constant Boolean := T = Self;
969
970       procedure Free is new
971         Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
972
973    begin
974       if not Single_Lock then
975          Result := pthread_mutex_destroy (T.Common.LL.L'Access);
976          pragma Assert (Result = 0);
977       end if;
978
979       Result := pthread_cond_destroy (T.Common.LL.CV'Access);
980       pragma Assert (Result = 0);
981
982       if T.Known_Tasks_Index /= -1 then
983          Known_Tasks (T.Known_Tasks_Index) := null;
984       end if;
985
986       Free (Tmp);
987
988       if Is_Self then
989          Specific.Set (null);
990       end if;
991    end Finalize_TCB;
992
993    ---------------
994    -- Exit_Task --
995    ---------------
996
997    procedure Exit_Task is
998    begin
999       --  Mark this task as unknown, so that if Self is called, it won't
1000       --  return a dangling pointer.
1001
1002       Specific.Set (null);
1003    end Exit_Task;
1004
1005    ----------------
1006    -- Abort_Task --
1007    ----------------
1008
1009    procedure Abort_Task (T : Task_Id) is
1010       Result : Interfaces.C.int;
1011    begin
1012       Result := pthread_kill (T.Common.LL.Thread,
1013         Signal (System.Interrupt_Management.Abort_Task_Interrupt));
1014       pragma Assert (Result = 0);
1015    end Abort_Task;
1016
1017    ----------------
1018    -- Initialize --
1019    ----------------
1020
1021    procedure Initialize (S : in out Suspension_Object) is
1022       Mutex_Attr : aliased pthread_mutexattr_t;
1023       Cond_Attr  : aliased pthread_condattr_t;
1024       Result     : Interfaces.C.int;
1025    begin
1026       --  Initialize internal state. It is always initialized to False (ARM
1027       --  D.10 par. 6).
1028
1029       S.State := False;
1030       S.Waiting := False;
1031
1032       --  Initialize internal mutex
1033
1034       Result := pthread_mutexattr_init (Mutex_Attr'Access);
1035       pragma Assert (Result = 0 or else Result = ENOMEM);
1036
1037       if Result = ENOMEM then
1038          raise Storage_Error;
1039       end if;
1040
1041       Result := pthread_mutex_init (S.L'Access, Mutex_Attr'Access);
1042       pragma Assert (Result = 0 or else Result = ENOMEM);
1043
1044       if Result = ENOMEM then
1045          Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
1046          pragma Assert (Result = 0);
1047
1048          raise Storage_Error;
1049       end if;
1050
1051       Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
1052       pragma Assert (Result = 0);
1053
1054       --  Initialize internal condition variable
1055
1056       Result := pthread_condattr_init (Cond_Attr'Access);
1057       pragma Assert (Result = 0 or else Result = ENOMEM);
1058
1059       if Result /= 0 then
1060          Result := pthread_mutex_destroy (S.L'Access);
1061          pragma Assert (Result = 0);
1062
1063          if Result = ENOMEM then
1064             raise Storage_Error;
1065          end if;
1066       end if;
1067
1068       Result := pthread_cond_init (S.CV'Access, Cond_Attr'Access);
1069       pragma Assert (Result = 0 or else Result = ENOMEM);
1070
1071       if Result /= 0 then
1072          Result := pthread_mutex_destroy (S.L'Access);
1073          pragma Assert (Result = 0);
1074
1075          if Result = ENOMEM then
1076             Result := pthread_condattr_destroy (Cond_Attr'Access);
1077             pragma Assert (Result = 0);
1078
1079             raise Storage_Error;
1080          end if;
1081       end if;
1082
1083       Result := pthread_condattr_destroy (Cond_Attr'Access);
1084       pragma Assert (Result = 0);
1085    end Initialize;
1086
1087    --------------
1088    -- Finalize --
1089    --------------
1090
1091    procedure Finalize (S : in out Suspension_Object) is
1092       Result  : Interfaces.C.int;
1093    begin
1094       --  Destroy internal mutex
1095
1096       Result := pthread_mutex_destroy (S.L'Access);
1097       pragma Assert (Result = 0);
1098
1099       --  Destroy internal condition variable
1100
1101       Result := pthread_cond_destroy (S.CV'Access);
1102       pragma Assert (Result = 0);
1103    end Finalize;
1104
1105    -------------------
1106    -- Current_State --
1107    -------------------
1108
1109    function Current_State (S : Suspension_Object) return Boolean is
1110    begin
1111       --  We do not want to use lock on this read operation. State is marked
1112       --  as Atomic so that we ensure that the value retrieved is correct.
1113
1114       return S.State;
1115    end Current_State;
1116
1117    ---------------
1118    -- Set_False --
1119    ---------------
1120
1121    procedure Set_False (S : in out Suspension_Object) is
1122       Result  : Interfaces.C.int;
1123    begin
1124       SSL.Abort_Defer.all;
1125
1126       Result := pthread_mutex_lock (S.L'Access);
1127       pragma Assert (Result = 0);
1128
1129       S.State := False;
1130
1131       Result := pthread_mutex_unlock (S.L'Access);
1132       pragma Assert (Result = 0);
1133
1134       SSL.Abort_Undefer.all;
1135    end Set_False;
1136
1137    --------------
1138    -- Set_True --
1139    --------------
1140
1141    procedure Set_True (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       --  If there is already a task waiting on this suspension object then
1150       --  we resume it, leaving the state of the suspension object to False,
1151       --  as it is specified in ARM D.10 par. 9. Otherwise, it just leaves
1152       --  the state to True.
1153
1154       if S.Waiting then
1155          S.Waiting := False;
1156          S.State := False;
1157
1158          Result := pthread_cond_signal (S.CV'Access);
1159          pragma Assert (Result = 0);
1160       else
1161          S.State := True;
1162       end if;
1163
1164       Result := pthread_mutex_unlock (S.L'Access);
1165       pragma Assert (Result = 0);
1166
1167       SSL.Abort_Undefer.all;
1168    end Set_True;
1169
1170    ------------------------
1171    -- Suspend_Until_True --
1172    ------------------------
1173
1174    procedure Suspend_Until_True (S : in out Suspension_Object) is
1175       Result : Interfaces.C.int;
1176    begin
1177       SSL.Abort_Defer.all;
1178
1179       Result := pthread_mutex_lock (S.L'Access);
1180       pragma Assert (Result = 0);
1181
1182       if S.Waiting then
1183          --  Program_Error must be raised upon calling Suspend_Until_True
1184          --  if another task is already waiting on that suspension object
1185          --  (ARM D.10 par. 10).
1186
1187          Result := pthread_mutex_unlock (S.L'Access);
1188          pragma Assert (Result = 0);
1189
1190          SSL.Abort_Undefer.all;
1191
1192          raise Program_Error;
1193       else
1194          --  Suspend the task if the state is False. Otherwise, the task
1195          --  continues its execution, and the state of the suspension object
1196          --  is set to False (ARM D.10 par. 9).
1197
1198          if S.State then
1199             S.State := False;
1200          else
1201             S.Waiting := True;
1202             Result := pthread_cond_wait (S.CV'Access, S.L'Access);
1203          end if;
1204
1205          Result := pthread_mutex_unlock (S.L'Access);
1206          pragma Assert (Result = 0);
1207
1208          SSL.Abort_Undefer.all;
1209       end if;
1210    end Suspend_Until_True;
1211
1212    ----------------
1213    -- Check_Exit --
1214    ----------------
1215
1216    --  Dummy version
1217
1218    function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1219       pragma Warnings (Off, Self_ID);
1220    begin
1221       return True;
1222    end Check_Exit;
1223
1224    --------------------
1225    -- Check_No_Locks --
1226    --------------------
1227
1228    function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1229       pragma Warnings (Off, Self_ID);
1230    begin
1231       return True;
1232    end Check_No_Locks;
1233
1234    ----------------------
1235    -- Environment_Task --
1236    ----------------------
1237
1238    function Environment_Task return Task_Id is
1239    begin
1240       return Environment_Task_Id;
1241    end Environment_Task;
1242
1243    --------------
1244    -- Lock_RTS --
1245    --------------
1246
1247    procedure Lock_RTS is
1248    begin
1249       Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
1250    end Lock_RTS;
1251
1252    ----------------
1253    -- Unlock_RTS --
1254    ----------------
1255
1256    procedure Unlock_RTS is
1257    begin
1258       Unlock (Single_RTS_Lock'Access, Global_Lock => True);
1259    end Unlock_RTS;
1260
1261    ------------------
1262    -- Suspend_Task --
1263    ------------------
1264
1265    function Suspend_Task
1266      (T           : ST.Task_Id;
1267       Thread_Self : Thread_Id) return Boolean
1268    is
1269       pragma Warnings (Off, T);
1270       pragma Warnings (Off, Thread_Self);
1271    begin
1272       return False;
1273    end Suspend_Task;
1274
1275    -----------------
1276    -- Resume_Task --
1277    -----------------
1278
1279    function Resume_Task
1280      (T           : ST.Task_Id;
1281       Thread_Self : Thread_Id) return Boolean
1282    is
1283       pragma Warnings (Off, T);
1284       pragma Warnings (Off, Thread_Self);
1285    begin
1286       return False;
1287    end Resume_Task;
1288
1289    ----------------
1290    -- Initialize --
1291    ----------------
1292
1293    procedure Initialize (Environment_Task : Task_Id) is
1294       act     : aliased struct_sigaction;
1295       old_act : aliased struct_sigaction;
1296       Tmp_Set : aliased sigset_t;
1297       Result  : Interfaces.C.int;
1298
1299       function State
1300         (Int : System.Interrupt_Management.Interrupt_ID) return Character;
1301       pragma Import (C, State, "__gnat_get_interrupt_state");
1302       --  Get interrupt state.  Defined in a-init.c
1303       --  The input argument is the interrupt number,
1304       --  and the result is one of the following:
1305
1306       Default : constant Character := 's';
1307       --    'n'   this interrupt not set by any Interrupt_State pragma
1308       --    'u'   Interrupt_State pragma set state to User
1309       --    'r'   Interrupt_State pragma set state to Runtime
1310       --    's'   Interrupt_State pragma set state to System (use "default"
1311       --           system handler)
1312
1313    begin
1314       Environment_Task_Id := Environment_Task;
1315
1316       Interrupt_Management.Initialize;
1317
1318       --  Prepare the set of signals that should unblocked in all tasks
1319
1320       Result := sigemptyset (Unblocked_Signal_Mask'Access);
1321       pragma Assert (Result = 0);
1322
1323       for J in Interrupt_Management.Interrupt_ID loop
1324          if System.Interrupt_Management.Keep_Unmasked (J) then
1325             Result := sigaddset (Unblocked_Signal_Mask'Access, Signal (J));
1326             pragma Assert (Result = 0);
1327          end if;
1328       end loop;
1329
1330       --  Initialize the lock used to synchronize chain of all ATCBs.
1331
1332       Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1333
1334       Specific.Initialize (Environment_Task);
1335
1336       Enter_Task (Environment_Task);
1337
1338       --  Install the abort-signal handler
1339
1340       if State (System.Interrupt_Management.Abort_Task_Interrupt)
1341         /= Default
1342       then
1343          act.sa_flags := 0;
1344          act.sa_handler := Abort_Handler'Address;
1345
1346          Result := sigemptyset (Tmp_Set'Access);
1347          pragma Assert (Result = 0);
1348          act.sa_mask := Tmp_Set;
1349
1350          Result :=
1351            sigaction
1352            (Signal (System.Interrupt_Management.Abort_Task_Interrupt),
1353             act'Unchecked_Access,
1354             old_act'Unchecked_Access);
1355          pragma Assert (Result = 0);
1356       end if;
1357    end Initialize;
1358
1359 end System.Task_Primitives.Operations;