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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [gcc/] [ada/] [s-taprop-lynxos.adb] - Blame information for rev 12

Details | Compare with Previous | View Log

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