OSDN Git Service

2005-06-15 Andrew Pinski <pinskia@physics.uc.edu>
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-taprop-posix.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-2004, 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.Stages.
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       : constant 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    begin
692       Result := clock_gettime
693         (clock_id => CLOCK_REALTIME, tp => TS'Unchecked_Access);
694       pragma Assert (Result = 0);
695       return To_Duration (TS);
696    end Monotonic_Clock;
697
698    -------------------
699    -- RT_Resolution --
700    -------------------
701
702    function RT_Resolution return Duration is
703    begin
704       return 10#1.0#E-6;
705    end RT_Resolution;
706
707    ------------
708    -- Wakeup --
709    ------------
710
711    procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
712       pragma Warnings (Off, Reason);
713       Result : Interfaces.C.int;
714    begin
715       Result := pthread_cond_signal (T.Common.LL.CV'Access);
716       pragma Assert (Result = 0);
717    end Wakeup;
718
719    -----------
720    -- Yield --
721    -----------
722
723    procedure Yield (Do_Yield : Boolean := True) is
724       Result : Interfaces.C.int;
725       pragma Unreferenced (Result);
726    begin
727       if Do_Yield then
728          Result := sched_yield;
729       end if;
730    end Yield;
731
732    ------------------
733    -- Set_Priority --
734    ------------------
735
736    procedure Set_Priority
737      (T                   : Task_Id;
738       Prio                : System.Any_Priority;
739       Loss_Of_Inheritance : Boolean := False)
740    is
741       pragma Warnings (Off, Loss_Of_Inheritance);
742
743       Result : Interfaces.C.int;
744       Param  : aliased struct_sched_param;
745
746    begin
747       T.Common.Current_Priority := Prio;
748       Param.sched_priority := Interfaces.C.int (Prio);
749
750       if Time_Slice_Supported and then Time_Slice_Val > 0 then
751          Result := pthread_setschedparam
752            (T.Common.LL.Thread, SCHED_RR, Param'Access);
753
754       elsif FIFO_Within_Priorities or else Time_Slice_Val = 0 then
755          Result := pthread_setschedparam
756            (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
757
758       else
759          Result := pthread_setschedparam
760            (T.Common.LL.Thread, SCHED_OTHER, Param'Access);
761       end if;
762
763       pragma Assert (Result = 0);
764    end Set_Priority;
765
766    ------------------
767    -- Get_Priority --
768    ------------------
769
770    function Get_Priority (T : Task_Id) return System.Any_Priority is
771    begin
772       return T.Common.Current_Priority;
773    end Get_Priority;
774
775    ----------------
776    -- Enter_Task --
777    ----------------
778
779    procedure Enter_Task (Self_ID : Task_Id) is
780    begin
781       Self_ID.Common.LL.Thread := pthread_self;
782       Self_ID.Common.LL.LWP := lwp_self;
783
784       Specific.Set (Self_ID);
785
786       Lock_RTS;
787
788       for J in Known_Tasks'Range loop
789          if Known_Tasks (J) = null then
790             Known_Tasks (J) := Self_ID;
791             Self_ID.Known_Tasks_Index := J;
792             exit;
793          end if;
794       end loop;
795
796       Unlock_RTS;
797    end Enter_Task;
798
799    --------------
800    -- New_ATCB --
801    --------------
802
803    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
804    begin
805       return new Ada_Task_Control_Block (Entry_Num);
806    end New_ATCB;
807
808    -------------------
809    -- Is_Valid_Task --
810    -------------------
811
812    function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
813
814    -----------------------------
815    -- Register_Foreign_Thread --
816    -----------------------------
817
818    function Register_Foreign_Thread return Task_Id is
819    begin
820       if Is_Valid_Task then
821          return Self;
822       else
823          return Register_Foreign_Thread (pthread_self);
824       end if;
825    end Register_Foreign_Thread;
826
827    --------------------
828    -- Initialize_TCB --
829    --------------------
830
831    procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
832       Mutex_Attr : aliased pthread_mutexattr_t;
833       Result     : Interfaces.C.int;
834       Cond_Attr  : aliased pthread_condattr_t;
835
836    begin
837       --  Give the task a unique serial number.
838
839       Self_ID.Serial_Number := Next_Serial_Number;
840       Next_Serial_Number := Next_Serial_Number + 1;
841       pragma Assert (Next_Serial_Number /= 0);
842
843       if not Single_Lock then
844          Result := pthread_mutexattr_init (Mutex_Attr'Access);
845          pragma Assert (Result = 0 or else Result = ENOMEM);
846
847          if Result = 0 then
848             if Locking_Policy = 'C' then
849                Result := pthread_mutexattr_setprotocol
850                  (Mutex_Attr'Access, PTHREAD_PRIO_PROTECT);
851                pragma Assert (Result = 0);
852
853                Result := pthread_mutexattr_setprioceiling
854                   (Mutex_Attr'Access,
855                    Interfaces.C.int (System.Any_Priority'Last));
856                pragma Assert (Result = 0);
857
858             elsif Locking_Policy = 'I' then
859                Result := pthread_mutexattr_setprotocol
860                  (Mutex_Attr'Access, PTHREAD_PRIO_INHERIT);
861                pragma Assert (Result = 0);
862             end if;
863
864             Result := pthread_mutex_init (Self_ID.Common.LL.L'Access,
865               Mutex_Attr'Access);
866             pragma Assert (Result = 0 or else Result = ENOMEM);
867          end if;
868
869          if Result /= 0 then
870             Succeeded := False;
871             return;
872          end if;
873
874          Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
875          pragma Assert (Result = 0);
876       end if;
877
878       Result := pthread_condattr_init (Cond_Attr'Access);
879       pragma Assert (Result = 0 or else Result = ENOMEM);
880
881       if Result = 0 then
882          Result := pthread_cond_init (Self_ID.Common.LL.CV'Access,
883            Cond_Attr'Access);
884          pragma Assert (Result = 0 or else Result = ENOMEM);
885       end if;
886
887       if Result = 0 then
888          Succeeded := True;
889       else
890          if not Single_Lock then
891             Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
892             pragma Assert (Result = 0);
893          end if;
894
895          Succeeded := False;
896       end if;
897
898       Result := pthread_condattr_destroy (Cond_Attr'Access);
899       pragma Assert (Result = 0);
900    end Initialize_TCB;
901
902    -----------------
903    -- Create_Task --
904    -----------------
905
906    procedure Create_Task
907      (T          : Task_Id;
908       Wrapper    : System.Address;
909       Stack_Size : System.Parameters.Size_Type;
910       Priority   : System.Any_Priority;
911       Succeeded  : out Boolean)
912    is
913       Attributes          : aliased pthread_attr_t;
914       Adjusted_Stack_Size : Interfaces.C.size_t;
915       Result              : Interfaces.C.int;
916
917       function Thread_Body_Access is new
918         Unchecked_Conversion (System.Address, Thread_Body);
919
920       use System.Task_Info;
921
922    begin
923       if Stack_Size = Unspecified_Size then
924          Adjusted_Stack_Size := Interfaces.C.size_t (Default_Stack_Size);
925
926       elsif Stack_Size < Minimum_Stack_Size then
927          Adjusted_Stack_Size := Interfaces.C.size_t (Minimum_Stack_Size);
928
929       else
930          Adjusted_Stack_Size := Interfaces.C.size_t (Stack_Size);
931       end if;
932
933       if Stack_Base_Available then
934          --  If Stack Checking is supported then allocate 2 additional pages:
935          --
936          --  In the worst case, stack is allocated at something like
937          --  N * Get_Page_Size - epsilon, we need to add the size for 2 pages
938          --  to be sure the effective stack size is greater than what
939          --  has been asked.
940
941          Adjusted_Stack_Size := Adjusted_Stack_Size + 2 * Get_Page_Size;
942       end if;
943
944       Result := pthread_attr_init (Attributes'Access);
945       pragma Assert (Result = 0 or else Result = ENOMEM);
946
947       if Result /= 0 then
948          Succeeded := False;
949          return;
950       end if;
951
952       Result := pthread_attr_setdetachstate
953         (Attributes'Access, PTHREAD_CREATE_DETACHED);
954       pragma Assert (Result = 0);
955
956       Result := pthread_attr_setstacksize
957         (Attributes'Access, Adjusted_Stack_Size);
958       pragma Assert (Result = 0);
959
960       if T.Common.Task_Info /= Default_Scope then
961
962          --  We are assuming that Scope_Type has the same values than the
963          --  corresponding C macros
964
965          Result := pthread_attr_setscope
966            (Attributes'Access, Task_Info_Type'Pos (T.Common.Task_Info));
967          pragma Assert (Result = 0);
968       end if;
969
970       --  Since the initial signal mask of a thread is inherited from the
971       --  creator, and the Environment task has all its signals masked, we
972       --  do not need to manipulate caller's signal mask at this point.
973       --  All tasks in RTS will have All_Tasks_Mask initially.
974
975       Result := pthread_create
976         (T.Common.LL.Thread'Access,
977          Attributes'Access,
978          Thread_Body_Access (Wrapper),
979          To_Address (T));
980       pragma Assert (Result = 0 or else Result = EAGAIN);
981
982       Succeeded := Result = 0;
983
984       Result := pthread_attr_destroy (Attributes'Access);
985       pragma Assert (Result = 0);
986
987       Set_Priority (T, Priority);
988    end Create_Task;
989
990    ------------------
991    -- Finalize_TCB --
992    ------------------
993
994    procedure Finalize_TCB (T : Task_Id) is
995       Result  : Interfaces.C.int;
996       Tmp     : Task_Id := T;
997       Is_Self : constant Boolean := T = Self;
998
999       procedure Free is new
1000         Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
1001
1002    begin
1003       if not Single_Lock then
1004          Result := pthread_mutex_destroy (T.Common.LL.L'Access);
1005          pragma Assert (Result = 0);
1006       end if;
1007
1008       Result := pthread_cond_destroy (T.Common.LL.CV'Access);
1009       pragma Assert (Result = 0);
1010
1011       if T.Known_Tasks_Index /= -1 then
1012          Known_Tasks (T.Known_Tasks_Index) := null;
1013       end if;
1014
1015       Free (Tmp);
1016
1017       if Is_Self then
1018          Specific.Set (null);
1019       end if;
1020    end Finalize_TCB;
1021
1022    ---------------
1023    -- Exit_Task --
1024    ---------------
1025
1026    procedure Exit_Task is
1027    begin
1028       --  Mark this task as unknown, so that if Self is called, it won't
1029       --  return a dangling pointer.
1030
1031       Specific.Set (null);
1032    end Exit_Task;
1033
1034    ----------------
1035    -- Abort_Task --
1036    ----------------
1037
1038    procedure Abort_Task (T : Task_Id) is
1039       Result : Interfaces.C.int;
1040
1041    begin
1042       Result := pthread_kill (T.Common.LL.Thread,
1043         Signal (System.Interrupt_Management.Abort_Task_Interrupt));
1044       pragma Assert (Result = 0);
1045    end Abort_Task;
1046
1047    ----------------
1048    -- Check_Exit --
1049    ----------------
1050
1051    --  Dummy version
1052
1053    function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1054       pragma Warnings (Off, Self_ID);
1055    begin
1056       return True;
1057    end Check_Exit;
1058
1059    --------------------
1060    -- Check_No_Locks --
1061    --------------------
1062
1063    function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1064       pragma Warnings (Off, Self_ID);
1065    begin
1066       return True;
1067    end Check_No_Locks;
1068
1069    ----------------------
1070    -- Environment_Task --
1071    ----------------------
1072
1073    function Environment_Task return Task_Id is
1074    begin
1075       return Environment_Task_Id;
1076    end Environment_Task;
1077
1078    --------------
1079    -- Lock_RTS --
1080    --------------
1081
1082    procedure Lock_RTS is
1083    begin
1084       Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
1085    end Lock_RTS;
1086
1087    ----------------
1088    -- Unlock_RTS --
1089    ----------------
1090
1091    procedure Unlock_RTS is
1092    begin
1093       Unlock (Single_RTS_Lock'Access, Global_Lock => True);
1094    end Unlock_RTS;
1095
1096    ------------------
1097    -- Suspend_Task --
1098    ------------------
1099
1100    function Suspend_Task
1101      (T           : ST.Task_Id;
1102       Thread_Self : Thread_Id) return Boolean
1103    is
1104       pragma Warnings (Off, T);
1105       pragma Warnings (Off, Thread_Self);
1106    begin
1107       return False;
1108    end Suspend_Task;
1109
1110    -----------------
1111    -- Resume_Task --
1112    -----------------
1113
1114    function Resume_Task
1115      (T           : ST.Task_Id;
1116       Thread_Self : Thread_Id) return Boolean
1117    is
1118       pragma Warnings (Off, T);
1119       pragma Warnings (Off, Thread_Self);
1120    begin
1121       return False;
1122    end Resume_Task;
1123
1124    ----------------
1125    -- Initialize --
1126    ----------------
1127
1128    procedure Initialize (Environment_Task : Task_Id) is
1129       act     : aliased struct_sigaction;
1130       old_act : aliased struct_sigaction;
1131       Tmp_Set : aliased sigset_t;
1132       Result  : Interfaces.C.int;
1133
1134       function State
1135         (Int : System.Interrupt_Management.Interrupt_ID) return Character;
1136       pragma Import (C, State, "__gnat_get_interrupt_state");
1137       --  Get interrupt state.  Defined in a-init.c
1138       --  The input argument is the interrupt number,
1139       --  and the result is one of the following:
1140
1141       Default : constant Character := 's';
1142       --    'n'   this interrupt not set by any Interrupt_State pragma
1143       --    'u'   Interrupt_State pragma set state to User
1144       --    'r'   Interrupt_State pragma set state to Runtime
1145       --    's'   Interrupt_State pragma set state to System (use "default"
1146       --           system handler)
1147
1148    begin
1149       Environment_Task_Id := Environment_Task;
1150
1151       --  Initialize the lock used to synchronize chain of all ATCBs.
1152
1153       Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1154
1155       Specific.Initialize (Environment_Task);
1156
1157       Enter_Task (Environment_Task);
1158
1159       --  Install the abort-signal handler
1160
1161       if State (System.Interrupt_Management.Abort_Task_Interrupt)
1162         /= Default
1163       then
1164          act.sa_flags := 0;
1165          act.sa_handler := Abort_Handler'Address;
1166
1167          Result := sigemptyset (Tmp_Set'Access);
1168          pragma Assert (Result = 0);
1169          act.sa_mask := Tmp_Set;
1170
1171          Result :=
1172            sigaction
1173            (Signal (System.Interrupt_Management.Abort_Task_Interrupt),
1174             act'Unchecked_Access,
1175             old_act'Unchecked_Access);
1176          pragma Assert (Result = 0);
1177       end if;
1178    end Initialize;
1179
1180 begin
1181    declare
1182       Result : Interfaces.C.int;
1183    begin
1184       --  Mask Environment task for all signals. The original mask of the
1185       --  Environment task will be recovered by Interrupt_Server task
1186       --  during the elaboration of s-interr.adb.
1187
1188       System.Interrupt_Management.Operations.Set_Interrupt_Mask
1189         (System.Interrupt_Management.Operations.All_Tasks_Mask'Access);
1190
1191       --  Prepare the set of signals that should unblocked in all tasks
1192
1193       Result := sigemptyset (Unblocked_Signal_Mask'Access);
1194       pragma Assert (Result = 0);
1195
1196       for J in Interrupt_Management.Interrupt_ID loop
1197          if System.Interrupt_Management.Keep_Unmasked (J) then
1198             Result := sigaddset (Unblocked_Signal_Mask'Access, Signal (J));
1199             pragma Assert (Result = 0);
1200          end if;
1201       end loop;
1202    end;
1203 end System.Task_Primitives.Operations;