OSDN Git Service

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