OSDN Git Service

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