OSDN Git Service

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