OSDN Git Service

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