OSDN Git Service

PR c++/9704
[pf3gnuchains/gcc-fork.git] / gcc / ada / 5ftaprop.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 --                                                                          --
10 --         Copyright (C) 1992-2001, Free Software Foundation, Inc.          --
11 --                                                                          --
12 -- GNARL is free software; you can  redistribute it  and/or modify it under --
13 -- terms of the  GNU General Public License as published  by the Free Soft- --
14 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
15 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
18 -- for  more details.  You should have  received  a copy of the GNU General --
19 -- Public License  distributed with GNARL; see file COPYING.  If not, write --
20 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
21 -- MA 02111-1307, USA.                                                      --
22 --                                                                          --
23 -- As a special exception,  if other files  instantiate  generics from this --
24 -- unit, or you link  this unit with other files  to produce an executable, --
25 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
26 -- covered  by the  GNU  General  Public  License.  This exception does not --
27 -- however invalidate  any other reasons why  the executable file  might be --
28 -- covered by the  GNU Public License.                                      --
29 --                                                                          --
30 -- GNARL was developed by the GNARL team at Florida State University.       --
31 -- Extensive contributions were provided by Ada Core Technologies, Inc.     --
32 --                                                                          --
33 ------------------------------------------------------------------------------
34
35 --  This is a IRIX (pthread library) version of this package.
36
37 --  This package contains all the GNULL primitives that interface directly
38 --  with the underlying OS.
39
40 pragma Polling (Off);
41 --  Turn off polling, we do not want ATC polling to take place during
42 --  tasking operations. It causes infinite loops and other problems.
43
44 with Interfaces.C;
45 --  used for int
46 --           size_t
47
48 with System.Task_Info;
49
50 with System.Tasking.Debug;
51 --  used for Known_Tasks
52
53 with System.IO;
54 --  used for Put_Line
55
56 with System.Interrupt_Management;
57 --  used for Keep_Unmasked
58 --           Abort_Task_Interrupt
59 --           Interrupt_ID
60
61 with System.Interrupt_Management.Operations;
62 --  used for Set_Interrupt_Mask
63 --           All_Tasks_Mask
64 pragma Elaborate_All (System.Interrupt_Management.Operations);
65
66 with System.Parameters;
67 --  used for Size_Type
68
69 with System.Tasking;
70 --  used for Ada_Task_Control_Block
71 --           Task_ID
72
73 with System.Soft_Links;
74 --  used for Defer/Undefer_Abort
75
76 --  Note that we do not use System.Tasking.Initialization directly since
77 --  this is a higher level package that we shouldn't depend on. For example
78 --  when using the restricted run time, it is replaced by
79 --  System.Tasking.Restricted.Initialization
80
81 with System.Program_Info;
82 --  used for Default_Task_Stack
83 --           Default_Time_Slice
84 --           Stack_Guard_Pages
85 --           Pthread_Sched_Signal
86 --           Pthread_Arena_Size
87
88 with System.OS_Interface;
89 --  used for various type, constant, and operations
90
91 with System.OS_Primitives;
92 --  used for Delay_Modes
93
94 with Unchecked_Conversion;
95 with Unchecked_Deallocation;
96
97 package body System.Task_Primitives.Operations is
98
99    use System.Tasking;
100    use System.Tasking.Debug;
101    use Interfaces.C;
102    use System.OS_Interface;
103    use System.OS_Primitives;
104    use System.Parameters;
105
106    package SSL renames System.Soft_Links;
107
108    ------------------
109    --  Local Data  --
110    ------------------
111
112    --  The followings are logically constants, but need to be initialized
113    --  at run time.
114
115    ATCB_Key : aliased pthread_key_t;
116    --  Key used to find the Ada Task_ID associated with a thread
117
118    Single_RTS_Lock : aliased RTS_Lock;
119    --  This is a lock to allow only one thread of control in the RTS at
120    --  a time; it is used to execute in mutual exclusion from all other tasks.
121    --  Used mainly in Single_Lock mode, but also to protect All_Tasks_List
122
123    Environment_Task_ID : Task_ID;
124    --  A variable to hold Task_ID for the environment task.
125
126    Locking_Policy : Character;
127    pragma Import (C, Locking_Policy, "__gl_locking_policy");
128
129    Real_Time_Clock_Id : constant clockid_t := CLOCK_REALTIME;
130
131    Unblocked_Signal_Mask : aliased sigset_t;
132
133    -----------------------
134    -- Local Subprograms --
135    -----------------------
136
137    function To_Task_ID is new Unchecked_Conversion (System.Address, Task_ID);
138
139    function To_Address is new Unchecked_Conversion (Task_ID, System.Address);
140
141    procedure Abort_Handler (Sig : Signal);
142
143    -------------------
144    -- Abort_Handler --
145    -------------------
146
147    procedure Abort_Handler (Sig : Signal) is
148       T       : Task_ID := Self;
149       Result  : Interfaces.C.int;
150       Old_Set : aliased sigset_t;
151
152    begin
153       if T.Deferral_Level = 0
154         and then T.Pending_ATC_Level < T.ATC_Nesting_Level
155       then
156          --  Make sure signals used for RTS internal purpose are unmasked
157
158          Result := pthread_sigmask
159            (SIG_UNBLOCK,
160             Unblocked_Signal_Mask'Unchecked_Access,
161             Old_Set'Unchecked_Access);
162          pragma Assert (Result = 0);
163
164          raise Standard'Abort_Signal;
165       end if;
166    end Abort_Handler;
167
168    -----------------
169    -- Stack_Guard --
170    -----------------
171
172    --  The underlying thread system sets a guard page at the
173    --  bottom of a thread stack, so nothing is needed.
174
175    procedure Stack_Guard (T : ST.Task_ID; On : Boolean) is
176    begin
177       null;
178    end Stack_Guard;
179
180    -------------------
181    -- Get_Thread_Id --
182    -------------------
183
184    function Get_Thread_Id (T : ST.Task_ID) return OSI.Thread_Id is
185    begin
186       return T.Common.LL.Thread;
187    end Get_Thread_Id;
188
189    ----------
190    -- Self --
191    ----------
192
193    function Self return Task_ID is
194       Result : System.Address;
195
196    begin
197       Result := pthread_getspecific (ATCB_Key);
198       pragma Assert (Result /= System.Null_Address);
199
200       return To_Task_ID (Result);
201    end Self;
202
203    ---------------------
204    -- Initialize_Lock --
205    ---------------------
206
207    --  Note: mutexes and cond_variables needed per-task basis are
208    --        initialized in Initialize_TCB and the Storage_Error is
209    --        handled. Other mutexes (such as RTS_Lock, Memory_Lock...)
210    --        used in RTS is initialized before any status change of RTS.
211    --        Therefore rasing Storage_Error in the following routines
212    --        should be able to be handled safely.
213
214    procedure Initialize_Lock
215      (Prio : System.Any_Priority;
216       L    : access Lock)
217    is
218       Attributes : aliased pthread_mutexattr_t;
219       Result     : Interfaces.C.int;
220
221    begin
222       Result := pthread_mutexattr_init (Attributes'Access);
223       pragma Assert (Result = 0 or else Result = ENOMEM);
224
225       if Result = ENOMEM then
226          raise Storage_Error;
227       end if;
228
229       if Locking_Policy = 'C' then
230          Result := pthread_mutexattr_setprotocol
231            (Attributes'Access, PTHREAD_PRIO_PROTECT);
232          pragma Assert (Result = 0);
233
234          Result := pthread_mutexattr_setprioceiling
235             (Attributes'Access, Interfaces.C.int (Prio));
236          pragma Assert (Result = 0);
237       end if;
238
239       Result := pthread_mutex_init (L, Attributes'Access);
240       pragma Assert (Result = 0 or else Result = ENOMEM);
241
242       if Result = ENOMEM then
243          Result := pthread_mutexattr_destroy (Attributes'Access);
244          raise Storage_Error;
245       end if;
246
247       Result := pthread_mutexattr_destroy (Attributes'Access);
248       pragma Assert (Result = 0);
249    end Initialize_Lock;
250
251    procedure Initialize_Lock (L : access RTS_Lock; Level : Lock_Level) is
252       Attributes : aliased pthread_mutexattr_t;
253       Result : Interfaces.C.int;
254
255    begin
256       Result := pthread_mutexattr_init (Attributes'Access);
257       pragma Assert (Result = 0 or else Result = ENOMEM);
258
259       if Result = ENOMEM then
260          raise Storage_Error;
261       end if;
262
263       if Locking_Policy = 'C' then
264          Result := pthread_mutexattr_setprotocol
265            (Attributes'Access, PTHREAD_PRIO_PROTECT);
266          pragma Assert (Result = 0);
267
268          Result := pthread_mutexattr_setprioceiling
269             (Attributes'Access, Interfaces.C.int (System.Any_Priority'Last));
270          pragma Assert (Result = 0);
271       end if;
272
273       Result := pthread_mutex_init (L, Attributes'Access);
274
275       pragma Assert (Result = 0 or else Result = ENOMEM);
276
277       if Result = ENOMEM then
278          Result := pthread_mutexattr_destroy (Attributes'Access);
279          raise Storage_Error;
280       end if;
281
282       Result := pthread_mutexattr_destroy (Attributes'Access);
283    end Initialize_Lock;
284
285    -------------------
286    -- Finalize_Lock --
287    -------------------
288
289    procedure Finalize_Lock (L : access Lock) is
290       Result : Interfaces.C.int;
291
292    begin
293       Result := pthread_mutex_destroy (L);
294       pragma Assert (Result = 0);
295    end Finalize_Lock;
296
297    procedure Finalize_Lock (L : access RTS_Lock) is
298       Result : Interfaces.C.int;
299
300    begin
301       Result := pthread_mutex_destroy (L);
302       pragma Assert (Result = 0);
303    end Finalize_Lock;
304
305    ----------------
306    -- Write_Lock --
307    ----------------
308
309    procedure Write_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
310       Result : Interfaces.C.int;
311    begin
312       Result := pthread_mutex_lock (L);
313       Ceiling_Violation := Result = EINVAL;
314
315       --  assumes the cause of EINVAL is a priority ceiling violation
316
317       pragma Assert (Result = 0 or else Result = EINVAL);
318    end Write_Lock;
319
320    procedure Write_Lock
321      (L : access RTS_Lock; Global_Lock : Boolean := False)
322    is
323       Result : Interfaces.C.int;
324    begin
325       if not Single_Lock or else Global_Lock then
326          Result := pthread_mutex_lock (L);
327          pragma Assert (Result = 0);
328       end if;
329    end Write_Lock;
330
331    procedure Write_Lock (T : Task_ID) is
332       Result : Interfaces.C.int;
333    begin
334       if not Single_Lock then
335          Result := pthread_mutex_lock (T.Common.LL.L'Access);
336          pragma Assert (Result = 0);
337       end if;
338    end Write_Lock;
339
340    ---------------
341    -- Read_Lock --
342    ---------------
343
344    procedure Read_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
345    begin
346       Write_Lock (L, Ceiling_Violation);
347    end Read_Lock;
348
349    ------------
350    -- Unlock --
351    ------------
352
353    procedure Unlock (L : access Lock) is
354       Result : Interfaces.C.int;
355    begin
356       Result := pthread_mutex_unlock (L);
357       pragma Assert (Result = 0);
358    end Unlock;
359
360    procedure Unlock (L : access RTS_Lock; Global_Lock : Boolean := False) is
361       Result : Interfaces.C.int;
362    begin
363       if not Single_Lock or else Global_Lock then
364          Result := pthread_mutex_unlock (L);
365          pragma Assert (Result = 0);
366       end if;
367    end Unlock;
368
369    procedure Unlock (T : Task_ID) is
370       Result : Interfaces.C.int;
371    begin
372       if not Single_Lock then
373          Result := pthread_mutex_unlock (T.Common.LL.L'Access);
374          pragma Assert (Result = 0);
375       end if;
376    end Unlock;
377
378    -----------
379    -- Sleep --
380    -----------
381
382    procedure Sleep
383      (Self_ID : ST.Task_ID;
384       Reason  : System.Tasking.Task_States)
385    is
386       Result : Interfaces.C.int;
387    begin
388       if Single_Lock then
389          Result := pthread_cond_wait
390            (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access);
391       else
392          Result := pthread_cond_wait
393            (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
394       end if;
395
396       --  EINTR is not considered a failure.
397
398       pragma Assert (Result = 0 or else Result = EINTR);
399    end Sleep;
400
401    -----------------
402    -- Timed_Sleep --
403    -----------------
404
405    procedure Timed_Sleep
406      (Self_ID  : Task_ID;
407       Time     : Duration;
408       Mode     : ST.Delay_Modes;
409       Reason   : Task_States;
410       Timedout : out Boolean;
411       Yielded  : out Boolean)
412    is
413       Check_Time : constant Duration := Monotonic_Clock;
414       Abs_Time   : Duration;
415       Request    : aliased timespec;
416       Result     : Interfaces.C.int;
417
418    begin
419       Timedout := True;
420       Yielded  := False;
421
422       if Mode = Relative then
423          Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
424       else
425          Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
426       end if;
427
428       if Abs_Time > Check_Time then
429          Request := To_Timespec (Abs_Time);
430
431          loop
432             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
433               or else Self_ID.Pending_Priority_Change;
434
435             if Single_Lock then
436                Result := pthread_cond_timedwait
437                  (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access,
438                   Request'Access);
439
440             else
441                Result := pthread_cond_timedwait
442                  (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access,
443                   Request'Access);
444             end if;
445
446             exit when Abs_Time <= Monotonic_Clock;
447
448             if Result = 0 or else errno = EINTR then
449                Timedout := False;
450                exit;
451             end if;
452          end loop;
453       end if;
454    end Timed_Sleep;
455
456    -----------------
457    -- Timed_Delay --
458    -----------------
459
460    --  This is for use in implementing delay statements, so
461    --  we assume the caller is abort-deferred but is holding
462    --  no locks.
463
464    procedure Timed_Delay
465      (Self_ID : Task_ID;
466       Time    : Duration;
467       Mode    : ST.Delay_Modes)
468    is
469       Check_Time : constant Duration := Monotonic_Clock;
470       Abs_Time   : Duration;
471       Request    : aliased timespec;
472       Result     : Interfaces.C.int;
473
474    begin
475       --  Only the little window between deferring abort and
476       --  locking Self_ID is the reason we need to
477       --  check for pending abort and priority change below! :(
478
479       SSL.Abort_Defer.all;
480
481       if Single_Lock then
482          Lock_RTS;
483       end if;
484
485       Write_Lock (Self_ID);
486
487       if Mode = Relative then
488          Abs_Time := Time + Check_Time;
489       else
490          Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
491       end if;
492
493       if Abs_Time > Check_Time then
494          Request := To_Timespec (Abs_Time);
495          Self_ID.Common.State := Delay_Sleep;
496
497          loop
498             if Self_ID.Pending_Priority_Change then
499                Self_ID.Pending_Priority_Change := False;
500                Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
501                Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
502             end if;
503
504             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
505
506             Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
507               Self_ID.Common.LL.L'Access, Request'Access);
508             exit when Abs_Time <= Monotonic_Clock;
509
510             pragma Assert (Result = 0
511               or else Result = ETIMEDOUT
512               or else Result = EINTR);
513          end loop;
514
515          Self_ID.Common.State := Runnable;
516       end if;
517
518       Unlock (Self_ID);
519
520       if Single_Lock then
521          Unlock_RTS;
522       end if;
523
524       Yield;
525       SSL.Abort_Undefer.all;
526    end Timed_Delay;
527
528    ---------------------
529    -- Monotonic_Clock --
530    ---------------------
531
532    function Monotonic_Clock return Duration is
533       TS     : aliased timespec;
534       Result : Interfaces.C.int;
535
536    begin
537       Result := clock_gettime (Real_Time_Clock_Id, TS'Unchecked_Access);
538       pragma Assert (Result = 0);
539       return To_Duration (TS);
540    end Monotonic_Clock;
541
542    -------------------
543    -- RT_Resolution --
544    -------------------
545
546    function RT_Resolution return Duration is
547    begin
548       --  The clock_getres (Real_Time_Clock_Id) function appears to return
549       --  the interrupt resolution of the realtime clock and not the actual
550       --  resolution of reading the clock. Even though this last value is
551       --  only guaranteed to be 100 Hz, at least the Origin 200 appears to
552       --  have a microsecond resolution or better.
553       --  ??? We should figure out a method to return the right value on
554       --  all SGI hardware.
555
556       return 0.000_001; --  Assume microsecond resolution of clock
557    end RT_Resolution;
558
559    ------------
560    -- Wakeup --
561    ------------
562
563    procedure Wakeup (T : ST.Task_ID; Reason : System.Tasking.Task_States) is
564       Result : Interfaces.C.int;
565    begin
566       Result := pthread_cond_signal (T.Common.LL.CV'Access);
567       pragma Assert (Result = 0);
568    end Wakeup;
569
570    -----------
571    -- Yield --
572    -----------
573
574    procedure Yield (Do_Yield : Boolean := True) is
575       Result : Interfaces.C.int;
576    begin
577       if Do_Yield then
578          Result := sched_yield;
579       end if;
580    end Yield;
581
582    ------------------
583    -- Set_Priority --
584    ------------------
585
586    procedure Set_Priority
587      (T                   : Task_ID;
588       Prio                : System.Any_Priority;
589       Loss_Of_Inheritance : Boolean := False)
590    is
591       Result       : Interfaces.C.int;
592       Param        : aliased struct_sched_param;
593       Sched_Policy : Interfaces.C.int;
594
595       use type System.Task_Info.Task_Info_Type;
596
597       function To_Int is new Unchecked_Conversion
598         (System.Task_Info.Thread_Scheduling_Policy, Interfaces.C.int);
599
600    begin
601       T.Common.Current_Priority := Prio;
602       Param.sched_priority := Interfaces.C.int (Prio);
603
604       if T.Common.Task_Info /= null then
605          Sched_Policy := To_Int (T.Common.Task_Info.Policy);
606       else
607          Sched_Policy := SCHED_FIFO;
608       end if;
609
610       Result := pthread_setschedparam (T.Common.LL.Thread, Sched_Policy,
611         Param'Access);
612       pragma Assert (Result = 0);
613    end Set_Priority;
614
615    ------------------
616    -- Get_Priority --
617    ------------------
618
619    function Get_Priority (T : Task_ID) return System.Any_Priority is
620    begin
621       return T.Common.Current_Priority;
622    end Get_Priority;
623
624    ----------------
625    -- Enter_Task --
626    ----------------
627
628    procedure Enter_Task (Self_ID : Task_ID) is
629       Result : Interfaces.C.int;
630
631       function To_Int is new Unchecked_Conversion
632         (System.Task_Info.CPU_Number, Interfaces.C.int);
633
634       use System.Task_Info;
635
636    begin
637       Self_ID.Common.LL.Thread := pthread_self;
638       Result := pthread_setspecific (ATCB_Key, To_Address (Self_ID));
639       pragma Assert (Result = 0);
640
641       if Self_ID.Common.Task_Info /= null
642         and then Self_ID.Common.Task_Info.Scope = PTHREAD_SCOPE_SYSTEM
643         and then Self_ID.Common.Task_Info.Runon_CPU /= ANY_CPU
644       then
645          Result := pthread_setrunon_np
646            (To_Int (Self_ID.Common.Task_Info.Runon_CPU));
647          pragma Assert (Result = 0);
648       end if;
649
650       Lock_RTS;
651
652       for J in Known_Tasks'Range loop
653          if Known_Tasks (J) = null then
654             Known_Tasks (J) := Self_ID;
655             Self_ID.Known_Tasks_Index := J;
656             exit;
657          end if;
658       end loop;
659
660       Unlock_RTS;
661    end Enter_Task;
662
663    --------------
664    -- New_ATCB --
665    --------------
666
667    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_ID is
668    begin
669       return new Ada_Task_Control_Block (Entry_Num);
670    end New_ATCB;
671
672    --------------------
673    -- Initialize_TCB --
674    --------------------
675
676    procedure Initialize_TCB (Self_ID : Task_ID; Succeeded : out Boolean) is
677       Result    : Interfaces.C.int;
678       Cond_Attr : aliased pthread_condattr_t;
679
680    begin
681       if not Single_Lock then
682          Initialize_Lock (Self_ID.Common.LL.L'Access, ATCB_Level);
683       end if;
684
685       Result := pthread_condattr_init (Cond_Attr'Access);
686       pragma Assert (Result = 0 or else Result = ENOMEM);
687
688       if Result = 0 then
689          Result := pthread_cond_init (Self_ID.Common.LL.CV'Access,
690            Cond_Attr'Access);
691          pragma Assert (Result = 0 or else Result = ENOMEM);
692       end if;
693
694       if Result = 0 then
695          Succeeded := True;
696       else
697          if not Single_Lock then
698             Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
699             pragma Assert (Result = 0);
700          end if;
701
702          Succeeded := False;
703       end if;
704
705       Result := pthread_condattr_destroy (Cond_Attr'Access);
706       pragma Assert (Result = 0);
707    end Initialize_TCB;
708
709    -----------------
710    -- Create_Task --
711    -----------------
712
713    procedure Create_Task
714      (T          : Task_ID;
715       Wrapper    : System.Address;
716       Stack_Size : System.Parameters.Size_Type;
717       Priority   : System.Any_Priority;
718       Succeeded  : out Boolean)
719    is
720       use System.Task_Info;
721
722       Attributes          : aliased pthread_attr_t;
723       Sched_Param         : aliased struct_sched_param;
724       Adjusted_Stack_Size : Interfaces.C.size_t;
725       Result              : Interfaces.C.int;
726
727       function Thread_Body_Access is new
728         Unchecked_Conversion (System.Address, Thread_Body);
729
730       function To_Int is new Unchecked_Conversion
731         (System.Task_Info.Thread_Scheduling_Scope, Interfaces.C.int);
732       function To_Int is new Unchecked_Conversion
733         (System.Task_Info.Thread_Scheduling_Inheritance, Interfaces.C.int);
734       function To_Int is new Unchecked_Conversion
735         (System.Task_Info.Thread_Scheduling_Policy, Interfaces.C.int);
736
737    begin
738       if Stack_Size = System.Parameters.Unspecified_Size then
739          Adjusted_Stack_Size :=
740            Interfaces.C.size_t (System.Program_Info.Default_Task_Stack);
741
742       elsif Stack_Size < Size_Type (Minimum_Stack_Size) then
743          Adjusted_Stack_Size :=
744            Interfaces.C.size_t (Minimum_Stack_Size);
745
746       else
747          Adjusted_Stack_Size := Interfaces.C.size_t (Stack_Size);
748       end if;
749
750       Result := pthread_attr_init (Attributes'Access);
751       pragma Assert (Result = 0 or else Result = ENOMEM);
752
753       if Result /= 0 then
754          Succeeded := False;
755          return;
756       end if;
757
758       Result := pthread_attr_setdetachstate
759         (Attributes'Access, PTHREAD_CREATE_DETACHED);
760       pragma Assert (Result = 0);
761
762       Result := pthread_attr_setstacksize
763         (Attributes'Access, Interfaces.C.size_t (Adjusted_Stack_Size));
764       pragma Assert (Result = 0);
765
766       if T.Common.Task_Info /= null then
767          Result := pthread_attr_setscope
768            (Attributes'Access, To_Int (T.Common.Task_Info.Scope));
769          pragma Assert (Result = 0);
770
771          Result := pthread_attr_setinheritsched
772            (Attributes'Access, To_Int (T.Common.Task_Info.Inheritance));
773          pragma Assert (Result = 0);
774
775          Result := pthread_attr_setschedpolicy
776            (Attributes'Access, To_Int (T.Common.Task_Info.Policy));
777          pragma Assert (Result = 0);
778
779          Sched_Param.sched_priority :=
780            Interfaces.C.int (T.Common.Task_Info.Priority);
781
782          Result := pthread_attr_setschedparam
783            (Attributes'Access, Sched_Param'Access);
784          pragma Assert (Result = 0);
785       end if;
786
787       --  Since the initial signal mask of a thread is inherited from the
788       --  creator, and the Environment task has all its signals masked, we
789       --  do not need to manipulate caller's signal mask at this point.
790       --  All tasks in RTS will have All_Tasks_Mask initially.
791
792       Result := pthread_create
793         (T.Common.LL.Thread'Access,
794          Attributes'Access,
795          Thread_Body_Access (Wrapper),
796          To_Address (T));
797
798       if Result /= 0
799         and then T.Common.Task_Info /= null
800         and then T.Common.Task_Info.Scope = PTHREAD_SCOPE_SYSTEM
801       then
802          --  The pthread_create call may have failed because we
803          --  asked for a system scope pthread and none were
804          --  available (probably because the program was not executed
805          --  by the superuser). Let's try for a process scope pthread
806          --  instead of raising Tasking_Error.
807
808          System.IO.Put_Line
809            ("Request for PTHREAD_SCOPE_SYSTEM in Task_Info pragma for task");
810          System.IO.Put ("""");
811          System.IO.Put (T.Common.Task_Image.all);
812          System.IO.Put_Line (""" could not be honored. ");
813          System.IO.Put_Line ("Scope changed to PTHREAD_SCOPE_PROCESS");
814
815          T.Common.Task_Info.Scope := PTHREAD_SCOPE_PROCESS;
816          Result := pthread_attr_setscope
817            (Attributes'Access, To_Int (T.Common.Task_Info.Scope));
818          pragma Assert (Result = 0);
819
820          Result := pthread_create
821            (T.Common.LL.Thread'Access,
822             Attributes'Access,
823             Thread_Body_Access (Wrapper),
824             To_Address (T));
825       end if;
826
827       pragma Assert (Result = 0 or else Result = EAGAIN);
828
829       Succeeded := Result = 0;
830
831       Set_Priority (T, Priority);
832
833       Result := pthread_attr_destroy (Attributes'Access);
834       pragma Assert (Result = 0);
835    end Create_Task;
836
837    ------------------
838    -- Finalize_TCB --
839    ------------------
840
841    procedure Finalize_TCB (T : Task_ID) is
842       Result : Interfaces.C.int;
843       Tmp    : Task_ID := T;
844
845       procedure Free is new
846         Unchecked_Deallocation (Ada_Task_Control_Block, Task_ID);
847
848    begin
849       if not Single_Lock then
850          Result := pthread_mutex_destroy (T.Common.LL.L'Access);
851          pragma Assert (Result = 0);
852       end if;
853
854       Result := pthread_cond_destroy (T.Common.LL.CV'Access);
855       pragma Assert (Result = 0);
856
857       if T.Known_Tasks_Index /= -1 then
858          Known_Tasks (T.Known_Tasks_Index) := null;
859       end if;
860
861       Free (Tmp);
862    end Finalize_TCB;
863
864    ---------------
865    -- Exit_Task --
866    ---------------
867
868    procedure Exit_Task is
869    begin
870       pthread_exit (System.Null_Address);
871    end Exit_Task;
872
873    ----------------
874    -- Abort_Task --
875    ----------------
876
877    procedure Abort_Task (T : Task_ID) is
878       Result : Interfaces.C.int;
879    begin
880       Result := pthread_kill (T.Common.LL.Thread,
881         Signal (System.Interrupt_Management.Abort_Task_Interrupt));
882       pragma Assert (Result = 0);
883    end Abort_Task;
884
885    ----------------
886    -- Check_Exit --
887    ----------------
888
889    --  Dummy versions. The only currently working versions is for solaris
890    --  (native).
891
892    function Check_Exit (Self_ID : ST.Task_ID) return Boolean is
893    begin
894       return True;
895    end Check_Exit;
896
897    --------------------
898    -- Check_No_Locks --
899    --------------------
900
901    function Check_No_Locks (Self_ID : ST.Task_ID) return Boolean is
902    begin
903       return True;
904    end Check_No_Locks;
905
906    ----------------------
907    -- Environment_Task --
908    ----------------------
909
910    function Environment_Task return Task_ID is
911    begin
912       return Environment_Task_ID;
913    end Environment_Task;
914
915    --------------
916    -- Lock_RTS --
917    --------------
918
919    procedure Lock_RTS is
920    begin
921       Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
922    end Lock_RTS;
923
924    ----------------
925    -- Unlock_RTS --
926    ----------------
927
928    procedure Unlock_RTS is
929    begin
930       Unlock (Single_RTS_Lock'Access, Global_Lock => True);
931    end Unlock_RTS;
932
933    ------------------
934    -- Suspend_Task --
935    ------------------
936
937    function Suspend_Task
938      (T           : ST.Task_ID;
939       Thread_Self : Thread_Id) return Boolean is
940    begin
941       return False;
942    end Suspend_Task;
943
944    -----------------
945    -- Resume_Task --
946    -----------------
947
948    function Resume_Task
949      (T           : ST.Task_ID;
950       Thread_Self : Thread_Id) return Boolean is
951    begin
952       return False;
953    end Resume_Task;
954
955    ----------------
956    -- Initialize --
957    ----------------
958
959    procedure Initialize (Environment_Task : Task_ID) is
960       act     : aliased struct_sigaction;
961       old_act : aliased struct_sigaction;
962       Tmp_Set : aliased sigset_t;
963       Result  : Interfaces.C.int;
964
965    begin
966       Environment_Task_ID := Environment_Task;
967
968       --  Initialize the lock used to synchronize chain of all ATCBs.
969       Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
970
971       Enter_Task (Environment_Task);
972
973       --  Install the abort-signal handler
974
975       act.sa_flags := 0;
976       act.sa_handler := Abort_Handler'Address;
977
978       Result := sigemptyset (Tmp_Set'Access);
979       pragma Assert (Result = 0);
980       act.sa_mask := Tmp_Set;
981
982       Result :=
983         sigaction (
984           Signal (System.Interrupt_Management.Abort_Task_Interrupt),
985           act'Unchecked_Access,
986           old_act'Unchecked_Access);
987       pragma Assert (Result = 0);
988    end Initialize;
989
990 begin
991    declare
992       Result : Interfaces.C.int;
993    begin
994       --  Mask Environment task for all signals. The original mask of the
995       --  Environment task will be recovered by Interrupt_Server task
996       --  during the elaboration of s-interr.adb.
997
998       System.Interrupt_Management.Operations.Set_Interrupt_Mask
999         (System.Interrupt_Management.Operations.All_Tasks_Mask'Access);
1000
1001       --  Prepare the set of signals that should unblocked in all tasks
1002
1003       Result := sigemptyset (Unblocked_Signal_Mask'Access);
1004       pragma Assert (Result = 0);
1005
1006       for J in Interrupt_Management.Interrupt_ID loop
1007          if System.Interrupt_Management.Keep_Unmasked (J) then
1008             Result := sigaddset (Unblocked_Signal_Mask'Access, Signal (J));
1009             pragma Assert (Result = 0);
1010          end if;
1011       end loop;
1012
1013       Result := pthread_key_create (ATCB_Key'Access, null);
1014       pragma Assert (Result = 0);
1015
1016       --  Pick the highest resolution Clock for Clock_Realtime
1017       --  ??? This code currently doesn't work (see c94007[ab] for example)
1018       --
1019       --  if syssgi (SGI_CYCLECNTR_SIZE) = 64 then
1020       --     Real_Time_Clock_Id := CLOCK_SGI_CYCLE;
1021       --  else
1022       --     Real_Time_Clock_Id := CLOCK_REALTIME;
1023       --  end if;
1024    end;
1025 end System.Task_Primitives.Operations;