OSDN Git Service

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