OSDN Git Service

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