OSDN Git Service

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