OSDN Git Service

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