OSDN Git Service

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