OSDN Git Service

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