OSDN Git Service

2005-11-14 Cyrille Comar <comar@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-taprop-linux.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                GNU ADA 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 GNU/Linux (GNU/LinuxThreads) version of this package
35
36 --  This package contains all the GNULL primitives that interface directly
37 --  with the underlying OS.
38
39 pragma Polling (Off);
40 --  Turn off polling, we do not want ATC polling to take place during
41 --  tasking operations. It causes infinite loops and other problems.
42
43 with Interfaces.C;
44 --  used for int
45 --           size_t
46
47 with System.Parameters;
48 --  used for Size_Type
49
50 with System.Tasking.Debug;
51 --  used for Known_Tasks
52
53 with System.Interrupt_Management;
54 --  used for Keep_Unmasked
55 --           Abort_Task_Interrupt
56 --           Interrupt_ID
57
58 with System.OS_Primitives;
59 --  used for Delay_Modes
60
61 with System.Soft_Links;
62 --  used for Abort_Defer/Undefer
63
64 with Ada.Exceptions;
65 --  used for Raise_Exception
66 --           Raise_From_Signal_Handler
67 --           Exception_Id
68
69 with Unchecked_Conversion;
70 with Unchecked_Deallocation;
71
72 package body System.Task_Primitives.Operations is
73
74    use System.Tasking.Debug;
75    use System.Tasking;
76    use Interfaces.C;
77    use System.OS_Interface;
78    use System.Parameters;
79    use System.OS_Primitives;
80
81    ----------------
82    -- Local Data --
83    ----------------
84
85    --  The followings are logically constants, but need to be initialized
86    --  at run time.
87
88    Single_RTS_Lock : aliased RTS_Lock;
89    --  This is a lock to allow only one thread of control in the RTS at
90    --  a time; it is used to execute in mutual exclusion from all other tasks.
91    --  Used mainly in Single_Lock mode, but also to protect All_Tasks_List
92
93    ATCB_Key : aliased pthread_key_t;
94    --  Key used to find the Ada Task_Id associated with a thread
95
96    Environment_Task_Id : Task_Id;
97    --  A variable to hold Task_Id for the environment task
98
99    Unblocked_Signal_Mask : aliased sigset_t;
100    --  The set of signals that should be unblocked in all tasks
101
102    --  The followings are internal configuration constants needed
103
104    Next_Serial_Number : Task_Serial_Number := 100;
105    --  We start at 100, to reserve some special values for
106    --  using in error checking.
107
108    Time_Slice_Val : Integer;
109    pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
110
111    Dispatching_Policy : Character;
112    pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
113
114    --  The following are effectively constants, but they need to
115    --  be initialized by calling a pthread_ function.
116
117    Mutex_Attr   : aliased pthread_mutexattr_t;
118    Cond_Attr    : aliased pthread_condattr_t;
119
120    Foreign_Task_Elaborated : aliased Boolean := True;
121    --  Used to identified fake tasks (i.e., non-Ada Threads)
122
123    --------------------
124    -- Local Packages --
125    --------------------
126
127    package Specific is
128
129       procedure Initialize (Environment_Task : Task_Id);
130       pragma Inline (Initialize);
131       --  Initialize various data needed by this package
132
133       function Is_Valid_Task return Boolean;
134       pragma Inline (Is_Valid_Task);
135       --  Does executing thread have a TCB?
136
137       procedure Set (Self_Id : Task_Id);
138       pragma Inline (Set);
139       --  Set the self id for the current task
140
141       function Self return Task_Id;
142       pragma Inline (Self);
143       --  Return a pointer to the Ada Task Control Block of the calling task.
144
145    end Specific;
146
147    package body Specific is separate;
148    --  The body of this package is target specific
149
150    ---------------------------------
151    -- Support for foreign threads --
152    ---------------------------------
153
154    function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
155    --  Allocate and Initialize a new ATCB for the current Thread
156
157    function Register_Foreign_Thread
158      (Thread : Thread_Id) return Task_Id is separate;
159
160    -----------------------
161    -- Local Subprograms --
162    -----------------------
163
164    subtype unsigned_long is Interfaces.C.unsigned_long;
165
166    procedure Abort_Handler (signo : Signal);
167
168    function To_pthread_t is new Unchecked_Conversion
169      (unsigned_long, System.OS_Interface.pthread_t);
170
171    -------------------
172    -- Abort_Handler --
173    -------------------
174
175    procedure Abort_Handler (signo : Signal) is
176       pragma Unreferenced (signo);
177
178       Self_Id : constant Task_Id := Self;
179       Result  : Interfaces.C.int;
180       Old_Set : aliased sigset_t;
181
182    begin
183       if ZCX_By_Default and then GCC_ZCX_Support then
184          return;
185       end if;
186
187       if Self_Id.Deferral_Level = 0
188         and then Self_Id.Pending_ATC_Level < Self_Id.ATC_Nesting_Level
189         and then not Self_Id.Aborting
190       then
191          Self_Id.Aborting := True;
192
193          --  Make sure signals used for RTS internal purpose are unmasked
194
195          Result := pthread_sigmask (SIG_UNBLOCK,
196            Unblocked_Signal_Mask'Unchecked_Access, Old_Set'Unchecked_Access);
197          pragma Assert (Result = 0);
198
199          raise Standard'Abort_Signal;
200       end if;
201    end Abort_Handler;
202
203    --------------
204    -- Lock_RTS --
205    --------------
206
207    procedure Lock_RTS is
208    begin
209       Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
210    end Lock_RTS;
211
212    ----------------
213    -- Unlock_RTS --
214    ----------------
215
216    procedure Unlock_RTS is
217    begin
218       Unlock (Single_RTS_Lock'Access, Global_Lock => True);
219    end Unlock_RTS;
220
221    -----------------
222    -- Stack_Guard --
223    -----------------
224
225    --  The underlying thread system extends the memory (up to 2MB) when needed
226
227    procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is
228       pragma Unreferenced (T);
229       pragma Unreferenced (On);
230    begin
231       null;
232    end Stack_Guard;
233
234    --------------------
235    -- Get_Thread_Id  --
236    --------------------
237
238    function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is
239    begin
240       return T.Common.LL.Thread;
241    end Get_Thread_Id;
242
243    ----------
244    -- Self --
245    ----------
246
247    function Self return Task_Id renames Specific.Self;
248
249    ---------------------
250    -- Initialize_Lock --
251    ---------------------
252
253    --  Note: mutexes and cond_variables needed per-task basis are
254    --  initialized in Initialize_TCB and the Storage_Error is
255    --  handled. Other mutexes (such as RTS_Lock, Memory_Lock...)
256    --  used in RTS is initialized before any status change of RTS.
257    --  Therefore rasing Storage_Error in the following routines
258    --  should be able to be handled safely.
259
260    procedure Initialize_Lock
261      (Prio : System.Any_Priority;
262       L    : access Lock)
263    is
264       pragma Unreferenced (Prio);
265
266       Result : Interfaces.C.int;
267    begin
268       Result := pthread_mutex_init (L, Mutex_Attr'Access);
269
270       pragma Assert (Result = 0 or else Result = ENOMEM);
271
272       if Result = ENOMEM then
273          Ada.Exceptions.Raise_Exception (Storage_Error'Identity,
274            "Failed to allocate a lock");
275       end if;
276    end Initialize_Lock;
277
278    procedure Initialize_Lock (L : access RTS_Lock; Level : Lock_Level) is
279       pragma Unreferenced (Level);
280
281       Result : Interfaces.C.int;
282
283    begin
284       Result := pthread_mutex_init (L, Mutex_Attr'Access);
285
286       pragma Assert (Result = 0 or else Result = ENOMEM);
287
288       if Result = ENOMEM then
289          raise Storage_Error;
290       end if;
291    end Initialize_Lock;
292
293    -------------------
294    -- Finalize_Lock --
295    -------------------
296
297    procedure Finalize_Lock (L : access Lock) is
298       Result : Interfaces.C.int;
299    begin
300       Result := pthread_mutex_destroy (L);
301       pragma Assert (Result = 0);
302    end Finalize_Lock;
303
304    procedure Finalize_Lock (L : access RTS_Lock) is
305       Result : Interfaces.C.int;
306    begin
307       Result := pthread_mutex_destroy (L);
308       pragma Assert (Result = 0);
309    end Finalize_Lock;
310
311    ----------------
312    -- Write_Lock --
313    ----------------
314
315    procedure Write_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
316       Result : Interfaces.C.int;
317    begin
318       Result := pthread_mutex_lock (L);
319       Ceiling_Violation := Result = EINVAL;
320
321       --  Assume the cause of EINVAL is a priority ceiling violation
322
323       pragma Assert (Result = 0 or else Result = EINVAL);
324    end Write_Lock;
325
326    procedure Write_Lock
327      (L           : access RTS_Lock;
328       Global_Lock : Boolean := False)
329    is
330       Result : Interfaces.C.int;
331    begin
332       if not Single_Lock or else Global_Lock then
333          Result := pthread_mutex_lock (L);
334          pragma Assert (Result = 0);
335       end if;
336    end Write_Lock;
337
338    procedure Write_Lock (T : Task_Id) is
339       Result : Interfaces.C.int;
340    begin
341       if not Single_Lock then
342          Result := pthread_mutex_lock (T.Common.LL.L'Access);
343          pragma Assert (Result = 0);
344       end if;
345    end Write_Lock;
346
347    ---------------
348    -- Read_Lock --
349    ---------------
350
351    procedure Read_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
352    begin
353       Write_Lock (L, Ceiling_Violation);
354    end Read_Lock;
355
356    ------------
357    -- Unlock --
358    ------------
359
360    procedure Unlock (L : access Lock) is
361       Result : Interfaces.C.int;
362    begin
363       Result := pthread_mutex_unlock (L);
364       pragma Assert (Result = 0);
365    end Unlock;
366
367    procedure Unlock (L : access RTS_Lock; Global_Lock : Boolean := False) is
368       Result : Interfaces.C.int;
369    begin
370       if not Single_Lock or else Global_Lock then
371          Result := pthread_mutex_unlock (L);
372          pragma Assert (Result = 0);
373       end if;
374    end Unlock;
375
376    procedure Unlock (T : Task_Id) is
377       Result : Interfaces.C.int;
378    begin
379       if not Single_Lock then
380          Result := pthread_mutex_unlock (T.Common.LL.L'Access);
381          pragma Assert (Result = 0);
382       end if;
383    end Unlock;
384
385    -----------
386    -- Sleep --
387    -----------
388
389    procedure Sleep
390      (Self_ID  : Task_Id;
391       Reason   : System.Tasking.Task_States)
392    is
393       pragma Unreferenced (Reason);
394
395       Result : Interfaces.C.int;
396
397    begin
398       pragma Assert (Self_ID = Self);
399
400       if Single_Lock then
401          Result := pthread_cond_wait
402            (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access);
403       else
404          Result := pthread_cond_wait
405            (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
406       end if;
407
408       --  EINTR is not considered a failure
409
410       pragma Assert (Result = 0 or else Result = EINTR);
411    end Sleep;
412
413    -----------------
414    -- Timed_Sleep --
415    -----------------
416
417    --  This is for use within the run-time system, so abort is
418    --  assumed to be already deferred, and the caller should be
419    --  holding its own ATCB lock.
420
421    procedure Timed_Sleep
422      (Self_ID  : Task_Id;
423       Time     : Duration;
424       Mode     : ST.Delay_Modes;
425       Reason   : System.Tasking.Task_States;
426       Timedout : out Boolean;
427       Yielded  : out Boolean)
428    is
429       pragma Unreferenced (Reason);
430
431       Check_Time : constant Duration := Monotonic_Clock;
432       Abs_Time   : Duration;
433       Request    : aliased timespec;
434       Result     : Interfaces.C.int;
435
436    begin
437       Timedout := True;
438       Yielded := False;
439
440       if Mode = Relative then
441          Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
442       else
443          Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
444       end if;
445
446       if Abs_Time > Check_Time then
447          Request := To_Timespec (Abs_Time);
448
449          loop
450             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
451               or else Self_ID.Pending_Priority_Change;
452
453             if Single_Lock then
454                Result := pthread_cond_timedwait
455                  (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access,
456                   Request'Access);
457
458             else
459                Result := pthread_cond_timedwait
460                  (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access,
461                   Request'Access);
462             end if;
463
464             exit when Abs_Time <= Monotonic_Clock;
465
466             if Result = 0 or Result = EINTR then
467                --  somebody may have called Wakeup for us
468                Timedout := False;
469                exit;
470             end if;
471
472             pragma Assert (Result = ETIMEDOUT);
473          end loop;
474       end if;
475    end Timed_Sleep;
476
477    -----------------
478    -- Timed_Delay --
479    -----------------
480
481    --  This is for use in implementing delay statements, so
482    --  we assume the caller is abort-deferred but is holding
483    --  no locks.
484
485    procedure Timed_Delay
486      (Self_ID  : Task_Id;
487       Time     : Duration;
488       Mode     : ST.Delay_Modes)
489    is
490       Check_Time : constant Duration := Monotonic_Clock;
491       Abs_Time   : Duration;
492       Request    : aliased timespec;
493       Result     : Interfaces.C.int;
494
495    begin
496       if Single_Lock then
497          Lock_RTS;
498       end if;
499
500       Write_Lock (Self_ID);
501
502       if Mode = Relative then
503          Abs_Time := Time + Check_Time;
504       else
505          Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
506       end if;
507
508       if Abs_Time > Check_Time then
509          Request := To_Timespec (Abs_Time);
510          Self_ID.Common.State := Delay_Sleep;
511
512          loop
513             if Self_ID.Pending_Priority_Change then
514                Self_ID.Pending_Priority_Change := False;
515                Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
516                Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
517             end if;
518
519             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
520
521             if Single_Lock then
522                Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
523                  Single_RTS_Lock'Access, Request'Access);
524             else
525                Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
526                  Self_ID.Common.LL.L'Access, Request'Access);
527             end if;
528
529             exit when Abs_Time <= Monotonic_Clock;
530
531             pragma Assert (Result = 0 or else
532               Result = ETIMEDOUT or else
533               Result = EINTR);
534          end loop;
535
536          Self_ID.Common.State := Runnable;
537       end if;
538
539       Unlock (Self_ID);
540
541       if Single_Lock then
542          Unlock_RTS;
543       end if;
544
545       Result := sched_yield;
546    end Timed_Delay;
547
548    ---------------------
549    -- Monotonic_Clock --
550    ---------------------
551
552    function Monotonic_Clock return Duration is
553       TV     : aliased struct_timeval;
554       Result : Interfaces.C.int;
555    begin
556       Result := gettimeofday (TV'Access, System.Null_Address);
557       pragma Assert (Result = 0);
558       return To_Duration (TV);
559    end Monotonic_Clock;
560
561    -------------------
562    -- RT_Resolution --
563    -------------------
564
565    function RT_Resolution return Duration is
566    begin
567       return 10#1.0#E-6;
568    end RT_Resolution;
569
570    ------------
571    -- Wakeup --
572    ------------
573
574    procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
575       pragma Unreferenced (Reason);
576       Result : Interfaces.C.int;
577    begin
578       Result := pthread_cond_signal (T.Common.LL.CV'Access);
579       pragma Assert (Result = 0);
580    end Wakeup;
581
582    -----------
583    -- Yield --
584    -----------
585
586    procedure Yield (Do_Yield : Boolean := True) is
587       Result : Interfaces.C.int;
588       pragma Unreferenced (Result);
589    begin
590       if Do_Yield then
591          Result := sched_yield;
592       end if;
593    end Yield;
594
595    ------------------
596    -- Set_Priority --
597    ------------------
598
599    procedure Set_Priority
600      (T                   : Task_Id;
601       Prio                : System.Any_Priority;
602       Loss_Of_Inheritance : Boolean := False)
603    is
604       pragma Unreferenced (Loss_Of_Inheritance);
605
606       Result : Interfaces.C.int;
607       Param  : aliased struct_sched_param;
608
609    begin
610       T.Common.Current_Priority := Prio;
611
612       --  Priorities are in range 1 .. 99 on GNU/Linux, so we map
613       --  map 0 .. 31 to 1 .. 32
614
615       Param.sched_priority := Interfaces.C.int (Prio) + 1;
616
617       if Time_Slice_Val > 0 then
618          Result := pthread_setschedparam
619            (T.Common.LL.Thread, SCHED_RR, Param'Access);
620
621       elsif Dispatching_Policy = 'F' or else Time_Slice_Val = 0 then
622          Result := pthread_setschedparam
623            (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
624
625       else
626          Param.sched_priority := 0;
627          Result := pthread_setschedparam
628            (T.Common.LL.Thread, SCHED_OTHER, Param'Access);
629       end if;
630
631       pragma Assert (Result = 0 or else Result = EPERM);
632    end Set_Priority;
633
634    ------------------
635    -- Get_Priority --
636    ------------------
637
638    function Get_Priority (T : Task_Id) return System.Any_Priority is
639    begin
640       return T.Common.Current_Priority;
641    end Get_Priority;
642
643    ----------------
644    -- Enter_Task --
645    ----------------
646
647    procedure Enter_Task (Self_ID : Task_Id) is
648    begin
649       Self_ID.Common.LL.Thread := pthread_self;
650
651       Specific.Set (Self_ID);
652
653       Lock_RTS;
654
655       for J in Known_Tasks'Range loop
656          if Known_Tasks (J) = null then
657             Known_Tasks (J) := Self_ID;
658             Self_ID.Known_Tasks_Index := J;
659             exit;
660          end if;
661       end loop;
662
663       Unlock_RTS;
664    end Enter_Task;
665
666    --------------
667    -- New_ATCB --
668    --------------
669
670    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
671    begin
672       return new Ada_Task_Control_Block (Entry_Num);
673    end New_ATCB;
674
675    -------------------
676    -- Is_Valid_Task --
677    -------------------
678
679    function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
680
681    -----------------------------
682    -- Register_Foreign_Thread --
683    -----------------------------
684
685    function Register_Foreign_Thread return Task_Id is
686    begin
687       if Is_Valid_Task then
688          return Self;
689       else
690          return Register_Foreign_Thread (pthread_self);
691       end if;
692    end Register_Foreign_Thread;
693
694    --------------------
695    -- Initialize_TCB --
696    --------------------
697
698    procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
699       Result : Interfaces.C.int;
700
701    begin
702       --  Give the task a unique serial number
703
704       Self_ID.Serial_Number := Next_Serial_Number;
705       Next_Serial_Number := Next_Serial_Number + 1;
706       pragma Assert (Next_Serial_Number /= 0);
707
708       Self_ID.Common.LL.Thread := To_pthread_t (-1);
709
710       if not Single_Lock then
711          Result := pthread_mutex_init (Self_ID.Common.LL.L'Access,
712            Mutex_Attr'Access);
713          pragma Assert (Result = 0 or else Result = ENOMEM);
714
715          if Result /= 0 then
716             Succeeded := False;
717             return;
718          end if;
719       end if;
720
721       Result := pthread_cond_init (Self_ID.Common.LL.CV'Access,
722         Cond_Attr'Access);
723       pragma Assert (Result = 0 or else Result = ENOMEM);
724
725       if Result = 0 then
726          Succeeded := True;
727       else
728          if not Single_Lock then
729             Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
730             pragma Assert (Result = 0);
731          end if;
732
733          Succeeded := False;
734       end if;
735    end Initialize_TCB;
736
737    -----------------
738    -- Create_Task --
739    -----------------
740
741    procedure Create_Task
742      (T          : Task_Id;
743       Wrapper    : System.Address;
744       Stack_Size : System.Parameters.Size_Type;
745       Priority   : System.Any_Priority;
746       Succeeded  : out Boolean)
747    is
748       Adjusted_Stack_Size : Interfaces.C.size_t;
749
750       Attributes : aliased pthread_attr_t;
751       Result     : Interfaces.C.int;
752
753    begin
754       if Stack_Size = Unspecified_Size then
755          Adjusted_Stack_Size := Interfaces.C.size_t (Default_Stack_Size);
756
757       elsif Stack_Size < Minimum_Stack_Size then
758          Adjusted_Stack_Size := Interfaces.C.size_t (Minimum_Stack_Size);
759
760       else
761          Adjusted_Stack_Size := Interfaces.C.size_t (Stack_Size);
762       end if;
763
764       Result := pthread_attr_init (Attributes'Access);
765       pragma Assert (Result = 0 or else Result = ENOMEM);
766
767       if Result /= 0 then
768          Succeeded := False;
769          return;
770       end if;
771
772       Result :=
773         pthread_attr_setstacksize
774           (Attributes'Access, Adjusted_Stack_Size);
775       pragma Assert (Result = 0);
776
777       Result :=
778         pthread_attr_setdetachstate
779           (Attributes'Access, PTHREAD_CREATE_DETACHED);
780       pragma Assert (Result = 0);
781
782       --  Since the initial signal mask of a thread is inherited from the
783       --  creator, and the Environment task has all its signals masked, we
784       --  do not need to manipulate caller's signal mask at this point.
785       --  All tasks in RTS will have All_Tasks_Mask initially.
786
787       Result := pthread_create
788         (T.Common.LL.Thread'Access,
789          Attributes'Access,
790          Thread_Body_Access (Wrapper),
791          To_Address (T));
792       pragma Assert (Result = 0 or else Result = EAGAIN);
793
794       Succeeded := Result = 0;
795
796       Result := pthread_attr_destroy (Attributes'Access);
797       pragma Assert (Result = 0);
798
799       Set_Priority (T, Priority);
800    end Create_Task;
801
802    ------------------
803    -- Finalize_TCB --
804    ------------------
805
806    procedure Finalize_TCB (T : Task_Id) is
807       Result  : Interfaces.C.int;
808       Tmp     : Task_Id := T;
809       Is_Self : constant Boolean := T = Self;
810
811       procedure Free is new
812         Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
813
814    begin
815       if not Single_Lock then
816          Result := pthread_mutex_destroy (T.Common.LL.L'Access);
817          pragma Assert (Result = 0);
818       end if;
819
820       Result := pthread_cond_destroy (T.Common.LL.CV'Access);
821       pragma Assert (Result = 0);
822
823       if T.Known_Tasks_Index /= -1 then
824          Known_Tasks (T.Known_Tasks_Index) := null;
825       end if;
826
827       Free (Tmp);
828
829       if Is_Self then
830          Specific.Set (null);
831       end if;
832    end Finalize_TCB;
833
834    ---------------
835    -- Exit_Task --
836    ---------------
837
838    procedure Exit_Task is
839    begin
840       Specific.Set (null);
841    end Exit_Task;
842
843    ----------------
844    -- Abort_Task --
845    ----------------
846
847    procedure Abort_Task (T : Task_Id) is
848       Result : Interfaces.C.int;
849    begin
850       Result := pthread_kill (T.Common.LL.Thread,
851         Signal (System.Interrupt_Management.Abort_Task_Interrupt));
852       pragma Assert (Result = 0);
853    end Abort_Task;
854
855    ----------------
856    -- Initialize --
857    ----------------
858
859    procedure Initialize (S : in out Suspension_Object) is
860       Result : Interfaces.C.int;
861    begin
862       --  Initialize internal state. It is always initialized to False (ARM
863       --  D.10 par. 6).
864
865       S.State := False;
866       S.Waiting := False;
867
868       --  Initialize internal mutex
869
870       Result := pthread_mutex_init (S.L'Access, Mutex_Attr'Access);
871
872       pragma Assert (Result = 0 or else Result = ENOMEM);
873
874       if Result = ENOMEM then
875          raise Storage_Error;
876       end if;
877
878       --  Initialize internal condition variable
879
880       Result := pthread_cond_init (S.CV'Access, Cond_Attr'Access);
881
882       pragma Assert (Result = 0 or else Result = ENOMEM);
883
884       if Result /= 0 then
885          Result := pthread_mutex_destroy (S.L'Access);
886          pragma Assert (Result = 0);
887
888          if Result = ENOMEM then
889             raise Storage_Error;
890          end if;
891       end if;
892    end Initialize;
893
894    --------------
895    -- Finalize --
896    --------------
897
898    procedure Finalize (S : in out Suspension_Object) is
899       Result  : Interfaces.C.int;
900    begin
901       --  Destroy internal mutex
902
903       Result := pthread_mutex_destroy (S.L'Access);
904       pragma Assert (Result = 0);
905
906       --  Destroy internal condition variable
907
908       Result := pthread_cond_destroy (S.CV'Access);
909       pragma Assert (Result = 0);
910    end Finalize;
911
912    -------------------
913    -- Current_State --
914    -------------------
915
916    function Current_State (S : Suspension_Object) return Boolean is
917    begin
918       --  We do not want to use lock on this read operation. State is marked
919       --  as Atomic so that we ensure that the value retrieved is correct.
920
921       return S.State;
922    end Current_State;
923
924    ---------------
925    -- Set_False --
926    ---------------
927
928    procedure Set_False (S : in out Suspension_Object) is
929       Result  : Interfaces.C.int;
930    begin
931       Result := pthread_mutex_lock (S.L'Access);
932       pragma Assert (Result = 0);
933
934       S.State := False;
935
936       Result := pthread_mutex_unlock (S.L'Access);
937       pragma Assert (Result = 0);
938    end Set_False;
939
940    --------------
941    -- Set_True --
942    --------------
943
944    procedure Set_True (S : in out Suspension_Object) is
945       Result : Interfaces.C.int;
946    begin
947       Result := pthread_mutex_lock (S.L'Access);
948       pragma Assert (Result = 0);
949
950       --  If there is already a task waiting on this suspension object then
951       --  we resume it, leaving the state of the suspension object to False,
952       --  as it is specified in ARM D.10 par. 9. Otherwise, it just leaves
953       --  the state to True.
954
955       if S.Waiting then
956          S.Waiting := False;
957          S.State := False;
958
959          Result := pthread_cond_signal (S.CV'Access);
960          pragma Assert (Result = 0);
961       else
962          S.State := True;
963       end if;
964
965       Result := pthread_mutex_unlock (S.L'Access);
966       pragma Assert (Result = 0);
967    end Set_True;
968
969    ------------------------
970    -- Suspend_Until_True --
971    ------------------------
972
973    procedure Suspend_Until_True (S : in out Suspension_Object) is
974       Result : Interfaces.C.int;
975    begin
976       Result := pthread_mutex_lock (S.L'Access);
977       pragma Assert (Result = 0);
978
979       if S.Waiting then
980          --  Program_Error must be raised upon calling Suspend_Until_True
981          --  if another task is already waiting on that suspension object
982          --  (ARM D.10 par. 10).
983
984          Result := pthread_mutex_unlock (S.L'Access);
985          pragma Assert (Result = 0);
986
987          raise Program_Error;
988       else
989          --  Suspend the task if the state is False. Otherwise, the task
990          --  continues its execution, and the state of the suspension object
991          --  is set to False (ARM D.10 par. 9).
992
993          if S.State then
994             S.State := False;
995          else
996             S.Waiting := True;
997             Result := pthread_cond_wait (S.CV'Access, S.L'Access);
998          end if;
999       end if;
1000
1001       Result := pthread_mutex_unlock (S.L'Access);
1002       pragma Assert (Result = 0);
1003    end Suspend_Until_True;
1004
1005    ----------------
1006    -- Check_Exit --
1007    ----------------
1008
1009    --  Dummy version
1010
1011    function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1012       pragma Unreferenced (Self_ID);
1013    begin
1014       return True;
1015    end Check_Exit;
1016
1017    --------------------
1018    -- Check_No_Locks --
1019    --------------------
1020
1021    function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1022       pragma Unreferenced (Self_ID);
1023    begin
1024       return True;
1025    end Check_No_Locks;
1026
1027    ----------------------
1028    -- Environment_Task --
1029    ----------------------
1030
1031    function Environment_Task return Task_Id is
1032    begin
1033       return Environment_Task_Id;
1034    end Environment_Task;
1035
1036    ------------------
1037    -- Suspend_Task --
1038    ------------------
1039
1040    function Suspend_Task
1041      (T           : ST.Task_Id;
1042       Thread_Self : Thread_Id) return Boolean
1043    is
1044    begin
1045       if T.Common.LL.Thread /= Thread_Self then
1046          return pthread_kill (T.Common.LL.Thread, SIGSTOP) = 0;
1047       else
1048          return True;
1049       end if;
1050    end Suspend_Task;
1051
1052    -----------------
1053    -- Resume_Task --
1054    -----------------
1055
1056    function Resume_Task
1057      (T           : ST.Task_Id;
1058       Thread_Self : Thread_Id) return Boolean
1059    is
1060    begin
1061       if T.Common.LL.Thread /= Thread_Self then
1062          return pthread_kill (T.Common.LL.Thread, SIGCONT) = 0;
1063       else
1064          return True;
1065       end if;
1066    end Resume_Task;
1067
1068    ----------------
1069    -- Initialize --
1070    ----------------
1071
1072    procedure Initialize (Environment_Task : Task_Id) is
1073       act     : aliased struct_sigaction;
1074       old_act : aliased struct_sigaction;
1075       Tmp_Set : aliased sigset_t;
1076       Result  : Interfaces.C.int;
1077
1078       function State
1079         (Int : System.Interrupt_Management.Interrupt_ID) return Character;
1080       pragma Import (C, State, "__gnat_get_interrupt_state");
1081       --  Get interrupt state.  Defined in a-init.c
1082       --  The input argument is the interrupt number,
1083       --  and the result is one of the following:
1084
1085       Default : constant Character := 's';
1086       --    'n'   this interrupt not set by any Interrupt_State pragma
1087       --    'u'   Interrupt_State pragma set state to User
1088       --    'r'   Interrupt_State pragma set state to Runtime
1089       --    's'   Interrupt_State pragma set state to System (use "default"
1090       --           system handler)
1091
1092    begin
1093       Environment_Task_Id := Environment_Task;
1094
1095       Interrupt_Management.Initialize;
1096
1097       --  Prepare the set of signals that should be unblocked in all tasks
1098
1099       Result := sigemptyset (Unblocked_Signal_Mask'Access);
1100       pragma Assert (Result = 0);
1101
1102       for J in Interrupt_Management.Interrupt_ID loop
1103          if System.Interrupt_Management.Keep_Unmasked (J) then
1104             Result := sigaddset (Unblocked_Signal_Mask'Access, Signal (J));
1105             pragma Assert (Result = 0);
1106          end if;
1107       end loop;
1108
1109       Result := pthread_mutexattr_init (Mutex_Attr'Access);
1110       pragma Assert (Result = 0);
1111
1112       Result := pthread_condattr_init (Cond_Attr'Access);
1113       pragma Assert (Result = 0);
1114
1115       Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1116
1117       --  Initialize the global RTS lock
1118
1119       Specific.Initialize (Environment_Task);
1120
1121       Enter_Task (Environment_Task);
1122
1123       --  Install the abort-signal handler
1124
1125       if State (System.Interrupt_Management.Abort_Task_Interrupt)
1126         /= Default
1127       then
1128          act.sa_flags := 0;
1129          act.sa_handler := Abort_Handler'Address;
1130
1131          Result := sigemptyset (Tmp_Set'Access);
1132          pragma Assert (Result = 0);
1133          act.sa_mask := Tmp_Set;
1134
1135          Result :=
1136            sigaction
1137            (Signal (Interrupt_Management.Abort_Task_Interrupt),
1138             act'Unchecked_Access,
1139             old_act'Unchecked_Access);
1140          pragma Assert (Result = 0);
1141       end if;
1142    end Initialize;
1143
1144 end System.Task_Primitives.Operations;