OSDN Git Service

2003-12-05 Thomas Quinot <quinot@act-europe.fr>
[pf3gnuchains/gcc-fork.git] / gcc / ada / 7staprop.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                GNU ADA 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-2003, 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,  59 Temple Place - Suite 330,  Boston, --
20 -- MA 02111-1307, 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 POSIX-like version of this package
35
36 --  This package contains all the GNULL primitives that interface directly
37 --  with the underlying OS.
38
39 --  Note: this file can only be used for POSIX compliant systems that
40 --  implement SCHED_FIFO and Ceiling Locking correctly.
41
42 --  For configurations where SCHED_FIFO and priority ceiling are not a
43 --  requirement, this file can also be used (e.g AiX threads)
44
45 pragma Polling (Off);
46 --  Turn off polling, we do not want ATC polling to take place during
47 --  tasking operations. It causes infinite loops and other problems.
48
49 with System.Tasking.Debug;
50 --  used for Known_Tasks
51
52 with System.Task_Info;
53 --  used for Task_Info_Type
54
55 with Interfaces.C;
56 --  used for int
57 --           size_t
58
59 with System.Interrupt_Management;
60 --  used for Keep_Unmasked
61 --           Abort_Task_Interrupt
62 --           Interrupt_ID
63
64 with System.Interrupt_Management.Operations;
65 --  used for Set_Interrupt_Mask
66 --           All_Tasks_Mask
67 pragma Elaborate_All (System.Interrupt_Management.Operations);
68
69 with System.Parameters;
70 --  used for Size_Type
71
72 with System.Tasking;
73 --  used for Ada_Task_Control_Block
74 --           Task_ID
75
76 with System.Soft_Links;
77 --  used for Defer/Undefer_Abort
78
79 --  Note that we do not use System.Tasking.Initialization directly since
80 --  this is a higher level package that we shouldn't depend on. For example
81 --  when using the restricted run time, it is replaced by
82 --  System.Tasking.Restricted.Initialization
83
84 with System.OS_Primitives;
85 --  used for Delay_Modes
86
87 with Unchecked_Conversion;
88 with Unchecked_Deallocation;
89
90 package body System.Task_Primitives.Operations is
91
92    use System.Tasking.Debug;
93    use System.Tasking;
94    use Interfaces.C;
95    use System.OS_Interface;
96    use System.Parameters;
97    use System.OS_Primitives;
98
99    package SSL renames System.Soft_Links;
100
101    ----------------
102    -- Local Data --
103    ----------------
104
105    --  The followings are logically constants, but need to be initialized
106    --  at run time.
107
108    Single_RTS_Lock : aliased RTS_Lock;
109    --  This is a lock to allow only one thread of control in the RTS at
110    --  a time; it is used to execute in mutual exclusion from all other tasks.
111    --  Used mainly in Single_Lock mode, but also to protect All_Tasks_List
112
113    ATCB_Key : aliased pthread_key_t;
114    --  Key used to find the Ada Task_ID associated with a thread
115
116    Environment_Task_ID : Task_ID;
117    --  A variable to hold Task_ID for the environment task.
118
119    Locking_Policy : Character;
120    pragma Import (C, Locking_Policy, "__gl_locking_policy");
121    --  Value of the pragma Locking_Policy:
122    --    'C' for Ceiling_Locking
123    --    'I' for Inherit_Locking
124    --    ' ' for none.
125
126    Unblocked_Signal_Mask : aliased sigset_t;
127    --  The set of signals that should unblocked in all tasks
128
129    --  The followings are internal configuration constants needed.
130
131    Next_Serial_Number : Task_Serial_Number := 100;
132    --  We start at 100, to reserve some special values for
133    --  using in error checking.
134
135    Time_Slice_Val : Integer;
136    pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
137
138    Dispatching_Policy : Character;
139    pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
140
141    FIFO_Within_Priorities : constant Boolean := Dispatching_Policy = 'F';
142    --  Indicates whether FIFO_Within_Priorities is set.
143
144    Foreign_Task_Elaborated : aliased Boolean := True;
145    --  Used to identified fake tasks (i.e., non-Ada Threads).
146
147    --------------------
148    -- Local Packages --
149    --------------------
150
151    package Specific is
152
153       procedure Initialize (Environment_Task : Task_ID);
154       pragma Inline (Initialize);
155       --  Initialize various data needed by this package.
156
157       function Is_Valid_Task return Boolean;
158       pragma Inline (Is_Valid_Task);
159       --  Does executing thread have a TCB?
160
161       procedure Set (Self_Id : Task_ID);
162       pragma Inline (Set);
163       --  Set the self id for the current task.
164
165       function Self return Task_ID;
166       pragma Inline (Self);
167       --  Return a pointer to the Ada Task Control Block of the calling task.
168
169    end Specific;
170
171    package body Specific is separate;
172    --  The body of this package is target specific.
173
174    ---------------------------------
175    -- Support for foreign threads --
176    ---------------------------------
177
178    function Register_Foreign_Thread (Thread : Thread_Id) return Task_ID;
179    --  Allocate and Initialize a new ATCB for the current Thread.
180
181    function Register_Foreign_Thread
182      (Thread : Thread_Id) return Task_ID is separate;
183
184    -----------------------
185    -- Local Subprograms --
186    -----------------------
187
188    procedure Abort_Handler (Sig : Signal);
189    --  Signal handler used to implement asynchronous abort.
190    --  See also comment before body, below.
191
192    function To_Address is new Unchecked_Conversion (Task_ID, System.Address);
193
194    -------------------
195    -- Abort_Handler --
196    -------------------
197
198    --  Target-dependent binding of inter-thread Abort signal to
199    --  the raising of the Abort_Signal exception.
200
201    --  The technical issues and alternatives here are essentially
202    --  the same as for raising exceptions in response to other
203    --  signals (e.g. Storage_Error). See code and comments in
204    --  the package body System.Interrupt_Management.
205
206    --  Some implementations may not allow an exception to be propagated
207    --  out of a handler, and others might leave the signal or
208    --  interrupt that invoked this handler masked after the exceptional
209    --  return to the application code.
210
211    --  GNAT exceptions are originally implemented using setjmp()/longjmp().
212    --  On most UNIX systems, this will allow transfer out of a signal handler,
213    --  which is usually the only mechanism available for implementing
214    --  asynchronous handlers of this kind. However, some
215    --  systems do not restore the signal mask on longjmp(), leaving the
216    --  abort signal masked.
217
218    procedure Abort_Handler (Sig : Signal) is
219       pragma Warnings (Off, Sig);
220
221       T       : Task_ID := Self;
222       Result  : Interfaces.C.int;
223       Old_Set : aliased sigset_t;
224
225    begin
226       --  It is not safe to raise an exception when using ZCX and the GCC
227       --  exception handling mechanism.
228
229       if ZCX_By_Default and then GCC_ZCX_Support then
230          return;
231       end if;
232
233       if T.Deferral_Level = 0
234         and then T.Pending_ATC_Level < T.ATC_Nesting_Level and then
235         not T.Aborting
236       then
237          T.Aborting := True;
238
239          --  Make sure signals used for RTS internal purpose are unmasked
240
241          Result := pthread_sigmask (SIG_UNBLOCK,
242            Unblocked_Signal_Mask'Unchecked_Access, Old_Set'Unchecked_Access);
243          pragma Assert (Result = 0);
244
245          raise Standard'Abort_Signal;
246       end if;
247    end Abort_Handler;
248
249    -----------------
250    -- Stack_Guard --
251    -----------------
252
253    procedure Stack_Guard (T : ST.Task_ID; On : Boolean) is
254       Stack_Base : constant Address := Get_Stack_Base (T.Common.LL.Thread);
255       Guard_Page_Address : Address;
256
257       Res : Interfaces.C.int;
258
259    begin
260       if Stack_Base_Available then
261
262          --  Compute the guard page address
263
264          Guard_Page_Address :=
265            Stack_Base - (Stack_Base mod Get_Page_Size) + Get_Page_Size;
266
267          if On then
268             Res := mprotect (Guard_Page_Address, Get_Page_Size, PROT_ON);
269          else
270             Res := mprotect (Guard_Page_Address, Get_Page_Size, PROT_OFF);
271          end if;
272
273          pragma Assert (Res = 0);
274       end if;
275    end Stack_Guard;
276
277    --------------------
278    -- Get_Thread_Id  --
279    --------------------
280
281    function Get_Thread_Id (T : ST.Task_ID) return OSI.Thread_Id is
282    begin
283       return T.Common.LL.Thread;
284    end Get_Thread_Id;
285
286    ----------
287    -- Self --
288    ----------
289
290    function Self return Task_ID renames Specific.Self;
291
292    ---------------------
293    -- Initialize_Lock --
294    ---------------------
295
296    --  Note: mutexes and cond_variables needed per-task basis are
297    --        initialized in Intialize_TCB and the Storage_Error is
298    --        handled. Other mutexes (such as RTS_Lock, Memory_Lock...)
299    --        used in RTS is initialized before any status change of RTS.
300    --        Therefore rasing Storage_Error in the following routines
301    --        should be able to be handled safely.
302
303    procedure Initialize_Lock
304      (Prio : System.Any_Priority;
305       L    : access Lock)
306    is
307       Attributes : aliased pthread_mutexattr_t;
308       Result : Interfaces.C.int;
309
310    begin
311       Result := pthread_mutexattr_init (Attributes'Access);
312       pragma Assert (Result = 0 or else Result = ENOMEM);
313
314       if Result = ENOMEM then
315          raise Storage_Error;
316       end if;
317
318       if Locking_Policy = 'C' then
319          Result := pthread_mutexattr_setprotocol
320            (Attributes'Access, PTHREAD_PRIO_PROTECT);
321          pragma Assert (Result = 0);
322
323          Result := pthread_mutexattr_setprioceiling
324             (Attributes'Access, Interfaces.C.int (Prio));
325          pragma Assert (Result = 0);
326
327       elsif Locking_Policy = 'I' then
328          Result := pthread_mutexattr_setprotocol
329            (Attributes'Access, PTHREAD_PRIO_INHERIT);
330          pragma Assert (Result = 0);
331       end if;
332
333       Result := pthread_mutex_init (L, Attributes'Access);
334       pragma Assert (Result = 0 or else Result = ENOMEM);
335
336       if Result = ENOMEM then
337          raise Storage_Error;
338       end if;
339
340       Result := pthread_mutexattr_destroy (Attributes'Access);
341       pragma Assert (Result = 0);
342    end Initialize_Lock;
343
344    procedure Initialize_Lock (L : access RTS_Lock; Level : Lock_Level) is
345       pragma Warnings (Off, Level);
346
347       Attributes : aliased pthread_mutexattr_t;
348       Result     : Interfaces.C.int;
349
350    begin
351       Result := pthread_mutexattr_init (Attributes'Access);
352       pragma Assert (Result = 0 or else Result = ENOMEM);
353
354       if Result = ENOMEM then
355          raise Storage_Error;
356       end if;
357
358       if Locking_Policy = 'C' then
359          Result := pthread_mutexattr_setprotocol
360            (Attributes'Access, PTHREAD_PRIO_PROTECT);
361          pragma Assert (Result = 0);
362
363          Result := pthread_mutexattr_setprioceiling
364             (Attributes'Access, Interfaces.C.int (System.Any_Priority'Last));
365          pragma Assert (Result = 0);
366
367       elsif Locking_Policy = 'I' then
368          Result := pthread_mutexattr_setprotocol
369            (Attributes'Access, PTHREAD_PRIO_INHERIT);
370          pragma Assert (Result = 0);
371       end if;
372
373       Result := pthread_mutex_init (L, Attributes'Access);
374       pragma Assert (Result = 0 or else Result = ENOMEM);
375
376       if Result = ENOMEM then
377          Result := pthread_mutexattr_destroy (Attributes'Access);
378          raise Storage_Error;
379       end if;
380
381       Result := pthread_mutexattr_destroy (Attributes'Access);
382       pragma Assert (Result = 0);
383    end Initialize_Lock;
384
385    -------------------
386    -- Finalize_Lock --
387    -------------------
388
389    procedure Finalize_Lock (L : access Lock) is
390       Result : Interfaces.C.int;
391
392    begin
393       Result := pthread_mutex_destroy (L);
394       pragma Assert (Result = 0);
395    end Finalize_Lock;
396
397    procedure Finalize_Lock (L : access RTS_Lock) is
398       Result : Interfaces.C.int;
399
400    begin
401       Result := pthread_mutex_destroy (L);
402       pragma Assert (Result = 0);
403    end Finalize_Lock;
404
405    ----------------
406    -- Write_Lock --
407    ----------------
408
409    procedure Write_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
410       Result : Interfaces.C.int;
411
412    begin
413       Result := pthread_mutex_lock (L);
414
415       --  Assume that the cause of EINVAL is a priority ceiling violation
416
417       Ceiling_Violation := (Result = EINVAL);
418       pragma Assert (Result = 0 or else Result = EINVAL);
419    end Write_Lock;
420
421    procedure Write_Lock
422      (L           : access RTS_Lock;
423       Global_Lock : Boolean := False)
424    is
425       Result : Interfaces.C.int;
426
427    begin
428       if not Single_Lock or else Global_Lock then
429          Result := pthread_mutex_lock (L);
430          pragma Assert (Result = 0);
431       end if;
432    end Write_Lock;
433
434    procedure Write_Lock (T : Task_ID) is
435       Result : Interfaces.C.int;
436
437    begin
438       if not Single_Lock then
439          Result := pthread_mutex_lock (T.Common.LL.L'Access);
440          pragma Assert (Result = 0);
441       end if;
442    end Write_Lock;
443
444    ---------------
445    -- Read_Lock --
446    ---------------
447
448    procedure Read_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
449    begin
450       Write_Lock (L, Ceiling_Violation);
451    end Read_Lock;
452
453    ------------
454    -- Unlock --
455    ------------
456
457    procedure Unlock (L : access Lock) is
458       Result : Interfaces.C.int;
459
460    begin
461       Result := pthread_mutex_unlock (L);
462       pragma Assert (Result = 0);
463    end Unlock;
464
465    procedure Unlock (L : access RTS_Lock; Global_Lock : Boolean := False) is
466       Result : Interfaces.C.int;
467
468    begin
469       if not Single_Lock or else Global_Lock then
470          Result := pthread_mutex_unlock (L);
471          pragma Assert (Result = 0);
472       end if;
473    end Unlock;
474
475    procedure Unlock (T : Task_ID) is
476       Result : Interfaces.C.int;
477
478    begin
479       if not Single_Lock then
480          Result := pthread_mutex_unlock (T.Common.LL.L'Access);
481          pragma Assert (Result = 0);
482       end if;
483    end Unlock;
484
485    -----------
486    -- Sleep --
487    -----------
488
489    procedure Sleep
490      (Self_ID : Task_ID;
491       Reason   : System.Tasking.Task_States)
492    is
493       pragma Warnings (Off, Reason);
494
495       Result : Interfaces.C.int;
496
497    begin
498       if Single_Lock then
499          Result := pthread_cond_wait
500            (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access);
501       else
502          Result := pthread_cond_wait
503            (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
504       end if;
505
506       --  EINTR is not considered a failure.
507
508       pragma Assert (Result = 0 or else Result = EINTR);
509    end Sleep;
510
511    -----------------
512    -- Timed_Sleep --
513    -----------------
514
515    --  This is for use within the run-time system, so abort is
516    --  assumed to be already deferred, and the caller should be
517    --  holding its own ATCB lock.
518
519    procedure Timed_Sleep
520      (Self_ID  : Task_ID;
521       Time     : Duration;
522       Mode     : ST.Delay_Modes;
523       Reason   : Task_States;
524       Timedout : out Boolean;
525       Yielded  : out Boolean)
526    is
527       pragma Warnings (Off, Reason);
528
529       Check_Time : constant Duration := Monotonic_Clock;
530       Rel_Time   : Duration;
531       Abs_Time   : Duration;
532       Request    : aliased timespec;
533       Result     : Interfaces.C.int;
534
535    begin
536       Timedout := True;
537       Yielded := False;
538
539       if Mode = Relative then
540          Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
541
542          if Relative_Timed_Wait then
543             Rel_Time := Duration'Min (Max_Sensible_Delay, Time);
544          end if;
545
546       else
547          Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
548
549          if Relative_Timed_Wait then
550             Rel_Time := Duration'Min (Max_Sensible_Delay, Time - Check_Time);
551          end if;
552       end if;
553
554       if Abs_Time > Check_Time then
555          if Relative_Timed_Wait then
556             Request := To_Timespec (Rel_Time);
557          else
558             Request := To_Timespec (Abs_Time);
559          end if;
560
561          loop
562             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
563               or else Self_ID.Pending_Priority_Change;
564
565             if Single_Lock then
566                Result := pthread_cond_timedwait
567                  (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access,
568                   Request'Access);
569
570             else
571                Result := pthread_cond_timedwait
572                  (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access,
573                   Request'Access);
574             end if;
575
576             exit when Abs_Time <= Monotonic_Clock;
577
578             if Result = 0 or Result = EINTR then
579
580                --  Somebody may have called Wakeup for us
581
582                Timedout := False;
583                exit;
584             end if;
585
586             pragma Assert (Result = ETIMEDOUT);
587          end loop;
588       end if;
589    end Timed_Sleep;
590
591    -----------------
592    -- Timed_Delay --
593    -----------------
594
595    --  This is for use in implementing delay statements, so
596    --  we assume the caller is abort-deferred but is holding
597    --  no locks.
598
599    procedure Timed_Delay
600      (Self_ID  : Task_ID;
601       Time     : Duration;
602       Mode     : ST.Delay_Modes)
603    is
604       Check_Time : constant Duration := Monotonic_Clock;
605       Abs_Time   : Duration;
606       Rel_Time   : Duration;
607       Request    : aliased timespec;
608       Result     : Interfaces.C.int;
609
610    begin
611       --  Only the little window between deferring abort and
612       --  locking Self_ID is the reason we need to
613       --  check for pending abort and priority change below! :(
614
615       SSL.Abort_Defer.all;
616
617       if Single_Lock then
618          Lock_RTS;
619       end if;
620
621       Write_Lock (Self_ID);
622
623       if Mode = Relative then
624          Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
625
626          if Relative_Timed_Wait then
627             Rel_Time := Duration'Min (Max_Sensible_Delay, Time);
628          end if;
629
630       else
631          Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
632
633          if Relative_Timed_Wait then
634             Rel_Time := Duration'Min (Max_Sensible_Delay, Time - Check_Time);
635          end if;
636       end if;
637
638       if Abs_Time > Check_Time then
639          if Relative_Timed_Wait then
640             Request := To_Timespec (Rel_Time);
641          else
642             Request := To_Timespec (Abs_Time);
643          end if;
644
645          Self_ID.Common.State := Delay_Sleep;
646
647          loop
648             if Self_ID.Pending_Priority_Change then
649                Self_ID.Pending_Priority_Change := False;
650                Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
651                Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
652             end if;
653
654             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
655
656             if Single_Lock then
657                Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
658                  Single_RTS_Lock'Access, Request'Access);
659             else
660                Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
661                  Self_ID.Common.LL.L'Access, Request'Access);
662             end if;
663
664             exit when Abs_Time <= Monotonic_Clock;
665
666             pragma Assert (Result = 0
667                              or else Result = ETIMEDOUT
668                              or else Result = EINTR);
669          end loop;
670
671          Self_ID.Common.State := Runnable;
672       end if;
673
674       Unlock (Self_ID);
675
676       if Single_Lock then
677          Unlock_RTS;
678       end if;
679
680       Result := sched_yield;
681       SSL.Abort_Undefer.all;
682    end Timed_Delay;
683
684    ---------------------
685    -- Monotonic_Clock --
686    ---------------------
687
688    function Monotonic_Clock return Duration is
689       TS     : aliased timespec;
690       Result : Interfaces.C.int;
691
692    begin
693       Result := clock_gettime
694         (clock_id => CLOCK_REALTIME, tp => TS'Unchecked_Access);
695       pragma Assert (Result = 0);
696       return To_Duration (TS);
697    end Monotonic_Clock;
698
699    -------------------
700    -- RT_Resolution --
701    -------------------
702
703    function RT_Resolution return Duration is
704    begin
705       return 10#1.0#E-6;
706    end RT_Resolution;
707
708    ------------
709    -- Wakeup --
710    ------------
711
712    procedure Wakeup (T : Task_ID; Reason : System.Tasking.Task_States) is
713       pragma Warnings (Off, Reason);
714
715       Result : Interfaces.C.int;
716
717    begin
718       Result := pthread_cond_signal (T.Common.LL.CV'Access);
719       pragma Assert (Result = 0);
720    end Wakeup;
721
722    -----------
723    -- Yield --
724    -----------
725
726    procedure Yield (Do_Yield : Boolean := True) is
727       Result : Interfaces.C.int;
728
729    begin
730       if Do_Yield then
731          Result := sched_yield;
732       end if;
733    end Yield;
734
735    ------------------
736    -- Set_Priority --
737    ------------------
738
739    procedure Set_Priority
740      (T                   : Task_ID;
741       Prio                : System.Any_Priority;
742       Loss_Of_Inheritance : Boolean := False)
743    is
744       pragma Warnings (Off, Loss_Of_Inheritance);
745
746       Result : Interfaces.C.int;
747       Param  : aliased struct_sched_param;
748
749    begin
750       T.Common.Current_Priority := Prio;
751       Param.sched_priority := Interfaces.C.int (Prio);
752
753       if Time_Slice_Supported and then Time_Slice_Val > 0 then
754          Result := pthread_setschedparam
755            (T.Common.LL.Thread, SCHED_RR, Param'Access);
756
757       elsif FIFO_Within_Priorities or else Time_Slice_Val = 0 then
758          Result := pthread_setschedparam
759            (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
760
761       else
762          Result := pthread_setschedparam
763            (T.Common.LL.Thread, SCHED_OTHER, Param'Access);
764       end if;
765
766       pragma Assert (Result = 0);
767    end Set_Priority;
768
769    ------------------
770    -- Get_Priority --
771    ------------------
772
773    function Get_Priority (T : Task_ID) return System.Any_Priority is
774    begin
775       return T.Common.Current_Priority;
776    end Get_Priority;
777
778    ----------------
779    -- Enter_Task --
780    ----------------
781
782    procedure Enter_Task (Self_ID : Task_ID) is
783    begin
784       Self_ID.Common.LL.Thread := pthread_self;
785       Self_ID.Common.LL.LWP := lwp_self;
786
787       Specific.Set (Self_ID);
788
789       Lock_RTS;
790
791       for J in Known_Tasks'Range loop
792          if Known_Tasks (J) = null then
793             Known_Tasks (J) := Self_ID;
794             Self_ID.Known_Tasks_Index := J;
795             exit;
796          end if;
797       end loop;
798
799       Unlock_RTS;
800    end Enter_Task;
801
802    --------------
803    -- New_ATCB --
804    --------------
805
806    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_ID is
807    begin
808       return new Ada_Task_Control_Block (Entry_Num);
809    end New_ATCB;
810
811    -------------------
812    -- Is_Valid_Task --
813    -------------------
814
815    function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
816
817    -----------------------------
818    -- Register_Foreign_Thread --
819    -----------------------------
820
821    function Register_Foreign_Thread return Task_ID is
822    begin
823       if Is_Valid_Task then
824          return Self;
825       else
826          return Register_Foreign_Thread (pthread_self);
827       end if;
828    end Register_Foreign_Thread;
829
830    --------------------
831    -- Initialize_TCB --
832    --------------------
833
834    procedure Initialize_TCB (Self_ID : Task_ID; Succeeded : out Boolean) is
835       Mutex_Attr : aliased pthread_mutexattr_t;
836       Result     : Interfaces.C.int;
837       Cond_Attr  : aliased pthread_condattr_t;
838
839    begin
840       --  Give the task a unique serial number.
841
842       Self_ID.Serial_Number := Next_Serial_Number;
843       Next_Serial_Number := Next_Serial_Number + 1;
844       pragma Assert (Next_Serial_Number /= 0);
845
846       if not Single_Lock then
847          Result := pthread_mutexattr_init (Mutex_Attr'Access);
848          pragma Assert (Result = 0 or else Result = ENOMEM);
849
850          if Result = 0 then
851             if Locking_Policy = 'C' then
852                Result := pthread_mutexattr_setprotocol
853                  (Mutex_Attr'Access, PTHREAD_PRIO_PROTECT);
854                pragma Assert (Result = 0);
855
856                Result := pthread_mutexattr_setprioceiling
857                   (Mutex_Attr'Access,
858                    Interfaces.C.int (System.Any_Priority'Last));
859                pragma Assert (Result = 0);
860
861             elsif Locking_Policy = 'I' then
862                Result := pthread_mutexattr_setprotocol
863                  (Mutex_Attr'Access, PTHREAD_PRIO_INHERIT);
864                pragma Assert (Result = 0);
865             end if;
866
867             Result := pthread_mutex_init (Self_ID.Common.LL.L'Access,
868               Mutex_Attr'Access);
869             pragma Assert (Result = 0 or else Result = ENOMEM);
870          end if;
871
872          if Result /= 0 then
873             Succeeded := False;
874             return;
875          end if;
876
877          Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
878          pragma Assert (Result = 0);
879       end if;
880
881       Result := pthread_condattr_init (Cond_Attr'Access);
882       pragma Assert (Result = 0 or else Result = ENOMEM);
883
884       if Result = 0 then
885          Result := pthread_cond_init (Self_ID.Common.LL.CV'Access,
886            Cond_Attr'Access);
887          pragma Assert (Result = 0 or else Result = ENOMEM);
888       end if;
889
890       if Result = 0 then
891          Succeeded := True;
892       else
893          if not Single_Lock then
894             Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
895             pragma Assert (Result = 0);
896          end if;
897
898          Succeeded := False;
899       end if;
900
901       Result := pthread_condattr_destroy (Cond_Attr'Access);
902       pragma Assert (Result = 0);
903    end Initialize_TCB;
904
905    -----------------
906    -- Create_Task --
907    -----------------
908
909    procedure Create_Task
910      (T          : Task_ID;
911       Wrapper    : System.Address;
912       Stack_Size : System.Parameters.Size_Type;
913       Priority   : System.Any_Priority;
914       Succeeded  : out Boolean)
915    is
916       Attributes          : aliased pthread_attr_t;
917       Adjusted_Stack_Size : Interfaces.C.size_t;
918       Result              : Interfaces.C.int;
919
920       function Thread_Body_Access is new
921         Unchecked_Conversion (System.Address, Thread_Body);
922
923       use System.Task_Info;
924
925    begin
926       if Stack_Size = Unspecified_Size then
927          Adjusted_Stack_Size := Interfaces.C.size_t (Default_Stack_Size);
928
929       elsif Stack_Size < Minimum_Stack_Size then
930          Adjusted_Stack_Size := Interfaces.C.size_t (Minimum_Stack_Size);
931
932       else
933          Adjusted_Stack_Size := Interfaces.C.size_t (Stack_Size);
934       end if;
935
936       if Stack_Base_Available then
937          --  If Stack Checking is supported then allocate 2 additional pages:
938          --
939          --  In the worst case, stack is allocated at something like
940          --  N * Get_Page_Size - epsilon, we need to add the size for 2 pages
941          --  to be sure the effective stack size is greater than what
942          --  has been asked.
943
944          Adjusted_Stack_Size := Adjusted_Stack_Size + 2 * Get_Page_Size;
945       end if;
946
947       Result := pthread_attr_init (Attributes'Access);
948       pragma Assert (Result = 0 or else Result = ENOMEM);
949
950       if Result /= 0 then
951          Succeeded := False;
952          return;
953       end if;
954
955       Result := pthread_attr_setdetachstate
956         (Attributes'Access, PTHREAD_CREATE_DETACHED);
957       pragma Assert (Result = 0);
958
959       Result := pthread_attr_setstacksize
960         (Attributes'Access, Adjusted_Stack_Size);
961       pragma Assert (Result = 0);
962
963       if T.Common.Task_Info /= Default_Scope then
964
965          --  We are assuming that Scope_Type has the same values than the
966          --  corresponding C macros
967
968          Result := pthread_attr_setscope
969            (Attributes'Access, Task_Info_Type'Pos (T.Common.Task_Info));
970          pragma Assert (Result = 0);
971       end if;
972
973       --  Since the initial signal mask of a thread is inherited from the
974       --  creator, and the Environment task has all its signals masked, we
975       --  do not need to manipulate caller's signal mask at this point.
976       --  All tasks in RTS will have All_Tasks_Mask initially.
977
978       Result := pthread_create
979         (T.Common.LL.Thread'Access,
980          Attributes'Access,
981          Thread_Body_Access (Wrapper),
982          To_Address (T));
983       pragma Assert (Result = 0 or else Result = EAGAIN);
984
985       Succeeded := Result = 0;
986
987       Result := pthread_attr_destroy (Attributes'Access);
988       pragma Assert (Result = 0);
989
990       Set_Priority (T, Priority);
991    end Create_Task;
992
993    ------------------
994    -- Finalize_TCB --
995    ------------------
996
997    procedure Finalize_TCB (T : Task_ID) is
998       Result : Interfaces.C.int;
999       Tmp    : Task_ID := T;
1000       Is_Self : constant Boolean := T = Self;
1001
1002       procedure Free is new
1003         Unchecked_Deallocation (Ada_Task_Control_Block, Task_ID);
1004
1005    begin
1006       if not Single_Lock then
1007          Result := pthread_mutex_destroy (T.Common.LL.L'Access);
1008          pragma Assert (Result = 0);
1009       end if;
1010
1011       Result := pthread_cond_destroy (T.Common.LL.CV'Access);
1012       pragma Assert (Result = 0);
1013
1014       if T.Known_Tasks_Index /= -1 then
1015          Known_Tasks (T.Known_Tasks_Index) := null;
1016       end if;
1017
1018       Free (Tmp);
1019
1020       if Is_Self then
1021          Result := pthread_setspecific (ATCB_Key, System.Null_Address);
1022          pragma Assert (Result = 0);
1023       end if;
1024
1025    end Finalize_TCB;
1026
1027    ---------------
1028    -- Exit_Task --
1029    ---------------
1030
1031    procedure Exit_Task is
1032    begin
1033       --  Mark this task as unknown, so that if Self is called, it won't
1034       --  return a dangling pointer.
1035
1036       Specific.Set (null);
1037    end Exit_Task;
1038
1039    ----------------
1040    -- Abort_Task --
1041    ----------------
1042
1043    procedure Abort_Task (T : Task_ID) is
1044       Result : Interfaces.C.int;
1045
1046    begin
1047       Result := pthread_kill (T.Common.LL.Thread,
1048         Signal (System.Interrupt_Management.Abort_Task_Interrupt));
1049       pragma Assert (Result = 0);
1050    end Abort_Task;
1051
1052    ----------------
1053    -- Check_Exit --
1054    ----------------
1055
1056    --  Dummy version
1057
1058    function Check_Exit (Self_ID : ST.Task_ID) return Boolean is
1059       pragma Warnings (Off, Self_ID);
1060
1061    begin
1062       return True;
1063    end Check_Exit;
1064
1065    --------------------
1066    -- Check_No_Locks --
1067    --------------------
1068
1069    function Check_No_Locks (Self_ID : ST.Task_ID) return Boolean is
1070       pragma Warnings (Off, Self_ID);
1071
1072    begin
1073       return True;
1074    end Check_No_Locks;
1075
1076    ----------------------
1077    -- Environment_Task --
1078    ----------------------
1079
1080    function Environment_Task return Task_ID is
1081    begin
1082       return Environment_Task_ID;
1083    end Environment_Task;
1084
1085    --------------
1086    -- Lock_RTS --
1087    --------------
1088
1089    procedure Lock_RTS is
1090    begin
1091       Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
1092    end Lock_RTS;
1093
1094    ----------------
1095    -- Unlock_RTS --
1096    ----------------
1097
1098    procedure Unlock_RTS is
1099    begin
1100       Unlock (Single_RTS_Lock'Access, Global_Lock => True);
1101    end Unlock_RTS;
1102
1103    ------------------
1104    -- Suspend_Task --
1105    ------------------
1106
1107    function Suspend_Task
1108      (T           : ST.Task_ID;
1109       Thread_Self : Thread_Id)
1110       return        Boolean
1111    is
1112       pragma Warnings (Off, T);
1113       pragma Warnings (Off, Thread_Self);
1114
1115    begin
1116       return False;
1117    end Suspend_Task;
1118
1119    -----------------
1120    -- Resume_Task --
1121    -----------------
1122
1123    function Resume_Task
1124      (T           : ST.Task_ID;
1125       Thread_Self : Thread_Id)
1126       return        Boolean
1127    is
1128       pragma Warnings (Off, T);
1129       pragma Warnings (Off, Thread_Self);
1130
1131    begin
1132       return False;
1133    end Resume_Task;
1134
1135    ----------------
1136    -- Initialize --
1137    ----------------
1138
1139    procedure Initialize (Environment_Task : Task_ID) is
1140       act     : aliased struct_sigaction;
1141       old_act : aliased struct_sigaction;
1142       Tmp_Set : aliased sigset_t;
1143       Result  : Interfaces.C.int;
1144
1145       function State (Int : System.Interrupt_Management.Interrupt_ID)
1146                      return Character;
1147       pragma Import (C, State, "__gnat_get_interrupt_state");
1148       --  Get interrupt state.  Defined in a-init.c
1149       --  The input argument is the interrupt number,
1150       --  and the result is one of the following:
1151
1152       Default : constant Character := 's';
1153       --    'n'   this interrupt not set by any Interrupt_State pragma
1154       --    'u'   Interrupt_State pragma set state to User
1155       --    'r'   Interrupt_State pragma set state to Runtime
1156       --    's'   Interrupt_State pragma set state to System (use "default"
1157       --           system handler)
1158
1159    begin
1160       Environment_Task_ID := Environment_Task;
1161
1162       --  Initialize the lock used to synchronize chain of all ATCBs.
1163
1164       Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1165
1166       Specific.Initialize (Environment_Task);
1167
1168       Enter_Task (Environment_Task);
1169
1170       --  Install the abort-signal handler
1171
1172       if State (System.Interrupt_Management.Abort_Task_Interrupt)
1173         /= Default
1174       then
1175          act.sa_flags := 0;
1176          act.sa_handler := Abort_Handler'Address;
1177
1178          Result := sigemptyset (Tmp_Set'Access);
1179          pragma Assert (Result = 0);
1180          act.sa_mask := Tmp_Set;
1181
1182          Result :=
1183            sigaction
1184            (Signal (System.Interrupt_Management.Abort_Task_Interrupt),
1185             act'Unchecked_Access,
1186             old_act'Unchecked_Access);
1187          pragma Assert (Result = 0);
1188       end if;
1189    end Initialize;
1190
1191 begin
1192    declare
1193       Result : Interfaces.C.int;
1194    begin
1195       --  Mask Environment task for all signals. The original mask of the
1196       --  Environment task will be recovered by Interrupt_Server task
1197       --  during the elaboration of s-interr.adb.
1198
1199       System.Interrupt_Management.Operations.Set_Interrupt_Mask
1200         (System.Interrupt_Management.Operations.All_Tasks_Mask'Access);
1201
1202       --  Prepare the set of signals that should unblocked in all tasks
1203
1204       Result := sigemptyset (Unblocked_Signal_Mask'Access);
1205       pragma Assert (Result = 0);
1206
1207       for J in Interrupt_Management.Interrupt_ID loop
1208          if System.Interrupt_Management.Keep_Unmasked (J) then
1209             Result := sigaddset (Unblocked_Signal_Mask'Access, Signal (J));
1210             pragma Assert (Result = 0);
1211          end if;
1212       end loop;
1213    end;
1214 end System.Task_Primitives.Operations;