OSDN Git Service

2004-05-17 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
[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.Initialization
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
592       Result : Interfaces.C.int;
593
594    begin
595       Result := pthread_cond_signal (T.Common.LL.CV'Access);
596       pragma Assert (Result = 0);
597    end Wakeup;
598
599    -----------
600    -- Yield --
601    -----------
602
603    procedure Yield (Do_Yield : Boolean := True) is
604       Result : Interfaces.C.int;
605       pragma Unreferenced (Result);
606    begin
607       if Do_Yield then
608          Result := sched_yield;
609       end if;
610    end Yield;
611
612    ------------------
613    -- Set_Priority --
614    ------------------
615
616    procedure Set_Priority
617      (T                   : Task_Id;
618       Prio                : System.Any_Priority;
619       Loss_Of_Inheritance : Boolean := False)
620    is
621       pragma Unreferenced (Loss_Of_Inheritance);
622
623       Result : Interfaces.C.int;
624       Param  : aliased struct_sched_param;
625
626    begin
627       T.Common.Current_Priority := Prio;
628       Param.sched_priority := Interfaces.C.int (Underlying_Priorities (Prio));
629
630       if Time_Slice_Val > 0 then
631          Result := pthread_setschedparam
632            (T.Common.LL.Thread, SCHED_RR, Param'Access);
633
634       elsif FIFO_Within_Priorities or else Time_Slice_Val = 0 then
635          Result := pthread_setschedparam
636            (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
637
638       else
639          --  SCHED_OTHER priorities are restricted to the range 8 - 15.
640          --  Since the translation from Underlying priorities results
641          --  in a range of 16 - 31, dividing by 2 gives the correct result.
642
643          Param.sched_priority := Param.sched_priority / 2;
644          Result := pthread_setschedparam
645            (T.Common.LL.Thread, SCHED_OTHER, Param'Access);
646       end if;
647
648       pragma Assert (Result = 0);
649    end Set_Priority;
650
651    ------------------
652    -- Get_Priority --
653    ------------------
654
655    function Get_Priority (T : Task_Id) return System.Any_Priority is
656    begin
657       return T.Common.Current_Priority;
658    end Get_Priority;
659
660    ----------------
661    -- Enter_Task --
662    ----------------
663
664    procedure Enter_Task (Self_ID : Task_Id) is
665    begin
666       Self_ID.Common.LL.Thread := pthread_self;
667
668       Specific.Set (Self_ID);
669
670       Lock_RTS;
671
672       for J in Known_Tasks'Range loop
673          if Known_Tasks (J) = null then
674             Known_Tasks (J) := Self_ID;
675             Self_ID.Known_Tasks_Index := J;
676             exit;
677          end if;
678       end loop;
679
680       Unlock_RTS;
681    end Enter_Task;
682
683    --------------
684    -- New_ATCB --
685    --------------
686
687    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
688    begin
689       return new Ada_Task_Control_Block (Entry_Num);
690    end New_ATCB;
691
692    -------------------
693    -- Is_Valid_Task --
694    -------------------
695
696    function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
697
698    -----------------------------
699    -- Register_Foreign_Thread --
700    -----------------------------
701
702    function Register_Foreign_Thread return Task_Id is
703    begin
704       if Is_Valid_Task then
705          return Self;
706       else
707          return Register_Foreign_Thread (pthread_self);
708       end if;
709    end Register_Foreign_Thread;
710
711    ----------------------
712    --  Initialize_TCB  --
713    ----------------------
714
715    procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
716       Mutex_Attr : aliased pthread_mutexattr_t;
717       Result     : Interfaces.C.int;
718       Cond_Attr  : aliased pthread_condattr_t;
719
720    begin
721       --  More comments required in body below ???
722
723       if not Single_Lock then
724          Result := pthread_mutexattr_init (Mutex_Attr'Access);
725          pragma Assert (Result = 0 or else Result = ENOMEM);
726
727          if Result = 0 then
728             Result := pthread_mutex_init (Self_ID.Common.LL.L'Access,
729               Mutex_Attr'Access);
730             pragma Assert (Result = 0 or else Result = ENOMEM);
731          end if;
732
733          if Result /= 0 then
734             Succeeded := False;
735             return;
736          end if;
737
738          Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
739          pragma Assert (Result = 0);
740       end if;
741
742       Result := pthread_condattr_init (Cond_Attr'Access);
743       pragma Assert (Result = 0 or else Result = ENOMEM);
744
745       if Result = 0 then
746          Result := pthread_cond_init (Self_ID.Common.LL.CV'Access,
747            Cond_Attr'Access);
748          pragma Assert (Result = 0 or else Result = ENOMEM);
749       end if;
750
751       if Result = 0 then
752          Succeeded := True;
753          Self_ID.Common.LL.Exc_Stack_Ptr := new Exc_Stack_T;
754          SSL.Set_Exc_Stack_Addr
755            (To_Address (Self_ID),
756             Self_ID.Common.LL.Exc_Stack_Ptr (Exc_Stack_T'Last)'Address);
757
758       else
759          if not Single_Lock then
760             Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
761             pragma Assert (Result = 0);
762          end if;
763
764          Succeeded := False;
765       end if;
766
767       Result := pthread_condattr_destroy (Cond_Attr'Access);
768       pragma Assert (Result = 0);
769    end Initialize_TCB;
770
771    -----------------
772    -- Create_Task --
773    -----------------
774
775    procedure Create_Task
776      (T          : Task_Id;
777       Wrapper    : System.Address;
778       Stack_Size : System.Parameters.Size_Type;
779       Priority   : System.Any_Priority;
780       Succeeded  : out Boolean)
781    is
782       Attributes          : aliased pthread_attr_t;
783       Adjusted_Stack_Size : Interfaces.C.size_t;
784       Result              : Interfaces.C.int;
785
786       function Thread_Body_Access is new
787         Unchecked_Conversion (System.Address, Thread_Body);
788
789    begin
790       if Stack_Size = Unspecified_Size then
791          Adjusted_Stack_Size := Interfaces.C.size_t (Default_Stack_Size);
792
793       elsif Stack_Size < Minimum_Stack_Size then
794          Adjusted_Stack_Size := Interfaces.C.size_t (Minimum_Stack_Size);
795
796       else
797          Adjusted_Stack_Size := Interfaces.C.size_t (Stack_Size);
798       end if;
799
800       --  Since the initial signal mask of a thread is inherited from the
801       --  creator, we need to set our local signal mask mask all signals
802       --  during the creation operation, to make sure the new thread is
803       --  not disturbed by signals before it has set its own Task_Id.
804
805       Result := pthread_attr_init (Attributes'Access);
806       pragma Assert (Result = 0 or else Result = ENOMEM);
807
808       if Result /= 0 then
809          Succeeded := False;
810          return;
811       end if;
812
813       Result := pthread_attr_setdetachstate
814         (Attributes'Access, PTHREAD_CREATE_DETACHED);
815       pragma Assert (Result = 0);
816
817       Result := pthread_attr_setstacksize
818         (Attributes'Access, Adjusted_Stack_Size);
819       pragma Assert (Result = 0);
820
821       --  This call may be unnecessary, not sure. ???
822
823       Result :=
824         pthread_attr_setinheritsched
825           (Attributes'Access, PTHREAD_EXPLICIT_SCHED);
826       pragma Assert (Result = 0);
827
828       Result := pthread_create
829         (T.Common.LL.Thread'Access,
830          Attributes'Access,
831          Thread_Body_Access (Wrapper),
832          To_Address (T));
833
834       --  ENOMEM is a valid run-time error.  Don't shut down.
835
836       pragma Assert (Result = 0
837         or else Result = EAGAIN or else Result = ENOMEM);
838
839       Succeeded := Result = 0;
840
841       Result := pthread_attr_destroy (Attributes'Access);
842       pragma Assert (Result = 0);
843
844       if Succeeded then
845          Set_Priority (T, Priority);
846       end if;
847    end Create_Task;
848
849    ------------------
850    -- Finalize_TCB --
851    ------------------
852
853    procedure Finalize_TCB (T : Task_Id) is
854       Result  : Interfaces.C.int;
855       Tmp     : Task_Id := T;
856       Is_Self : constant Boolean := T = Self;
857
858       procedure Free is new
859         Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
860
861       procedure Free is new Unchecked_Deallocation
862        (Exc_Stack_T, Exc_Stack_Ptr_T);
863
864    begin
865       if not Single_Lock then
866          Result := pthread_mutex_destroy (T.Common.LL.L'Access);
867          pragma Assert (Result = 0);
868       end if;
869
870       Result := pthread_cond_destroy (T.Common.LL.CV'Access);
871       pragma Assert (Result = 0);
872
873       if T.Known_Tasks_Index /= -1 then
874          Known_Tasks (T.Known_Tasks_Index) := null;
875       end if;
876
877       Free (T.Common.LL.Exc_Stack_Ptr);
878
879       Free (Tmp);
880
881       if Is_Self then
882          Specific.Set (null);
883       end if;
884    end Finalize_TCB;
885
886    ---------------
887    -- Exit_Task --
888    ---------------
889
890    procedure Exit_Task is
891    begin
892       Specific.Set (null);
893    end Exit_Task;
894
895    ----------------
896    -- Abort_Task --
897    ----------------
898
899    procedure Abort_Task (T : Task_Id) is
900    begin
901       --  Interrupt Server_Tasks may be waiting on an event flag
902
903       if T.Common.State = Interrupt_Server_Blocked_On_Event_Flag then
904          Wakeup (T, Interrupt_Server_Blocked_On_Event_Flag);
905       end if;
906    end Abort_Task;
907
908    ----------------
909    -- Check_Exit --
910    ----------------
911
912    --  Dummy version
913
914    function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
915       pragma Unreferenced (Self_ID);
916
917    begin
918       return True;
919    end Check_Exit;
920
921    --------------------
922    -- Check_No_Locks --
923    --------------------
924
925    function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
926       pragma Unreferenced (Self_ID);
927
928    begin
929       return True;
930    end Check_No_Locks;
931
932    ----------------------
933    -- Environment_Task --
934    ----------------------
935
936    function Environment_Task return Task_Id is
937    begin
938       return Environment_Task_Id;
939    end Environment_Task;
940
941    --------------
942    -- Lock_RTS --
943    --------------
944
945    procedure Lock_RTS is
946    begin
947       Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
948    end Lock_RTS;
949
950    ----------------
951    -- Unlock_RTS --
952    ----------------
953
954    procedure Unlock_RTS is
955    begin
956       Unlock (Single_RTS_Lock'Access, Global_Lock => True);
957    end Unlock_RTS;
958
959    ------------------
960    -- Suspend_Task --
961    ------------------
962
963    function Suspend_Task
964      (T           : ST.Task_Id;
965       Thread_Self : Thread_Id) return Boolean
966    is
967       pragma Unreferenced (T);
968       pragma Unreferenced (Thread_Self);
969
970    begin
971       return False;
972    end Suspend_Task;
973
974    -----------------
975    -- Resume_Task --
976    -----------------
977
978    function Resume_Task
979      (T           : ST.Task_Id;
980       Thread_Self : Thread_Id) return Boolean
981    is
982       pragma Unreferenced (T);
983       pragma Unreferenced (Thread_Self);
984    begin
985       return False;
986    end Resume_Task;
987
988    ----------------
989    -- Initialize --
990    ----------------
991
992    procedure Initialize (Environment_Task : Task_Id) is
993    begin
994       Environment_Task_Id := Environment_Task;
995
996       --  Initialize the lock used to synchronize chain of all ATCBs
997
998       Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
999
1000       Specific.Initialize (Environment_Task);
1001
1002       Enter_Task (Environment_Task);
1003    end Initialize;
1004
1005 end System.Task_Primitives.Operations;