OSDN Git Service

* rtl.h (mem_attrs): Rename decl to expr; adjust all users.
[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 --                             $Revision: 1.60 $
10 --                                                                          --
11 --             Copyright (C) 1991-2001, Florida State University            --
12 --                                                                          --
13 -- GNARL is free software; you can  redistribute it  and/or modify it under --
14 -- terms of the  GNU General Public License as published  by the Free Soft- --
15 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
16 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
19 -- for  more details.  You should have  received  a copy of the GNU General --
20 -- Public License  distributed with GNARL; see file COPYING.  If not, write --
21 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
22 -- MA 02111-1307, USA.                                                      --
23 --                                                                          --
24 -- As a special exception,  if other files  instantiate  generics from this --
25 -- unit, or you link  this unit with other files  to produce an executable, --
26 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
27 -- covered  by the  GNU  General  Public  License.  This exception does not --
28 -- however invalidate  any other reasons why  the executable file  might be --
29 -- covered by the  GNU Public License.                                      --
30 --                                                                          --
31 -- GNARL was developed by the GNARL team at Florida State University. It is --
32 -- now maintained by Ada Core Technologies Inc. in cooperation with Florida --
33 -- State University (http://www.gnat.com).                                  --
34 --                                                                          --
35 ------------------------------------------------------------------------------
36
37 --  This is a DEC Unix 4.0d version of this package
38
39 --  This package contains all the GNULL primitives that interface directly
40 --  with the underlying OS.
41
42 pragma Polling (Off);
43 --  Turn off polling, we do not want ATC polling to take place during
44 --  tasking operations. It causes infinite loops and other problems.
45
46 with System.Tasking.Debug;
47 --  used for Known_Tasks
48
49 with System.Task_Info;
50 --  used for Task_Info_Type
51
52 with Interfaces;
53 --  used for Shift_Left
54
55 with Interfaces.C;
56 --  used for int
57 --           size_t
58
59 with System.Interrupt_Management;
60 --  used for Keep_Unmasked
61 --           Abort_Task_Interrupt
62 --           Interrupt_ID
63
64 with System.Interrupt_Management.Operations;
65 --  used for Set_Interrupt_Mask
66 --           All_Tasks_Mask
67 pragma Elaborate_All (System.Interrupt_Management.Operations);
68
69 with System.Parameters;
70 --  used for Size_Type
71
72 with System.Tasking;
73 --  used for Ada_Task_Control_Block
74 --           Task_ID
75 --           ATCB components and types
76
77 with System.Soft_Links;
78 --  used for Defer/Undefer_Abort
79
80 --  Note that we do not use System.Tasking.Initialization directly since
81 --  this is a higher level package that we shouldn't depend on. For example
82 --  when using the restricted run time, it is replaced by
83 --  System.Tasking.Restricted.Initialization
84
85 with System.OS_Primitives;
86 --  used for Delay_Modes
87
88 with Unchecked_Conversion;
89 with Unchecked_Deallocation;
90
91 package body System.Task_Primitives.Operations is
92
93    use System.Tasking.Debug;
94    use System.Tasking;
95    use Interfaces.C;
96    use System.OS_Interface;
97    use System.Parameters;
98    use System.OS_Primitives;
99
100    package SSL renames System.Soft_Links;
101
102    -----------------
103    -- Local Data  --
104    -----------------
105
106    --  The followings are logically constants, but need to be initialized
107    --  at run time.
108
109    All_Tasks_L : aliased System.Task_Primitives.RTS_Lock;
110    --  See comments on locking rules in System.Tasking (spec).
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 Intialize_TCB and the Storage_Error is
224    --        handled. Other mutexes (such as All_Tasks_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          if All_Tasks_Link /= Null_Task and then
322             L.Ceiling < Interfaces.C.int (Current_Prio) then
323             Ceiling_Violation := True;
324             return;
325          end if;
326       end if;
327
328       Result := pthread_mutex_lock (L.L'Access);
329
330       pragma Assert (Result = 0);
331
332       Ceiling_Violation := False;
333    end Write_Lock;
334
335    procedure Write_Lock (L : access RTS_Lock) is
336       Result : Interfaces.C.int;
337    begin
338       Result := pthread_mutex_lock (L);
339       pragma Assert (Result = 0);
340    end Write_Lock;
341
342    procedure Write_Lock (T : Task_ID) is
343       Result : Interfaces.C.int;
344    begin
345       Result := pthread_mutex_lock (T.Common.LL.L'Access);
346       pragma Assert (Result = 0);
347    end Write_Lock;
348
349    ---------------
350    -- Read_Lock --
351    ---------------
352
353    procedure Read_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
354    begin
355       Write_Lock (L, Ceiling_Violation);
356    end Read_Lock;
357
358    ------------
359    -- Unlock --
360    ------------
361
362    procedure Unlock (L : access Lock) is
363       Result : Interfaces.C.int;
364    begin
365       Result := pthread_mutex_unlock (L.L'Access);
366       pragma Assert (Result = 0);
367    end Unlock;
368
369    procedure Unlock (L : access RTS_Lock) is
370       Result : Interfaces.C.int;
371    begin
372       Result := pthread_mutex_unlock (L);
373       pragma Assert (Result = 0);
374    end Unlock;
375
376    procedure Unlock (T : Task_ID) is
377       Result : Interfaces.C.int;
378    begin
379       Result := pthread_mutex_unlock (T.Common.LL.L'Access);
380       pragma Assert (Result = 0);
381    end Unlock;
382
383    -----------
384    -- Sleep --
385    -----------
386
387    procedure Sleep
388      (Self_ID : Task_ID;
389       Reason  : System.Tasking.Task_States)
390    is
391       Result : Interfaces.C.int;
392    begin
393       pragma Assert (Self_ID = Self);
394       Result := pthread_cond_wait
395         (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
396
397       --  EINTR is not considered a failure.
398
399       pragma Assert (Result = 0 or else Result = EINTR);
400    end Sleep;
401
402    -----------------
403    -- Timed_Sleep --
404    -----------------
405
406    --  This is for use within the run-time system, so abort is
407    --  assumed to be already deferred, and the caller should be
408    --  holding its own ATCB lock.
409
410    procedure Timed_Sleep
411      (Self_ID  : Task_ID;
412       Time     : Duration;
413       Mode     : ST.Delay_Modes;
414       Reason   : System.Tasking.Task_States;
415       Timedout : out Boolean;
416       Yielded  : out Boolean)
417    is
418       Check_Time : constant Duration := Monotonic_Clock;
419       Abs_Time   : Duration;
420       Request    : aliased timespec;
421       Result     : Interfaces.C.int;
422
423    begin
424       Timedout := True;
425       Yielded := False;
426
427       if Mode = Relative then
428          Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
429       else
430          Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
431       end if;
432
433       if Abs_Time > Check_Time then
434          Request := To_Timespec (Abs_Time);
435
436          loop
437             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
438               or else Self_ID.Pending_Priority_Change;
439
440             Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
441               Self_ID.Common.LL.L'Access, Request'Access);
442
443             exit when Abs_Time <= Monotonic_Clock;
444
445             if Result = 0 or Result = EINTR then
446                --  somebody may have called Wakeup for us
447                Timedout := False;
448                exit;
449             end if;
450
451             pragma Assert (Result = ETIMEDOUT);
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       Write_Lock (Self_ID);
481
482       if Mode = Relative then
483          Abs_Time := Time + Check_Time;
484       else
485          Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
486       end if;
487
488       if Abs_Time > Check_Time then
489          Request := To_Timespec (Abs_Time);
490          Self_ID.Common.State := Delay_Sleep;
491
492          loop
493             if Self_ID.Pending_Priority_Change then
494                Self_ID.Pending_Priority_Change := False;
495                Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
496                Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
497             end if;
498
499             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
500
501             Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
502               Self_ID.Common.LL.L'Access, Request'Access);
503
504             exit when Abs_Time <= Monotonic_Clock;
505
506             pragma Assert (Result = 0 or else
507               Result = ETIMEDOUT or else
508               Result = EINTR);
509          end loop;
510
511          Self_ID.Common.State := Runnable;
512       end if;
513
514       Unlock (Self_ID);
515       Yield;
516       SSL.Abort_Undefer.all;
517    end Timed_Delay;
518
519    ---------------------
520    -- Monotonic_Clock --
521    ---------------------
522
523    function Monotonic_Clock return Duration is
524       TS     : aliased timespec;
525       Result : Interfaces.C.int;
526
527    begin
528       Result := clock_gettime (CLOCK_REALTIME, TS'Unchecked_Access);
529       pragma Assert (Result = 0);
530       return To_Duration (TS);
531    end Monotonic_Clock;
532
533    -------------------
534    -- RT_Resolution --
535    -------------------
536
537    function RT_Resolution return Duration is
538    begin
539       return 1.0 / 1024.0; --  Clock on DEC Alpha ticks at 1024 Hz
540    end RT_Resolution;
541
542    ------------
543    -- Wakeup --
544    ------------
545
546    procedure Wakeup (T : Task_ID; Reason : System.Tasking.Task_States) is
547       Result : Interfaces.C.int;
548    begin
549       Result := pthread_cond_signal (T.Common.LL.CV'Access);
550       pragma Assert (Result = 0);
551    end Wakeup;
552
553    -----------
554    -- Yield --
555    -----------
556
557    procedure Yield (Do_Yield : Boolean := True) is
558       Result : Interfaces.C.int;
559    begin
560       if Do_Yield then
561          Result := sched_yield;
562       end if;
563    end Yield;
564
565    ------------------
566    -- Set_Priority --
567    ------------------
568
569    procedure Set_Priority
570      (T : Task_ID;
571       Prio : System.Any_Priority;
572       Loss_Of_Inheritance : Boolean := False)
573    is
574       Result : Interfaces.C.int;
575       Param  : aliased struct_sched_param;
576
577    begin
578       T.Common.Current_Priority := Prio;
579       Param.sched_priority  := Interfaces.C.int (Underlying_Priorities (Prio));
580
581       if Time_Slice_Val > 0 then
582          Result := pthread_setschedparam
583            (T.Common.LL.Thread, SCHED_RR, Param'Access);
584
585       elsif FIFO_Within_Priorities or else Time_Slice_Val = 0 then
586          Result := pthread_setschedparam
587            (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
588
589       else
590          Result := pthread_setschedparam
591            (T.Common.LL.Thread, SCHED_OTHER, Param'Access);
592       end if;
593
594       pragma Assert (Result = 0);
595    end Set_Priority;
596
597    ------------------
598    -- Get_Priority --
599    ------------------
600
601    function Get_Priority (T : Task_ID) return System.Any_Priority is
602    begin
603       return T.Common.Current_Priority;
604    end Get_Priority;
605
606    ----------------
607    -- Enter_Task --
608    ----------------
609
610    procedure Enter_Task (Self_ID : Task_ID) is
611    begin
612       Self_ID.Common.LL.Thread := pthread_self;
613       Specific.Set (Self_ID);
614
615       Lock_All_Tasks_List;
616
617       for J in Known_Tasks'Range loop
618          if Known_Tasks (J) = null then
619             Known_Tasks (J) := Self_ID;
620             Self_ID.Known_Tasks_Index := J;
621             exit;
622          end if;
623       end loop;
624
625       Unlock_All_Tasks_List;
626    end Enter_Task;
627
628    --------------
629    -- New_ATCB --
630    --------------
631
632    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_ID is
633    begin
634       return new Ada_Task_Control_Block (Entry_Num);
635    end New_ATCB;
636
637    --------------------
638    -- Initialize_TCB --
639    --------------------
640
641    procedure Initialize_TCB (Self_ID : Task_ID; Succeeded : out Boolean) is
642       Mutex_Attr : aliased pthread_mutexattr_t;
643       Result     : Interfaces.C.int;
644       Cond_Attr  : aliased pthread_condattr_t;
645
646    begin
647       Result := pthread_mutexattr_init (Mutex_Attr'Access);
648       pragma Assert (Result = 0 or else Result = ENOMEM);
649
650       if Result /= 0 then
651          Succeeded := False;
652          return;
653       end if;
654
655       Result := pthread_mutex_init (Self_ID.Common.LL.L'Access,
656         Mutex_Attr'Access);
657       pragma Assert (Result = 0 or else Result = ENOMEM);
658
659       if Result /= 0 then
660          Succeeded := False;
661          return;
662       end if;
663
664       Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
665       pragma Assert (Result = 0);
666
667       Result := pthread_condattr_init (Cond_Attr'Access);
668       pragma Assert (Result = 0 or else Result = ENOMEM);
669
670       if Result /= 0 then
671          Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
672          pragma Assert (Result = 0);
673          Succeeded := False;
674          return;
675       end if;
676
677       Result := pthread_cond_init (Self_ID.Common.LL.CV'Access,
678         Cond_Attr'Access);
679       pragma Assert (Result = 0 or else Result = ENOMEM);
680
681       if Result = 0 then
682          Succeeded := True;
683       else
684          Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
685          pragma Assert (Result = 0);
686          Succeeded := False;
687       end if;
688
689       Result := pthread_condattr_destroy (Cond_Attr'Access);
690       pragma Assert (Result = 0);
691    end Initialize_TCB;
692
693    -----------------
694    -- Create_Task --
695    -----------------
696
697    procedure Create_Task
698      (T          : Task_ID;
699       Wrapper    : System.Address;
700       Stack_Size : System.Parameters.Size_Type;
701       Priority   : System.Any_Priority;
702       Succeeded  : out Boolean)
703    is
704       Attributes          : aliased pthread_attr_t;
705       Adjusted_Stack_Size : Interfaces.C.size_t;
706       Result              : Interfaces.C.int;
707       Param               : aliased System.OS_Interface.struct_sched_param;
708
709       function Thread_Body_Access is new
710         Unchecked_Conversion (System.Address, Thread_Body);
711
712       use System.Task_Info;
713
714    begin
715       if Stack_Size = Unspecified_Size then
716          Adjusted_Stack_Size := Interfaces.C.size_t (Default_Stack_Size);
717
718       elsif Stack_Size < Minimum_Stack_Size then
719          Adjusted_Stack_Size := Interfaces.C.size_t (Minimum_Stack_Size);
720
721       else
722          Adjusted_Stack_Size := Interfaces.C.size_t (Stack_Size);
723       end if;
724
725       Result := pthread_attr_init (Attributes'Access);
726       pragma Assert (Result = 0 or else Result = ENOMEM);
727
728       if Result /= 0 then
729          Succeeded := False;
730          return;
731       end if;
732
733       Result := pthread_attr_setdetachstate
734         (Attributes'Access, PTHREAD_CREATE_DETACHED);
735       pragma Assert (Result = 0);
736
737       Result := pthread_attr_setstacksize
738         (Attributes'Access, Adjusted_Stack_Size);
739       pragma Assert (Result = 0);
740
741       --  Set the scheduling parameters explicitely, since this is the only
742       --  way to force the OS to take the scope attribute into account
743
744       Result := pthread_attr_setinheritsched
745         (Attributes'Access, PTHREAD_EXPLICIT_SCHED);
746       pragma Assert (Result = 0);
747
748       Param.sched_priority :=
749         Interfaces.C.int (Underlying_Priorities (Priority));
750       Result := pthread_attr_setschedparam
751         (Attributes'Access, Param'Access);
752       pragma Assert (Result = 0);
753
754       if Time_Slice_Val > 0 then
755          Result := pthread_attr_setschedpolicy
756            (Attributes'Access, System.OS_Interface.SCHED_RR);
757
758       elsif FIFO_Within_Priorities or else Time_Slice_Val = 0 then
759          Result := pthread_attr_setschedpolicy
760            (Attributes'Access, System.OS_Interface.SCHED_FIFO);
761
762       else
763          Result := pthread_attr_setschedpolicy
764            (Attributes'Access, System.OS_Interface.SCHED_OTHER);
765       end if;
766
767       pragma Assert (Result = 0);
768
769       T.Common.Current_Priority := Priority;
770
771       if T.Common.Task_Info /= null then
772          case T.Common.Task_Info.Contention_Scope is
773             when System.Task_Info.Process_Scope =>
774                Result := pthread_attr_setscope
775                   (Attributes'Access, PTHREAD_SCOPE_PROCESS);
776
777             when System.Task_Info.System_Scope =>
778                Result := pthread_attr_setscope
779                   (Attributes'Access, PTHREAD_SCOPE_SYSTEM);
780
781             when System.Task_Info.Default_Scope =>
782                Result := 0;
783          end case;
784
785          pragma Assert (Result = 0);
786       end if;
787
788       --  Since the initial signal mask of a thread is inherited from the
789       --  creator, and the Environment task has all its signals masked, we
790       --  do not need to manipulate caller's signal mask at this point.
791       --  All tasks in RTS will have All_Tasks_Mask initially.
792
793       Result := pthread_create
794         (T.Common.LL.Thread'Access,
795          Attributes'Access,
796          Thread_Body_Access (Wrapper),
797          To_Address (T));
798       pragma Assert (Result = 0 or else Result = EAGAIN);
799
800       Succeeded := Result = 0;
801
802       Result := pthread_attr_destroy (Attributes'Access);
803       pragma Assert (Result = 0);
804
805       if T.Common.Task_Info /= null then
806          if T.Common.Task_Info.Bind_To_Cpu_Number = 0 then
807             Result := bind_to_cpu (Curpid, 0);
808          elsif T.Common.Task_Info.Bind_To_Cpu_Number > 0 then
809             Result := bind_to_cpu
810               (Curpid,
811                Interfaces.C.unsigned_long (
812                  Interfaces.Shift_Left
813                    (Interfaces.Unsigned_64'(1),
814                     T.Common.Task_Info.Bind_To_Cpu_Number - 1)));
815             pragma Assert (Result = 0);
816          end if;
817       end if;
818    end Create_Task;
819
820    ------------------
821    -- Finalize_TCB --
822    ------------------
823
824    procedure Finalize_TCB (T : Task_ID) is
825       Result : Interfaces.C.int;
826       Tmp    : Task_ID := T;
827
828       procedure Free is new
829         Unchecked_Deallocation (Ada_Task_Control_Block, Task_ID);
830
831    begin
832       Result := pthread_mutex_destroy (T.Common.LL.L'Access);
833       pragma Assert (Result = 0);
834       Result := pthread_cond_destroy (T.Common.LL.CV'Access);
835       pragma Assert (Result = 0);
836       if T.Known_Tasks_Index /= -1 then
837          Known_Tasks (T.Known_Tasks_Index) := null;
838       end if;
839       Free (Tmp);
840    end Finalize_TCB;
841
842    ---------------
843    -- Exit_Task --
844    ---------------
845
846    procedure Exit_Task is
847    begin
848       pthread_exit (System.Null_Address);
849    end Exit_Task;
850
851    ----------------
852    -- Abort_Task --
853    ----------------
854
855    procedure Abort_Task (T : Task_ID) is
856       Result : Interfaces.C.int;
857
858    begin
859       Result := pthread_kill (T.Common.LL.Thread,
860         Signal (System.Interrupt_Management.Abort_Task_Interrupt));
861       pragma Assert (Result = 0);
862    end Abort_Task;
863
864    ----------------
865    -- Check_Exit --
866    ----------------
867
868    --  Dummy versions. The only currently working versions is for solaris
869    --  (native).
870
871    function Check_Exit (Self_ID : ST.Task_ID) return Boolean is
872    begin
873       return True;
874    end Check_Exit;
875
876    --------------------
877    -- Check_No_Locks --
878    --------------------
879
880    function Check_No_Locks (Self_ID : ST.Task_ID) return Boolean is
881    begin
882       return True;
883    end Check_No_Locks;
884
885    ----------------------
886    -- Environment_Task --
887    ----------------------
888
889    function Environment_Task return Task_ID is
890    begin
891       return Environment_Task_ID;
892    end Environment_Task;
893
894    -------------------------
895    -- Lock_All_Tasks_List --
896    -------------------------
897
898    procedure Lock_All_Tasks_List is
899    begin
900       Write_Lock (All_Tasks_L'Access);
901    end Lock_All_Tasks_List;
902
903    ---------------------------
904    -- Unlock_All_Tasks_List --
905    ---------------------------
906
907    procedure Unlock_All_Tasks_List is
908    begin
909       Unlock (All_Tasks_L'Access);
910    end Unlock_All_Tasks_List;
911
912    ------------------
913    -- Suspend_Task --
914    ------------------
915
916    function Suspend_Task
917      (T           : ST.Task_ID;
918       Thread_Self : Thread_Id) return Boolean is
919    begin
920       return False;
921    end Suspend_Task;
922
923    -----------------
924    -- Resume_Task --
925    -----------------
926
927    function Resume_Task
928      (T           : ST.Task_ID;
929       Thread_Self : Thread_Id) return Boolean is
930    begin
931       return False;
932    end Resume_Task;
933
934    ----------------
935    -- Initialize --
936    ----------------
937
938    procedure Initialize (Environment_Task : Task_ID) is
939       act       : aliased struct_sigaction;
940       old_act   : aliased struct_sigaction;
941       Tmp_Set   : aliased sigset_t;
942       Result    : Interfaces.C.int;
943
944    begin
945       Environment_Task_ID := Environment_Task;
946
947       Initialize_Lock (All_Tasks_L'Access, All_Tasks_Level);
948       --  Initialize the lock used to synchronize chain of all ATCBs.
949
950       Specific.Initialize (Environment_Task);
951
952       Enter_Task (Environment_Task);
953
954       --  Install the abort-signal handler
955
956       act.sa_flags := 0;
957       act.sa_handler := Abort_Handler'Address;
958
959       Result := sigemptyset (Tmp_Set'Access);
960       pragma Assert (Result = 0);
961       act.sa_mask := Tmp_Set;
962
963       Result :=
964         sigaction
965           (Signal (System.Interrupt_Management.Abort_Task_Interrupt),
966            act'Unchecked_Access,
967            old_act'Unchecked_Access);
968       pragma Assert (Result = 0);
969    end Initialize;
970
971 begin
972    declare
973       Result : Interfaces.C.int;
974
975    begin
976       --  Mask Environment task for all signals. The original mask of the
977       --  Environment task will be recovered by Interrupt_Server task
978       --  during the elaboration of s-interr.adb.
979
980       System.Interrupt_Management.Operations.Set_Interrupt_Mask
981         (System.Interrupt_Management.Operations.All_Tasks_Mask'Access);
982
983       --  Prepare the set of signals that should unblocked in all tasks
984
985       Result := sigemptyset (Unblocked_Signal_Mask'Access);
986       pragma Assert (Result = 0);
987
988       for J in Interrupt_Management.Interrupt_ID loop
989          if System.Interrupt_Management.Keep_Unmasked (J) then
990             Result := sigaddset (Unblocked_Signal_Mask'Access, Signal (J));
991             pragma Assert (Result = 0);
992          end if;
993       end loop;
994    end;
995
996    Curpid := getpid;
997 end System.Task_Primitives.Operations;