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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ada/] [s-taprop-vxworks.adb] - Blame information for rev 747

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

Line No. Rev Author Line
1 706 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-2011, Free Software Foundation, Inc.          --
10
--                                                                          --
11
-- GNARL is free software; you can  redistribute it  and/or modify it under --
12
-- terms of the  GNU General Public License as published  by the Free Soft- --
13
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16
-- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
17
--                                                                          --
18
-- As a special exception under Section 7 of GPL version 3, you are granted --
19
-- additional permissions described in the GCC Runtime Library Exception,   --
20
-- version 3.1, as published by the Free Software Foundation.               --
21
--                                                                          --
22
-- You should have received a copy of the GNU General Public License and    --
23
-- a copy of the GCC Runtime Library Exception along with this program;     --
24
-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
25
-- <http://www.gnu.org/licenses/>.                                          --
26
--                                                                          --
27
-- GNARL was developed by the GNARL team at Florida State University.       --
28
-- Extensive contributions were provided by Ada Core Technologies, Inc.     --
29
--                                                                          --
30
------------------------------------------------------------------------------
31
 
32
--  This is the VxWorks version of this package
33
 
34
--  This package contains all the GNULL primitives that interface directly with
35
--  the underlying OS.
36
 
37
pragma Polling (Off);
38
--  Turn off polling, we do not want ATC polling to take place during tasking
39
--  operations. It causes infinite loops and other problems.
40
 
41
with Ada.Unchecked_Conversion;
42
 
43
with Interfaces.C;
44
 
45
with System.Multiprocessors;
46
with System.Tasking.Debug;
47
with System.Interrupt_Management;
48
with System.Float_Control;
49
with System.OS_Constants;
50
 
51
with System.Soft_Links;
52
--  We use System.Soft_Links instead of System.Tasking.Initialization
53
--  because the later is a higher level package that we shouldn't depend
54
--  on. For example when using the restricted run time, it is replaced by
55
--  System.Tasking.Restricted.Stages.
56
 
57
with System.Task_Info;
58
with System.VxWorks.Ext;
59
 
60
package body System.Task_Primitives.Operations is
61
 
62
   package OSC renames System.OS_Constants;
63
   package SSL renames System.Soft_Links;
64
 
65
   use System.Tasking.Debug;
66
   use System.Tasking;
67
   use System.OS_Interface;
68
   use System.Parameters;
69
   use type System.VxWorks.Ext.t_id;
70
   use type Interfaces.C.int;
71
   use type System.OS_Interface.unsigned;
72
 
73
   subtype int is System.OS_Interface.int;
74
   subtype unsigned is System.OS_Interface.unsigned;
75
 
76
   Relative : constant := 0;
77
 
78
   ----------------
79
   -- Local Data --
80
   ----------------
81
 
82
   --  The followings are logically constants, but need to be initialized at
83
   --  run time.
84
 
85
   Environment_Task_Id : Task_Id;
86
   --  A variable to hold Task_Id for the environment task
87
 
88
   --  The followings are internal configuration constants needed
89
 
90
   Dispatching_Policy : Character;
91
   pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
92
 
93
   Foreign_Task_Elaborated : aliased Boolean := True;
94
   --  Used to identified fake tasks (i.e., non-Ada Threads)
95
 
96
   Locking_Policy : Character;
97
   pragma Import (C, Locking_Policy, "__gl_locking_policy");
98
 
99
   Mutex_Protocol : Priority_Type;
100
 
101
   Single_RTS_Lock : aliased RTS_Lock;
102
   --  This is a lock to allow only one thread of control in the RTS at a
103
   --  time; it is used to execute in mutual exclusion from all other tasks.
104
   --  Used mainly in Single_Lock mode, but also to protect All_Tasks_List
105
 
106
   Time_Slice_Val : Integer;
107
   pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
108
 
109
   Null_Thread_Id : constant Thread_Id := 0;
110
   --  Constant to indicate that the thread identifier has not yet been
111
   --  initialized.
112
 
113
   --------------------
114
   -- Local Packages --
115
   --------------------
116
 
117
   package Specific is
118
 
119
      procedure Initialize;
120
      pragma Inline (Initialize);
121
      --  Initialize task specific data
122
 
123
      function Is_Valid_Task return Boolean;
124
      pragma Inline (Is_Valid_Task);
125
      --  Does executing thread have a TCB?
126
 
127
      procedure Set (Self_Id : Task_Id);
128
      pragma Inline (Set);
129
      --  Set the self id for the current task, unless Self_Id is null, in
130
      --  which case the task specific data is deleted.
131
 
132
      function Self return Task_Id;
133
      pragma Inline (Self);
134
      --  Return a pointer to the Ada Task Control Block of the calling task
135
 
136
   end Specific;
137
 
138
   package body Specific is separate;
139
   --  The body of this package is target specific
140
 
141
   ----------------------------------
142
   -- ATCB allocation/deallocation --
143
   ----------------------------------
144
 
145
   package body ATCB_Allocation is separate;
146
   --  The body of this package is shared across several targets
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 Is_Task_Context return Boolean;
169
   --  This function returns True if the current execution is in the context
170
   --  of a task, and False if it is an interrupt context.
