OSDN Git Service

2009-04-16 Ed Schonberg <schonberg@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-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       --  If stack checking is enabled, set the stack limit for this task
837
838       if Set_Stack_Limit_Hook /= null then
839          Set_Stack_Limit_Hook.all;
840       end if;
841    end Enter_Task;
842
843    --------------
844    -- New_ATCB --
845    --------------
846
847    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
848    begin
849       return new Ada_Task_Control_Block (Entry_Num);
850    end New_ATCB;
851
852    -------------------
853    -- Is_Valid_Task --
854    -------------------
855
856    function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
857
858    -----------------------------
859    -- Register_Foreign_Thread --
860    -----------------------------
861
862    function Register_Foreign_Thread return Task_Id is
863    begin
864       if Is_Valid_Task then
865          return Self;
866       else
867          return Register_Foreign_Thread (taskIdSelf);
868       end if;
869    end Register_Foreign_Thread;
870
871    --------------------
872    -- Initialize_TCB --
873    --------------------
874
875    procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
876    begin
877       Self_ID.Common.LL.CV := semBCreate (SEM_Q_PRIORITY, SEM_EMPTY);
878       Self_ID.Common.LL.Thread := 0;
879
880       if Self_ID.Common.LL.CV = 0 then
881          Succeeded := False;
882
883       else
884          Succeeded := True;
885
886          if not Single_Lock then
887             Initialize_Lock (Self_ID.Common.LL.L'Access, ATCB_Level);
888          end if;
889       end if;
890    end Initialize_TCB;
891
892    -----------------
893    -- Create_Task --
894    -----------------
895
896    procedure Create_Task
897      (T          : Task_Id;
898       Wrapper    : System.Address;
899       Stack_Size : System.Parameters.Size_Type;
900       Priority   : System.Any_Priority;
901       Succeeded  : out Boolean)
902    is
903       Adjusted_Stack_Size : size_t;
904    begin
905       --  Ask for four extra bytes of stack space so that the ATCB pointer can
906       --  be stored below the stack limit, plus extra space for the frame of
907       --  Task_Wrapper. This is so the user gets the amount of stack requested
908       --  exclusive of the needs.
909
910       --  We also have to allocate n more bytes for the task name storage and
911       --  enough space for the Wind Task Control Block which is around 0x778
912       --  bytes. VxWorks also seems to carve out additional space, so use 2048
913       --  as a nice round number. We might want to increment to the nearest
914       --  page size in case we ever support VxVMI.
915
916       --  ??? - we should come back and visit this so we can set the task name
917       --        to something appropriate.
918
919       Adjusted_Stack_Size := size_t (Stack_Size) + 2048;
920
921       --  Since the initial signal mask of a thread is inherited from the
922       --  creator, and the Environment task has all its signals masked, we do
923       --  not need to manipulate caller's signal mask at this point. All tasks
924       --  in RTS will have All_Tasks_Mask initially.
925
926       --  We now compute the VxWorks task name and options, then spawn ...
927
928       declare
929          Name         : aliased String (1 .. T.Common.Task_Image_Len + 1);
930          Name_Address : System.Address;
931          --  Task name we are going to hand down to VxWorks
932
933          function Get_Task_Options return int;
934          pragma Import (C, Get_Task_Options, "__gnat_get_task_options");
935          --  Function that returns the options to be set for the task that we
936          --  are creating. We fetch the options assigned to the current task,
937          --  so offering some user level control over the options for a task
938          --  hierarchy, and force VX_FP_TASK because it is almost always
939          --  required.
940
941       begin
942          --  If there is no Ada task name handy, let VxWorks choose one.
943          --  Otherwise, tell VxWorks what the Ada task name is.
944
945          if T.Common.Task_Image_Len = 0 then
946             Name_Address := System.Null_Address;
947          else
948             Name (1 .. Name'Last - 1) :=
949               T.Common.Task_Image (1 .. T.Common.Task_Image_Len);
950             Name (Name'Last) := ASCII.NUL;
951             Name_Address := Name'Address;
952          end if;
953
954          --  Now spawn the VxWorks task for real
955
956          T.Common.LL.Thread :=
957            taskSpawn
958              (Name_Address,
959               To_VxWorks_Priority (int (Priority)),
960               Get_Task_Options,
961               Adjusted_Stack_Size,
962               Wrapper,
963               To_Address (T));
964       end;
965
966       if T.Common.LL.Thread = -1 then
967          Succeeded := False;
968       else
969          Succeeded := True;
970          Task_Creation_Hook (T.Common.LL.Thread);
971          Set_Priority (T, Priority);
972       end if;
973    end Create_Task;
974
975    ------------------
976    -- Finalize_TCB --
977    ------------------
978
979    procedure Finalize_TCB (T : Task_Id) is
980       Result  : int;
981       Tmp     : Task_Id          := T;
982       Is_Self : constant Boolean := (T = Self);
983
984       procedure Free is new
985         Ada.Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
986
987    begin
988       if not Single_Lock then
989          Result := semDelete (T.Common.LL.L.Mutex);
990          pragma Assert (Result = 0);
991       end if;
992
993       T.Common.LL.Thread := 0;
994
995       Result := semDelete (T.Common.LL.CV);
996       pragma Assert (Result = 0);
997
998       if T.Known_Tasks_Index /= -1 then
999          Known_Tasks (T.Known_Tasks_Index) := null;
1000       end if;
1001
1002       Free (Tmp);
1003
1004       if Is_Self then
1005          Specific.Delete;
1006       end if;
1007    end Finalize_TCB;
1008
1009    ---------------
1010    -- Exit_Task --
1011    ---------------
1012
1013    procedure Exit_Task is
1014    begin
1015       Specific.Set (null);
1016    end Exit_Task;
1017
1018    ----------------
1019    -- Abort_Task --
1020    ----------------
1021
1022    procedure Abort_Task (T : Task_Id) is
1023       Result : int;
1024    begin
1025       Result :=
1026         kill
1027           (T.Common.LL.Thread,
1028            Signal (Interrupt_Management.Abort_Task_Interrupt));
1029       pragma Assert (Result = 0);
1030    end Abort_Task;
1031
1032    ----------------
1033    -- Initialize --
1034    ----------------
1035
1036    procedure Initialize (S : in out Suspension_Object) is
1037    begin
1038       --  Initialize internal state (always to False (RM D.10(6)))
1039
1040       S.State := False;
1041       S.Waiting := False;
1042
1043       --  Initialize internal mutex
1044
1045       --  Use simpler binary semaphore instead of VxWorks
1046       --  mutual exclusion semaphore, because we don't need
1047       --  the fancier semantics and their overhead.
1048
1049       S.L := semBCreate (SEM_Q_FIFO, SEM_FULL);
1050
1051       --  Initialize internal condition variable
1052
1053       S.CV := semBCreate (SEM_Q_FIFO, SEM_EMPTY);
1054    end Initialize;
1055
1056    --------------
1057    -- Finalize --
1058    --------------
1059
1060    procedure Finalize (S : in out Suspension_Object) is
1061       pragma Unmodified (S);
1062       --  S may be modified on other targets, but not on VxWorks
1063
1064       Result : STATUS;
1065
1066    begin
1067       --  Destroy internal mutex
1068
1069       Result := semDelete (S.L);
1070       pragma Assert (Result = OK);
1071
1072       --  Destroy internal condition variable
1073
1074       Result := semDelete (S.CV);
1075       pragma Assert (Result = OK);
1076    end Finalize;
1077
1078    -------------------
1079    -- Current_State --
1080    -------------------
1081
1082    function Current_State (S : Suspension_Object) return Boolean is
1083    begin
1084       --  We do not want to use lock on this read operation. State is marked
1085       --  as Atomic so that we ensure that the value retrieved is correct.
1086
1087       return S.State;
1088    end Current_State;
1089
1090    ---------------
1091    -- Set_False --
1092    ---------------
1093
1094    procedure Set_False (S : in out Suspension_Object) is
1095       Result : STATUS;
1096
1097    begin
1098       SSL.Abort_Defer.all;
1099
1100       Result := semTake (S.L, WAIT_FOREVER);
1101       pragma Assert (Result = OK);
1102
1103       S.State := False;
1104
1105       Result := semGive (S.L);
1106       pragma Assert (Result = OK);
1107
1108       SSL.Abort_Undefer.all;
1109    end Set_False;
1110
1111    --------------
1112    -- Set_True --
1113    --------------
1114
1115    procedure Set_True (S : in out Suspension_Object) is
1116       Result : STATUS;
1117
1118    begin
1119       SSL.Abort_Defer.all;
1120
1121       Result := semTake (S.L, WAIT_FOREVER);
1122       pragma Assert (Result = OK);
1123
1124       --  If there is already a task waiting on this suspension object then
1125       --  we resume it, leaving the state of the suspension object to False,
1126       --  as it is specified in ARM D.10 par. 9. Otherwise, it just leaves
1127       --  the state to True.
1128
1129       if S.Waiting then
1130          S.Waiting := False;
1131          S.State := False;
1132
1133          Result := semGive (S.CV);
1134          pragma Assert (Result = OK);
1135       else
1136          S.State := True;
1137       end if;
1138
1139       Result := semGive (S.L);
1140       pragma Assert (Result = OK);
1141
1142       SSL.Abort_Undefer.all;
1143    end Set_True;
1144
1145    ------------------------
1146    -- Suspend_Until_True --
1147    ------------------------
1148
1149    procedure Suspend_Until_True (S : in out Suspension_Object) is
1150       Result : STATUS;
1151
1152    begin
1153       SSL.Abort_Defer.all;
1154
1155       Result := semTake (S.L, WAIT_FOREVER);
1156
1157       if S.Waiting then
1158
1159          --  Program_Error must be raised upon calling Suspend_Until_True
1160          --  if another task is already waiting on that suspension object
1161          --  (ARM D.10 par. 10).
1162
1163          Result := semGive (S.L);
1164          pragma Assert (Result = OK);
1165
1166          SSL.Abort_Undefer.all;
1167
1168          raise Program_Error;
1169
1170       else
1171          --  Suspend the task if the state is False. Otherwise, the task
1172          --  continues its execution, and the state of the suspension object
1173          --  is set to False (ARM D.10 par. 9).
1174
1175          if S.State then
1176             S.State := False;
1177
1178             Result := semGive (S.L);
1179             pragma Assert (Result = 0);
1180
1181             SSL.Abort_Undefer.all;
1182
1183          else
1184             S.Waiting := True;
1185
1186             --  Release the mutex before sleeping
1187
1188             Result := semGive (S.L);
1189             pragma Assert (Result = OK);
1190
1191             SSL.Abort_Undefer.all;
1192
1193             Result := semTake (S.CV, WAIT_FOREVER);
1194             pragma Assert (Result = 0);
1195          end if;
1196       end if;
1197    end Suspend_Until_True;
1198
1199    ----------------
1200    -- Check_Exit --
1201    ----------------
1202
1203    --  Dummy version
1204
1205    function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1206       pragma Unreferenced (Self_ID);
1207    begin
1208       return True;
1209    end Check_Exit;
1210
1211    --------------------
1212    -- Check_No_Locks --
1213    --------------------
1214
1215    function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1216       pragma Unreferenced (Self_ID);
1217    begin
1218       return True;
1219    end Check_No_Locks;
1220
1221    ----------------------
1222    -- Environment_Task --
1223    ----------------------
1224
1225    function Environment_Task return Task_Id is
1226    begin
1227       return Environment_Task_Id;
1228    end Environment_Task;
1229
1230    --------------
1231    -- Lock_RTS --
1232    --------------
1233
1234    procedure Lock_RTS is
1235    begin
1236       Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
1237    end Lock_RTS;
1238
1239    ----------------
1240    -- Unlock_RTS --
1241    ----------------
1242
1243    procedure Unlock_RTS is
1244    begin
1245       Unlock (Single_RTS_Lock'Access, Global_Lock => True);
1246    end Unlock_RTS;
1247
1248    ------------------
1249    -- Suspend_Task --
1250    ------------------
1251
1252    function Suspend_Task
1253      (T           : ST.Task_Id;
1254       Thread_Self : Thread_Id) return Boolean
1255    is
1256    begin
1257       if T.Common.LL.Thread /= 0
1258         and then T.Common.LL.Thread /= Thread_Self
1259       then
1260          return taskSuspend (T.Common.LL.Thread) = 0;
1261       else
1262          return True;
1263       end if;
1264    end Suspend_Task;
1265
1266    -----------------
1267    -- Resume_Task --
1268    -----------------
1269
1270    function Resume_Task
1271      (T           : ST.Task_Id;
1272       Thread_Self : Thread_Id) return Boolean
1273    is
1274    begin
1275       if T.Common.LL.Thread /= 0
1276         and then T.Common.LL.Thread /= Thread_Self
1277       then
1278          return taskResume (T.Common.LL.Thread) = 0;
1279       else
1280          return True;
1281       end if;
1282    end Resume_Task;
1283
1284    --------------------
1285    -- Stop_All_Tasks --
1286    --------------------
1287
1288    procedure Stop_All_Tasks
1289    is
1290       Thread_Self : constant Thread_Id := taskIdSelf;
1291       C           : Task_Id;
1292
1293       Dummy : int;
1294       pragma Unreferenced (Dummy);
1295
1296    begin
1297       Dummy := Int_Lock;
1298
1299       C := All_Tasks_List;
1300       while C /= null loop
1301          if C.Common.LL.Thread /= 0
1302            and then C.Common.LL.Thread /= Thread_Self
1303          then
1304             Dummy := Task_Stop (C.Common.LL.Thread);
1305          end if;
1306
1307          C := C.Common.All_Tasks_Link;
1308       end loop;
1309
1310       Dummy := Int_Unlock;
1311    end Stop_All_Tasks;
1312
1313    ---------------
1314    -- Stop_Task --
1315    ---------------
1316
1317    function Stop_Task (T : ST.Task_Id) return Boolean is
1318    begin
1319       if T.Common.LL.Thread /= 0 then
1320          return Task_Stop (T.Common.LL.Thread) = 0;
1321       else
1322          return True;
1323       end if;
1324    end Stop_Task;
1325
1326    -------------------
1327    -- Continue_Task --
1328    -------------------
1329
1330    function Continue_Task (T : ST.Task_Id) return Boolean
1331    is
1332    begin
1333       if T.Common.LL.Thread /= 0 then
1334          return Task_Cont (T.Common.LL.Thread) = 0;
1335       else
1336          return True;
1337       end if;
1338    end Continue_Task;
1339
1340    ----------------
1341    -- Initialize --
1342    ----------------
1343
1344    procedure Initialize (Environment_Task : Task_Id) is
1345       Result : int;
1346
1347    begin
1348       Environment_Task_Id := Environment_Task;
1349
1350       Interrupt_Management.Initialize;
1351       Specific.Initialize;
1352
1353       if Locking_Policy = 'C' then
1354          Mutex_Protocol := Prio_Protect;
1355       elsif Locking_Policy = 'I' then
1356          Mutex_Protocol := Prio_Inherit;
1357       else
1358          Mutex_Protocol := Prio_None;
1359       end if;
1360
1361       if Time_Slice_Val > 0 then
1362          Result :=
1363            Set_Time_Slice
1364              (To_Clock_Ticks
1365                 (Duration (Time_Slice_Val) / Duration (1_000_000.0)));
1366
1367       elsif Dispatching_Policy = 'R' then
1368          Result := Set_Time_Slice (To_Clock_Ticks (0.01));
1369
1370       end if;
1371
1372       Result := sigemptyset (Unblocked_Signal_Mask'Access);
1373       pragma Assert (Result = 0);
1374
1375       for J in Interrupt_Management.Signal_ID loop
1376          if System.Interrupt_Management.Keep_Unmasked (J) then
1377             Result := sigaddset (Unblocked_Signal_Mask'Access, Signal (J));
1378             pragma Assert (Result = 0);
1379          end if;
1380       end loop;
1381
1382       --  Initialize the lock used to synchronize chain of all ATCBs
1383
1384       Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1385
1386       --  Make environment task known here because it doesn't go through
1387       --  Activate_Tasks, which does it for all other tasks.
1388
1389       Known_Tasks (Known_Tasks'First) := Environment_Task;
1390       Environment_Task.Known_Tasks_Index := Known_Tasks'First;
1391
1392       Enter_Task (Environment_Task);
1393    end Initialize;
1394
1395 end System.Task_Primitives.Operations;