OSDN Git Service

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