OSDN Git Service

2011-08-05 Yannick Moy <moy@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-taprop-vxworks.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-2011, 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 the VxWorks 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.Multiprocessors;
47 with System.Tasking.Debug;
48 with System.Interrupt_Management;
49 with System.Float_Control;
50
51 with System.Soft_Links;
52 --  We use System.Soft_Links instead of System.Tasking.Initialization
53 --  because the later is a higher level package that we shouldn't depend
54 --  on. For example when using the restricted run time, it is replaced by
55 --  System.Tasking.Restricted.Stages.
56
57 with System.Task_Info;
58 with System.VxWorks.Ext;
59
60 package body System.Task_Primitives.Operations is
61
62    package SSL renames System.Soft_Links;
63
64    use System.Tasking.Debug;
65    use System.Tasking;
66    use System.OS_Interface;
67    use System.Parameters;
68    use type System.VxWorks.Ext.t_id;
69    use type Interfaces.C.int;
70
71    subtype int is System.OS_Interface.int;
72
73    Relative : constant := 0;
74
75    ----------------
76    -- Local Data --
77    ----------------
78
79    --  The followings are logically constants, but need to be initialized at
80    --  run time.
81
82    Environment_Task_Id : Task_Id;
83    --  A variable to hold Task_Id for the environment task
84
85    --  The followings are internal configuration constants needed
86
87    Dispatching_Policy : Character;
88    pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
89
90    Foreign_Task_Elaborated : aliased Boolean := True;
91    --  Used to identified fake tasks (i.e., non-Ada Threads)
92
93    Locking_Policy : Character;
94    pragma Import (C, Locking_Policy, "__gl_locking_policy");
95
96    Mutex_Protocol : Priority_Type;
97
98    Single_RTS_Lock : aliased RTS_Lock;
99    --  This is a lock to allow only one thread of control in the RTS at a
100    --  time; it is used to execute in mutual exclusion from all other tasks.
101    --  Used mainly in Single_Lock mode, but also to protect All_Tasks_List
102
103    Time_Slice_Val : Integer;
104    pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
105
106    --------------------
107    -- Local Packages --
108    --------------------
109
110    package Specific is
111
112       procedure Initialize;
113       pragma Inline (Initialize);
114       --  Initialize task specific data
115
116       function Is_Valid_Task return Boolean;
117       pragma Inline (Is_Valid_Task);
118       --  Does executing thread have a TCB?
119
120       procedure Set (Self_Id : Task_Id);
121       pragma Inline (Set);
122       --  Set the self id for the current task
123
124       procedure Delete;
125       pragma Inline (Delete);
126       --  Delete the task specific data associated with the current task
127
128       function Self return Task_Id;
129       pragma Inline (Self);
130       --  Return a pointer to the Ada Task Control Block of the calling task
131
132    end Specific;
133
134    package body Specific is separate;
135    --  The body of this package is target specific
136
137    ---------------------------------
138    -- Support for foreign threads --
139    ---------------------------------
140
141    function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
142    --  Allocate and Initialize a new ATCB for the current Thread
143
144    function Register_Foreign_Thread
145      (Thread : Thread_Id) return Task_Id is separate;
146
147    -----------------------
148    -- Local Subprograms --
149    -----------------------
150
151    procedure Abort_Handler (signo : Signal);
152    --  Handler for the abort (SIGABRT) signal to handle asynchronous abort
153
154    procedure Install_Signal_Handlers;
155    --  Install the default signal handlers for the current task
156
157    function Is_Task_Context return Boolean;
158    --  This function returns True if the current execution is in the context
159    --  of a task, and False if it is an interrupt context.
160
161    type Set_Stack_Limit_Proc_Acc is access procedure;
162    pragma Convention (C, Set_Stack_Limit_Proc_Acc);
163
164    Set_Stack_Limit_Hook : Set_Stack_Limit_Proc_Acc;
165    pragma Import (C, Set_Stack_Limit_Hook, "__gnat_set_stack_limit_hook");
166    --  Procedure to be called when a task is created to set stack
167    --  limit. Used only for VxWorks 5 and VxWorks MILS guest OS.
168
169    function To_Address is
170      new Ada.Unchecked_Conversion (Task_Id, System.Address);
171
172    -------------------
173    -- Abort_Handler --
174    -------------------
175
176    procedure Abort_Handler (signo : Signal) is
177       pragma Unreferenced (signo);
178
179       Self_ID        : constant Task_Id := Self;
180       Old_Set        : aliased sigset_t;
181       Unblocked_Mask : aliased sigset_t;
182       Result         : int;
183       pragma Warnings (Off, Result);
184
185       use System.Interrupt_Management;
186
187    begin
188       --  It is not safe to raise an exception when using ZCX and the GCC
189       --  exception handling mechanism.
190
191       if ZCX_By_Default and then GCC_ZCX_Support then
192          return;
193       end if;
194
195       if Self_ID.Deferral_Level = 0
196         and then Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
197         and then not Self_ID.Aborting
198       then
199          Self_ID.Aborting := True;
200
201          --  Make sure signals used for RTS internal purposes are unmasked
202
203          Result := sigemptyset (Unblocked_Mask'Access);
204          pragma Assert (Result = 0);
205          Result :=
206            sigaddset
207            (Unblocked_Mask'Access,
208             Signal (Abort_Task_Interrupt));
209          pragma Assert (Result = 0);
210          Result := sigaddset (Unblocked_Mask'Access, SIGBUS);
211          pragma Assert (Result = 0);
212          Result := sigaddset (Unblocked_Mask'Access, SIGFPE);
213          pragma Assert (Result = 0);
214          Result := sigaddset (Unblocked_Mask'Access, SIGILL);
215          pragma Assert (Result = 0);
216          Result := sigaddset (Unblocked_Mask'Access, SIGSEGV);
217          pragma Assert (Result = 0);
218
219          Result :=
220            pthread_sigmask
221              (SIG_UNBLOCK,
222               Unblocked_Mask'Access,
223               Old_Set'Access);
224          pragma Assert (Result = 0);
225
226          raise Standard'Abort_Signal;
227       end if;
228    end Abort_Handler;
229
230    -----------------
231    -- Stack_Guard --
232    -----------------
233
234    procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is
235       pragma Unreferenced (T);
236       pragma Unreferenced (On);
237
238    begin
239       --  Nothing needed (why not???)
240
241       null;
242    end Stack_Guard;
243
244    -------------------
245    -- Get_Thread_Id --
246    -------------------
247
248    function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is
249    begin
250       return T.Common.LL.Thread;
251    end Get_Thread_Id;
252
253    ----------
254    -- Self --
255    ----------
256
257    function Self return Task_Id renames Specific.Self;
258
259    -----------------------------
260    -- Install_Signal_Handlers --
261    -----------------------------
262
263    procedure Install_Signal_Handlers is
264       act     : aliased struct_sigaction;
265       old_act : aliased struct_sigaction;
266       Tmp_Set : aliased sigset_t;
267       Result  : int;
268
269    begin
270       act.sa_flags := 0;
271       act.sa_handler := Abort_Handler'Address;
272
273       Result := sigemptyset (Tmp_Set'Access);
274       pragma Assert (Result = 0);
275       act.sa_mask := Tmp_Set;
276
277       Result :=
278         sigaction
279           (Signal (Interrupt_Management.Abort_Task_Interrupt),
280            act'Unchecked_Access,
281            old_act'Unchecked_Access);
282       pragma Assert (Result = 0);
283
284       Interrupt_Management.Initialize_Interrupts;
285    end Install_Signal_Handlers;
286
287    ---------------------
288    -- Initialize_Lock --
289    ---------------------
290
291    procedure Initialize_Lock
292      (Prio : System.Any_Priority;
293       L    : not null access Lock)
294    is
295    begin
296       L.Mutex := semMCreate (SEM_Q_PRIORITY + SEM_INVERSION_SAFE);
297       L.Prio_Ceiling := int (Prio);
298       L.Protocol := Mutex_Protocol;
299       pragma Assert (L.Mutex /= 0);
300    end Initialize_Lock;
301
302    procedure Initialize_Lock
303      (L     : not null access RTS_Lock;
304       Level : Lock_Level)
305    is
306       pragma Unreferenced (Level);
307    begin
308       L.Mutex := semMCreate (SEM_Q_PRIORITY + SEM_INVERSION_SAFE);
309       L.Prio_Ceiling := int (System.Any_Priority'Last);
310       L.Protocol := Mutex_Protocol;
311       pragma Assert (L.Mutex /= 0);
312    end Initialize_Lock;
313
314    -------------------
315    -- Finalize_Lock --
316    -------------------
317
318    procedure Finalize_Lock (L : not null access Lock) is
319       Result : int;
320    begin
321       Result := semDelete (L.Mutex);
322       pragma Assert (Result = 0);
323    end Finalize_Lock;
324
325    procedure Finalize_Lock (L : not null access RTS_Lock) is
326       Result : int;
327    begin
328       Result := semDelete (L.Mutex);
329       pragma Assert (Result = 0);
330    end Finalize_Lock;
331
332    ----------------
333    -- Write_Lock --
334    ----------------
335
336    procedure Write_Lock
337      (L                 : not null access Lock;
338       Ceiling_Violation : out Boolean)
339    is
340       Result : int;
341
342    begin
343       if L.Protocol = Prio_Protect
344         and then int (Self.Common.Current_Priority) > L.Prio_Ceiling
345       then
346          Ceiling_Violation := True;
347          return;
348       else
349          Ceiling_Violation := False;
350       end if;
351
352       Result := semTake (L.Mutex, WAIT_FOREVER);
353       pragma Assert (Result = 0);
354    end Write_Lock;
355
356    procedure Write_Lock
357      (L           : not null access RTS_Lock;
358       Global_Lock : Boolean := False)
359    is
360       Result : int;
361    begin
362       if not Single_Lock or else Global_Lock then
363          Result := semTake (L.Mutex, WAIT_FOREVER);
364          pragma Assert (Result = 0);
365       end if;
366    end Write_Lock;
367
368    procedure Write_Lock (T : Task_Id) is
369       Result : int;
370    begin
371       if not Single_Lock then
372          Result := semTake (T.Common.LL.L.Mutex, WAIT_FOREVER);
373          pragma Assert (Result = 0);
374       end if;
375    end Write_Lock;
376
377    ---------------
378    -- Read_Lock --
379    ---------------
380
381    procedure Read_Lock
382      (L                 : not null access Lock;
383       Ceiling_Violation : out Boolean)
384    is
385    begin
386       Write_Lock (L, Ceiling_Violation);
387    end Read_Lock;
388
389    ------------
390    -- Unlock --
391    ------------
392
393    procedure Unlock (L : not null access Lock) is
394       Result : int;
395    begin
396       Result := semGive (L.Mutex);
397       pragma Assert (Result = 0);
398    end Unlock;
399
400    procedure Unlock
401      (L           : not null access RTS_Lock;
402       Global_Lock : Boolean := False)
403    is
404       Result : int;
405    begin
406       if not Single_Lock or else Global_Lock then
407          Result := semGive (L.Mutex);
408          pragma Assert (Result = 0);
409       end if;
410    end Unlock;
411
412    procedure Unlock (T : Task_Id) is
413       Result : int;
414    begin
415       if not Single_Lock then
416          Result := semGive (T.Common.LL.L.Mutex);
417          pragma Assert (Result = 0);
418       end if;
419    end Unlock;
420
421    -----------------
422    -- Set_Ceiling --
423    -----------------
424
425    --  Dynamic priority ceilings are not supported by the underlying system
426
427    procedure Set_Ceiling
428      (L    : not null access Lock;
429       Prio : System.Any_Priority)
430    is
431       pragma Unreferenced (L, Prio);
432    begin
433       null;
434    end Set_Ceiling;
435
436    -----------
437    -- Sleep --
438    -----------
439
440    procedure Sleep (Self_ID : Task_Id; Reason : System.Tasking.Task_States) is
441       pragma Unreferenced (Reason);
442
443       Result : int;
444
445    begin
446       pragma Assert (Self_ID = Self);
447
448       --  Release the mutex before sleeping
449
450       Result :=
451         semGive (if Single_Lock
452                  then Single_RTS_Lock.Mutex
453                  else Self_ID.Common.LL.L.Mutex);
454       pragma Assert (Result = 0);
455
456       --  Perform a blocking operation to take the CV semaphore. Note that a
457       --  blocking operation in VxWorks will reenable task scheduling. When we
458       --  are no longer blocked and control is returned, task scheduling will
459       --  again be disabled.
460
461       Result := semTake (Self_ID.Common.LL.CV, WAIT_FOREVER);
462       pragma Assert (Result = 0);
463
464       --  Take the mutex back
465
466       Result :=
467         semTake ((if Single_Lock
468                   then Single_RTS_Lock.Mutex
469                   else Self_ID.Common.LL.L.Mutex), WAIT_FOREVER);
470       pragma Assert (Result = 0);
471    end Sleep;
472
473    -----------------
474    -- Timed_Sleep --
475    -----------------
476
477    --  This is for use within the run-time system, so abort is assumed to be
478    --  already deferred, and the caller should be holding its own ATCB lock.
479
480    procedure Timed_Sleep
481      (Self_ID  : Task_Id;
482       Time     : Duration;
483       Mode     : ST.Delay_Modes;
484       Reason   : System.Tasking.Task_States;
485       Timedout : out Boolean;
486       Yielded  : out Boolean)
487    is
488       pragma Unreferenced (Reason);
489
490       Orig     : constant Duration := Monotonic_Clock;
491       Absolute : Duration;
492       Ticks    : int;
493       Result   : int;
494       Wakeup   : Boolean := False;
495
496    begin
497       Timedout := False;
498       Yielded  := True;
499
500       if Mode = Relative then
501          Absolute := Orig + Time;
502
503          --  Systematically add one since the first tick will delay *at most*
504          --  1 / Rate_Duration seconds, so we need to add one to be on the
505          --  safe side.
506
507          Ticks := To_Clock_Ticks (Time);
508
509          if Ticks > 0 and then Ticks < int'Last then
510             Ticks := Ticks + 1;
511          end if;
512
513       else
514          Absolute := Time;
515          Ticks    := To_Clock_Ticks (Time - Monotonic_Clock);
516       end if;
517
518       if Ticks > 0 then
519          loop
520             --  Release the mutex before sleeping
521
522             Result :=
523               semGive (if Single_Lock
524                        then Single_RTS_Lock.Mutex
525                        else Self_ID.Common.LL.L.Mutex);
526             pragma Assert (Result = 0);
527
528             --  Perform a blocking operation to take the CV semaphore. Note
529             --  that a blocking operation in VxWorks will reenable task
530             --  scheduling. When we are no longer blocked and control is
531             --  returned, task scheduling will again be disabled.
532
533             Result := semTake (Self_ID.Common.LL.CV, Ticks);
534
535             if Result = 0 then
536
537                --  Somebody may have called Wakeup for us
538
539                Wakeup := True;
540
541             else
542                if errno /= S_objLib_OBJ_TIMEOUT then
543                   Wakeup := True;
544
545                else
546                   --  If Ticks = int'last, it was most probably truncated so
547                   --  let's make another round after recomputing Ticks from
548                   --  the absolute time.
549
550                   if Ticks /= int'Last then
551                      Timedout := True;
552
553                   else
554                      Ticks := To_Clock_Ticks (Absolute - Monotonic_Clock);
555
556                      if Ticks < 0 then
557                         Timedout := True;
558                      end if;
559                   end if;
560                end if;
561             end if;
562
563             --  Take the mutex back
564
565             Result :=
566               semTake ((if Single_Lock
567                         then Single_RTS_Lock.Mutex
568                         else Self_ID.Common.LL.L.Mutex), WAIT_FOREVER);
569             pragma Assert (Result = 0);
570
571             exit when Timedout or Wakeup;
572          end loop;
573
574       else
575          Timedout := True;
576
577          --  Should never hold a lock while yielding
578
579          if Single_Lock then
580             Result := semGive (Single_RTS_Lock.Mutex);
581             taskDelay (0);
582             Result := semTake (Single_RTS_Lock.Mutex, WAIT_FOREVER);
583
584          else
585             Result := semGive (Self_ID.Common.LL.L.Mutex);
586             taskDelay (0);
587             Result := semTake (Self_ID.Common.LL.L.Mutex, WAIT_FOREVER);
588          end if;
589       end if;
590    end Timed_Sleep;
591
592    -----------------
593    -- Timed_Delay --
594    -----------------
595
596    --  This is for use in implementing delay statements, so we assume the
597    --  caller is holding no locks.
598
599    procedure Timed_Delay
600      (Self_ID : Task_Id;
601       Time    : Duration;
602       Mode    : ST.Delay_Modes)
603    is
604       Orig     : constant Duration := Monotonic_Clock;
605       Absolute : Duration;
606       Ticks    : int;
607       Timedout : Boolean;
608       Aborted  : Boolean := False;
609
610       Result : int;
611       pragma Warnings (Off, Result);
612
613    begin
614       if Mode = Relative then
615          Absolute := Orig + Time;
616          Ticks    := To_Clock_Ticks (Time);
617
618          if Ticks > 0 and then Ticks < int'Last then
619
620             --  First tick will delay anytime between 0 and 1 / sysClkRateGet
621             --  seconds, so we need to add one to be on the safe side.
622
623             Ticks := Ticks + 1;
624          end if;
625
626       else
627          Absolute := Time;
628          Ticks    := To_Clock_Ticks (Time - Orig);
629       end if;
630
631       if Ticks > 0 then
632
633          --  Modifying State, locking the TCB
634
635          Result :=
636            semTake ((if Single_Lock
637                      then Single_RTS_Lock.Mutex
638                      else Self_ID.Common.LL.L.Mutex), WAIT_FOREVER);
639
640          pragma Assert (Result = 0);
641
642          Self_ID.Common.State := Delay_Sleep;
643          Timedout := False;
644
645          loop
646             Aborted := Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
647
648             --  Release the TCB before sleeping
649
650             Result :=
651               semGive (if Single_Lock
652                        then Single_RTS_Lock.Mutex
653                        else Self_ID.Common.LL.L.Mutex);
654             pragma Assert (Result = 0);
655
656             exit when Aborted;
657
658             Result := semTake (Self_ID.Common.LL.CV, Ticks);
659
660             if Result /= 0 then
661
662                --  If Ticks = int'last, it was most probably truncated
663                --  so let's make another round after recomputing Ticks
664                --  from the absolute time.
665
666                if errno = S_objLib_OBJ_TIMEOUT and then Ticks /= int'Last then
667                   Timedout := True;
668                else
669                   Ticks := To_Clock_Ticks (Absolute - Monotonic_Clock);
670
671                   if Ticks < 0 then
672                      Timedout := True;
673                   end if;
674                end if;
675             end if;
676
677             --  Take back the lock after having slept, to protect further
678             --  access to Self_ID.
679
680             Result :=
681               semTake
682                 ((if Single_Lock
683                   then Single_RTS_Lock.Mutex
684                   else Self_ID.Common.LL.L.Mutex), WAIT_FOREVER);
685
686             pragma Assert (Result = 0);
687
688             exit when Timedout;
689          end loop;
690
691          Self_ID.Common.State := Runnable;
692
693          Result :=
694            semGive
695              (if Single_Lock
696               then Single_RTS_Lock.Mutex
697               else Self_ID.Common.LL.L.Mutex);
698
699       else
700          taskDelay (0);
701       end if;
702    end Timed_Delay;
703
704    ---------------------
705    -- Monotonic_Clock --
706    ---------------------
707
708    function Monotonic_Clock return Duration is
709       TS     : aliased timespec;
710       Result : int;
711    begin
712       Result := clock_gettime (CLOCK_REALTIME, TS'Unchecked_Access);
713       pragma Assert (Result = 0);
714       return To_Duration (TS);
715    end Monotonic_Clock;
716
717    -------------------
718    -- RT_Resolution --
719    -------------------
720
721    function RT_Resolution return Duration is
722    begin
723       return 1.0 / Duration (sysClkRateGet);
724    end RT_Resolution;
725
726    ------------
727    -- Wakeup --
728    ------------
729
730    procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
731       pragma Unreferenced (Reason);
732       Result : int;
733    begin
734       Result := semGive (T.Common.LL.CV);
735       pragma Assert (Result = 0);
736    end Wakeup;
737
738    -----------
739    -- Yield --
740    -----------
741
742    procedure Yield (Do_Yield : Boolean := True) is
743       pragma Unreferenced (Do_Yield);
744       Result : int;
745       pragma Unreferenced (Result);
746    begin
747       Result := taskDelay (0);
748    end Yield;
749
750    ------------------
751    -- Set_Priority --
752    ------------------
753
754    procedure Set_Priority
755      (T                   : Task_Id;
756       Prio                : System.Any_Priority;
757       Loss_Of_Inheritance : Boolean := False)
758    is
759       pragma Unreferenced (Loss_Of_Inheritance);
760
761       Result     : int;
762
763    begin
764       Result :=
765         taskPrioritySet
766           (T.Common.LL.Thread, To_VxWorks_Priority (int (Prio)));
767       pragma Assert (Result = 0);
768
769       --  Note: in VxWorks 6.6 (or earlier), the task is placed at the end of
770       --  the priority queue instead of the head. This is not the behavior
771       --  required by Annex D (RM D.2.3(5/2)), but we consider it an acceptable
772       --  variation (RM 1.1.3(6)), given this is the built-in behavior of the
773       --  operating system. VxWorks versions starting from 6.7 implement the
774       --  required Annex D semantics.
775
776       --  In older versions we attempted to better approximate the Annex D
777       --  required behavior, but this simulation was not entirely accurate,
778       --  and it seems better to live with the standard VxWorks semantics.
779
780       T.Common.Current_Priority := Prio;
781    end Set_Priority;
782
783    ------------------
784    -- Get_Priority --
785    ------------------
786
787    function Get_Priority (T : Task_Id) return System.Any_Priority is
788    begin
789       return T.Common.Current_Priority;
790    end Get_Priority;
791
792    ----------------
793    -- Enter_Task --
794    ----------------
795
796    procedure Enter_Task (Self_ID : Task_Id) is
797    begin
798       --  Store the user-level task id in the Thread field (to be used
799       --  internally by the run-time system) and the kernel-level task id in
800       --  the LWP field (to be used by the debugger).
801
802       Self_ID.Common.LL.Thread := taskIdSelf;
803       Self_ID.Common.LL.LWP := getpid;
804
805       Specific.Set (Self_ID);
806
807       --  Properly initializes the FPU for PPC/MIPS systems
808
809       System.Float_Control.Reset;
810
811       --  Install the signal handlers
812
813       --  This is called for each task since there is no signal inheritance
814       --  between VxWorks tasks.
815
816       Install_Signal_Handlers;
817
818       --  If stack checking is enabled, set the stack limit for this task
819
820       if Set_Stack_Limit_Hook /= null then
821          Set_Stack_Limit_Hook.all;
822       end if;
823    end Enter_Task;
824
825    --------------
826    -- New_ATCB --
827    --------------
828
829    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
830    begin
831       return new Ada_Task_Control_Block (Entry_Num);
832    end New_ATCB;
833
834    -------------------
835    -- Is_Valid_Task --
836    -------------------
837
838    function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
839
840    -----------------------------
841    -- Register_Foreign_Thread --
842    -----------------------------
843
844    function Register_Foreign_Thread return Task_Id is
845    begin
846       if Is_Valid_Task then
847          return Self;
848       else
849          return Register_Foreign_Thread (taskIdSelf);
850       end if;
851    end Register_Foreign_Thread;
852
853    --------------------
854    -- Initialize_TCB --
855    --------------------
856
857    procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
858    begin
859       Self_ID.Common.LL.CV := semBCreate (SEM_Q_PRIORITY, SEM_EMPTY);
860       Self_ID.Common.LL.Thread := 0;
861
862       if Self_ID.Common.LL.CV = 0 then
863          Succeeded := False;
864
865       else
866          Succeeded := True;
867
868          if not Single_Lock then
869             Initialize_Lock (Self_ID.Common.LL.L'Access, ATCB_Level);
870          end if;
871       end if;
872    end Initialize_TCB;
873
874    -----------------
875    -- Create_Task --
876    -----------------
877
878    procedure Create_Task
879      (T          : Task_Id;
880       Wrapper    : System.Address;
881       Stack_Size : System.Parameters.Size_Type;
882       Priority   : System.Any_Priority;
883       Succeeded  : out Boolean)
884    is
885       Adjusted_Stack_Size : size_t;
886       Result : int := 0;
887
888       use System.Task_Info;
889       use type System.Multiprocessors.CPU_Range;
890
891    begin
892       --  Ask for four extra bytes of stack space so that the ATCB pointer can
893       --  be stored below the stack limit, plus extra space for the frame of
894       --  Task_Wrapper. This is so the user gets the amount of stack requested
895       --  exclusive of the needs.
896
897       --  We also have to allocate n more bytes for the task name storage and
898       --  enough space for the Wind Task Control Block which is around 0x778
899       --  bytes. VxWorks also seems to carve out additional space, so use 2048
900       --  as a nice round number. We might want to increment to the nearest
901       --  page size in case we ever support VxVMI.
902
903       --  ??? - we should come back and visit this so we can set the task name
904       --        to something appropriate.
905
906       Adjusted_Stack_Size := size_t (Stack_Size) + 2048;
907
908       --  Since the initial signal mask of a thread is inherited from the
909       --  creator, and the Environment task has all its signals masked, we do
910       --  not need to manipulate caller's signal mask at this point. All tasks
911       --  in RTS will have All_Tasks_Mask initially.
912
913       --  We now compute the VxWorks task name and options, then spawn ...
914
915       declare
916          Name         : aliased String (1 .. T.Common.Task_Image_Len + 1);
917          Name_Address : System.Address;
918          --  Task name we are going to hand down to VxWorks
919
920          function Get_Task_Options return int;
921          pragma Import (C, Get_Task_Options, "__gnat_get_task_options");
922          --  Function that returns the options to be set for the task that we
923          --  are creating. We fetch the options assigned to the current task,
924          --  so offering some user level control over the options for a task
925          --  hierarchy, and force VX_FP_TASK because it is almost always
926          --  required.
927
928       begin
929          --  If there is no Ada task name handy, let VxWorks choose one.
930          --  Otherwise, tell VxWorks what the Ada task name is.
931
932          if T.Common.Task_Image_Len = 0 then
933             Name_Address := System.Null_Address;
934          else
935             Name (1 .. Name'Last - 1) :=
936               T.Common.Task_Image (1 .. T.Common.Task_Image_Len);
937             Name (Name'Last) := ASCII.NUL;
938             Name_Address := Name'Address;
939          end if;
940
941          --  Now spawn the VxWorks task for real
942
943          T.Common.LL.Thread :=
944            taskSpawn
945              (Name_Address,
946               To_VxWorks_Priority (int (Priority)),
947               Get_Task_Options,
948               Adjusted_Stack_Size,
949               Wrapper,
950               To_Address (T));
951       end;
952
953       --  Set processor affinity
954
955       if T.Common.Base_CPU /= System.Multiprocessors.Not_A_Specific_CPU then
956          --  Ada 2012 pragma CPU uses CPU numbers starting from 1, while
957          --  on VxWorks the first CPU is identified by a 0, so we need to
958          --  adjust.
959
960          Result :=
961            taskCpuAffinitySet
962              (T.Common.LL.Thread, int (T.Common.Base_CPU) - 1);
963
964       elsif T.Common.Task_Info /= Unspecified_Task_Info then
965          Result :=
966            taskCpuAffinitySet (T.Common.LL.Thread, T.Common.Task_Info);
967       end if;
968
969       if Result = -1 then
970          taskDelete (T.Common.LL.Thread);
971          T.Common.LL.Thread := -1;
972       end if;
973
974       if T.Common.LL.Thread = -1 then
975          Succeeded := False;
976       else
977          Succeeded := True;
978          Task_Creation_Hook (T.Common.LL.Thread);
979          Set_Priority (T, Priority);
980       end if;
981    end Create_Task;
982
983    ------------------
984    -- Finalize_TCB --
985    ------------------
986
987    procedure Finalize_TCB (T : Task_Id) is
988       Result  : int;
989       Tmp     : Task_Id          := T;
990       Is_Self : constant Boolean := (T = Self);
991
992       procedure Free is new
993         Ada.Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
994
995    begin
996       if not Single_Lock then
997          Result := semDelete (T.Common.LL.L.Mutex);
998          pragma Assert (Result = 0);
999       end if;
1000
1001       T.Common.LL.Thread := 0;
1002
1003       Result := semDelete (T.Common.LL.CV);
1004       pragma Assert (Result = 0);
1005
1006       if T.Known_Tasks_Index /= -1 then
1007          Known_Tasks (T.Known_Tasks_Index) := null;
1008       end if;
1009
1010       Free (Tmp);
1011
1012       if Is_Self then
1013          Specific.Delete;
1014       end if;
1015    end Finalize_TCB;
1016
1017    ---------------
1018    -- Exit_Task --
1019    ---------------
1020
1021    procedure Exit_Task is
1022    begin
1023       Specific.Set (null);
1024    end Exit_Task;
1025
1026    ----------------
1027    -- Abort_Task --
1028    ----------------
1029
1030    procedure Abort_Task (T : Task_Id) is
1031       Result : int;
1032    begin
1033       Result :=
1034         kill
1035           (T.Common.LL.Thread,
1036            Signal (Interrupt_Management.Abort_Task_Interrupt));
1037       pragma Assert (Result = 0);
1038    end Abort_Task;
1039
1040    ----------------
1041    -- Initialize --
1042    ----------------
1043
1044    procedure Initialize (S : in out Suspension_Object) is
1045    begin
1046       --  Initialize internal state (always to False (RM D.10(6)))
1047
1048       S.State := False;
1049       S.Waiting := False;
1050
1051       --  Initialize internal mutex
1052
1053       --  Use simpler binary semaphore instead of VxWorks
1054       --  mutual exclusion semaphore, because we don't need
1055       --  the fancier semantics and their overhead.
1056
1057       S.L := semBCreate (SEM_Q_FIFO, SEM_FULL);
1058
1059       --  Initialize internal condition variable
1060
1061       S.CV := semBCreate (SEM_Q_FIFO, SEM_EMPTY);
1062    end Initialize;
1063
1064    --------------
1065    -- Finalize --
1066    --------------
1067
1068    procedure Finalize (S : in out Suspension_Object) is
1069       pragma Unmodified (S);
1070       --  S may be modified on other targets, but not on VxWorks
1071
1072       Result : STATUS;
1073
1074    begin
1075       --  Destroy internal mutex
1076
1077       Result := semDelete (S.L);
1078       pragma Assert (Result = OK);
1079
1080       --  Destroy internal condition variable
1081
1082       Result := semDelete (S.CV);
1083       pragma Assert (Result = OK);
1084    end Finalize;
1085
1086    -------------------
1087    -- Current_State --
1088    -------------------
1089
1090    function Current_State (S : Suspension_Object) return Boolean is
1091    begin
1092       --  We do not want to use lock on this read operation. State is marked
1093       --  as Atomic so that we ensure that the value retrieved is correct.
1094
1095       return S.State;
1096    end Current_State;
1097
1098    ---------------
1099    -- Set_False --
1100    ---------------
1101
1102    procedure Set_False (S : in out Suspension_Object) is
1103       Result : STATUS;
1104
1105    begin
1106       SSL.Abort_Defer.all;
1107
1108       Result := semTake (S.L, WAIT_FOREVER);
1109       pragma Assert (Result = OK);
1110
1111       S.State := False;
1112
1113       Result := semGive (S.L);
1114       pragma Assert (Result = OK);
1115
1116       SSL.Abort_Undefer.all;
1117    end Set_False;
1118
1119    --------------
1120    -- Set_True --
1121    --------------
1122
1123    procedure Set_True (S : in out Suspension_Object) is
1124       Result : STATUS;
1125
1126    begin
1127       --  Set_True can be called from an interrupt context, in which case
1128       --  Abort_Defer is undefined.
1129
1130       if Is_Task_Context then
1131          SSL.Abort_Defer.all;
1132       end if;
1133
1134       Result := semTake (S.L, WAIT_FOREVER);
1135       pragma Assert (Result = OK);
1136
1137       --  If there is already a task waiting on this suspension object then
1138       --  we resume it, leaving the state of the suspension object to False,
1139       --  as it is specified in ARM D.10 par. 9. Otherwise, it just leaves
1140       --  the state to True.
1141
1142       if S.Waiting then
1143          S.Waiting := False;
1144          S.State := False;
1145
1146          Result := semGive (S.CV);
1147          pragma Assert (Result = OK);
1148       else
1149          S.State := True;
1150       end if;
1151
1152       Result := semGive (S.L);
1153       pragma Assert (Result = OK);
1154
1155       --  Set_True can be called from an interrupt context, in which case
1156       --  Abort_Undefer is undefined.
1157
1158       if Is_Task_Context then
1159          SSL.Abort_Undefer.all;
1160       end if;
1161
1162    end Set_True;
1163
1164    ------------------------
1165    -- Suspend_Until_True --
1166    ------------------------
1167
1168    procedure Suspend_Until_True (S : in out Suspension_Object) is
1169       Result : STATUS;
1170
1171    begin
1172       SSL.Abort_Defer.all;
1173
1174       Result := semTake (S.L, WAIT_FOREVER);
1175
1176       if S.Waiting then
1177
1178          --  Program_Error must be raised upon calling Suspend_Until_True
1179          --  if another task is already waiting on that suspension object
1180          --  (ARM D.10 par. 10).
1181
1182          Result := semGive (S.L);
1183          pragma Assert (Result = OK);
1184
1185          SSL.Abort_Undefer.all;
1186
1187          raise Program_Error;
1188
1189       else
1190          --  Suspend the task if the state is False. Otherwise, the task
1191          --  continues its execution, and the state of the suspension object
1192          --  is set to False (ARM D.10 par. 9).
1193
1194          if S.State then
1195             S.State := False;
1196
1197             Result := semGive (S.L);
1198             pragma Assert (Result = 0);
1199
1200             SSL.Abort_Undefer.all;
1201
1202          else
1203             S.Waiting := True;
1204
1205             --  Release the mutex before sleeping
1206
1207             Result := semGive (S.L);
1208             pragma Assert (Result = OK);
1209
1210             SSL.Abort_Undefer.all;
1211
1212             Result := semTake (S.CV, WAIT_FOREVER);
1213             pragma Assert (Result = 0);
1214          end if;
1215       end if;
1216    end Suspend_Until_True;
1217
1218    ----------------
1219    -- Check_Exit --
1220    ----------------
1221
1222    --  Dummy version
1223
1224    function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1225       pragma Unreferenced (Self_ID);
1226    begin
1227       return True;
1228    end Check_Exit;
1229
1230    --------------------
1231    -- Check_No_Locks --
1232    --------------------
1233
1234    function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1235       pragma Unreferenced (Self_ID);
1236    begin
1237       return True;
1238    end Check_No_Locks;
1239
1240    ----------------------
1241    -- Environment_Task --
1242    ----------------------
1243
1244    function Environment_Task return Task_Id is
1245    begin
1246       return Environment_Task_Id;
1247    end Environment_Task;
1248
1249    --------------
1250    -- Lock_RTS --
1251    --------------
1252
1253    procedure Lock_RTS is
1254    begin
1255       Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
1256    end Lock_RTS;
1257
1258    ----------------
1259    -- Unlock_RTS --
1260    ----------------
1261
1262    procedure Unlock_RTS is
1263    begin
1264       Unlock (Single_RTS_Lock'Access, Global_Lock => True);
1265    end Unlock_RTS;
1266
1267    ------------------
1268    -- Suspend_Task --
1269    ------------------
1270
1271    function Suspend_Task
1272      (T           : ST.Task_Id;
1273       Thread_Self : Thread_Id) return Boolean
1274    is
1275    begin
1276       if T.Common.LL.Thread /= 0
1277         and then T.Common.LL.Thread /= Thread_Self
1278       then
1279          return taskSuspend (T.Common.LL.Thread) = 0;
1280       else
1281          return True;
1282       end if;
1283    end Suspend_Task;
1284
1285    -----------------
1286    -- Resume_Task --
1287    -----------------
1288
1289    function Resume_Task
1290      (T           : ST.Task_Id;
1291       Thread_Self : Thread_Id) return Boolean
1292    is
1293    begin
1294       if T.Common.LL.Thread /= 0
1295         and then T.Common.LL.Thread /= Thread_Self
1296       then
1297          return taskResume (T.Common.LL.Thread) = 0;
1298       else
1299          return True;
1300       end if;
1301    end Resume_Task;
1302
1303    --------------------
1304    -- Stop_All_Tasks --
1305    --------------------
1306
1307    procedure Stop_All_Tasks
1308    is
1309       Thread_Self : constant Thread_Id := taskIdSelf;
1310       C           : Task_Id;
1311
1312       Dummy : int;
1313       pragma Unreferenced (Dummy);
1314
1315    begin
1316       Dummy := Int_Lock;
1317
1318       C := All_Tasks_List;
1319       while C /= null loop
1320          if C.Common.LL.Thread /= 0
1321            and then C.Common.LL.Thread /= Thread_Self
1322          then
1323             Dummy := Task_Stop (C.Common.LL.Thread);
1324          end if;
1325
1326          C := C.Common.All_Tasks_Link;
1327       end loop;
1328
1329       Dummy := Int_Unlock;
1330    end Stop_All_Tasks;
1331
1332    ---------------
1333    -- Stop_Task --
1334    ---------------
1335
1336    function Stop_Task (T : ST.Task_Id) return Boolean is
1337    begin
1338       if T.Common.LL.Thread /= 0 then
1339          return Task_Stop (T.Common.LL.Thread) = 0;
1340       else
1341          return True;
1342       end if;
1343    end Stop_Task;
1344
1345    -------------------
1346    -- Continue_Task --
1347    -------------------
1348
1349    function Continue_Task (T : ST.Task_Id) return Boolean
1350    is
1351    begin
1352       if T.Common.LL.Thread /= 0 then
1353          return Task_Cont (T.Common.LL.Thread) = 0;
1354       else
1355          return True;
1356       end if;
1357    end Continue_Task;
1358
1359    ---------------------
1360    -- Is_Task_Context --
1361    ---------------------
1362
1363    function Is_Task_Context return Boolean is
1364    begin
1365       return System.OS_Interface.Interrupt_Context /= 1;
1366    end Is_Task_Context;
1367
1368    ----------------
1369    -- Initialize --
1370    ----------------
1371
1372    procedure Initialize (Environment_Task : Task_Id) is
1373       Result : int;
1374
1375       use type System.Multiprocessors.CPU_Range;
1376
1377    begin
1378       Environment_Task_Id := Environment_Task;
1379
1380       Interrupt_Management.Initialize;
1381       Specific.Initialize;
1382
1383       if Locking_Policy = 'C' then
1384          Mutex_Protocol := Prio_Protect;
1385       elsif Locking_Policy = 'I' then
1386          Mutex_Protocol := Prio_Inherit;
1387       else
1388          Mutex_Protocol := Prio_None;
1389       end if;
1390
1391       if Time_Slice_Val > 0 then
1392          Result :=
1393            Set_Time_Slice
1394              (To_Clock_Ticks
1395                 (Duration (Time_Slice_Val) / Duration (1_000_000.0)));
1396
1397       elsif Dispatching_Policy = 'R' then
1398          Result := Set_Time_Slice (To_Clock_Ticks (0.01));
1399
1400       end if;
1401
1402       --  Initialize the lock used to synchronize chain of all ATCBs
1403
1404       Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1405
1406       --  Make environment task known here because it doesn't go through
1407       --  Activate_Tasks, which does it for all other tasks.
1408
1409       Known_Tasks (Known_Tasks'First) := Environment_Task;
1410       Environment_Task.Known_Tasks_Index := Known_Tasks'First;
1411
1412       Enter_Task (Environment_Task);
1413
1414       --  Set processor affinity
1415
1416       if Environment_Task.Common.Base_CPU /=
1417          System.Multiprocessors.Not_A_Specific_CPU
1418       then
1419          --  Ada 2012 pragma CPU uses CPU numbers starting from 1, while
1420          --  on VxWorks the first CPU is identified by a 0, so we need to
1421          --  adjust.
1422
1423          Result :=
1424            taskCpuAffinitySet
1425              (Environment_Task.Common.LL.Thread,
1426               int (Environment_Task.Common.Base_CPU) - 1);
1427          pragma Assert (Result /= -1);
1428       end if;
1429    end Initialize;
1430
1431 end System.Task_Primitives.Operations;