OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [gcc/] [ada/] [s-taprop-vxworks.adb] - Blame information for rev 847

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.