OSDN Git Service

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