* einfo.h, sinfo.h, treeprs.ads: Regenerate.
[platform/upstream/gcc.git] / gcc / ada / 5htaprop.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 --                             $Revision: 1.42 $
10 --                                                                          --
11 --             Copyright (C) 1991-2001, Florida State University            --
12 --                                                                          --
13 -- GNARL is free software; you can  redistribute it  and/or modify it under --
14 -- terms of the  GNU General Public License as published  by the Free Soft- --
15 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
16 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
19 -- for  more details.  You should have  received  a copy of the GNU General --
20 -- Public License  distributed with GNARL; see file COPYING.  If not, write --
21 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
22 -- MA 02111-1307, USA.                                                      --
23 --                                                                          --
24 -- As a special exception,  if other files  instantiate  generics from this --
25 -- unit, or you link  this unit with other files  to produce an executable, --
26 -- this  unit  does not  by itself cause  the resulting  executable  to  be --
27 -- covered  by the  GNU  General  Public  License.  This exception does not --
28 -- however invalidate  any other reasons why  the executable file  might be --
29 -- covered by the  GNU Public License.                                      --
30 --                                                                          --
31 -- GNARL was developed by the GNARL team at Florida State University. It is --
32 -- now maintained by Ada Core Technologies Inc. in cooperation with Florida --
33 -- State University (http://www.gnat.com).                                  --
34 --                                                                          --
35 ------------------------------------------------------------------------------
36
37 --  This is a HP-UX version of this package
38
39 --  This package contains all the GNULL primitives that interface directly
40 --  with the underlying OS.
41
42 pragma Polling (Off);
43 --  Turn off polling, we do not want ATC polling to take place during
44 --  tasking operations. It causes infinite loops and other problems.
45
46 with System.Tasking.Debug;
47 --  used for Known_Tasks
48
49 with Interfaces.C;
50 --  used for int
51 --           size_t
52
53 with System.Interrupt_Management;
54 --  used for Keep_Unmasked
55 --           Abort_Task_Interrupt
56 --           Interrupt_ID
57
58 with System.Interrupt_Management.Operations;
59 --  used for Set_Interrupt_Mask
60 --           All_Tasks_Mask
61 pragma Elaborate_All (System.Interrupt_Management.Operations);
62
63 with System.Parameters;
64 --  used for Size_Type
65
66 with System.Task_Primitives.Interrupt_Operations;
67 --  used for Get_Interrupt_ID
68
69 with System.Tasking;
70 --  used for Ada_Task_Control_Block
71 --           Task_ID
72
73 with System.Soft_Links;
74 --  used for Defer/Undefer_Abort
75
76 --  Note that we do not use System.Tasking.Initialization directly since
77 --  this is a higher level package that we shouldn't depend on. For example
78 --  when using the restricted run time, it is replaced by
79 --  System.Tasking.Restricted.Initialization
80
81 with System.OS_Primitives;
82 --  used for Delay_Modes
83
84 with Unchecked_Conversion;
85 with Unchecked_Deallocation;
86
87 package body System.Task_Primitives.Operations is
88
89    use System.Tasking.Debug;
90    use System.Tasking;
91    use Interfaces.C;
92    use System.OS_Interface;
93    use System.Parameters;
94    use System.OS_Primitives;
95
96    package PIO renames System.Task_Primitives.Interrupt_Operations;
97    package SSL renames System.Soft_Links;
98
99    ------------------
100    --  Local Data  --
101    ------------------
102
103    --  The followings are logically constants, but need to be initialized
104    --  at run time.
105
106    ATCB_Key : aliased pthread_key_t;
107    --  Key used to find the Ada Task_ID associated with a thread
108
109    All_Tasks_L : aliased System.Task_Primitives.RTS_Lock;
110    --  See comments on locking rules in System.Tasking (spec).
111
112    Environment_Task_ID : Task_ID;
113    --  A variable to hold Task_ID for the environment task.
114
115    Unblocked_Signal_Mask : aliased sigset_t;
116    --  The set of signals that should unblocked in all tasks
117
118    Time_Slice_Val : Integer;
119    pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
120
121    Locking_Policy : Character;
122    pragma Import (C, Locking_Policy, "__gl_locking_policy");
123
124    Dispatching_Policy : Character;
125    pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
126
127    FIFO_Within_Priorities : constant Boolean := Dispatching_Policy = 'F';
128    --  Indicates whether FIFO_Within_Priorities is set.
129
130    --  The followings are internal configuration constants needed.
131
132    -----------------------
133    -- Local Subprograms --
134    -----------------------
135
136    procedure Abort_Handler (Sig : Signal);
137
138    function To_Task_ID is new Unchecked_Conversion (System.Address, Task_ID);
139
140    function To_Address is new Unchecked_Conversion (Task_ID, System.Address);
141
142    -------------------
143    -- Abort_Handler --
144    -------------------
145
146    --  Target-dependent binding of inter-thread Abort signal to
147    --  the raising of the Abort_Signal exception.
148
149    --  The technical issues and alternatives here are essentially
150    --  the same as for raising exceptions in response to other
151    --  signals (e.g. Storage_Error).  See code and comments in
152    --  the package body System.Interrupt_Management.
153
154    --  Some implementations may not allow an exception to be propagated
155    --  out of a handler, and others might leave the signal or
156    --  interrupt that invoked this handler masked after the exceptional
157    --  return to the application code.
158
159    --  GNAT exceptions are originally implemented using setjmp()/longjmp().
160    --  On most UNIX systems, this will allow transfer out of a signal handler,
161    --  which is usually the only mechanism available for implementing
162    --  asynchronous handlers of this kind.  However, some
163    --  systems do not restore the signal mask on longjmp(), leaving the
164    --  abort signal masked.
165
166    --  Alternative solutions include:
167
168    --       1. Change the PC saved in the system-dependent Context
169    --          parameter to point to code that raises the exception.
170    --          Normal return from this handler will then raise
171    --          the exception after the mask and other system state has
172    --          been restored (see example below).
173    --       2. Use siglongjmp()/sigsetjmp() to implement exceptions.
174    --       3. Unmask the signal in the Abortion_Signal exception handler
175    --          (in the RTS).
176
177    --  The following procedure would be needed if we can't lonjmp out of
178    --  a signal handler.  (See below.)
179    --  procedure Raise_Abort_Signal is
180    --  begin
181    --     raise Standard'Abort_Signal;
182    --  end if;
183
184    procedure Abort_Handler (Sig : Signal) is
185       Self_Id : constant Task_ID := Self;
186       Result  : Interfaces.C.int;
187       Old_Set : aliased sigset_t;
188
189    begin
190       --  Assuming it is safe to longjmp out of a signal handler, the
191       --  following code can be used:
192
193       if Self_Id.Deferral_Level = 0
194         and then Self_Id.Pending_ATC_Level < Self_Id.ATC_Nesting_Level and then
195         not Self_Id.Aborting
196       then
197          Self_Id.Aborting := True;
198
199          --  Make sure signals used for RTS internal purpose are unmasked
200
201          Result := pthread_sigmask (SIG_UNBLOCK,
202            Unblocked_Signal_Mask'Unchecked_Access, Old_Set'Unchecked_Access);
203          pragma Assert (Result = 0);
204
205          raise Standard'Abort_Signal;
206       end if;
207
208       --  Otherwise, something like this is required:
209       --  if not Abort_Is_Deferred.all then
210       --    --  Overwrite the return PC address with the address of the
211       --    --  special raise routine, and "return" to that routine's
212       --    --  starting address.
213       --    Context.PC := Raise_Abort_Signal'Address;
214       --    return;
215       --  end if;
216    end Abort_Handler;
217
218    -----------------
219    -- Stack_Guard --
220    -----------------
221
222    --  The underlying thread system sets a guard page at the
223    --  bottom of a thread stack, so nothing is needed.
224    --  ??? Check the comment above
225
226    procedure Stack_Guard (T : ST.Task_ID; On : Boolean) is
227    begin
228       null;
229    end Stack_Guard;
230
231    -------------------
232    -- Get_Thread_Id --
233    -------------------
234
235    function Get_Thread_Id (T : ST.Task_ID) return OSI.Thread_Id is
236    begin
237       return T.Common.LL.Thread;
238    end Get_Thread_Id;
239
240    ----------
241    -- Self --
242    ----------
243
244    function Self return Task_ID is
245       Result : System.Address;
246
247    begin
248       Result := pthread_getspecific (ATCB_Key);
249       pragma Assert (Result /= System.Null_Address);
250       return To_Task_ID (Result);
251    end Self;
252
253    ---------------------
254    -- Initialize_Lock --
255    ---------------------
256
257    --  Note: mutexes and cond_variables needed per-task basis are
258    --        initialized in Intialize_TCB and the Storage_Error is
259    --        handled. Other mutexes (such as All_Tasks_Lock, Memory_Lock...)
260    --        used in RTS is initialized before any status change of RTS.
261    --        Therefore rasing Storage_Error in the following routines
262    --        should be able to be handled safely.
263
264    procedure Initialize_Lock
265      (Prio : System.Any_Priority;
266       L    : access Lock)
267    is
268       Attributes : aliased pthread_mutexattr_t;
269       Result : Interfaces.C.int;
270    begin
271       Result := pthread_mutexattr_init (Attributes'Access);
272       pragma Assert (Result = 0 or else Result = ENOMEM);
273
274       if Result = ENOMEM then
275          raise Storage_Error;
276       end if;
277
278       L.Priority := Prio;
279
280       Result := pthread_mutex_init (L.L'Access, Attributes'Access);
281       pragma Assert (Result = 0 or else Result = ENOMEM);
282
283       if Result = ENOMEM then
284          raise Storage_Error;
285       end if;
286
287       Result := pthread_mutexattr_destroy (Attributes'Access);
288       pragma Assert (Result = 0);
289    end Initialize_Lock;
290
291    procedure Initialize_Lock (L : access RTS_Lock; Level : Lock_Level) is
292       Attributes : aliased pthread_mutexattr_t;
293       Result : Interfaces.C.int;
294
295    begin
296       Result := pthread_mutexattr_init (Attributes'Access);
297       pragma Assert (Result = 0 or else Result = ENOMEM);
298
299       if Result = ENOMEM then
300          raise Storage_Error;
301       end if;
302
303       Result := pthread_mutex_init (L, Attributes'Access);
304
305       pragma Assert (Result = 0 or else Result = ENOMEM);
306
307       if Result = ENOMEM then
308          raise Storage_Error;
309       end if;
310
311       Result := pthread_mutexattr_destroy (Attributes'Access);
312       pragma Assert (Result = 0);
313    end Initialize_Lock;
314
315    -------------------
316    -- Finalize_Lock --
317    -------------------
318
319    procedure Finalize_Lock (L : access Lock) is
320       Result : Interfaces.C.int;
321
322    begin
323       Result := pthread_mutex_destroy (L.L'Access);
324       pragma Assert (Result = 0);
325    end Finalize_Lock;
326
327    procedure Finalize_Lock (L : access RTS_Lock) is
328       Result : Interfaces.C.int;
329
330    begin
331       Result := pthread_mutex_destroy (L);
332       pragma Assert (Result = 0);
333    end Finalize_Lock;
334
335    ----------------
336    -- Write_Lock --
337    ----------------
338
339    procedure Write_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
340       Result    : Interfaces.C.int;
341
342    begin
343       L.Owner_Priority := Get_Priority (Self);
344
345       if L.Priority < L.Owner_Priority then
346          Ceiling_Violation := True;
347          return;
348       end if;
349
350       Result := pthread_mutex_lock (L.L'Access);
351       pragma Assert (Result = 0);
352       Ceiling_Violation := False;
353    end Write_Lock;
354
355    procedure Write_Lock (L : access RTS_Lock) is
356       Result : Interfaces.C.int;
357
358    begin
359       Result := pthread_mutex_lock (L);
360       pragma Assert (Result = 0);
361    end Write_Lock;
362
363    procedure Write_Lock (T : Task_ID) is
364       Result : Interfaces.C.int;
365
366    begin
367       Result := pthread_mutex_lock (T.Common.LL.L'Access);
368       pragma Assert (Result = 0);
369    end Write_Lock;
370
371    ---------------
372    -- Read_Lock --
373    ---------------
374
375    procedure Read_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
376    begin
377       Write_Lock (L, Ceiling_Violation);
378    end Read_Lock;
379
380    ------------
381    -- Unlock --
382    ------------
383
384    procedure Unlock (L : access Lock) is
385       Result    : Interfaces.C.int;
386
387    begin
388       Result := pthread_mutex_unlock (L.L'Access);
389       pragma Assert (Result = 0);
390    end Unlock;
391
392    procedure Unlock (L : access RTS_Lock) is
393       Result : Interfaces.C.int;
394
395    begin
396       Result := pthread_mutex_unlock (L);
397       pragma Assert (Result = 0);
398    end Unlock;
399
400    procedure Unlock (T : Task_ID) is
401       Result : Interfaces.C.int;
402
403    begin
404       Result := pthread_mutex_unlock (T.Common.LL.L'Access);
405       pragma Assert (Result = 0);
406    end Unlock;
407
408    -------------
409    --  Sleep  --
410    -------------
411
412    procedure Sleep (Self_ID : Task_ID;
413                     Reason   : System.Tasking.Task_States) is
414       Result : Interfaces.C.int;
415
416    begin
417       pragma Assert (Self_ID = Self);
418       Result := pthread_cond_wait (Self_ID.Common.LL.CV'Access,
419         Self_ID.Common.LL.L'Access);
420       --  EINTR is not considered a failure.
421       pragma Assert (Result = 0 or else Result = EINTR);
422    end Sleep;
423
424    -----------------
425    -- Timed_Sleep --
426    -----------------
427
428    --  This is for use within the run-time system, so abort is
429    --  assumed to be already deferred, and the caller should be
430    --  holding its own ATCB lock.
431
432    procedure Timed_Sleep
433      (Self_ID  : Task_ID;
434       Time     : Duration;
435       Mode     : ST.Delay_Modes;
436       Reason   : System.Tasking.Task_States;
437       Timedout : out Boolean;
438       Yielded  : out Boolean)
439    is
440       Check_Time : constant Duration := Monotonic_Clock;
441       Abs_Time   : Duration;
442       Request    : aliased timespec;
443       Result     : Interfaces.C.int;
444    begin
445       Timedout := True;
446       Yielded := False;
447
448       if Mode = Relative then
449          Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
450       else
451          Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
452       end if;
453
454       if Abs_Time > Check_Time then
455          Request := To_Timespec (Abs_Time);
456
457          loop
458             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
459               or else Self_ID.Pending_Priority_Change;
460
461             Result := pthread_cond_timedwait
462               (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access,
463                Request'Access);
464
465             exit when Abs_Time <= Monotonic_Clock;
466
467             if Result = 0 or Result = EINTR then
468                --  somebody may have called Wakeup for us
469                Timedout := False;
470                exit;
471             end if;
472
473             pragma Assert (Result = ETIMEDOUT);
474          end loop;
475       end if;
476    end Timed_Sleep;
477
478    -----------------
479    -- Timed_Delay --
480    -----------------
481
482    --  This is for use in implementing delay statements, so
483    --  we assume the caller is abort-deferred but is holding
484    --  no locks.
485
486    procedure Timed_Delay
487      (Self_ID  : Task_ID;
488       Time     : Duration;
489       Mode     : ST.Delay_Modes)
490    is
491       Check_Time : constant Duration := Monotonic_Clock;
492       Abs_Time   : Duration;
493       Request    : aliased timespec;
494       Result     : Interfaces.C.int;
495    begin
496
497       --  Only the little window between deferring abort and
498       --  locking Self_ID is the reason we need to
499       --  check for pending abort and priority change below! :(
500
501       SSL.Abort_Defer.all;
502       Write_Lock (Self_ID);
503
504       if Mode = Relative then
505          Abs_Time := Time + Check_Time;
506       else
507          Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
508       end if;
509
510       if Abs_Time > Check_Time then
511          Request := To_Timespec (Abs_Time);
512          Self_ID.Common.State := Delay_Sleep;
513
514          loop
515             if Self_ID.Pending_Priority_Change then
516                Self_ID.Pending_Priority_Change := False;
517                Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
518                Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
519             end if;
520
521             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
522
523             Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
524               Self_ID.Common.LL.L'Access, Request'Access);
525
526             exit when Abs_Time <= Monotonic_Clock;
527
528             pragma Assert (Result = 0 or else
529               Result = ETIMEDOUT or else
530               Result = EINTR);
531          end loop;
532
533          Self_ID.Common.State := Runnable;
534       end if;
535
536       Unlock (Self_ID);
537       Result := sched_yield;
538       SSL.Abort_Undefer.all;
539    end Timed_Delay;
540
541    ---------------------
542    -- Monotonic_Clock --
543    ---------------------
544
545    function Monotonic_Clock return Duration is
546       TS     : aliased timespec;
547       Result : Interfaces.C.int;
548
549    begin
550       Result := Clock_Gettime (CLOCK_REALTIME, TS'Unchecked_Access);
551       pragma Assert (Result = 0);
552       return To_Duration (TS);
553    end Monotonic_Clock;
554
555    -------------------
556    -- RT_Resolution --
557    -------------------
558
559    function RT_Resolution return Duration is
560    begin
561       return 10#1.0#E-6;
562    end RT_Resolution;
563
564    ------------
565    -- Wakeup --
566    ------------
567
568    procedure Wakeup (T : Task_ID; Reason : System.Tasking.Task_States) is
569       Result : Interfaces.C.int;
570
571    begin
572       Result := pthread_cond_signal (T.Common.LL.CV'Access);
573       pragma Assert (Result = 0);
574    end Wakeup;
575
576    -----------
577    -- Yield --
578    -----------
579
580    procedure Yield (Do_Yield : Boolean := True) is
581       Result : Interfaces.C.int;
582
583    begin
584       if Do_Yield then
585          Result := sched_yield;
586       end if;
587    end Yield;
588
589    ------------------
590    -- Set_Priority --
591    ------------------
592
593    type Prio_Array_Type is array (System.Any_Priority) of Integer;
594    pragma Atomic_Components (Prio_Array_Type);
595
596    Prio_Array : Prio_Array_Type;
597    --  Global array containing the id of the currently running task for
598    --  each priority.
599    --
600    --  Note: we assume that we are on a single processor with run-til-blocked
601    --  scheduling.
602
603    procedure Set_Priority
604      (T : Task_ID;
605       Prio : System.Any_Priority;
606       Loss_Of_Inheritance : Boolean := False)
607    is
608       Result     : Interfaces.C.int;
609       Array_Item : Integer;
610       Param      : aliased struct_sched_param;
611
612    begin
613       Param.sched_priority  := Interfaces.C.int (Underlying_Priorities (Prio));
614
615       if Time_Slice_Val > 0 then
616          Result := pthread_setschedparam
617            (T.Common.LL.Thread, SCHED_RR, Param'Access);
618
619       elsif FIFO_Within_Priorities or else Time_Slice_Val = 0 then
620          Result := pthread_setschedparam
621            (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
622
623       else
624          Result := pthread_setschedparam
625            (T.Common.LL.Thread, SCHED_OTHER, Param'Access);
626       end if;
627
628       pragma Assert (Result = 0);
629
630       if FIFO_Within_Priorities then
631
632          --  Annex D requirement [RM D.2.2 par. 9]:
633          --    If the task drops its priority due to the loss of inherited
634          --    priority, it is added at the head of the ready queue for its
635          --    new active priority.
636
637          if Loss_Of_Inheritance
638            and then Prio < T.Common.Current_Priority
639          then
640             Array_Item := Prio_Array (T.Common.Base_Priority) + 1;
641             Prio_Array (T.Common.Base_Priority) := Array_Item;
642
643             loop
644                --  Let some processes a chance to arrive
645
646                Yield;
647
648                --  Then wait for our turn to proceed
649
650                exit when Array_Item = Prio_Array (T.Common.Base_Priority)
651                  or else Prio_Array (T.Common.Base_Priority) = 1;
652             end loop;
653
654             Prio_Array (T.Common.Base_Priority) :=
655               Prio_Array (T.Common.Base_Priority) - 1;
656          end if;
657       end if;
658
659       T.Common.Current_Priority := Prio;
660    end Set_Priority;
661
662    ------------------
663    -- Get_Priority --
664    ------------------
665
666    function Get_Priority (T : Task_ID) return System.Any_Priority is
667    begin
668       return T.Common.Current_Priority;
669    end Get_Priority;
670
671    ----------------
672    -- Enter_Task --
673    ----------------
674
675    procedure Enter_Task (Self_ID : Task_ID) is
676       Result  : Interfaces.C.int;
677
678    begin
679       Self_ID.Common.LL.Thread := pthread_self;
680
681       Result := pthread_setspecific (ATCB_Key, To_Address (Self_ID));
682       pragma Assert (Result = 0);
683
684       Lock_All_Tasks_List;
685       for I in Known_Tasks'Range loop
686          if Known_Tasks (I) = null then
687             Known_Tasks (I) := Self_ID;
688             Self_ID.Known_Tasks_Index := I;
689             exit;
690          end if;
691       end loop;
692       Unlock_All_Tasks_List;
693    end Enter_Task;
694
695    --------------
696    -- New_ATCB --
697    --------------
698
699    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_ID is
700    begin
701       return new Ada_Task_Control_Block (Entry_Num);
702    end New_ATCB;
703
704    ----------------------
705    --  Initialize_TCB  --
706    ----------------------
707
708    procedure Initialize_TCB (Self_ID : Task_ID; Succeeded : out Boolean) is
709       Mutex_Attr : aliased pthread_mutexattr_t;
710       Result : Interfaces.C.int;
711       Cond_Attr : aliased pthread_condattr_t;
712
713    begin
714       Result := pthread_mutexattr_init (Mutex_Attr'Access);
715       pragma Assert (Result = 0 or else Result = ENOMEM);
716
717       if Result /= 0 then
718          Succeeded := False;
719          return;
720       end if;
721
722       Result := pthread_mutex_init (Self_ID.Common.LL.L'Access,
723         Mutex_Attr'Access);
724       pragma Assert (Result = 0 or else Result = ENOMEM);
725
726       if Result /= 0 then
727          Succeeded := False;
728          return;
729       end if;
730
731       Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
732       pragma Assert (Result = 0);
733
734       Result := pthread_condattr_init (Cond_Attr'Access);
735       pragma Assert (Result = 0 or else Result = ENOMEM);
736
737       if Result /= 0 then
738          Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
739          pragma Assert (Result = 0);
740          Succeeded := False;
741          return;
742       end if;
743
744       Result := pthread_cond_init (Self_ID.Common.LL.CV'Access,
745         Cond_Attr'Access);
746       pragma Assert (Result = 0 or else Result = ENOMEM);
747
748       if Result = 0 then
749          Succeeded := True;
750       else
751          Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
752          pragma Assert (Result = 0);
753          Succeeded := False;
754       end if;
755
756       Result := pthread_condattr_destroy (Cond_Attr'Access);
757       pragma Assert (Result = 0);
758    end Initialize_TCB;
759
760    -----------------
761    -- Create_Task --
762    -----------------
763
764    procedure Create_Task
765      (T          : Task_ID;
766       Wrapper    : System.Address;
767       Stack_Size : System.Parameters.Size_Type;
768       Priority   : System.Any_Priority;
769       Succeeded  : out Boolean)
770    is
771       Attributes          : aliased pthread_attr_t;
772       Adjusted_Stack_Size : Interfaces.C.size_t;
773       Result              : Interfaces.C.int;
774
775       function Thread_Body_Access is new
776         Unchecked_Conversion (System.Address, Thread_Body);
777
778    begin
779       if Stack_Size = Unspecified_Size then
780          Adjusted_Stack_Size := Interfaces.C.size_t (Default_Stack_Size);
781
782       elsif Stack_Size < Minimum_Stack_Size then
783          Adjusted_Stack_Size := Interfaces.C.size_t (Minimum_Stack_Size);
784
785       else
786          Adjusted_Stack_Size := Interfaces.C.size_t (Stack_Size);
787       end if;
788
789       Result := pthread_attr_init (Attributes'Access);
790       pragma Assert (Result = 0 or else Result = ENOMEM);
791
792       if Result /= 0 then
793          Succeeded := False;
794          return;
795       end if;
796
797       Result := pthread_attr_setstacksize
798         (Attributes'Access, Adjusted_Stack_Size);
799       pragma Assert (Result = 0);
800
801       --  Since the initial signal mask of a thread is inherited from the
802       --  creator, and the Environment task has all its signals masked, we
803       --  do not need to manipulate caller's signal mask at this point.
804       --  All tasks in RTS will have All_Tasks_Mask initially.
805
806       Result := pthread_create
807         (T.Common.LL.Thread'Access,
808          Attributes'Access,
809          Thread_Body_Access (Wrapper),
810          To_Address (T));
811       pragma Assert (Result = 0 or else Result = EAGAIN);
812
813       Succeeded := Result = 0;
814
815       pthread_detach (T.Common.LL.Thread'Access);
816       --  Detach the thread using pthread_detach, sinc DCE threads do not have
817       --  pthread_attr_set_detachstate.
818
819       Result := pthread_attr_destroy (Attributes'Access);
820       pragma Assert (Result = 0);
821
822       Set_Priority (T, Priority);
823    end Create_Task;
824
825    ------------------
826    -- Finalize_TCB --
827    ------------------
828
829    procedure Finalize_TCB (T : Task_ID) is
830       Result : Interfaces.C.int;
831       Tmp    : Task_ID := T;
832
833       procedure Free is new
834         Unchecked_Deallocation (Ada_Task_Control_Block, Task_ID);
835
836    begin
837       Result := pthread_mutex_destroy (T.Common.LL.L'Access);
838       pragma Assert (Result = 0);
839       Result := pthread_cond_destroy (T.Common.LL.CV'Access);
840       pragma Assert (Result = 0);
841
842       if T.Known_Tasks_Index /= -1 then
843          Known_Tasks (T.Known_Tasks_Index) := null;
844       end if;
845
846       Free (Tmp);
847    end Finalize_TCB;
848
849    ---------------
850    -- Exit_Task --
851    ---------------
852
853    procedure Exit_Task is
854    begin
855       pthread_exit (System.Null_Address);
856    end Exit_Task;
857
858    ----------------
859    -- Abort_Task --
860    ----------------
861
862    procedure Abort_Task (T : Task_ID) is
863    begin
864       --
865       --  Interrupt Server_Tasks may be waiting on an "event" flag (signal)
866       --
867       if T.Common.State = Interrupt_Server_Blocked_On_Event_Flag then
868          System.Interrupt_Management.Operations.Interrupt_Self_Process
869            (System.Interrupt_Management.Interrupt_ID
870              (PIO.Get_Interrupt_ID (T)));
871       end if;
872    end Abort_Task;
873
874    ----------------
875    -- Check_Exit --
876    ----------------
877
878    --  Dummy versions.  The only currently working versions is for solaris
879    --  (native).
880
881    function Check_Exit (Self_ID : ST.Task_ID) return Boolean is
882    begin
883       return True;
884    end Check_Exit;
885
886    --------------------
887    -- Check_No_Locks --
888    --------------------
889
890    function Check_No_Locks (Self_ID : ST.Task_ID) return Boolean is
891    begin
892       return True;
893    end Check_No_Locks;
894
895    ----------------------
896    -- Environment_Task --
897    ----------------------
898
899    function Environment_Task return Task_ID is
900    begin
901       return Environment_Task_ID;
902    end Environment_Task;
903
904    -------------------------
905    -- Lock_All_Tasks_List --
906    -------------------------
907
908    procedure Lock_All_Tasks_List is
909    begin
910       Write_Lock (All_Tasks_L'Access);
911    end Lock_All_Tasks_List;
912
913    ---------------------------
914    -- Unlock_All_Tasks_List --
915    ---------------------------
916
917    procedure Unlock_All_Tasks_List is
918    begin
919       Unlock (All_Tasks_L'Access);
920    end Unlock_All_Tasks_List;
921
922    ------------------
923    -- Suspend_Task --
924    ------------------
925
926    function Suspend_Task
927      (T           : ST.Task_ID;
928       Thread_Self : Thread_Id) return Boolean is
929    begin
930       return False;
931    end Suspend_Task;
932
933    -----------------
934    -- Resume_Task --
935    -----------------
936
937    function Resume_Task
938      (T           : ST.Task_ID;
939       Thread_Self : Thread_Id) return Boolean is
940    begin
941       return False;
942    end Resume_Task;
943
944    ----------------
945    -- Initialize --
946    ----------------
947
948    procedure Initialize (Environment_Task : Task_ID) is
949       act       : aliased struct_sigaction;
950       old_act   : aliased struct_sigaction;
951       Tmp_Set   : aliased sigset_t;
952       Result    : Interfaces.C.int;
953
954    begin
955
956       Environment_Task_ID := Environment_Task;
957
958       Initialize_Lock (All_Tasks_L'Access, All_Tasks_Level);
959       --  Initialize the lock used to synchronize chain of all ATCBs.
960
961       Enter_Task (Environment_Task);
962
963       --  Install the abort-signal handler
964
965       act.sa_flags := 0;
966       act.sa_handler := Abort_Handler'Address;
967
968       Result := sigemptyset (Tmp_Set'Access);
969       pragma Assert (Result = 0);
970       act.sa_mask := Tmp_Set;
971
972       Result :=
973         sigaction (
974           Signal (System.Interrupt_Management.Abort_Task_Interrupt),
975           act'Unchecked_Access,
976           old_act'Unchecked_Access);
977       pragma Assert (Result = 0);
978    end Initialize;
979
980    procedure do_nothing (arg : System.Address);
981
982    procedure do_nothing (arg : System.Address) is
983    begin
984       null;
985    end do_nothing;
986
987 begin
988
989    declare
990       Result : Interfaces.C.int;
991    begin
992       --  NOTE: Unlike other pthread implementations, we do *not* mask all
993       --  signals here since we handle signals using the process-wide primitive
994       --  signal, rather than using sigthreadmask and sigwait. The reason of
995       --  this difference is that sigwait doesn't work when some critical
996       --  signals (SIGABRT, SIGPIPE) are masked.
997
998       Result := pthread_key_create (ATCB_Key'Access, do_nothing'Access);
999       pragma Assert (Result = 0);
1000    end;
1001
1002 end System.Task_Primitives.Operations;