171
 
172
   type Set_Stack_Limit_Proc_Acc is access procedure;
173
   pragma Convention (C, Set_Stack_Limit_Proc_Acc);
174
 
175
   Set_Stack_Limit_Hook : Set_Stack_Limit_Proc_Acc;
176
   pragma Import (C, Set_Stack_Limit_Hook, "__gnat_set_stack_limit_hook");
177
   --  Procedure to be called when a task is created to set stack
178
   --  limit. Used only for VxWorks 5 and VxWorks MILS guest OS.
179
 
180
   function To_Address is
181
     new Ada.Unchecked_Conversion (Task_Id, System.Address);
182
 
183
   -------------------
184
   -- Abort_Handler --
185
   -------------------
186
 
187
   procedure Abort_Handler (signo : Signal) is
188
      pragma Unreferenced (signo);
189
 
190
      Self_ID        : constant Task_Id := Self;
191
      Old_Set        : aliased sigset_t;
192
      Unblocked_Mask : aliased sigset_t;
193
      Result         : int;
194
      pragma Warnings (Off, Result);
195
 
196
      use System.Interrupt_Management;
197
 
198
   begin
199
      --  It is not safe to raise an exception when using ZCX and the GCC
200
      --  exception handling mechanism.
201
 
202
      if ZCX_By_Default then
203
         return;
204
      end if;
205
 
206
      if Self_ID.Deferral_Level = 0
207
        and then Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
208
        and then not Self_ID.Aborting
209
      then
210
         Self_ID.Aborting := True;
211
 
212
         --  Make sure signals used for RTS internal purposes are unmasked
213
 
