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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.5.1/] [gcc/] [ada/] [s-taprop-tru64.adb] - Blame information for rev 299

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

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