OSDN Git Service

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