214
         Result := sigemptyset (Unblocked_Mask'Access);
215
         pragma Assert (Result = 0);
216
         Result :=
217
           sigaddset
218
           (Unblocked_Mask'Access,
219
            Signal (Abort_Task_Interrupt));
220
         pragma Assert (Result = 0);
221
         Result := sigaddset (Unblocked_Mask'Access, SIGBUS);
222
         pragma Assert (Result = 0);
223
         Result := sigaddset (Unblocked_Mask'Access, SIGFPE);
224
         pragma Assert (Result = 0);
225
         Result := sigaddset (Unblocked_Mask'Access, SIGILL);
226
         pragma Assert (Result = 0);
227
         Result := sigaddset (Unblocked_Mask'Access, SIGSEGV);
228
         pragma Assert (Result = 0);
229
 
230
         Result :=
231
           pthread_sigmask
232
             (SIG_UNBLOCK,
233
              Unblocked_Mask'Access,
234
              Old_Set'Access);
235
         pragma Assert (Result = 0);
236
 
237
         raise Standard'Abort_Signal;
238
      end if;
239
   end Abort_Handler;
240
 
241
   -----------------
242
   -- Stack_Guard --
243
   -----------------
244
 
245
   procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is
246
      pragma Unreferenced (T);
247
      pragma Unreferenced (On);
248
 
249
   begin
250
      --  Nothing needed (why not???)
251
 
252
      null;
253
   end Stack_Guard;
254
 
255
   -------------------
256
   -- Get_Thread_Id --
257
   -------------------
258
 
259
   function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is
260
   begin
261
      return T.Common.LL.Thread;
262
   end Get_Thread_Id;
263
 
264
   ----------
265
   -- Self --
266
   ----------
267
 
268
   function Self return Task_Id renames Specific.Self;
269
 
270
   -----------------------------
271
   -- Install_Signal_Handlers --
272
   -----------------------------
273
 
274
   procedure Install_Signal_Handlers is
275
      act     : aliased struct_sigaction;
276
      old_act : aliased struct_sigaction;
277
      Tmp_Set : aliased sigset_t;
278
      Result  : int;
279
 
280
   begin
281
      act.sa_flags := 0;
282
      act.sa_handler := Abort_Handler'Address;
283
 
284
      Result := sigemptyset (Tmp_Set'Access);
285
      pragma Assert (Result = 0);
286
      act.sa_mask := Tmp_Set;
287
 
288
      Result :=
289
        sigaction
290
          (Signal (Interrupt_Management.Abort_Task_Interrupt),
291
           act'Unchecked_Access,
292
           old_act'Unchecked_Access);
293
      pragma Assert (Result = 0);
294
 
295
      Interrupt_Management.Initialize_Interrupts;
296
   end Install_Signal_Handlers;
297
 
298
   ---------------------
299
   -- Initialize_Lock --
300
   ---------------------
301
 
302
   procedure Initialize_Lock
303
     (Prio : System.Any_Priority;
304
      L    : not null access Lock)
305
   is
306
   begin
307
      L.Mutex := semMCreate (SEM_Q_PRIORITY + SEM_INVERSION_SAFE);
308
      L.Prio_Ceiling := int (Prio);
309
      L.Protocol := Mutex_Protocol;
310
      pragma Assert (L.Mutex /= 0);
311
   end Initialize_Lock;
312
 
313
   procedure Initialize_Lock
314
     (L     : not null access RTS_Lock;
315
      Level : Lock_Level)
316
   is
317
      pragma Unreferenced (Level);
318
   begin
319
      L.Mutex := semMCreate (SEM_Q_PRIORITY + SEM_INVERSION_SAFE);
320
      L.Prio_Ceiling := int (System.Any_Priority'Last);
321
      L.Protocol := Mutex_Protocol;
322
      pragma Assert (L.Mutex /= 0);
323
   end Initialize_Lock;
324
 
325
   -------------------
326
   -- Finalize_Lock --
327
   -------------------
328
 
329
   procedure Finalize_Lock (L : not null access Lock) is
330
      Result : int;
331
   begin
332
      Result := semDelete (L.Mutex);
333
      pragma Assert (Result = 0);
334
   end Finalize_Lock;
335
 
336
   procedure Finalize_Lock (L : not null access RTS_Lock) is
337
      Result : int;
338
   begin
339
      Result := semDelete (L.Mutex);
340
      pragma Assert (Result = 0);
341
   end Finalize_Lock;
342
 
343
   ----------------
344
   -- Write_Lock --
345
   ----------------
346
 
347
   procedure Write_Lock
348
     (L                 : not null access Lock;
349
      Ceiling_Violation : out Boolean)
350
   is
351
      Result : int;
352
 
353
   begin
354
      if L.Protocol = Prio_Protect
355
        and then int (Self.Common.Current_Priority) > L.Prio_Ceiling
356
      then
357
         Ceiling_Violation := True;
358
         return;
359
      else
360
         Ceiling_Violation := False;
361
      end if;
362
 
363
      Result := semTake (L.Mutex, WAIT_FOREVER);
364
      pragma Assert (Result = 0);
365
   end Write_Lock;
366
 
367
   procedure Write_Lock
368
     (L           : not null access RTS_Lock;
369
      Global_Lock : Boolean := False)
370
   is
371
      Result : int;
372
   begin
373
      if not Single_Lock or else Global_Lock then
374
         Result := semTake (L.Mutex, WAIT_FOREVER);
375
         pragma Assert (Result = 0);
376
      end if;
377
   end Write_Lock;
378
 
379
   procedure Write_Lock (T : Task_Id) is
380
      Result : int;
381
   begin
382
      if not Single_Lock then
383
         Result := semTake (T.Common.LL.L.Mutex, WAIT_FOREVER);
384
         pragma Assert (Result = 0);
385
      end if;
386
   end Write_Lock;
387
 
388
   ---------------
389
   -- Read_Lock --
390
   ---------------
391
 
392
   procedure Read_Lock
393
     (L                 : not null access Lock;
394
      Ceiling_Violation : out Boolean)
395
   is
396
   begin
397
      Write_Lock (L, Ceiling_Violation);
398
   end Read_Lock;
399
 
400
   ------------
401
   -- Unlock --
402
   ------------
403
 
404
   procedure Unlock (L : not null access Lock) is
405
      Result : int;
406
   begin
407
      Result := semGive (L.Mutex);
408
      pragma Assert (Result = 0);
409
   end Unlock;
410
 
411
   procedure Unlock
412
     (L           : not null access RTS_Lock;
413
      Global_Lock : Boolean := False)
414
   is
415
      Result : int;
416
   begin
417
      if not Single_Lock or else Global_Lock then
418
         Result := semGive (L.Mutex);
419
         pragma Assert (Result = 0);
420
      end if;
421
   end Unlock;
422
 
423
   procedure Unlock (T : Task_Id) is
424
      Result : int;
425
   begin
426
      if not Single_Lock then
427
         Result := semGive (T.Common.LL.L.Mutex);
428
         pragma Assert (Result = 0);
429
      end if;
430
   end Unlock;
431
 
432
   -----------------
433
   -- Set_Ceiling --
434
   -----------------
435
 
436
   --  Dynamic priority ceilings are not supported by the underlying system
437
 
438
   procedure Set_Ceiling
439
     (L    : not null access Lock;
440
      Prio : System.Any_Priority)
441
   is
442
      pragma Unreferenced (L, Prio);
443
   begin
444
      null;
445
   end Set_Ceiling;
446
 
447
   -----------
448
   -- Sleep --
449
   -----------
450
 
451
   procedure Sleep (Self_ID : Task_Id; Reason : System.Tasking.Task_States) is
452
      pragma Unreferenced (Reason);
453
 
454
      Result : int;
455
 
456
   begin
457
      pragma Assert (Self_ID = Self);
458
 
459
      --  Release the mutex before sleeping
460
 
461
      Result :=
462
        semGive (if Single_Lock
463
                 then Single_RTS_Lock.Mutex
464
                 else Self_ID.Common.LL.L.Mutex);
465
      pragma Assert (Result = 0);
466
 
467
      --  Perform a blocking operation to take the CV semaphore. Note that a
468
      --  blocking operation in VxWorks will reenable task scheduling. When we
469
      --  are no longer blocked and control is returned, task scheduling will
470
      --  again be disabled.
471
 
472
      Result := semTake (Self_ID.Common.LL.CV, WAIT_FOREVER);
473
      pragma Assert (Result = 0);
474
 
475
      --  Take the mutex back
476
 
477
      Result :=
478
        semTake ((if Single_Lock
479
                  then Single_RTS_Lock.Mutex
480
                  else Self_ID.Common.LL.L.Mutex), WAIT_FOREVER);
481
      pragma Assert (Result = 0);
482
   end Sleep;
483
 
484
   -----------------
485
   -- Timed_Sleep --
486
   -----------------
487
 
488
   --  This is for use within the run-time system, so abort is assumed to be
489
   --  already deferred, and the caller should be holding its own ATCB lock.
490
 
491
   procedure Timed_Sleep
492
     (Self_ID  : Task_Id;
493
      Time     : Duration;
494
      Mode     : ST.Delay_Modes;
495
      Reason   : System.Tasking.Task_States;
496
      Timedout : out Boolean;
497
      Yielded  : out Boolean)
498
   is
499
      pragma Unreferenced (Reason);
500
 
501
      Orig     : constant Duration := Monotonic_Clock;
502
      Absolute : Duration;
503
      Ticks    : int;
504
      Result   : int;
505
      Wakeup   : Boolean := False;
506
 
507
   begin
508
      Timedout := False;
509
      Yielded  := True;
510
 
511
      if Mode = Relative then
512
         Absolute := Orig + Time;
513
 
514
         --  Systematically add one since the first tick will delay *at most*
515
         --  1 / Rate_Duration seconds, so we need to add one to be on the
516
         --  safe side.
517
 
518
         Ticks := To_Clock_Ticks (Time);
519
 
520
         if Ticks > 0 and then Ticks < int'Last then
521
            Ticks := Ticks + 1;
522
         end if;
523
 
524
      else
525
         Absolute := Time;
526
         Ticks    := To_Clock_Ticks (Time - Monotonic_Clock);
527
      end if;
528
 
529
      if Ticks > 0 then
530
         loop
531
            --  Release the mutex before sleeping
532
 
533
            Result :=
534
              semGive (if Single_Lock
535
                       then Single_RTS_Lock.Mutex
536
                       else Self_ID.Common.LL.L.Mutex);
537
            pragma Assert (Result = 0);
538
 
539
            --  Perform a blocking operation to take the CV semaphore. Note
540
            --  that a blocking operation in VxWorks will reenable task
541
            --  scheduling. When we are no longer blocked and control is
542
            --  returned, task scheduling will again be disabled.
543
 
544
            Result := semTake (Self_ID.Common.LL.CV, Ticks);
545
 
546
            if Result = 0 then
547
 
548
               --  Somebody may have called Wakeup for us
549
 
550
               Wakeup := True;
551
 
552
            else
553
               if errno /= S_objLib_OBJ_TIMEOUT then
554
                  Wakeup := True;
555
 
556
               else
557
                  --  If Ticks = int'last, it was most probably truncated so
558
                  --  let's make another round after recomputing Ticks from
559
                  --  the absolute time.
560
 
561
                  if Ticks /= int'Last then
562
                     Timedout := True;
563
 
564
                  else
565
                     Ticks := To_Clock_Ticks (Absolute - Monotonic_Clock);
566
 
567
                     if Ticks < 0 then
568
                        Timedout := True;
569
                     end if;
570
                  end if;
571
               end if;
572
            end if;
573
 
574
            --  Take the mutex back
575
 
576
            Result :=
577
              semTake ((if Single_Lock
578
                        then Single_RTS_Lock.Mutex
579
                        else Self_ID.Common.LL.L.Mutex), WAIT_FOREVER);
580
            pragma Assert (Result = 0);
581
 
582
            exit when Timedout or Wakeup;
583
         end loop;
584
 
585
      else
586
         Timedout := True;
587
 
588
         --  Should never hold a lock while yielding
589
 
590
         if Single_Lock then
591
            Result := semGive (Single_RTS_Lock.Mutex);
592
            taskDelay (0);
593
            Result := semTake (Single_RTS_Lock.Mutex, WAIT_FOREVER);
594
 
595
         else
596
            Result := semGive (Self_ID.Common.LL.L.Mutex);
597
            taskDelay (0);
598
            Result := semTake (Self_ID.Common.LL.L.Mutex, WAIT_FOREVER);
599
         end if;
600
      end if;
601
   end Timed_Sleep;
602
 
603
   -----------------
604
   -- Timed_Delay --
605
   -----------------
606
 
607
   --  This is for use in implementing delay statements, so we assume the
608
   --  caller is holding no locks.
609
 
610
   procedure Timed_Delay
611
     (Self_ID : Task_Id;
612
      Time    : Duration;
613
      Mode    : ST.Delay_Modes)
614
   is
615
      Orig     : constant Duration := Monotonic_Clock;
616
      Absolute : Duration;
617
      Ticks    : int;
618
      Timedout : Boolean;
619
      Aborted  : Boolean := False;
620
 
621
      Result : int;
622
      pragma Warnings (Off, Result);
623
 
624
   begin
625
      if Mode = Relative then
626
         Absolute := Orig + Time;
627
         Ticks    := To_Clock_Ticks (Time);
628
 
629
         if Ticks > 0 and then Ticks < int'Last then
630
 
631
            --  First tick will delay anytime between 0 and 1 / sysClkRateGet
632
            --  seconds, so we need to add one to be on the safe side.
633
 
634
            Ticks := Ticks + 1;
635
         end if;
636
 
637
      else
638
         Absolute := Time;
639
         Ticks    := To_Clock_Ticks (Time - Orig);
640
      end if;
641
 
642
      if Ticks > 0 then
643
 
644
         --  Modifying State, locking the TCB
645
 
646
         Result :=
647
           semTake ((if Single_Lock
648
                     then Single_RTS_Lock.Mutex
649
                     else Self_ID.Common.LL.L.Mutex), WAIT_FOREVER);
650
 
651
         pragma Assert (Result = 0);
652
 
653
         Self_ID.Common.State := Delay_Sleep;
654
         Timedout := False;
655
 
656
         loop
657
            Aborted := Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
658
 
659
            --  Release the TCB before sleeping
660
 
661
            Result :=
662
              semGive (if Single_Lock
663
                       then Single_RTS_Lock.Mutex
664
                       else Self_ID.Common.LL.L.Mutex);
665
            pragma Assert (Result = 0);
666
 
667
            exit when Aborted;
668
 
669
            Result := semTake (Self_ID.Common.LL.CV, Ticks);
670
 
671
            if Result /= 0 then
672
 
673
               --  If Ticks = int'last, it was most probably truncated
674
               --  so let's make another round after recomputing Ticks
675
               --  from the absolute time.
676
 
677
               if errno = S_objLib_OBJ_TIMEOUT and then Ticks /= int'Last then
678
                  Timedout := True;
679
               else
680
                  Ticks := To_Clock_Ticks (Absolute - Monotonic_Clock);
681
 
682
                  if Ticks < 0 then
683
                     Timedout := True;
684
                  end if;
685
               end if;
686
            end if;
687
 
688
            --  Take back the lock after having slept, to protect further
689
            --  access to Self_ID.
690
 
691
            Result :=
692
              semTake
693
                ((if Single_Lock
694
                  then Single_RTS_Lock.Mutex
695
                  else Self_ID.Common.LL.L.Mutex), WAIT_FOREVER);
696
 
697
            pragma Assert (Result = 0);
698
 
699
            exit when Timedout;
700
         end loop;
701
 
702
         Self_ID.Common.State := Runnable;
703
 
704
         Result :=
705
           semGive
706
             (if Single_Lock
707
              then Single_RTS_Lock.Mutex
708
              else Self_ID.Common.LL.L.Mutex);
709
 
710
      else
711
         taskDelay (0);
712
      end if;
713
   end Timed_Delay;
714
 
715
   ---------------------
716
   -- Monotonic_Clock --
717
   ---------------------
718
 
719
   function Monotonic_Clock return Duration is
720
      TS     : aliased timespec;
721
      Result : int;
722
   begin
723
      Result := clock_gettime (OSC.CLOCK_RT_Ada, TS'Unchecked_Access);
724
      pragma Assert (Result = 0);
725
      return To_Duration (TS);
726
   end Monotonic_Clock;
727
 
728
   -------------------
729
   -- RT_Resolution --
730
   -------------------
731
 
732
   function RT_Resolution return Duration is
733
   begin
734
      return 1.0 / Duration (sysClkRateGet);
735
   end RT_Resolution;
736
 
737
   ------------
738
   -- Wakeup --
739
   ------------
740
 
741
   procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
742
      pragma Unreferenced (Reason);
743
      Result : int;
744
   begin
745
      Result := semGive (T.Common.LL.CV);
746
      pragma Assert (Result = 0);
747
   end Wakeup;
748
 
749
   -----------
750
   -- Yield --
751
   -----------
752
 
753
   procedure Yield (Do_Yield : Boolean := True) is
754
      pragma Unreferenced (Do_Yield);
755
      Result : int;
756
      pragma Unreferenced (Result);
757
   begin
758
      Result := taskDelay (0);
759
   end Yield;
760
 
761
   ------------------
762
   -- Set_Priority --
763
   ------------------
764
 
765
   procedure Set_Priority
766
     (T                   : Task_Id;
767
      Prio                : System.Any_Priority;
768
      Loss_Of_Inheritance : Boolean := False)
769
   is
770
      pragma Unreferenced (Loss_Of_Inheritance);
771
 
772
      Result     : int;
773
 
774
   begin
775
      Result :=
776
        taskPrioritySet
777
          (T.Common.LL.Thread, To_VxWorks_Priority (int (Prio)));
778
      pragma Assert (Result = 0);
779
 
780
      --  Note: in VxWorks 6.6 (or earlier), the task is placed at the end of
781
      --  the priority queue instead of the head. This is not the behavior
782
      --  required by Annex D (RM D.2.3(5/2)), but we consider it an acceptable
783
      --  variation (RM 1.1.3(6)), given this is the built-in behavior of the
784
      --  operating system. VxWorks versions starting from 6.7 implement the
785
      --  required Annex D semantics.
786
 
787
      --  In older versions we attempted to better approximate the Annex D
788
      --  required behavior, but this simulation was not entirely accurate,
789
      --  and it seems better to live with the standard VxWorks semantics.
790
 
791
      T.Common.Current_Priority := Prio;
792
   end Set_Priority;
793
 
794
   ------------------
795
   -- Get_Priority --
796
   ------------------
797
 
798
   function Get_Priority (T : Task_Id) return System.Any_Priority is
799
   begin
800
      return T.Common.Current_Priority;
801
   end Get_Priority;
802
 
803
   ----------------
804
   -- Enter_Task --
805
   ----------------
806
 
807
   procedure Enter_Task (Self_ID : Task_Id) is
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
      --  Properly initializes the FPU for PPC/MIPS systems
819
 
820
      System.Float_Control.Reset;
821
 
822
      --  Install the signal handlers
823
 
824
      --  This is called for each task since there is no signal inheritance
825
      --  between VxWorks tasks.
826
 
827
      Install_Signal_Handlers;
828
 
829
      --  If stack checking is enabled, set the stack limit for this task
830
 
831
      if Set_Stack_Limit_Hook /= null then
832
         Set_Stack_Limit_Hook.all;
833
      end if;
834
   end Enter_Task;
835
 
836
   -------------------
837
   -- Is_Valid_Task --
838
   -------------------
839
 
840
   function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
841
 
842
   -----------------------------
843
   -- Register_Foreign_Thread --
844
   -----------------------------
845
 
846
   function Register_Foreign_Thread return Task_Id is
847
   begin
848
      if Is_Valid_Task then
849
         return Self;
850
      else
851
         return Register_Foreign_Thread (taskIdSelf);
852
      end if;
853
   end Register_Foreign_Thread;
854
 
855
   --------------------
856
   -- Initialize_TCB --
857
   --------------------
858
 
859
   procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
860
   begin
861
      Self_ID.Common.LL.CV := semBCreate (SEM_Q_PRIORITY, SEM_EMPTY);
862
      Self_ID.Common.LL.Thread := Null_Thread_Id;
863
 
864
      if Self_ID.Common.LL.CV = 0 then
865
         Succeeded := False;
866
 
867
      else
868
         Succeeded := True;
869
 
870
         if not Single_Lock then
871
            Initialize_Lock (Self_ID.Common.LL.L'Access, ATCB_Level);
872
         end if;
873
      end if;
874
   end Initialize_TCB;
875
 
876
   -----------------
877
   -- Create_Task --
878
   -----------------
879
 
880
   procedure Create_Task
881
     (T          : Task_Id;
882
      Wrapper    : System.Address;
883
      Stack_Size : System.Parameters.Size_Type;
884
      Priority   : System.Any_Priority;
885
      Succeeded  : out Boolean)
886
   is
887
      Adjusted_Stack_Size : size_t;
888
 
889
      use type System.Multiprocessors.CPU_Range;
890
 
891
   begin
892
      --  Check whether both Dispatching_Domain and CPU are specified for the
893
      --  task, and the CPU value is not contained within the range of
894
      --  processors for the domain.
895
 
896
      if T.Common.Domain /= null
897
        and then T.Common.Base_CPU /= System.Multiprocessors.Not_A_Specific_CPU
898
        and then
899
          (T.Common.Base_CPU not in T.Common.Domain'Range
900
            or else not T.Common.Domain (T.Common.Base_CPU))
901
      then
902
         Succeeded := False;
903
         return;
904
      end if;
905
 
906
      --  Ask for four extra bytes of stack space so that the ATCB pointer can
907
      --  be stored below the stack limit, plus extra space for the frame of
908
      --  Task_Wrapper. This is so the user gets the amount of stack requested
909
      --  exclusive of the needs.
910
 
911
      --  We also have to allocate n more bytes for the task name storage and
912
      --  enough space for the Wind Task Control Block which is around 0x778
913
      --  bytes. VxWorks also seems to carve out additional space, so use 2048
914
      --  as a nice round number. We might want to increment to the nearest
915
      --  page size in case we ever support VxVMI.
916
 
917
      --  ??? - we should come back and visit this so we can set the task name
918
      --        to something appropriate.
919
 
920
      Adjusted_Stack_Size := size_t (Stack_Size) + 2048;
921
 
922
      --  Since the initial signal mask of a thread is inherited from the
923
      --  creator, and the Environment task has all its signals masked, we do
924
      --  not need to manipulate caller's signal mask at this point. All tasks
925
      --  in RTS will have All_Tasks_Mask initially.
926
 
927
      --  We now compute the VxWorks task name and options, then spawn ...
928
 
929
      declare
930
         Name         : aliased String (1 .. T.Common.Task_Image_Len + 1);
931
         Name_Address : System.Address;
932
         --  Task name we are going to hand down to VxWorks
933
 
934
         function Get_Task_Options return int;
935
         pragma Import (C, Get_Task_Options, "__gnat_get_task_options");
936
         --  Function that returns the options to be set for the task that we
937
         --  are creating. We fetch the options assigned to the current task,
938
         --  so offering some user level control over the options for a task
939
         --  hierarchy, and force VX_FP_TASK because it is almost always
940
         --  required.
941
 
942
      begin
943
         --  If there is no Ada task name handy, let VxWorks choose one.
944
         --  Otherwise, tell VxWorks what the Ada task name is.
945
 
946
         if T.Common.Task_Image_Len = 0 then
947
            Name_Address := System.Null_Address;
948
         else
949
            Name (1 .. Name'Last - 1) :=
950
              T.Common.Task_Image (1 .. T.Common.Task_Image_Len);
951
            Name (Name'Last) := ASCII.NUL;
952
            Name_Address := Name'Address;
953
         end if;
954
 
955
         --  Now spawn the VxWorks task for real
956
 
957
         T.Common.LL.Thread :=
958
           taskSpawn
959
             (Name_Address,
960
              To_VxWorks_Priority (int (Priority)),
961
              Get_Task_Options,
962
              Adjusted_Stack_Size,
963
              Wrapper,
964
              To_Address (T));
965
      end;
966
 
967
      --  Set processor affinity
968
 
969
      Set_Task_Affinity (T);
970
 
971
      if T.Common.LL.Thread <= Null_Thread_Id then
972
         Succeeded := False;
973
      else
974
         Succeeded := True;
975
         Task_Creation_Hook (T.Common.LL.Thread);
976
         Set_Priority (T, Priority);
977
      end if;
978
   end Create_Task;
979
 
980
   ------------------
981
   -- Finalize_TCB --
982
   ------------------
983
 
984
   procedure Finalize_TCB (T : Task_Id) is
985
      Result : int;
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 := Null_Thread_Id;
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
      ATCB_Allocation.Free_ATCB (T);
1003
   end Finalize_TCB;
1004
 
1005
   ---------------
1006
   -- Exit_Task --
1007
   ---------------
1008
 
1009
   procedure Exit_Task is
1010
   begin
1011
      Specific.Set (null);
1012
   end Exit_Task;
1013
 
1014
   ----------------
1015
   -- Abort_Task --
1016
   ----------------
1017
 
1018
   procedure Abort_Task (T : Task_Id) is
1019
      Result : int;
1020
   begin
1021
      Result :=
1022
        kill
1023
          (T.Common.LL.Thread,
1024
           Signal (Interrupt_Management.Abort_Task_Interrupt));
1025
      pragma Assert (Result = 0);
1026
   end Abort_Task;
1027
 
1028
   ----------------
1029
   -- Initialize --
1030
   ----------------
1031
 
1032
   procedure Initialize (S : in out Suspension_Object) is
1033
   begin
1034
      --  Initialize internal state (always to False (RM D.10(6)))
1035
 
1036
      S.State := False;
1037
      S.Waiting := False;
1038
 
1039
      --  Initialize internal mutex
1040
 
1041
      --  Use simpler binary semaphore instead of VxWorks
1042
      --  mutual exclusion semaphore, because we don't need
1043
      --  the fancier semantics and their overhead.
1044
 
1045
      S.L := semBCreate (SEM_Q_FIFO, SEM_FULL);
1046
 
1047
      --  Initialize internal condition variable
1048
 
1049
      S.CV := semBCreate (SEM_Q_FIFO, SEM_EMPTY);
1050
   end Initialize;
1051
 
1052
   --------------
1053
   -- Finalize --
1054
   --------------
1055
 
1056
   procedure Finalize (S : in out Suspension_Object) is
1057
      pragma Unmodified (S);
1058
      --  S may be modified on other targets, but not on VxWorks
1059
 
1060
      Result : STATUS;
1061
 
1062
   begin
1063
      --  Destroy internal mutex
1064
 
1065
      Result := semDelete (S.L);
1066
      pragma Assert (Result = OK);
1067
 
1068
      --  Destroy internal condition variable
1069
 
1070
      Result := semDelete (S.CV);
1071
      pragma Assert (Result = OK);
1072
   end Finalize;
1073
 
1074
   -------------------
1075
   -- Current_State --
1076
   -------------------
1077
 
1078
   function Current_State (S : Suspension_Object) return Boolean is
1079
   begin
1080
      --  We do not want to use lock on this read operation. State is marked
1081
      --  as Atomic so that we ensure that the value retrieved is correct.
1082
 
1083
      return S.State;
1084
   end Current_State;
1085
 
1086
   ---------------
1087
   -- Set_False --
1088
   ---------------
1089
 
1090
   procedure Set_False (S : in out Suspension_Object) is
1091
      Result : STATUS;
1092
 
1093
   begin
1094
      SSL.Abort_Defer.all;
1095
 
1096
      Result := semTake (S.L, WAIT_FOREVER);
1097
      pragma Assert (Result = OK);
1098
 
1099
      S.State := False;
1100
 
1101
      Result := semGive (S.L);
1102
      pragma Assert (Result = OK);
1103
 
1104
      SSL.Abort_Undefer.all;
1105
   end Set_False;
1106
 
1107
   --------------
1108
   -- Set_True --
1109
   --------------
1110
 
1111
   procedure Set_True (S : in out Suspension_Object) is
1112
      Result : STATUS;
1113
 
1114
   begin
1115
      --  Set_True can be called from an interrupt context, in which case
1116
      --  Abort_Defer is undefined.
1117
 
1118
      if Is_Task_Context then
1119
         SSL.Abort_Defer.all;
1120
      end if;
1121
 
1122
      Result := semTake (S.L, WAIT_FOREVER);
1123
      pragma Assert (Result = OK);
1124
 
1125
      --  If there is already a task waiting on this suspension object then
1126
      --  we resume it, leaving the state of the suspension object to False,
1127
      --  as it is specified in ARM D.10 par. 9. Otherwise, it just leaves
1128
      --  the state to True.
1129
 
1130
      if S.Waiting then
1131
         S.Waiting := False;
1132
         S.State := False;
1133
 
1134
         Result := semGive (S.CV);
1135
         pragma Assert (Result = OK);
1136
      else
1137
         S.State := True;
1138
      end if;
1139
 
1140
      Result := semGive (S.L);
1141
      pragma Assert (Result = OK);
1142
 
1143
      --  Set_True can be called from an interrupt context, in which case
1144
      --  Abort_Undefer is undefined.
1145
 
1146
      if Is_Task_Context then
1147
         SSL.Abort_Undefer.all;
1148
      end if;
1149
 
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 /= Null_Thread_Id
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 /= Null_Thread_Id
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 /= Null_Thread_Id
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 /= Null_Thread_Id 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 /= Null_Thread_Id 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
   -- Is_Task_Context --
1349
   ---------------------
1350
 
1351
   function Is_Task_Context return Boolean is
1352
   begin
1353
      return System.OS_Interface.Interrupt_Context /= 1;
1354
   end Is_Task_Context;
1355
 
1356
   ----------------
1357
   -- Initialize --
1358
   ----------------
1359
 
1360
   procedure Initialize (Environment_Task : Task_Id) is
1361
      Result : int;
1362
      pragma Unreferenced (Result);
1363
 
1364
   begin
1365
      Environment_Task_Id := Environment_Task;
1366
 
1367
      Interrupt_Management.Initialize;
1368
      Specific.Initialize;
1369
 
1370
      if Locking_Policy = 'C' then
1371
         Mutex_Protocol := Prio_Protect;
1372
      elsif Locking_Policy = 'I' then
1373
         Mutex_Protocol := Prio_Inherit;
1374
      else
1375
         Mutex_Protocol := Prio_None;
1376
      end if;
1377
 
1378
      if Time_Slice_Val > 0 then
1379
         Result :=
1380
           Set_Time_Slice
1381
             (To_Clock_Ticks
1382
                (Duration (Time_Slice_Val) / Duration (1_000_000.0)));
1383
 
1384
      elsif Dispatching_Policy = 'R' then
1385
         Result := Set_Time_Slice (To_Clock_Ticks (0.01));
1386
 
1387
      end if;
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
 
1401
      --  Set processor affinity
1402
 
1403
      Set_Task_Affinity (Environment_Task);
1404
   end Initialize;
1405
 
1406
   -----------------------
1407
   -- Set_Task_Affinity --
1408
   -----------------------
1409
 
1410
   procedure Set_Task_Affinity (T : ST.Task_Id) is
1411
      Result : int := 0;
1412
      pragma Unreferenced (Result);
1413
 
1414
      use System.Task_Info;
1415
      use type System.Multiprocessors.CPU_Range;
1416
 
1417
   begin
1418
      --  Do nothing if the underlying thread has not yet been created. If the
1419
      --  thread has not yet been created then the proper affinity will be set
1420
      --  during its creation.
1421
 
1422
      if T.Common.LL.Thread = Null_Thread_Id then
1423
         null;
1424
 
1425
      --  pragma CPU
1426
 
1427
      elsif T.Common.Base_CPU /= Multiprocessors.Not_A_Specific_CPU then
1428
 
1429
         --  Ada 2012 pragma CPU uses CPU numbers starting from 1, while on
1430
         --  VxWorks the first CPU is identified by a 0, so we need to adjust.
1431
 
1432
         Result :=
1433
           taskCpuAffinitySet
1434
             (T.Common.LL.Thread, int (T.Common.Base_CPU) - 1);
1435
 
1436
      --  Task_Info
1437
 
1438
      elsif T.Common.Task_Info /= Unspecified_Task_Info then
1439
         Result := taskCpuAffinitySet (T.Common.LL.Thread, T.Common.Task_Info);
1440
 
1441
      --  Handle dispatching domains
1442
 
1443
      elsif T.Common.Domain /= null
1444
        and then (T.Common.Domain /= ST.System_Domain
1445
                   or else T.Common.Domain.all /=
1446
                             (Multiprocessors.CPU'First ..
1447
                              Multiprocessors.Number_Of_CPUs => True))
1448
      then
1449
         declare
1450
            CPU_Set : unsigned := 0;
1451
 
1452
         begin
1453
            --  Set the affinity to all the processors belonging to the
1454
            --  dispatching domain.
1455
 
1456
            for Proc in T.Common.Domain'Range loop
1457
               if T.Common.Domain (Proc) then
1458
 
1459
                  --  The thread affinity mask is a bit vector in which each
1460
                  --  bit represents a logical processor.
1461
 
1462
                  CPU_Set := CPU_Set + 2 ** (Integer (Proc) - 1);
1463
               end if;
1464
            end loop;
1465
 
1466
            Result := taskMaskAffinitySet (T.Common.LL.Thread, CPU_Set);
1467
         end;
1468
      end if;
1469
   end Set_Task_Affinity;
1470
 
1471
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.