OSDN Git Service

* config/vax/vax.h (target_flags, MASK_UNIX_ASM, MASK_VAXC_ALIGNMENT)
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-taprop-vms.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 OpenVMS/Alpha version of this package
35
36 --  This package contains all the GNULL primitives that interface directly
37 --  with the underlying OS.
38
39 pragma Polling (Off);
40 --  Turn off polling, we do not want ATC polling to take place during
41 --  tasking operations. It causes infinite loops and other problems.
42
43 with System.Tasking.Debug;
44 --  used for Known_Tasks
45
46 with Interfaces.C;
47 --  used for int
48 --           size_t
49
50 with System.Parameters;
51 --  used for Size_Type
52
53 with System.Tasking;
54 --  used for Ada_Task_Control_Block
55 --           Task_Id
56
57 with System.Soft_Links;
58 --  used for Defer/Undefer_Abort
59 --           Set_Exc_Stack_Addr
60
61 --  Note that we do not use System.Tasking.Initialization directly since
62 --  this is a higher level package that we shouldn't depend on. For example
63 --  when using the restricted run time, it is replaced by
64 --  System.Tasking.Restricted.Stages.
65
66 with System.OS_Primitives;
67 --  used for Delay_Modes
68
69 with Unchecked_Conversion;
70 with Unchecked_Deallocation;
71
72 package body System.Task_Primitives.Operations is
73
74    use System.Tasking.Debug;
75    use System.Tasking;
76    use Interfaces.C;
77    use System.OS_Interface;
78    use System.Parameters;
79    use System.OS_Primitives;
80    use type System.OS_Primitives.OS_Time;
81
82    package SSL renames System.Soft_Links;
83
84    ----------------
85    -- Local Data --
86    ----------------
87
88    --  The followings are logically constants, but need to be initialized
89    --  at run time.
90
91    Single_RTS_Lock : aliased RTS_Lock;
92    --  This is a lock to allow only one thread of control in the RTS at
93    --  a time; it is used to execute in mutual exclusion from all other tasks.
94    --  Used mainly in Single_Lock mode, but also to protect All_Tasks_List
95
96    ATCB_Key : aliased pthread_key_t;
97    --  Key used to find the Ada Task_Id associated with a thread
98
99    Environment_Task_Id : Task_Id;
100    --  A variable to hold Task_Id for the environment task.
101
102    Time_Slice_Val : Integer;
103    pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
104
105    Dispatching_Policy : Character;
106    pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
107
108    FIFO_Within_Priorities : constant Boolean := Dispatching_Policy = 'F';
109    --  Indicates whether FIFO_Within_Priorities is set.
110
111    Foreign_Task_Elaborated : aliased Boolean := True;
112    --  Used to identified fake tasks (i.e., non-Ada Threads).
113
114    --------------------
115    -- Local Packages --
116    --------------------
117
118    package Specific is
119
120       procedure Initialize (Environment_Task : Task_Id);
121       pragma Inline (Initialize);
122       --  Initialize various data needed by this package.
123
124       function Is_Valid_Task return Boolean;
125       pragma Inline (Is_Valid_Task);
126       --  Does executing thread have a TCB?
127
128       procedure Set (Self_Id : Task_Id);
129       pragma Inline (Set);
130       --  Set the self id for the current task
131
132       function Self return Task_Id;
133       pragma Inline (Self);
134       --  Return a pointer to the Ada Task Control Block of the calling task
135
136    end Specific;
137
138    package body Specific is separate;
139    --  The body of this package is target specific.
140
141    ---------------------------------
142    -- Support for foreign threads --
143    ---------------------------------
144
145    function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
146    --  Allocate and Initialize a new ATCB for the current Thread
147
148    function Register_Foreign_Thread
149      (Thread : Thread_Id) return Task_Id is separate;
150
151    -----------------------
152    -- Local Subprograms --
153    -----------------------
154
155    function To_Task_Id is new Unchecked_Conversion (System.Address, Task_Id);
156
157    function To_Address is new Unchecked_Conversion (Task_Id, System.Address);
158
159    procedure Timer_Sleep_AST (ID : Address);
160    --  Signal the condition variable when AST fires.
161
162    procedure Timer_Sleep_AST (ID : Address) is
163       Result  : Interfaces.C.int;
164       Self_ID : constant Task_Id := To_Task_Id (ID);
165    begin
166       Self_ID.Common.LL.AST_Pending := False;
167       Result := pthread_cond_signal_int_np (Self_ID.Common.LL.CV'Access);
168       pragma Assert (Result = 0);
169    end Timer_Sleep_AST;
170
171    -----------------
172    -- Stack_Guard --
173    -----------------
174
175    --  The underlying thread system sets a guard page at the
176    --  bottom of a thread stack, so nothing is needed.
177    --  ??? Check the comment above
178
179    procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is
180       pragma Unreferenced (T);
181       pragma Unreferenced (On);
182    begin
183       null;
184    end Stack_Guard;
185
186    --------------------
187    -- Get_Thread_Id  --
188    --------------------
189
190    function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is
191    begin
192       return T.Common.LL.Thread;
193    end Get_Thread_Id;
194
195    ----------
196    -- Self --
197    ----------
198
199    function Self return Task_Id renames Specific.Self;
200
201    ---------------------
202    -- Initialize_Lock --
203    ---------------------
204
205    --  Note: mutexes and cond_variables needed per-task basis are
206    --  initialized in Initialize_TCB and the Storage_Error is
207    --  handled. Other mutexes (such as RTS_Lock, Memory_Lock...)
208    --  used in RTS is initialized before any status change of RTS.
209    --  Therefore rasing Storage_Error in the following routines
210    --  should be able to be handled safely.
211
212    procedure Initialize_Lock (Prio : System.Any_Priority; L : access Lock) is
213       Attributes : aliased pthread_mutexattr_t;
214       Result     : Interfaces.C.int;
215
216    begin
217       Result := pthread_mutexattr_init (Attributes'Access);
218       pragma Assert (Result = 0 or else Result = ENOMEM);
219
220       if Result = ENOMEM then
221          raise Storage_Error;
222       end if;
223
224       L.Prio_Save := 0;
225       L.Prio := Interfaces.C.int (Prio);
226
227       Result := pthread_mutex_init (L.L'Access, Attributes'Access);
228       pragma Assert (Result = 0 or else Result = ENOMEM);
229
230       if Result = ENOMEM then
231          raise Storage_Error;
232       end if;
233
234       Result := pthread_mutexattr_destroy (Attributes'Access);
235       pragma Assert (Result = 0);
236    end Initialize_Lock;
237
238    procedure Initialize_Lock (L : access RTS_Lock; Level : Lock_Level) is
239       pragma Unreferenced (Level);
240
241       Attributes : aliased pthread_mutexattr_t;
242       Result : Interfaces.C.int;
243
244    begin
245       Result := pthread_mutexattr_init (Attributes'Access);
246       pragma Assert (Result = 0 or else Result = ENOMEM);
247
248       if Result = ENOMEM then
249          raise Storage_Error;
250       end if;
251
252 --      Don't use, see comment in s-osinte.ads about ERRORCHECK mutexes???
253 --      Result := pthread_mutexattr_settype_np
254 --        (Attributes'Access, PTHREAD_MUTEX_ERRORCHECK_NP);
255 --      pragma Assert (Result = 0);
256
257 --      Result := pthread_mutexattr_setprotocol
258 --        (Attributes'Access, PTHREAD_PRIO_PROTECT);
259 --      pragma Assert (Result = 0);
260
261 --      Result := pthread_mutexattr_setprioceiling
262 --         (Attributes'Access, Interfaces.C.int (System.Any_Priority'Last));
263 --      pragma Assert (Result = 0);
264
265       Result := pthread_mutex_init (L, Attributes'Access);
266
267       pragma Assert (Result = 0 or else Result = ENOMEM);
268
269       if Result = ENOMEM then
270          raise Storage_Error;
271       end if;
272
273       Result := pthread_mutexattr_destroy (Attributes'Access);
274       pragma Assert (Result = 0);
275    end Initialize_Lock;
276
277    -------------------
278    -- Finalize_Lock --
279    -------------------
280
281    procedure Finalize_Lock (L : access Lock) is
282       Result : Interfaces.C.int;
283    begin
284       Result := pthread_mutex_destroy (L.L'Access);
285       pragma Assert (Result = 0);
286    end Finalize_Lock;
287
288    procedure Finalize_Lock (L : access RTS_Lock) is
289       Result : Interfaces.C.int;
290    begin
291       Result := pthread_mutex_destroy (L);
292       pragma Assert (Result = 0);
293    end Finalize_Lock;
294
295    ----------------
296    -- Write_Lock --
297    ----------------
298
299    procedure Write_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
300       Self_ID        : constant Task_Id := Self;
301       All_Tasks_Link : constant Task_Id := Self.Common.All_Tasks_Link;
302       Current_Prio   : System.Any_Priority;
303       Result         : Interfaces.C.int;
304
305    begin
306       Current_Prio := Get_Priority (Self_ID);
307
308       --  If there is no other tasks, no need to check priorities
309
310       if All_Tasks_Link /= Null_Task
311         and then L.Prio < Interfaces.C.int (Current_Prio)
312       then
313          Ceiling_Violation := True;
314          return;
315       end if;
316
317       Result := pthread_mutex_lock (L.L'Access);
318       pragma Assert (Result = 0);
319
320       Ceiling_Violation := False;
321 --  Why is this commented out ???
322 --      L.Prio_Save := Interfaces.C.int (Current_Prio);
323 --      Set_Priority (Self_ID, System.Any_Priority (L.Prio));
324    end Write_Lock;
325
326    procedure Write_Lock
327      (L           : access RTS_Lock;
328       Global_Lock : Boolean := False)
329    is
330       Result : Interfaces.C.int;
331    begin
332       if not Single_Lock or else Global_Lock then
333          Result := pthread_mutex_lock (L);
334          pragma Assert (Result = 0);
335       end if;
336    end Write_Lock;
337
338    procedure Write_Lock (T : Task_Id) is
339       Result : Interfaces.C.int;
340    begin
341       if not Single_Lock then
342          Result := pthread_mutex_lock (T.Common.LL.L'Access);
343          pragma Assert (Result = 0);
344       end if;
345    end Write_Lock;
346
347    ---------------
348    -- Read_Lock --
349    ---------------
350
351    procedure Read_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
352    begin
353       Write_Lock (L, Ceiling_Violation);
354    end Read_Lock;
355
356    ------------
357    -- Unlock --
358    ------------
359
360    procedure Unlock (L : access Lock) is
361       Result : Interfaces.C.int;
362    begin
363       Result := pthread_mutex_unlock (L.L'Access);
364       pragma Assert (Result = 0);
365    end Unlock;
366
367    procedure Unlock (L : access RTS_Lock; Global_Lock : Boolean := False) is
368       Result : Interfaces.C.int;
369    begin
370       if not Single_Lock or else Global_Lock then
371          Result := pthread_mutex_unlock (L);
372          pragma Assert (Result = 0);
373       end if;
374    end Unlock;
375
376    procedure Unlock (T : Task_Id) is
377       Result : Interfaces.C.int;
378    begin
379       if not Single_Lock then
380          Result := pthread_mutex_unlock (T.Common.LL.L'Access);
381          pragma Assert (Result = 0);
382       end if;
383    end Unlock;
384
385    -----------
386    -- Sleep --
387    -----------
388
389    procedure Sleep
390      (Self_ID : Task_Id;
391       Reason  : System.Tasking.Task_States)
392    is
393       pragma Unreferenced (Reason);
394       Result : Interfaces.C.int;
395
396    begin
397       if Single_Lock then
398          Result := pthread_cond_wait
399            (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access);
400       else
401          Result := pthread_cond_wait
402            (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
403       end if;
404
405       --  EINTR is not considered a failure
406
407       pragma Assert (Result = 0 or else Result = EINTR);
408
409       if Self_ID.Deferral_Level = 0
410         and then Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
411       then
412          Unlock (Self_ID);
413          raise Standard'Abort_Signal;
414       end if;
415    end Sleep;
416
417    -----------------
418    -- Timed_Sleep --
419    -----------------
420
421    procedure Timed_Sleep
422      (Self_ID  : Task_Id;
423       Time     : Duration;
424       Mode     : ST.Delay_Modes;
425       Reason   : System.Tasking.Task_States;
426       Timedout : out Boolean;
427       Yielded  : out Boolean)
428    is
429       pragma Unreferenced (Reason);
430
431       Sleep_Time : OS_Time;
432       Result     : Interfaces.C.int;
433       Status     : Cond_Value_Type;
434
435       --  The body below requires more comments ???
436
437    begin
438       Timedout := False;
439       Yielded := False;
440
441       Sleep_Time := To_OS_Time (Time, Mode);
442
443       if Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
444         or else Self_ID.Pending_Priority_Change
445       then
446          return;
447       end if;
448
449       Self_ID.Common.LL.AST_Pending := True;
450
451       Sys_Setimr
452        (Status, 0, Sleep_Time,
453         Timer_Sleep_AST'Access, To_Address (Self_ID), 0);
454
455       if (Status and 1) /= 1 then
456          raise Storage_Error;
457       end if;
458
459       if Single_Lock then
460          Result := pthread_cond_wait
461            (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access);
462          pragma Assert (Result = 0);
463
464       else
465          Result := pthread_cond_wait
466            (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
467          pragma Assert (Result = 0);
468       end if;
469
470       Yielded := True;
471
472       if not Self_ID.Common.LL.AST_Pending then
473          Timedout := True;
474       else
475          Sys_Cantim (Status, To_Address (Self_ID), 0);
476          pragma Assert ((Status and 1) = 1);
477       end if;
478    end Timed_Sleep;
479
480    -----------------
481    -- Timed_Delay --
482    -----------------
483
484    procedure Timed_Delay
485      (Self_ID : Task_Id;
486       Time    : Duration;
487       Mode    : ST.Delay_Modes)
488    is
489       Sleep_Time : OS_Time;
490       Result     : Interfaces.C.int;
491       Status     : Cond_Value_Type;
492       Yielded    : Boolean := False;
493
494    begin
495       --  Only the little window between deferring abort and
496       --  locking Self_ID is the reason we need to
497       --  check for pending abort and priority change below!
498
499       if Single_Lock then
500          Lock_RTS;
501       end if;
502
503       --  More comments required in body below ???
504
505       SSL.Abort_Defer.all;
506       Write_Lock (Self_ID);
507
508       if Time /= 0.0 or else Mode /= Relative then
509          Sleep_Time := To_OS_Time (Time, Mode);
510
511          if Mode = Relative or else OS_Clock < Sleep_Time then
512             Self_ID.Common.State := Delay_Sleep;
513             Self_ID.Common.LL.AST_Pending := True;
514
515             Sys_Setimr
516              (Status, 0, Sleep_Time,
517               Timer_Sleep_AST'Access, To_Address (Self_ID), 0);
518
519             if (Status and 1) /= 1 then
520                raise Storage_Error;
521             end if;
522
523             loop
524                if Self_ID.Pending_Priority_Change then
525                   Self_ID.Pending_Priority_Change := False;
526                   Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
527                   Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
528                end if;
529
530                if Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level then
531                   Sys_Cantim (Status, To_Address (Self_ID), 0);
532                   pragma Assert ((Status and 1) = 1);
533                   exit;
534                end if;
535
536                if Single_Lock then
537                   Result := pthread_cond_wait
538                     (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access);
539                   pragma Assert (Result = 0);
540                else
541                   Result := pthread_cond_wait
542                     (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
543                   pragma Assert (Result = 0);
544                end if;
545
546                Yielded := True;
547
548                exit when not Self_ID.Common.LL.AST_Pending;
549             end loop;
550
551             Self_ID.Common.State := Runnable;
552          end if;
553       end if;
554
555       Unlock (Self_ID);
556
557       if Single_Lock then
558          Unlock_RTS;
559       end if;
560
561       if not Yielded then
562          Result := sched_yield;
563          pragma Assert (Result = 0);
564       end if;
565
566       SSL.Abort_Undefer.all;
567    end Timed_Delay;
568
569    ---------------------
570    -- Monotonic_Clock --
571    ---------------------
572
573    function Monotonic_Clock return Duration
574      renames System.OS_Primitives.Monotonic_Clock;
575
576    -------------------
577    -- RT_Resolution --
578    -------------------
579
580    function RT_Resolution return Duration is
581    begin
582       return 10#1.0#E-3;
583    end RT_Resolution;
584
585    ------------
586    -- Wakeup --
587    ------------
588
589    procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
590       pragma Unreferenced (Reason);
591       Result : Interfaces.C.int;
592    begin
593       Result := pthread_cond_signal (T.Common.LL.CV'Access);
594       pragma Assert (Result = 0);
595    end Wakeup;
596
597    -----------
598    -- Yield --
599    -----------
600
601    procedure Yield (Do_Yield : Boolean := True) is
602       Result : Interfaces.C.int;
603       pragma Unreferenced (Result);
604    begin
605       if Do_Yield then
606          Result := sched_yield;
607       end if;
608    end Yield;
609
610    ------------------
611    -- Set_Priority --
612    ------------------
613
614    procedure Set_Priority
615      (T                   : Task_Id;
616       Prio                : System.Any_Priority;
617       Loss_Of_Inheritance : Boolean := False)
618    is
619       pragma Unreferenced (Loss_Of_Inheritance);
620
621       Result : Interfaces.C.int;
622       Param  : aliased struct_sched_param;
623
624    begin
625       T.Common.Current_Priority := Prio;
626       Param.sched_priority := Interfaces.C.int (Underlying_Priorities (Prio));
627
628       if Time_Slice_Val > 0 then
629          Result := pthread_setschedparam
630            (T.Common.LL.Thread, SCHED_RR, Param'Access);
631
632       elsif FIFO_Within_Priorities or else Time_Slice_Val = 0 then
633          Result := pthread_setschedparam
634            (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
635
636       else
637          --  SCHED_OTHER priorities are restricted to the range 8 - 15.
638          --  Since the translation from Underlying priorities results
639          --  in a range of 16 - 31, dividing by 2 gives the correct result.
640
641          Param.sched_priority := Param.sched_priority / 2;
642          Result := pthread_setschedparam
643            (T.Common.LL.Thread, SCHED_OTHER, Param'Access);
644       end if;
645
646       pragma Assert (Result = 0);
647    end Set_Priority;
648
649    ------------------
650    -- Get_Priority --
651    ------------------
652
653    function Get_Priority (T : Task_Id) return System.Any_Priority is
654    begin
655       return T.Common.Current_Priority;
656    end Get_Priority;
657
658    ----------------
659    -- Enter_Task --
660    ----------------
661
662    procedure Enter_Task (Self_ID : Task_Id) is
663    begin
664       Self_ID.Common.LL.Thread := pthread_self;
665
666       Specific.Set (Self_ID);
667
668       Lock_RTS;
669
670       for J in Known_Tasks'Range loop
671          if Known_Tasks (J) = null then
672             Known_Tasks (J) := Self_ID;
673             Self_ID.Known_Tasks_Index := J;
674             exit;
675          end if;
676       end loop;
677
678       Unlock_RTS;
679    end Enter_Task;
680
681    --------------
682    -- New_ATCB --
683    --------------
684
685    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
686    begin
687       return new Ada_Task_Control_Block (Entry_Num);
688    end New_ATCB;
689
690    -------------------
691    -- Is_Valid_Task --
692    -------------------
693
694    function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
695
696    -----------------------------
697    -- Register_Foreign_Thread --
698    -----------------------------
699
700    function Register_Foreign_Thread return Task_Id is
701    begin
702       if Is_Valid_Task then
703          return Self;
704       else
705          return Register_Foreign_Thread (pthread_self);
706       end if;
707    end Register_Foreign_Thread;
708
709    --------------------
710    -- Initialize_TCB --
711    --------------------
712
713    procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
714       Mutex_Attr : aliased pthread_mutexattr_t;
715       Result     : Interfaces.C.int;
716       Cond_Attr  : aliased pthread_condattr_t;
717
718    begin
719       --  More comments required in body below ???
720
721       if not Single_Lock then
722          Result := pthread_mutexattr_init (Mutex_Attr'Access);
723          pragma Assert (Result = 0 or else Result = ENOMEM);
724
725          if Result = 0 then
726             Result := pthread_mutex_init (Self_ID.Common.LL.L'Access,
727               Mutex_Attr'Access);
728             pragma Assert (Result = 0 or else Result = ENOMEM);
729          end if;
730
731          if Result /= 0 then
732             Succeeded := False;
733             return;
734          end if;
735
736          Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
737          pragma Assert (Result = 0);
738       end if;
739
740       Result := pthread_condattr_init (Cond_Attr'Access);
741       pragma Assert (Result = 0 or else Result = ENOMEM);
742
743       if Result = 0 then
744          Result := pthread_cond_init (Self_ID.Common.LL.CV'Access,
745            Cond_Attr'Access);
746          pragma Assert (Result = 0 or else Result = ENOMEM);
747       end if;
748
749       if Result = 0 then
750          Succeeded := True;
751          Self_ID.Common.LL.Exc_Stack_Ptr := new Exc_Stack_T;
752          SSL.Set_Exc_Stack_Addr
753            (To_Address (Self_ID),
754             Self_ID.Common.LL.Exc_Stack_Ptr (Exc_Stack_T'Last)'Address);
755
756       else
757          if not Single_Lock then
758             Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
759             pragma Assert (Result = 0);
760          end if;
761
762          Succeeded := False;
763       end if;
764
765       Result := pthread_condattr_destroy (Cond_Attr'Access);
766       pragma Assert (Result = 0);
767    end Initialize_TCB;
768
769    -----------------
770    -- Create_Task --
771    -----------------
772
773    procedure Create_Task
774      (T          : Task_Id;
775       Wrapper    : System.Address;
776       Stack_Size : System.Parameters.Size_Type;
777       Priority   : System.Any_Priority;
778       Succeeded  : out Boolean)
779    is
780       Attributes          : aliased pthread_attr_t;
781       Adjusted_Stack_Size : Interfaces.C.size_t;
782       Result              : Interfaces.C.int;
783
784       function Thread_Body_Access is new
785         Unchecked_Conversion (System.Address, Thread_Body);
786
787    begin
788       if Stack_Size = Unspecified_Size then
789          Adjusted_Stack_Size := Interfaces.C.size_t (Default_Stack_Size);
790
791       elsif Stack_Size < Minimum_Stack_Size then
792          Adjusted_Stack_Size := Interfaces.C.size_t (Minimum_Stack_Size);
793
794       else
795          Adjusted_Stack_Size := Interfaces.C.size_t (Stack_Size);
796       end if;
797
798       --  Since the initial signal mask of a thread is inherited from the
799       --  creator, we need to set our local signal mask mask all signals
800       --  during the creation operation, to make sure the new thread is
801       --  not disturbed by signals before it has set its own Task_Id.
802
803       Result := pthread_attr_init (Attributes'Access);
804       pragma Assert (Result = 0 or else Result = ENOMEM);
805
806       if Result /= 0 then
807          Succeeded := False;
808          return;
809       end if;
810
811       Result := pthread_attr_setdetachstate
812         (Attributes'Access, PTHREAD_CREATE_DETACHED);
813       pragma Assert (Result = 0);
814
815       Result := pthread_attr_setstacksize
816         (Attributes'Access, Adjusted_Stack_Size);
817       pragma Assert (Result = 0);
818
819       --  This call may be unnecessary, not sure. ???
820
821       Result :=
822         pthread_attr_setinheritsched
823           (Attributes'Access, PTHREAD_EXPLICIT_SCHED);
824       pragma Assert (Result = 0);
825
826       Result := pthread_create
827         (T.Common.LL.Thread'Access,
828          Attributes'Access,
829          Thread_Body_Access (Wrapper),
830          To_Address (T));
831
832       --  ENOMEM is a valid run-time error.  Don't shut down.
833
834       pragma Assert (Result = 0
835         or else Result = EAGAIN or else Result = ENOMEM);
836
837       Succeeded := Result = 0;
838
839       Result := pthread_attr_destroy (Attributes'Access);
840       pragma Assert (Result = 0);
841
842       if Succeeded then
843          Set_Priority (T, Priority);
844       end if;
845    end Create_Task;
846
847    ------------------
848    -- Finalize_TCB --
849    ------------------
850
851    procedure Finalize_TCB (T : Task_Id) is
852       Result  : Interfaces.C.int;
853       Tmp     : Task_Id := T;
854       Is_Self : constant Boolean := T = Self;
855
856       procedure Free is new
857         Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
858
859       procedure Free is new Unchecked_Deallocation
860        (Exc_Stack_T, Exc_Stack_Ptr_T);
861
862    begin
863       if not Single_Lock then
864          Result := pthread_mutex_destroy (T.Common.LL.L'Access);
865          pragma Assert (Result = 0);
866       end if;
867
868       Result := pthread_cond_destroy (T.Common.LL.CV'Access);
869       pragma Assert (Result = 0);
870
871       if T.Known_Tasks_Index /= -1 then
872          Known_Tasks (T.Known_Tasks_Index) := null;
873       end if;
874
875       Free (T.Common.LL.Exc_Stack_Ptr);
876
877       Free (Tmp);
878
879       if Is_Self then
880          Specific.Set (null);
881       end if;
882    end Finalize_TCB;
883
884    ---------------
885    -- Exit_Task --
886    ---------------
887
888    procedure Exit_Task is
889    begin
890       Specific.Set (null);
891    end Exit_Task;
892
893    ----------------
894    -- Abort_Task --
895    ----------------
896
897    procedure Abort_Task (T : Task_Id) is
898    begin
899       --  Interrupt Server_Tasks may be waiting on an event flag
900
901       if T.Common.State = Interrupt_Server_Blocked_On_Event_Flag then
902          Wakeup (T, Interrupt_Server_Blocked_On_Event_Flag);
903       end if;
904    end Abort_Task;
905
906    ----------------
907    -- Check_Exit --
908    ----------------
909
910    --  Dummy version
911
912    function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
913       pragma Unreferenced (Self_ID);
914    begin
915       return True;
916    end Check_Exit;
917
918    --------------------
919    -- Check_No_Locks --
920    --------------------
921
922    function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
923       pragma Unreferenced (Self_ID);
924    begin
925       return True;
926    end Check_No_Locks;
927
928    ----------------------
929    -- Environment_Task --
930    ----------------------
931
932    function Environment_Task return Task_Id is
933    begin
934       return Environment_Task_Id;
935    end Environment_Task;
936
937    --------------
938    -- Lock_RTS --
939    --------------
940
941    procedure Lock_RTS is
942    begin
943       Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
944    end Lock_RTS;
945
946    ----------------
947    -- Unlock_RTS --
948    ----------------
949
950    procedure Unlock_RTS is
951    begin
952       Unlock (Single_RTS_Lock'Access, Global_Lock => True);
953    end Unlock_RTS;
954
955    ------------------
956    -- Suspend_Task --
957    ------------------
958
959    function Suspend_Task
960      (T           : ST.Task_Id;
961       Thread_Self : Thread_Id) return Boolean
962    is
963       pragma Unreferenced (T);
964       pragma Unreferenced (Thread_Self);
965    begin
966       return False;
967    end Suspend_Task;
968
969    -----------------
970    -- Resume_Task --
971    -----------------
972
973    function Resume_Task
974      (T           : ST.Task_Id;
975       Thread_Self : Thread_Id) return Boolean
976    is
977       pragma Unreferenced (T);
978       pragma Unreferenced (Thread_Self);
979    begin
980       return False;
981    end Resume_Task;
982
983    ----------------
984    -- Initialize --
985    ----------------
986
987    procedure Initialize (Environment_Task : Task_Id) is
988    begin
989       Environment_Task_Id := Environment_Task;
990
991       --  Initialize the lock used to synchronize chain of all ATCBs
992
993       Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
994
995       Specific.Initialize (Environment_Task);
996
997       Enter_Task (Environment_Task);
998    end Initialize;
999
1000 end System.Task_Primitives.Operations;