OSDN Git Service

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