OSDN Git Service

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