OSDN Git Service

2010-01-26 Thomas Quinot <quinot@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-taprop-vms.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                 GNAT 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-2009, 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 3,  or (at your option) any later ver- --
14 -- sion.  GNAT 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.                                     --
17 --                                                                          --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception,   --
20 -- version 3.1, as published by the Free Software Foundation.               --
21 --                                                                          --
22 -- You should have received a copy of the GNU General Public License and    --
23 -- a copy of the GCC Runtime Library Exception along with this program;     --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
25 -- <http://www.gnu.org/licenses/>.                                          --
26 --                                                                          --
27 -- GNARL was developed by the GNARL team at Florida State University.       --
28 -- Extensive contributions were provided by Ada Core Technologies, Inc.     --
29 --                                                                          --
30 ------------------------------------------------------------------------------
31
32 --  This is a OpenVMS/Alpha version of this package
33
34 --  This package contains all the GNULL primitives that interface directly with
35 --  the underlying OS.
36
37 pragma Polling (Off);
38 --  Turn off polling, we do not want ATC polling to take place during tasking
39 --  operations. It causes infinite loops and other problems.
40
41 with Ada.Unchecked_Conversion;
42 with Ada.Unchecked_Deallocation;
43
44 with Interfaces.C;
45
46 with System.Tasking.Debug;
47 with System.OS_Primitives;
48 with System.Soft_Links;
49 with System.Aux_DEC;
50
51 package body System.Task_Primitives.Operations is
52
53    use System.Tasking.Debug;
54    use System.Tasking;
55    use Interfaces.C;
56    use System.OS_Interface;
57    use System.Parameters;
58    use System.OS_Primitives;
59    use type System.OS_Primitives.OS_Time;
60
61    package SSL renames System.Soft_Links;
62
63    ----------------
64    -- Local Data --
65    ----------------
66
67    --  The followings are logically constants, but need to be initialized
68    --  at run time.
69
70    Single_RTS_Lock : aliased RTS_Lock;
71    --  This is a lock to allow only one thread of control in the RTS at
72    --  a time; it is used to execute in mutual exclusion from all other tasks.
73    --  Used mainly in Single_Lock mode, but also to protect All_Tasks_List
74
75    ATCB_Key : aliased pthread_key_t;
76    --  Key used to find the Ada Task_Id associated with a thread
77
78    Environment_Task_Id : Task_Id;
79    --  A variable to hold Task_Id for the environment task
80
81    Time_Slice_Val : Integer;
82    pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
83
84    Dispatching_Policy : Character;
85    pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
86
87    Foreign_Task_Elaborated : aliased Boolean := True;
88    --  Used to identified fake tasks (i.e., non-Ada Threads)
89
90    --------------------
91    -- Local Packages --
92    --------------------
93
94    package Specific is
95
96       procedure Initialize (Environment_Task : Task_Id);
97       pragma Inline (Initialize);
98       --  Initialize various data needed by this package
99
100       function Is_Valid_Task return Boolean;
101       pragma Inline (Is_Valid_Task);
102       --  Does executing thread have a TCB?
103
104       procedure Set (Self_Id : Task_Id);
105       pragma Inline (Set);
106       --  Set the self id for the current task
107
108       function Self return Task_Id;
109       pragma Inline (Self);
110       --  Return a pointer to the Ada Task Control Block of the calling task
111
112    end Specific;
113
114    package body Specific is separate;
115    --  The body of this package is target specific
116
117    ---------------------------------
118    -- Support for foreign threads --
119    ---------------------------------
120
121    function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
122    --  Allocate and Initialize a new ATCB for the current Thread
123
124    function Register_Foreign_Thread
125      (Thread : Thread_Id) return Task_Id is separate;
126
127    -----------------------
128    -- Local Subprograms --
129    -----------------------
130
131    function To_Task_Id is
132      new Ada.Unchecked_Conversion
133        (System.Task_Primitives.Task_Address, Task_Id);
134
135    function To_Address is
136      new Ada.Unchecked_Conversion
137        (Task_Id, System.Task_Primitives.Task_Address);
138
139    function Get_Exc_Stack_Addr return Address;
140    --  Replace System.Soft_Links.Get_Exc_Stack_Addr_NT
141
142    procedure Timer_Sleep_AST (ID : Address);
143    pragma Convention (C, Timer_Sleep_AST);
144    --  Signal the condition variable when AST fires
145
146    procedure Timer_Sleep_AST (ID : Address) is
147       Result : Interfaces.C.int;
148       pragma Warnings (Off, Result);
149       Self_ID : constant Task_Id := To_Task_Id (ID);
150    begin
151       Self_ID.Common.LL.AST_Pending := False;
152       Result := pthread_cond_signal_int_np (Self_ID.Common.LL.CV'Access);
153       pragma Assert (Result = 0);
154    end Timer_Sleep_AST;
155
156    -----------------
157    -- Stack_Guard --
158    -----------------
159
160    --  The underlying thread system sets a guard page at the bottom of a thread
161    --  stack, so nothing is needed.
162    --  ??? Check the comment above
163
164    procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is
165       pragma Unreferenced (T);
166       pragma Unreferenced (On);
167    begin
168       null;
169    end Stack_Guard;
170
171    --------------------
172    -- Get_Thread_Id  --
173    --------------------
174
175    function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is
176    begin
177       return T.Common.LL.Thread;
178    end Get_Thread_Id;
179
180    ----------
181    -- Self --
182    ----------
183
184    function Self return Task_Id renames Specific.Self;
185
186    ---------------------
187    -- Initialize_Lock --
188    ---------------------
189
190    --  Note: mutexes and cond_variables needed per-task basis are initialized
191    --  in Initialize_TCB and the Storage_Error is handled. Other mutexes (such
192    --  as RTS_Lock, Memory_Lock...) used in RTS is initialized before any
193    --  status change of RTS. Therefore raising Storage_Error in the following
194    --  routines should be able to be handled safely.
195
196    procedure Initialize_Lock
197      (Prio : System.Any_Priority;
198       L    : not null access Lock)
199    is
200       Attributes : aliased pthread_mutexattr_t;
201       Result     : Interfaces.C.int;
202
203    begin
204       Result := pthread_mutexattr_init (Attributes'Access);
205       pragma Assert (Result = 0 or else Result = ENOMEM);
206
207       if Result = ENOMEM then
208          raise Storage_Error;
209       end if;
210
211       L.Prio_Save := 0;
212       L.Prio := Interfaces.C.int (Prio);
213
214       Result := pthread_mutex_init (L.L'Access, Attributes'Access);
215       pragma Assert (Result = 0 or else Result = ENOMEM);
216
217       if Result = ENOMEM then
218          raise Storage_Error;
219       end if;
220
221       Result := pthread_mutexattr_destroy (Attributes'Access);
222       pragma Assert (Result = 0);
223    end Initialize_Lock;
224
225    procedure Initialize_Lock
226      (L     : not null access RTS_Lock;
227       Level : Lock_Level)
228    is
229       pragma Unreferenced (Level);
230
231       Attributes : aliased pthread_mutexattr_t;
232       Result : Interfaces.C.int;
233
234    begin
235       Result := pthread_mutexattr_init (Attributes'Access);
236       pragma Assert (Result = 0 or else Result = ENOMEM);
237
238       if Result = ENOMEM then
239          raise Storage_Error;
240       end if;
241
242 --      Don't use, see comment in s-osinte.ads about ERRORCHECK mutexes???
243 --      Result := pthread_mutexattr_settype_np
244 --        (Attributes'Access, PTHREAD_MUTEX_ERRORCHECK_NP);
245 --      pragma Assert (Result = 0);
246
247 --      Result := pthread_mutexattr_setprotocol
248 --        (Attributes'Access, PTHREAD_PRIO_PROTECT);
249 --      pragma Assert (Result = 0);
250
251 --      Result := pthread_mutexattr_setprioceiling
252 --         (Attributes'Access, Interfaces.C.int (System.Any_Priority'Last));
253 --      pragma Assert (Result = 0);
254
255       Result := pthread_mutex_init (L, Attributes'Access);
256
257       pragma Assert (Result = 0 or else Result = ENOMEM);
258
259       if Result = ENOMEM then
260          raise Storage_Error;
261       end if;
262
263       Result := pthread_mutexattr_destroy (Attributes'Access);
264       pragma Assert (Result = 0);
265    end Initialize_Lock;
266
267    -------------------
268    -- Finalize_Lock --
269    -------------------
270
271    procedure Finalize_Lock (L : not null access Lock) is
272       Result : Interfaces.C.int;
273    begin
274       Result := pthread_mutex_destroy (L.L'Access);
275       pragma Assert (Result = 0);
276    end Finalize_Lock;
277
278    procedure Finalize_Lock (L : not null access RTS_Lock) is
279       Result : Interfaces.C.int;
280    begin
281       Result := pthread_mutex_destroy (L);
282       pragma Assert (Result = 0);
283    end Finalize_Lock;
284
285    ----------------
286    -- Write_Lock --
287    ----------------
288
289    procedure Write_Lock
290      (L                 : not null access Lock;
291       Ceiling_Violation : out Boolean)
292    is
293       Self_ID        : constant Task_Id := Self;
294       All_Tasks_Link : constant Task_Id := Self.Common.All_Tasks_Link;
295       Current_Prio   : System.Any_Priority;
296       Result         : Interfaces.C.int;
297
298    begin
299       Current_Prio := Get_Priority (Self_ID);
300
301       --  If there is no other tasks, no need to check priorities
302
303       if All_Tasks_Link /= Null_Task
304         and then L.Prio < Interfaces.C.int (Current_Prio)
305       then
306          Ceiling_Violation := True;
307          return;
308       end if;
309
310       Result := pthread_mutex_lock (L.L'Access);
311       pragma Assert (Result = 0);
312
313       Ceiling_Violation := False;
314 --  Why is this commented out ???
315 --      L.Prio_Save := Interfaces.C.int (Current_Prio);
316 --      Set_Priority (Self_ID, System.Any_Priority (L.Prio));
317    end Write_Lock;
318
319    procedure Write_Lock
320      (L           : not null access RTS_Lock;
321       Global_Lock : Boolean := False)
322    is
323       Result : Interfaces.C.int;
324    begin
325       if not Single_Lock or else Global_Lock then
326          Result := pthread_mutex_lock (L);
327          pragma Assert (Result = 0);
328       end if;
329    end Write_Lock;
330
331    procedure Write_Lock (T : Task_Id) is
332       Result : Interfaces.C.int;
333    begin
334       if not Single_Lock then
335          Result := pthread_mutex_lock (T.Common.LL.L'Access);
336          pragma Assert (Result = 0);
337       end if;
338    end Write_Lock;
339
340    ---------------
341    -- Read_Lock --
342    ---------------
343
344    procedure Read_Lock
345      (L                 : not null access Lock;
346       Ceiling_Violation : out Boolean)
347    is
348    begin
349       Write_Lock (L, Ceiling_Violation);
350    end Read_Lock;
351
352    ------------
353    -- Unlock --
354    ------------
355
356    procedure Unlock (L : not null access Lock) is
357       Result : Interfaces.C.int;
358    begin
359       Result := pthread_mutex_unlock (L.L'Access);
360       pragma Assert (Result = 0);
361    end Unlock;
362
363    procedure Unlock
364      (L           : not null access RTS_Lock;
365       Global_Lock : Boolean := False)
366    is
367       Result : Interfaces.C.int;
368    begin
369       if not Single_Lock or else Global_Lock then
370          Result := pthread_mutex_unlock (L);
371          pragma Assert (Result = 0);
372       end if;
373    end Unlock;
374
375    procedure Unlock (T : Task_Id) is
376       Result : Interfaces.C.int;
377    begin
378       if not Single_Lock then
379          Result := pthread_mutex_unlock (T.Common.LL.L'Access);
380          pragma Assert (Result = 0);
381       end if;
382    end Unlock;
383
384    -----------------
385    -- Set_Ceiling --
386    -----------------
387
388    --  Dynamic priority ceilings are not supported by the underlying system
389
390    procedure Set_Ceiling
391      (L    : not null access Lock;
392       Prio : System.Any_Priority)
393    is
394       pragma Unreferenced (L, Prio);
395    begin
396       null;
397    end Set_Ceiling;
398
399    -----------
400    -- Sleep --
401    -----------
402
403    procedure Sleep
404      (Self_ID : Task_Id;
405       Reason  : System.Tasking.Task_States)
406    is
407       pragma Unreferenced (Reason);
408       Result : Interfaces.C.int;
409
410    begin
411       Result :=
412         pthread_cond_wait
413           (cond  => Self_ID.Common.LL.CV'Access,
414            mutex => (if Single_Lock
415                      then Single_RTS_Lock'Access
416                      else Self_ID.Common.LL.L'Access));
417
418       --  EINTR is not considered a failure
419
420       pragma Assert (Result = 0 or else Result = EINTR);
421
422       if Self_ID.Deferral_Level = 0
423         and then Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
424       then
425          Unlock (Self_ID);
426          raise Standard'Abort_Signal;
427       end if;
428    end Sleep;
429
430    -----------------
431    -- Timed_Sleep --
432    -----------------
433
434    procedure Timed_Sleep
435      (Self_ID  : Task_Id;
436       Time     : Duration;
437       Mode     : ST.Delay_Modes;
438       Reason   : System.Tasking.Task_States;
439       Timedout : out Boolean;
440       Yielded  : out Boolean)
441    is
442       pragma Unreferenced (Reason);
443
444       Sleep_Time : OS_Time;
445       Result     : Interfaces.C.int;
446       Status     : Cond_Value_Type;
447
448       --  The body below requires more comments ???
449
450    begin
451       Timedout := False;
452       Yielded := False;
453
454       Sleep_Time := To_OS_Time (Time, Mode);
455
456       if Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level then
457          return;
458       end if;
459
460       Self_ID.Common.LL.AST_Pending := True;
461
462       Sys_Setimr
463        (Status, 0, Sleep_Time,
464         Timer_Sleep_AST'Access, To_Address (Self_ID), 0);
465
466       if (Status and 1) /= 1 then
467          raise Storage_Error;
468       end if;
469
470       if Single_Lock then
471          Result :=
472            pthread_cond_wait
473              (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access);
474          pragma Assert (Result = 0);
475
476       else
477          Result :=
478            pthread_cond_wait
479              (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
480          pragma Assert (Result = 0);
481       end if;
482
483       Yielded := True;
484
485       if not Self_ID.Common.LL.AST_Pending then
486          Timedout := True;
487       else
488          Sys_Cantim (Status, To_Address (Self_ID), 0);
489          pragma Assert ((Status and 1) = 1);
490       end if;
491    end Timed_Sleep;
492
493    -----------------
494    -- Timed_Delay --
495    -----------------
496
497    procedure Timed_Delay
498      (Self_ID : Task_Id;
499       Time    : Duration;
500       Mode    : ST.Delay_Modes)
501    is
502       Sleep_Time : OS_Time;
503       Result     : Interfaces.C.int;
504       Status     : Cond_Value_Type;
505       Yielded    : Boolean := False;
506
507    begin
508       if Single_Lock then
509          Lock_RTS;
510       end if;
511
512       --  More comments required in body below ???
513
514       Write_Lock (Self_ID);
515
516       if Time /= 0.0 or else Mode /= Relative then
517          Sleep_Time := To_OS_Time (Time, Mode);
518
519          if Mode = Relative or else OS_Clock <= Sleep_Time then
520             Self_ID.Common.State := Delay_Sleep;
521             Self_ID.Common.LL.AST_Pending := True;
522
523             Sys_Setimr
524              (Status, 0, Sleep_Time,
525               Timer_Sleep_AST'Access, To_Address (Self_ID), 0);
526
527             --  Comment following test
528
529             if (Status and 1) /= 1 then
530                raise Storage_Error;
531             end if;
532
533             loop
534                if Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level then
535                   Sys_Cantim (Status, To_Address (Self_ID), 0);
536                   pragma Assert ((Status and 1) = 1);
537                   exit;
538                end if;
539
540                Result :=
541                  pthread_cond_wait
542                    (cond  => Self_ID.Common.LL.CV'Access,
543                     mutex => (if Single_Lock
544                               then Single_RTS_Lock'Access
545                               else Self_ID.Common.LL.L'Access));
546                pragma Assert (Result = 0);
547
548                Yielded := True;
549
550                exit when not Self_ID.Common.LL.AST_Pending;
551             end loop;
552
553             Self_ID.Common.State := Runnable;
554          end if;
555       end if;
556
557       Unlock (Self_ID);
558
559       if Single_Lock then
560          Unlock_RTS;
561       end if;
562
563       if not Yielded then
564          Result := sched_yield;
565          pragma Assert (Result = 0);
566       end if;
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       --  Document origin of this magic constant ???
583       return 10#1.0#E-3;
584    end RT_Resolution;
585
586    ------------
587    -- Wakeup --
588    ------------
589
590    procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
591       pragma Unreferenced (Reason);
592       Result : Interfaces.C.int;
593    begin
594       Result := pthread_cond_signal (T.Common.LL.CV'Access);
595       pragma Assert (Result = 0);
596    end Wakeup;
597
598    -----------
599    -- Yield --
600    -----------
601
602    procedure Yield (Do_Yield : Boolean := True) is
603       Result : Interfaces.C.int;
604       pragma Unreferenced (Result);
605    begin
606       if Do_Yield then
607          Result := sched_yield;
608       end if;
609    end Yield;
610
611    ------------------
612    -- Set_Priority --
613    ------------------
614
615    procedure Set_Priority
616      (T                   : Task_Id;
617       Prio                : System.Any_Priority;
618       Loss_Of_Inheritance : Boolean := False)
619    is
620       pragma Unreferenced (Loss_Of_Inheritance);
621
622       Result : Interfaces.C.int;
623       Param  : aliased struct_sched_param;
624
625       function Get_Policy (Prio : System.Any_Priority) return Character;
626       pragma Import (C, Get_Policy, "__gnat_get_specific_dispatching");
627       --  Get priority specific dispatching policy
628
629       Priority_Specific_Policy : constant Character := Get_Policy (Prio);
630       --  Upper case first character of the policy name corresponding to the
631       --  task as set by a Priority_Specific_Dispatching pragma.
632
633    begin
634       T.Common.Current_Priority := Prio;
635       Param.sched_priority := Interfaces.C.int (Underlying_Priorities (Prio));
636
637       if Dispatching_Policy = 'R'
638         or else Priority_Specific_Policy = 'R'
639         or else Time_Slice_Val > 0
640       then
641          Result :=
642            pthread_setschedparam
643              (T.Common.LL.Thread, SCHED_RR, Param'Access);
644
645       elsif Dispatching_Policy = 'F'
646         or else Priority_Specific_Policy = 'F'
647         or else Time_Slice_Val = 0
648       then
649          Result :=
650            pthread_setschedparam
651              (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
652
653       else
654          --  SCHED_OTHER priorities are restricted to the range 8 - 15.
655          --  Since the translation from Underlying priorities results
656          --  in a range of 16 - 31, dividing by 2 gives the correct result.
657
658          Param.sched_priority := Param.sched_priority / 2;
659          Result :=
660            pthread_setschedparam
661              (T.Common.LL.Thread, SCHED_OTHER, Param'Access);
662       end if;
663
664       pragma Assert (Result = 0);
665    end Set_Priority;
666
667    ------------------
668    -- Get_Priority --
669    ------------------
670
671    function Get_Priority (T : Task_Id) return System.Any_Priority is
672    begin
673       return T.Common.Current_Priority;
674    end Get_Priority;
675
676    ----------------
677    -- Enter_Task --
678    ----------------
679
680    procedure Enter_Task (Self_ID : Task_Id) is
681    begin
682       Self_ID.Common.LL.Thread := pthread_self;
683       Specific.Set (Self_ID);
684    end Enter_Task;
685
686    --------------
687    -- New_ATCB --
688    --------------
689
690    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
691    begin
692       return new Ada_Task_Control_Block (Entry_Num);
693    end New_ATCB;
694
695    -------------------
696    -- Is_Valid_Task --
697    -------------------
698
699    function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
700
701    -----------------------------
702    -- Register_Foreign_Thread --
703    -----------------------------
704
705    function Register_Foreign_Thread return Task_Id is
706    begin
707       if Is_Valid_Task then
708          return Self;
709       else
710          return Register_Foreign_Thread (pthread_self);
711       end if;
712    end Register_Foreign_Thread;
713
714    --------------------
715    -- Initialize_TCB --
716    --------------------
717
718    procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
719       Mutex_Attr : aliased pthread_mutexattr_t;
720       Result     : Interfaces.C.int;
721       Cond_Attr  : aliased pthread_condattr_t;
722
723    begin
724       --  More comments required in body below ???
725
726       if not Single_Lock then
727          Result := pthread_mutexattr_init (Mutex_Attr'Access);
728          pragma Assert (Result = 0 or else Result = ENOMEM);
729
730          if Result = 0 then
731             Result :=
732               pthread_mutex_init
733                 (Self_ID.Common.LL.L'Access, Mutex_Attr'Access);
734             pragma Assert (Result = 0 or else Result = ENOMEM);
735          end if;
736
737          if Result /= 0 then
738             Succeeded := False;
739             return;
740          end if;
741
742          Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
743          pragma Assert (Result = 0);
744       end if;
745
746       Result := pthread_condattr_init (Cond_Attr'Access);
747       pragma Assert (Result = 0 or else Result = ENOMEM);
748
749       if Result = 0 then
750          Result :=
751            pthread_cond_init
752              (Self_ID.Common.LL.CV'Access, Cond_Attr'Access);
753          pragma Assert (Result = 0 or else Result = ENOMEM);
754       end if;
755
756       if Result = 0 then
757          Succeeded := True;
758          Self_ID.Common.LL.Exc_Stack_Ptr := new Exc_Stack_T;
759
760       else
761          if not Single_Lock then
762             Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
763             pragma Assert (Result = 0);
764          end if;
765
766          Succeeded := False;
767       end if;
768
769       Result := pthread_condattr_destroy (Cond_Attr'Access);
770       pragma Assert (Result = 0);
771    end Initialize_TCB;
772
773    ------------------------
774    -- Get_Exc_Stack_Addr --
775    ------------------------
776
777    function Get_Exc_Stack_Addr return Address is
778    begin
779       return Self.Common.LL.Exc_Stack_Ptr (Exc_Stack_T'Last)'Address;
780    end Get_Exc_Stack_Addr;
781
782    -----------------
783    -- Create_Task --
784    -----------------
785
786    procedure Create_Task
787      (T          : Task_Id;
788       Wrapper    : System.Address;
789       Stack_Size : System.Parameters.Size_Type;
790       Priority   : System.Any_Priority;
791       Succeeded  : out Boolean)
792    is
793       Attributes : aliased pthread_attr_t;
794       Result     : Interfaces.C.int;
795
796       function Thread_Body_Access is new
797         Ada.Unchecked_Conversion (System.Aux_DEC.Short_Address, Thread_Body);
798
799    begin
800       --  Since the initial signal mask of a thread is inherited from the
801       --  creator, we need to set our local signal mask to 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, Interfaces.C.size_t (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 :=
829         pthread_create
830           (T.Common.LL.Thread'Access,
831            Attributes'Access,
832            Thread_Body_Access (Wrapper),
833            To_Address (T));
834
835       --  ENOMEM is a valid run-time error -- do not shut down
836
837       pragma Assert (Result = 0
838         or else Result = EAGAIN or else Result = ENOMEM);
839
840       Succeeded := Result = 0;
841
842       Result := pthread_attr_destroy (Attributes'Access);
843       pragma Assert (Result = 0);
844
845       if Succeeded then
846          Set_Priority (T, Priority);
847       end if;
848    end Create_Task;
849
850    ------------------
851    -- Finalize_TCB --
852    ------------------
853
854    procedure Finalize_TCB (T : Task_Id) is
855       Result  : Interfaces.C.int;
856       Tmp     : Task_Id := T;
857       Is_Self : constant Boolean := T = Self;
858
859       procedure Free is new
860         Ada.Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
861
862       procedure Free is new Ada.Unchecked_Deallocation
863        (Exc_Stack_T, Exc_Stack_Ptr_T);
864
865    begin
866       if not Single_Lock then
867          Result := pthread_mutex_destroy (T.Common.LL.L'Access);
868          pragma Assert (Result = 0);
869       end if;
870
871       Result := pthread_cond_destroy (T.Common.LL.CV'Access);
872       pragma Assert (Result = 0);
873
874       if T.Known_Tasks_Index /= -1 then
875          Known_Tasks (T.Known_Tasks_Index) := null;
876       end if;
877
878       Free (T.Common.LL.Exc_Stack_Ptr);
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       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    -- Initialize --
910    ----------------
911
912    procedure Initialize (S : in out Suspension_Object) is
913       Mutex_Attr : aliased pthread_mutexattr_t;
914       Cond_Attr  : aliased pthread_condattr_t;
915       Result     : Interfaces.C.int;
916    begin
917       --  Initialize internal state (always to False (D.10 (6)))
918
919       S.State := False;
920       S.Waiting := False;
921
922       --  Initialize internal mutex
923
924       Result := pthread_mutexattr_init (Mutex_Attr'Access);
925       pragma Assert (Result = 0 or else Result = ENOMEM);
926
927       if Result = ENOMEM then
928          raise Storage_Error;
929       end if;
930
931       Result := pthread_mutex_init (S.L'Access, Mutex_Attr'Access);
932       pragma Assert (Result = 0 or else Result = ENOMEM);
933
934       if Result = ENOMEM then
935          Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
936          pragma Assert (Result = 0);
937
938          raise Storage_Error;
939       end if;
940
941       Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
942       pragma Assert (Result = 0);
943
944       --  Initialize internal condition variable
945
946       Result := pthread_condattr_init (Cond_Attr'Access);
947       pragma Assert (Result = 0 or else Result = ENOMEM);
948
949       if Result /= 0 then
950          Result := pthread_mutex_destroy (S.L'Access);
951          pragma Assert (Result = 0);
952
953          if Result = ENOMEM then
954             raise Storage_Error;
955          end if;
956       end if;
957
958       Result := pthread_cond_init (S.CV'Access, Cond_Attr'Access);
959       pragma Assert (Result = 0 or else Result = ENOMEM);
960
961       if Result /= 0 then
962          Result := pthread_mutex_destroy (S.L'Access);
963          pragma Assert (Result = 0);
964
965          if Result = ENOMEM then
966             Result := pthread_condattr_destroy (Cond_Attr'Access);
967             pragma Assert (Result = 0);
968
969             raise Storage_Error;
970          end if;
971       end if;
972
973       Result := pthread_condattr_destroy (Cond_Attr'Access);
974       pragma Assert (Result = 0);
975    end Initialize;
976
977    --------------
978    -- Finalize --
979    --------------
980
981    procedure Finalize (S : in out Suspension_Object) is
982       Result : Interfaces.C.int;
983
984    begin
985       --  Destroy internal mutex
986
987       Result := pthread_mutex_destroy (S.L'Access);
988       pragma Assert (Result = 0);
989
990       --  Destroy internal condition variable
991
992       Result := pthread_cond_destroy (S.CV'Access);
993       pragma Assert (Result = 0);
994    end Finalize;
995
996    -------------------
997    -- Current_State --
998    -------------------
999
1000    function Current_State (S : Suspension_Object) return Boolean is
1001    begin
1002       --  We do not want to use lock on this read operation. State is marked
1003       --  as Atomic so that we ensure that the value retrieved is correct.
1004
1005       return S.State;
1006    end Current_State;
1007
1008    ---------------
1009    -- Set_False --
1010    ---------------
1011
1012    procedure Set_False (S : in out Suspension_Object) is
1013       Result : Interfaces.C.int;
1014
1015    begin
1016       SSL.Abort_Defer.all;
1017
1018       Result := pthread_mutex_lock (S.L'Access);
1019       pragma Assert (Result = 0);
1020
1021       S.State := False;
1022
1023       Result := pthread_mutex_unlock (S.L'Access);
1024       pragma Assert (Result = 0);
1025
1026       SSL.Abort_Undefer.all;
1027    end Set_False;
1028
1029    --------------
1030    -- Set_True --
1031    --------------
1032
1033    procedure Set_True (S : in out Suspension_Object) is
1034       Result : Interfaces.C.int;
1035
1036    begin
1037       SSL.Abort_Defer.all;
1038
1039       Result := pthread_mutex_lock (S.L'Access);
1040       pragma Assert (Result = 0);
1041
1042       --  If there is already a task waiting on this suspension object then
1043       --  we resume it, leaving the state of the suspension object to False,
1044       --  as specified in (RM D.10(9)), otherwise leave state set to True.
1045
1046       if S.Waiting then
1047          S.Waiting := False;
1048          S.State := False;
1049
1050          Result := pthread_cond_signal (S.CV'Access);
1051          pragma Assert (Result = 0);
1052
1053       else
1054          S.State := True;
1055       end if;
1056
1057       Result := pthread_mutex_unlock (S.L'Access);
1058       pragma Assert (Result = 0);
1059
1060       SSL.Abort_Undefer.all;
1061    end Set_True;
1062
1063    ------------------------
1064    -- Suspend_Until_True --
1065    ------------------------
1066
1067    procedure Suspend_Until_True (S : in out Suspension_Object) is
1068       Result : Interfaces.C.int;
1069
1070    begin
1071       SSL.Abort_Defer.all;
1072
1073       Result := pthread_mutex_lock (S.L'Access);
1074       pragma Assert (Result = 0);
1075
1076       if S.Waiting then
1077
1078          --  Program_Error must be raised upon calling Suspend_Until_True
1079          --  if another task is already waiting on that suspension object
1080          --  (RM D.10(10)).
1081
1082          Result := pthread_mutex_unlock (S.L'Access);
1083          pragma Assert (Result = 0);
1084
1085          SSL.Abort_Undefer.all;
1086
1087          raise Program_Error;
1088
1089       else
1090          --  Suspend the task if the state is False. Otherwise, the task
1091          --  continues its execution, and the state of the suspension object
1092          --  is set to False (ARM D.10 par. 9).
1093
1094          if S.State then
1095             S.State := False;
1096          else
1097             S.Waiting := True;
1098
1099             loop
1100                --  Loop in case pthread_cond_wait returns earlier than expected
1101                --  (e.g. in case of EINTR caused by a signal).
1102
1103                Result := pthread_cond_wait (S.CV'Access, S.L'Access);
1104                pragma Assert (Result = 0 or else Result = EINTR);
1105
1106                exit when not S.Waiting;
1107             end loop;
1108          end if;
1109
1110          Result := pthread_mutex_unlock (S.L'Access);
1111          pragma Assert (Result = 0);
1112
1113          SSL.Abort_Undefer.all;
1114       end if;
1115    end Suspend_Until_True;
1116
1117    ----------------
1118    -- Check_Exit --
1119    ----------------
1120
1121    --  Dummy version
1122
1123    function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1124       pragma Unreferenced (Self_ID);
1125    begin
1126       return True;
1127    end Check_Exit;
1128
1129    --------------------
1130    -- Check_No_Locks --
1131    --------------------
1132
1133    function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1134       pragma Unreferenced (Self_ID);
1135    begin
1136       return True;
1137    end Check_No_Locks;
1138
1139    ----------------------
1140    -- Environment_Task --
1141    ----------------------
1142
1143    function Environment_Task return Task_Id is
1144    begin
1145       return Environment_Task_Id;
1146    end Environment_Task;
1147
1148    --------------
1149    -- Lock_RTS --
1150    --------------
1151
1152    procedure Lock_RTS is
1153    begin
1154       Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
1155    end Lock_RTS;
1156
1157    ----------------
1158    -- Unlock_RTS --
1159    ----------------
1160
1161    procedure Unlock_RTS is
1162    begin
1163       Unlock (Single_RTS_Lock'Access, Global_Lock => True);
1164    end Unlock_RTS;
1165
1166    ------------------
1167    -- Suspend_Task --
1168    ------------------
1169
1170    function Suspend_Task
1171      (T           : ST.Task_Id;
1172       Thread_Self : Thread_Id) return Boolean
1173    is
1174       pragma Unreferenced (T);
1175       pragma Unreferenced (Thread_Self);
1176    begin
1177       return False;
1178    end Suspend_Task;
1179
1180    -----------------
1181    -- Resume_Task --
1182    -----------------
1183
1184    function Resume_Task
1185      (T           : ST.Task_Id;
1186       Thread_Self : Thread_Id) return Boolean
1187    is
1188       pragma Unreferenced (T);
1189       pragma Unreferenced (Thread_Self);
1190    begin
1191       return False;
1192    end Resume_Task;
1193
1194    --------------------
1195    -- Stop_All_Tasks --
1196    --------------------
1197
1198    procedure Stop_All_Tasks is
1199    begin
1200       null;
1201    end Stop_All_Tasks;
1202
1203    ---------------
1204    -- Stop_Task --
1205    ---------------
1206
1207    function Stop_Task (T : ST.Task_Id) return Boolean is
1208       pragma Unreferenced (T);
1209    begin
1210       return False;
1211    end Stop_Task;
1212
1213    -------------------
1214    -- Continue_Task --
1215    -------------------
1216
1217    function Continue_Task (T : ST.Task_Id) return Boolean is
1218       pragma Unreferenced (T);
1219    begin
1220       return False;
1221    end Continue_Task;
1222
1223    ----------------
1224    -- Initialize --
1225    ----------------
1226
1227    procedure Initialize (Environment_Task : Task_Id) is
1228
1229       --  The DEC Ada facility code defined in Starlet
1230       Ada_Facility : constant := 49;
1231
1232       function DBGEXT (Control_Block : System.Address)
1233         return System.Aux_DEC.Unsigned_Word;
1234       --  DBGEXT is imported  from s-tasdeb.adb and its parameter re-typed
1235       --  as Address to avoid having a VMS specific s-tasdeb.ads.
1236       pragma Interface (C, DBGEXT);
1237       pragma Import_Function (DBGEXT, "GNAT$DBGEXT");
1238
1239       type Facility_Type is range 0 .. 65535;
1240
1241       procedure Debug_Register
1242         (ADBGEXT    : System.Address;
1243          ATCB_Key   : pthread_key_t;
1244          Facility   : Facility_Type;
1245          Std_Prolog : Integer);
1246       pragma Import (C, Debug_Register, "CMA$DEBUG_REGISTER");
1247    begin
1248       Environment_Task_Id := Environment_Task;
1249
1250       SSL.Get_Exc_Stack_Addr := Get_Exc_Stack_Addr'Access;
1251
1252       --  Initialize the lock used to synchronize chain of all ATCBs
1253
1254       Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1255
1256       Specific.Initialize (Environment_Task);
1257
1258       --  Pass the context key on to CMA along with the other parameters
1259       Debug_Register
1260        (
1261         DBGEXT'Address,    --  Our DEBUG handling entry point
1262         ATCB_Key,          --  CMA context key for our Ada TCB's
1263         Ada_Facility,      --  Out facility code
1264         0                  --  False, we don't have the std TCB prolog
1265        );
1266
1267       --  Make environment task known here because it doesn't go through
1268       --  Activate_Tasks, which does it for all other tasks.
1269
1270       Known_Tasks (Known_Tasks'First) := Environment_Task;
1271       Environment_Task.Known_Tasks_Index := Known_Tasks'First;
1272
1273       Enter_Task (Environment_Task);
1274    end Initialize;
1275
1276 end System.Task_Primitives.Operations;