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-hpux-dce.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 HP-UX DCE threads (HPUX 10) version of this package
35
 
36
--  This package contains all the GNULL primitives that interface directly
37
--  with the underlying OS.
38
 
39
pragma Polling (Off);
40
--  Turn off polling, we do not want ATC polling to take place during
41
--  tasking operations. It causes infinite loops and other problems.
42
 
43
with System.Tasking.Debug;
44
--  used for Known_Tasks
45
 
46
with System.Interrupt_Management;
47
--  used for Keep_Unmasked
48
--           Abort_Task_Interrupt
49
--           Interrupt_ID
50
 
51
pragma Warnings (Off);
52
with System.Interrupt_Management.Operations;
53
--  used for Set_Interrupt_Mask
54
--           All_Tasks_Mask
55
pragma Elaborate_All (System.Interrupt_Management.Operations);
56
 
57
pragma Warnings (On);
58
 
59
with System.OS_Primitives;
60
--  used for Delay_Modes
61
 
62
with Interfaces.C;
63
--  used for int
64
--           size_t
65
 
66
with System.Parameters;
67
--  used for Size_Type
68
 
69
with System.Task_Primitives.Interrupt_Operations;
70
--  used for Get_Interrupt_ID
71
 
72
with Unchecked_Conversion;
73
with Unchecked_Deallocation;
74
 
75
package body System.Task_Primitives.Operations is
76
 
77
   use System.Tasking.Debug;
78
   use System.Tasking;
79
   use Interfaces.C;
80
   use System.OS_Interface;
81
   use System.Parameters;
82
   use System.OS_Primitives;
83
 
84
   package PIO renames System.Task_Primitives.Interrupt_Operations;
85
 
86
   ----------------
87
   -- Local Data --
88
   ----------------
89
 
90
   --  The followings are logically constants, but need to be initialized
91
   --  at run time.
92
 
93
   Single_RTS_Lock : aliased RTS_Lock;
94
   --  This is a lock to allow only one thread of control in the RTS at
95
   --  a time; it is used to execute in mutual exclusion from all other tasks.
96
   --  Used mainly in Single_Lock mode, but also to protect All_Tasks_List
97
 
98
   ATCB_Key : aliased pthread_key_t;
99
   --  Key used to find the Ada Task_Id associated with a thread
100
 
101
   Environment_Task_Id : Task_Id;
102
   --  A variable to hold Task_Id for the environment task
103
 
104
   Unblocked_Signal_Mask : aliased sigset_t;
105
   --  The set of signals that should unblocked in all tasks
106
 
107
   Time_Slice_Val : Integer;
108
   pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
109
 
110
   Dispatching_Policy : Character;
111
   pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
112
 
113
   --  Note: the reason that Locking_Policy is not needed is that this
114
   --  is not implemented for DCE threads. The HPUX 10 port is at this
115
   --  stage considered dead, and no further work is planned on it.
116
 
117
   Foreign_Task_Elaborated : aliased Boolean := True;
118
   --  Used to identified fake tasks (i.e., non-Ada Threads)
119
 
120
   --------------------
121
   -- Local Packages --
122
   --------------------
123
 
124
   package Specific is
125
 
126
      procedure Initialize (Environment_Task : Task_Id);
127
      pragma Inline (Initialize);
128
      --  Initialize various data needed by this package
129
 
130
      function Is_Valid_Task return Boolean;
131
      pragma Inline (Is_Valid_Task);
132
      --  Does the executing thread have a TCB?
133
 
134
      procedure Set (Self_Id : Task_Id);
135
      pragma Inline (Set);
136
      --  Set the self id for the current task
137
 
138
      function Self return Task_Id;
139
      pragma Inline (Self);
140
      --  Return a pointer to the Ada Task Control Block of the calling task
141
 
142
   end Specific;
143
 
144
   package body Specific is separate;
145
   --  The body of this package is target specific
146
 
147
   ---------------------------------
148
   -- Support for foreign threads --
149
   ---------------------------------
150
 
151
   function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
152
   --  Allocate and Initialize a new ATCB for the current Thread
153
 
154
   function Register_Foreign_Thread
155
     (Thread : Thread_Id) return Task_Id is separate;
156
 
157
   -----------------------
158
   -- Local Subprograms --
159
   -----------------------
160
 
161
   procedure Abort_Handler (Sig : Signal);
162
 
163
   function To_Address is new Unchecked_Conversion (Task_Id, System.Address);
164
 
165
   -------------------
166
   -- Abort_Handler --
167
   -------------------
168
 
169
   procedure Abort_Handler (Sig : Signal) is
170
      pragma Unreferenced (Sig);
171
 
172
      Self_Id : constant Task_Id := Self;
173
      Result  : Interfaces.C.int;
174
      Old_Set : aliased sigset_t;
175
 
176
   begin
177
      if Self_Id.Deferral_Level = 0
178
        and then Self_Id.Pending_ATC_Level < Self_Id.ATC_Nesting_Level and then
179
        not Self_Id.Aborting
180
      then
181
         Self_Id.Aborting := True;
182
 
183
         --  Make sure signals used for RTS internal purpose are unmasked
184
 
185
         Result := pthread_sigmask (SIG_UNBLOCK,
186
           Unblocked_Signal_Mask'Unchecked_Access, Old_Set'Unchecked_Access);
187
         pragma Assert (Result = 0);
188
 
189
         raise Standard'Abort_Signal;
190
      end if;
191
   end Abort_Handler;
192
 
193
   -----------------
194
   -- Stack_Guard --
195
   -----------------
196
 
197
   --  The underlying thread system sets a guard page at the
198
   --  bottom of a thread stack, so nothing is needed.
199
   --  ??? Check the comment above
200
 
201
   procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is
202
      pragma Unreferenced (T, On);
203
   begin
204
      null;
205
   end Stack_Guard;
206
 
207
   -------------------
208
   -- Get_Thread_Id --
209
   -------------------
210
 
211
   function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is
212
   begin
213
      return T.Common.LL.Thread;
214
   end Get_Thread_Id;
215
 
216
   ----------
217
   -- Self --
218
   ----------
219
 
220
   function Self return Task_Id renames Specific.Self;
221
 
222
   ---------------------
223
   -- Initialize_Lock --
224
   ---------------------
225
 
226
   --  Note: mutexes and cond_variables needed per-task basis are
227
   --        initialized in Initialize_TCB and the Storage_Error is
228
   --        handled. Other mutexes (such as RTS_Lock, Memory_Lock...)
229
   --        used in RTS is initialized before any status change of RTS.
230
   --        Therefore rasing Storage_Error in the following routines
231
   --        should be able to be handled safely.
232
 
233
   procedure Initialize_Lock
234
     (Prio : System.Any_Priority;
235
      L    : access Lock)
236
   is
237
      Attributes : aliased pthread_mutexattr_t;
238
      Result     : Interfaces.C.int;
239
 
240
   begin
241
      Result := pthread_mutexattr_init (Attributes'Access);
242
      pragma Assert (Result = 0 or else Result = ENOMEM);
243
 
244
      if Result = ENOMEM then
245
         raise Storage_Error;
246
      end if;
247
 
248
      L.Priority := Prio;
249
 
250
      Result := pthread_mutex_init (L.L'Access, Attributes'Access);
251
      pragma Assert (Result = 0 or else Result = ENOMEM);
252
 
253
      if Result = ENOMEM then
254
         raise Storage_Error;
255
      end if;
256
 
257
      Result := pthread_mutexattr_destroy (Attributes'Access);
258
      pragma Assert (Result = 0);
259
   end Initialize_Lock;
260
 
261
   procedure Initialize_Lock (L : access RTS_Lock; Level : Lock_Level) is
262
      pragma Unreferenced (Level);
263
 
264
      Attributes : aliased pthread_mutexattr_t;
265
      Result     : Interfaces.C.int;
266
 
267
   begin
268
      Result := pthread_mutexattr_init (Attributes'Access);
269
      pragma Assert (Result = 0 or else Result = ENOMEM);
270
 
271
      if Result = ENOMEM then
272
         raise Storage_Error;
273
      end if;
274
 
275
      Result := pthread_mutex_init (L, Attributes'Access);
276
 
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_mutexattr_destroy (Attributes'Access);
284
      pragma Assert (Result = 0);
285
   end Initialize_Lock;
286
 
287
   -------------------
288
   -- Finalize_Lock --
289
   -------------------
290
 
291
   procedure Finalize_Lock (L : access Lock) is
292
      Result : Interfaces.C.int;
293
   begin
294
      Result := pthread_mutex_destroy (L.L'Access);
295
      pragma Assert (Result = 0);
296
   end Finalize_Lock;
297
 
298
   procedure Finalize_Lock (L : access RTS_Lock) is
299
      Result : Interfaces.C.int;
300
   begin
301
      Result := pthread_mutex_destroy (L);
302
      pragma Assert (Result = 0);
303
   end Finalize_Lock;
304
 
305
   ----------------
306
   -- Write_Lock --
307
   ----------------
308
 
309
   procedure Write_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
310
      Result : Interfaces.C.int;
311
 
312
   begin
313
      L.Owner_Priority := Get_Priority (Self);
314
 
315
      if L.Priority < L.Owner_Priority then
316
         Ceiling_Violation := True;
317
         return;
318
      end if;
319
 
320
      Result := pthread_mutex_lock (L.L'Access);
321
      pragma Assert (Result = 0);
322
      Ceiling_Violation := False;
323
   end Write_Lock;
324
 
325
   procedure Write_Lock
326
     (L : access RTS_Lock; Global_Lock : Boolean := False)
327
   is
328
      Result : Interfaces.C.int;
329
   begin
330
      if not Single_Lock or else Global_Lock then
331
         Result := pthread_mutex_lock (L);
332
         pragma Assert (Result = 0);
333
      end if;
334
   end Write_Lock;
335
 
336
   procedure Write_Lock (T : Task_Id) is
337
      Result : Interfaces.C.int;
338
   begin
339
      if not Single_Lock then
340
         Result := pthread_mutex_lock (T.Common.LL.L'Access);
341
         pragma Assert (Result = 0);
342
      end if;
343
   end Write_Lock;
344
 
345
   ---------------
346
   -- Read_Lock --
347
   ---------------
348
 
349
   procedure Read_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
350
   begin
351
      Write_Lock (L, Ceiling_Violation);
352
   end Read_Lock;
353
 
354
   ------------
355
   -- Unlock --
356
   ------------
357
 
358
   procedure Unlock (L : access Lock) is
359
      Result : Interfaces.C.int;
360
   begin
361
      Result := pthread_mutex_unlock (L.L'Access);
362
      pragma Assert (Result = 0);
363
   end Unlock;
364
 
365
   procedure Unlock (L : access RTS_Lock; Global_Lock : Boolean := False) is
366
      Result : Interfaces.C.int;
367
   begin
368
      if not Single_Lock or else Global_Lock then
369
         Result := pthread_mutex_unlock (L);
370
         pragma Assert (Result = 0);
371
      end if;
372
   end Unlock;
373
 
374
   procedure Unlock (T : Task_Id) is
375
      Result : Interfaces.C.int;
376
   begin
377
      if not Single_Lock then
378
         Result := pthread_mutex_unlock (T.Common.LL.L'Access);
379
         pragma Assert (Result = 0);
380
      end if;
381
   end Unlock;
382
 
383
   -----------
384
   -- Sleep --
385
   -----------
386
 
387
   procedure Sleep
388
     (Self_ID : Task_Id;
389
      Reason  : System.Tasking.Task_States)
390
   is
391
      pragma Unreferenced (Reason);
392
 
393
      Result : Interfaces.C.int;
394
   begin
395
      if Single_Lock then
396
         Result := pthread_cond_wait
397
           (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access);
398
      else
399
         Result := pthread_cond_wait
400
           (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
401
      end if;
402
 
403
      --  EINTR is not considered a failure
404
 
405
      pragma Assert (Result = 0 or else Result = EINTR);
406
   end Sleep;
407
 
408
   -----------------
409
   -- Timed_Sleep --
410
   -----------------
411
 
412
   procedure Timed_Sleep
413
     (Self_ID  : Task_Id;
414
      Time     : Duration;
415
      Mode     : ST.Delay_Modes;
416
      Reason   : System.Tasking.Task_States;
417
      Timedout : out Boolean;
418
      Yielded  : out Boolean)
419
   is
420
      pragma Unreferenced (Reason);
421
 
422
      Check_Time : constant Duration := Monotonic_Clock;
423
      Abs_Time   : Duration;
424
      Request    : aliased timespec;
425
      Result     : Interfaces.C.int;
426
 
427
   begin
428
      Timedout := True;
429
      Yielded := False;
430
 
431
      if Mode = Relative then
432
         Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
433
      else
434
         Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
435
      end if;
436
 
437
      if Abs_Time > Check_Time then
438
         Request := To_Timespec (Abs_Time);
439
 
440
         loop
441
            exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
442
              or else Self_ID.Pending_Priority_Change;
443
 
444
            if Single_Lock then
445
               Result := pthread_cond_timedwait
446
                 (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access,
447
                  Request'Access);
448
 
449
            else
450
               Result := pthread_cond_timedwait
451
                 (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access,
452
                  Request'Access);
453
            end if;
454
 
455
            exit when Abs_Time <= Monotonic_Clock;
456
 
457
            if Result = 0 or Result = EINTR then
458
 
459
               --  Somebody may have called Wakeup for us
460
 
461
               Timedout := False;
462
               exit;
463
            end if;
464
 
465
            pragma Assert (Result = ETIMEDOUT);
466
         end loop;
467
      end if;
468
   end Timed_Sleep;
469
 
470
   -----------------
471
   -- Timed_Delay --
472
   -----------------
473
 
474
   procedure Timed_Delay
475
     (Self_ID  : Task_Id;
476
      Time     : Duration;
477
      Mode     : ST.Delay_Modes)
478
   is
479
      Check_Time : constant Duration := Monotonic_Clock;
480
      Abs_Time   : Duration;
481
      Request    : aliased timespec;
482
      Result     : Interfaces.C.int;
483
 
484
   begin
485
      if Single_Lock then
486
         Lock_RTS;
487
      end if;
488
 
489
      Write_Lock (Self_ID);
490
 
491
      if Mode = Relative then
492
         Abs_Time := Time + Check_Time;
493
      else
494
         Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
495
      end if;
496
 
497
      if Abs_Time > Check_Time then
498
         Request := To_Timespec (Abs_Time);
499
         Self_ID.Common.State := Delay_Sleep;
500
 
501
         loop
502
            if Self_ID.Pending_Priority_Change then
503
               Self_ID.Pending_Priority_Change := False;
504
               Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
505
               Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
506
            end if;
507
 
508
            exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
509
 
510
            if Single_Lock then
511
               Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
512
                 Single_RTS_Lock'Access, Request'Access);
513
            else
514
               Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
515
                 Self_ID.Common.LL.L'Access, Request'Access);
516
            end if;
517
 
518
            exit when Abs_Time <= Monotonic_Clock;
519
 
520
            pragma Assert (Result = 0 or else
521
              Result = ETIMEDOUT or else
522
              Result = EINTR);
523
         end loop;
524
 
525
         Self_ID.Common.State := Runnable;
526
      end if;
527
 
528
      Unlock (Self_ID);
529
 
530
      if Single_Lock then
531
         Unlock_RTS;
532
      end if;
533
 
534
      Result := sched_yield;
535
   end Timed_Delay;
536
 
537
   ---------------------
538
   -- Monotonic_Clock --
539
   ---------------------
540
 
541
   function Monotonic_Clock return Duration is
542
      TS     : aliased timespec;
543
      Result : Interfaces.C.int;
544
   begin
545
      Result := Clock_Gettime (CLOCK_REALTIME, TS'Unchecked_Access);
546
      pragma Assert (Result = 0);
547
      return To_Duration (TS);
548
   end Monotonic_Clock;
549
 
550
   -------------------
551
   -- RT_Resolution --
552
   -------------------
553
 
554
   function RT_Resolution return Duration is
555
   begin
556
      return 10#1.0#E-6;
557
   end RT_Resolution;
558
 
559
   ------------
560
   -- Wakeup --
561
   ------------
562
 
563
   procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
564
      pragma Unreferenced (Reason);
565
 
566
      Result : Interfaces.C.int;
567
 
568
   begin
569
      Result := pthread_cond_signal (T.Common.LL.CV'Access);
570
      pragma Assert (Result = 0);
571
   end Wakeup;
572
 
573
   -----------
574
   -- Yield --
575
   -----------
576
 
577
   procedure Yield (Do_Yield : Boolean := True) is
578
      Result : Interfaces.C.int;
579
      pragma Unreferenced (Result);
580
   begin
581
      if Do_Yield then
582
         Result := sched_yield;
583
      end if;
584
   end Yield;
585
 
586
   ------------------
587
   -- Set_Priority --
588
   ------------------
589
 
590
   type Prio_Array_Type is array (System.Any_Priority) of Integer;
591
   pragma Atomic_Components (Prio_Array_Type);
592
 
593
   Prio_Array : Prio_Array_Type;
594
   --  Global array containing the id of the currently running task for
595
   --  each priority.
596
   --
597
   --  Note: we assume that we are on a single processor with run-til-blocked
598
   --  scheduling.
599
 
600
   procedure Set_Priority
601
     (T                   : Task_Id;
602
      Prio                : System.Any_Priority;
603
      Loss_Of_Inheritance : Boolean := False)
604
   is
605
      Result     : Interfaces.C.int;
606
      Array_Item : Integer;
607
      Param      : aliased struct_sched_param;
608
 
609
   begin
610
      Param.sched_priority  := Interfaces.C.int (Underlying_Priorities (Prio));
611
 
612
      if Time_Slice_Val > 0 then
613
         Result := pthread_setschedparam
614
           (T.Common.LL.Thread, SCHED_RR, Param'Access);
615
 
616
      elsif Dispatching_Policy = 'F' or else Time_Slice_Val = 0 then
617
         Result := pthread_setschedparam
618
           (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
619
 
620
      else
621
         Result := pthread_setschedparam
622
           (T.Common.LL.Thread, SCHED_OTHER, Param'Access);
623
      end if;
624
 
625
      pragma Assert (Result = 0);
626
 
627
      if Dispatching_Policy = 'F' then
628
 
629
         --  Annex D requirement [RM D.2.2 par. 9]:
630
         --    If the task drops its priority due to the loss of inherited
631
         --    priority, it is added at the head of the ready queue for its
632
         --    new active priority.
633
 
634
         if Loss_Of_Inheritance
635
           and then Prio < T.Common.Current_Priority
636
         then
637
            Array_Item := Prio_Array (T.Common.Base_Priority) + 1;
638
            Prio_Array (T.Common.Base_Priority) := Array_Item;
639
 
640
            loop
641
               --  Let some processes a chance to arrive
642
 
643
               Yield;
644
 
645
               --  Then wait for our turn to proceed
646
 
647
               exit when Array_Item = Prio_Array (T.Common.Base_Priority)
648
                 or else Prio_Array (T.Common.Base_Priority) = 1;
649
            end loop;
650
 
651
            Prio_Array (T.Common.Base_Priority) :=
652
              Prio_Array (T.Common.Base_Priority) - 1;
653
         end if;
654
      end if;
655
 
656
      T.Common.Current_Priority := Prio;
657
   end Set_Priority;
658
 
659
   ------------------
660
   -- Get_Priority --
661
   ------------------
662
 
663
   function Get_Priority (T : Task_Id) return System.Any_Priority is
664
   begin
665
      return T.Common.Current_Priority;
666
   end Get_Priority;
667
 
668
   ----------------
669
   -- Enter_Task --
670
   ----------------
671
 
672
   procedure Enter_Task (Self_ID : Task_Id) is
673
   begin
674
      Self_ID.Common.LL.Thread := pthread_self;
675
      Specific.Set (Self_ID);
676
 
677
      Lock_RTS;
678
 
679
      for J in Known_Tasks'Range loop
680
         if Known_Tasks (J) = null then
681
            Known_Tasks (J) := Self_ID;
682
            Self_ID.Known_Tasks_Index := J;
683
            exit;
684
         end if;
685
      end loop;
686
 
687
      Unlock_RTS;
688
   end Enter_Task;
689
 
690
   --------------
691
   -- New_ATCB --
692
   --------------
693
 
694
   function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
695
   begin
696
      return new Ada_Task_Control_Block (Entry_Num);
697
   end New_ATCB;
698
 
699
   -------------------
700
   -- Is_Valid_Task --
701
   -------------------
702
 
703
   function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
704
 
705
   -----------------------------
706
   -- Register_Foreign_Thread --
707
   -----------------------------
708
 
709
   function Register_Foreign_Thread return Task_Id is
710
   begin
711
      if Is_Valid_Task then
712
         return Self;
713
      else
714
         return Register_Foreign_Thread (pthread_self);
715
      end if;
716
   end Register_Foreign_Thread;
717
 
718
   --------------------
719
   -- Initialize_TCB --
720
   --------------------
721
 
722
   procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
723
      Mutex_Attr : aliased pthread_mutexattr_t;
724
      Result     : Interfaces.C.int;
725
      Cond_Attr  : aliased pthread_condattr_t;
726
 
727
   begin
728
      if not Single_Lock then
729
         Result := pthread_mutexattr_init (Mutex_Attr'Access);
730
         pragma Assert (Result = 0 or else Result = ENOMEM);
731
 
732
         if Result = 0 then
733
            Result := pthread_mutex_init (Self_ID.Common.LL.L'Access,
734
              Mutex_Attr'Access);
735
            pragma Assert (Result = 0 or else Result = ENOMEM);
736
         end if;
737
 
738
         if Result /= 0 then
739
            Succeeded := False;
740
            return;
741
         end if;
742
 
743
         Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
744
         pragma Assert (Result = 0);
745
      end if;
746
 
747
      Result := pthread_condattr_init (Cond_Attr'Access);
748
      pragma Assert (Result = 0 or else Result = ENOMEM);
749
 
750
      if Result = 0 then
751
         Result := pthread_cond_init (Self_ID.Common.LL.CV'Access,
752
           Cond_Attr'Access);
753
         pragma Assert (Result = 0 or else Result = ENOMEM);
754
      end if;
755
 
756
      if Result = 0 then
757
         Succeeded := True;
758
      else
759
         if not Single_Lock then
760
            Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
761
            pragma Assert (Result = 0);
762
         end if;
763
 
764
         Succeeded := False;
765
      end if;
766
 
767
      Result := pthread_condattr_destroy (Cond_Attr'Access);
768
      pragma Assert (Result = 0);
769
   end Initialize_TCB;
770
 
771
   -----------------
772
   -- Create_Task --
773
   -----------------
774
 
775
   procedure Create_Task
776
     (T          : Task_Id;
777
      Wrapper    : System.Address;
778
      Stack_Size : System.Parameters.Size_Type;
779
      Priority   : System.Any_Priority;
780
      Succeeded  : out Boolean)
781
   is
782
      Attributes          : aliased pthread_attr_t;
783
      Adjusted_Stack_Size : Interfaces.C.size_t;
784
      Result              : Interfaces.C.int;
785
 
786
      function Thread_Body_Access is new
787
        Unchecked_Conversion (System.Address, Thread_Body);
788
 
789
   begin
790
      if Stack_Size = Unspecified_Size then
791
         Adjusted_Stack_Size := Interfaces.C.size_t (Default_Stack_Size);
792
 
793
      elsif Stack_Size < Minimum_Stack_Size then
794
         Adjusted_Stack_Size := Interfaces.C.size_t (Minimum_Stack_Size);
795
 
796
      else
797
         Adjusted_Stack_Size := Interfaces.C.size_t (Stack_Size);
798
      end if;
799
 
800
      Result := pthread_attr_init (Attributes'Access);
801
      pragma Assert (Result = 0 or else Result = ENOMEM);
802
 
803
      if Result /= 0 then
804
         Succeeded := False;
805
         return;
806
      end if;
807
 
808
      Result := pthread_attr_setstacksize
809
        (Attributes'Access, Adjusted_Stack_Size);
810
      pragma Assert (Result = 0);
811
 
812
      --  Since the initial signal mask of a thread is inherited from the
813
      --  creator, and the Environment task has all its signals masked, we
814
      --  do not need to manipulate caller's signal mask at this point.
815
      --  All tasks in RTS will have All_Tasks_Mask initially.
816
 
817
      Result := pthread_create
818
        (T.Common.LL.Thread'Access,
819
         Attributes'Access,
820
         Thread_Body_Access (Wrapper),
821
         To_Address (T));
822
      pragma Assert (Result = 0 or else Result = EAGAIN);
823
 
824
      Succeeded := Result = 0;
825
 
826
      pthread_detach (T.Common.LL.Thread'Access);
827
      --  Detach the thread using pthread_detach, sinc DCE threads do not have
828
      --  pthread_attr_set_detachstate.
829
 
830
      Result := pthread_attr_destroy (Attributes'Access);
831
      pragma Assert (Result = 0);
832
 
833
      Set_Priority (T, Priority);
834
   end Create_Task;
835
 
836
   ------------------
837
   -- Finalize_TCB --
838
   ------------------
839
 
840
   procedure Finalize_TCB (T : Task_Id) is
841
      Result  : Interfaces.C.int;
842
      Tmp     : Task_Id := T;
843
      Is_Self : constant Boolean := T = Self;
844
 
845
      procedure Free is new
846
        Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
847
 
848
   begin
849
      if not Single_Lock then
850
         Result := pthread_mutex_destroy (T.Common.LL.L'Access);
851
         pragma Assert (Result = 0);
852
      end if;
853
 
854
      Result := pthread_cond_destroy (T.Common.LL.CV'Access);
855
      pragma Assert (Result = 0);
856
 
857
      if T.Known_Tasks_Index /= -1 then
858
         Known_Tasks (T.Known_Tasks_Index) := null;
859
      end if;
860
 
861
      Free (Tmp);
862
 
863
      if Is_Self then
864
         Specific.Set (null);
865
      end if;
866
   end Finalize_TCB;
867
 
868
   ---------------
869
   -- Exit_Task --
870
   ---------------
871
 
872
   procedure Exit_Task is
873
   begin
874
      Specific.Set (null);
875
   end Exit_Task;
876
 
877
   ----------------
878
   -- Abort_Task --
879
   ----------------
880
 
881
   procedure Abort_Task (T : Task_Id) is
882
   begin
883
      --
884
      --  Interrupt Server_Tasks may be waiting on an "event" flag (signal)
885
      --
886
      if T.Common.State = Interrupt_Server_Blocked_On_Event_Flag then
887
         System.Interrupt_Management.Operations.Interrupt_Self_Process
888
           (System.Interrupt_Management.Interrupt_ID
889
             (PIO.Get_Interrupt_ID (T)));
890
      end if;
891
   end Abort_Task;
892
 
893
   ----------------
894
   -- Initialize --
895
   ----------------
896
 
897
   procedure Initialize (S : in out Suspension_Object) is
898
      Mutex_Attr : aliased pthread_mutexattr_t;
899
      Cond_Attr  : aliased pthread_condattr_t;
900
      Result     : Interfaces.C.int;
901
   begin
902
      --  Initialize internal state. It is always initialized to False (ARM
903
      --  D.10 par. 6).
904
 
905
      S.State := False;
906
      S.Waiting := False;
907
 
908
      --  Initialize internal mutex
909
 
910
      Result := pthread_mutex_init (S.L'Access, Mutex_Attr'Access);
911
      pragma Assert (Result = 0 or else Result = ENOMEM);
912
 
913
      if Result = ENOMEM then
914
         raise Storage_Error;
915
      end if;
916
 
917
      --  Initialize internal condition variable
918
 
919
      Result := pthread_cond_init (S.CV'Access, Cond_Attr'Access);
920
      pragma Assert (Result = 0 or else Result = ENOMEM);
921
 
922
      if Result /= 0 then
923
         Result := pthread_mutex_destroy (S.L'Access);
924
         pragma Assert (Result = 0);
925
 
926
         if Result = ENOMEM then
927
            raise Storage_Error;
928
         end if;
929
      end if;
930
   end Initialize;
931
 
932
   --------------
933
   -- Finalize --
934
   --------------
935
 
936
   procedure Finalize (S : in out Suspension_Object) is
937
      Result  : Interfaces.C.int;
938
   begin
939
      --  Destroy internal mutex
940
 
941
      Result := pthread_mutex_destroy (S.L'Access);
942
      pragma Assert (Result = 0);
943
 
944
      --  Destroy internal condition variable
945
 
946
      Result := pthread_cond_destroy (S.CV'Access);
947
      pragma Assert (Result = 0);
948
   end Finalize;
949
 
950
   -------------------
951
   -- Current_State --
952
   -------------------
953
 
954
   function Current_State (S : Suspension_Object) return Boolean is
955
   begin
956
      --  We do not want to use lock on this read operation. State is marked
957
      --  as Atomic so that we ensure that the value retrieved is correct.
958
 
959
      return S.State;
960
   end Current_State;
961
 
962
   ---------------
963
   -- Set_False --
964
   ---------------
965
 
966
   procedure Set_False (S : in out Suspension_Object) is
967
      Result  : Interfaces.C.int;
968
   begin
969
      Result := pthread_mutex_lock (S.L'Access);
970
      pragma Assert (Result = 0);
971
 
972
      S.State := False;
973
 
974
      Result := pthread_mutex_unlock (S.L'Access);
975
      pragma Assert (Result = 0);
976
   end Set_False;
977
 
978
   --------------
979
   -- Set_True --
980
   --------------
981
 
982
   procedure Set_True (S : in out Suspension_Object) is
983
      Result : Interfaces.C.int;
984
   begin
985
      Result := pthread_mutex_lock (S.L'Access);
986
      pragma Assert (Result = 0);
987
 
988
      --  If there is already a task waiting on this suspension object then
989
      --  we resume it, leaving the state of the suspension object to False,
990
      --  as it is specified in ARM D.10 par. 9. Otherwise, it just leaves
991
      --  the state to True.
992
 
993
      if S.Waiting then
994
         S.Waiting := False;
995
         S.State := False;
996
 
997
         Result := pthread_cond_signal (S.CV'Access);
998
         pragma Assert (Result = 0);
999
      else
1000
         S.State := True;
1001
      end if;
1002
 
1003
      Result := pthread_mutex_unlock (S.L'Access);
1004
      pragma Assert (Result = 0);
1005
   end Set_True;
1006
 
1007
   ------------------------
1008
   -- Suspend_Until_True --
1009
   ------------------------
1010
 
1011
   procedure Suspend_Until_True (S : in out Suspension_Object) is
1012
      Result : Interfaces.C.int;
1013
   begin
1014
      Result := pthread_mutex_lock (S.L'Access);
1015
      pragma Assert (Result = 0);
1016
 
1017
      if S.Waiting then
1018
         --  Program_Error must be raised upon calling Suspend_Until_True
1019
         --  if another task is already waiting on that suspension object
1020
         --  (ARM D.10 par. 10).
1021
 
1022
         Result := pthread_mutex_unlock (S.L'Access);
1023
         pragma Assert (Result = 0);
1024
 
1025
         raise Program_Error;
1026
      else
1027
         --  Suspend the task if the state is False. Otherwise, the task
1028
         --  continues its execution, and the state of the suspension object
1029
         --  is set to False (ARM D.10 par. 9).
1030
 
1031
         if S.State then
1032
            S.State := False;
1033
         else
1034
            S.Waiting := True;
1035
            Result := pthread_cond_wait (S.CV'Access, S.L'Access);
1036
         end if;
1037
      end if;
1038
 
1039
      Result := pthread_mutex_unlock (S.L'Access);
1040
      pragma Assert (Result = 0);
1041
   end Suspend_Until_True;
1042
 
1043
   ----------------
1044
   -- Check_Exit --
1045
   ----------------
1046
 
1047
   --  Dummy version
1048
 
1049
   function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1050
      pragma Unreferenced (Self_ID);
1051
   begin
1052
      return True;
1053
   end Check_Exit;
1054
 
1055
   --------------------
1056
   -- Check_No_Locks --
1057
   --------------------
1058
 
1059
   function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1060
      pragma Unreferenced (Self_ID);
1061
   begin
1062
      return True;
1063
   end Check_No_Locks;
1064
 
1065
   ----------------------
1066
   -- Environment_Task --
1067
   ----------------------
1068
 
1069
   function Environment_Task return Task_Id is
1070
   begin
1071
      return Environment_Task_Id;
1072
   end Environment_Task;
1073
 
1074
   --------------
1075
   -- Lock_RTS --
1076
   --------------
1077
 
1078
   procedure Lock_RTS is
1079
   begin
1080
      Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
1081
   end Lock_RTS;
1082
 
1083
   ----------------
1084
   -- Unlock_RTS --
1085
   ----------------
1086
 
1087
   procedure Unlock_RTS is
1088
   begin
1089
      Unlock (Single_RTS_Lock'Access, Global_Lock => True);
1090
   end Unlock_RTS;
1091
 
1092
   ------------------
1093
   -- Suspend_Task --
1094
   ------------------
1095
 
1096
   function Suspend_Task
1097
     (T           : ST.Task_Id;
1098
      Thread_Self : Thread_Id) return Boolean
1099
   is
1100
      pragma Unreferenced (T);
1101
      pragma Unreferenced (Thread_Self);
1102
   begin
1103
      return False;
1104
   end Suspend_Task;
1105
 
1106
   -----------------
1107
   -- Resume_Task --
1108
   -----------------
1109
 
1110
   function Resume_Task
1111
     (T           : ST.Task_Id;
1112
      Thread_Self : Thread_Id) return Boolean
1113
   is
1114
      pragma Unreferenced (T);
1115
      pragma Unreferenced (Thread_Self);
1116
   begin
1117
      return False;
1118
   end Resume_Task;
1119
 
1120
   ----------------
1121
   -- Initialize --
1122
   ----------------
1123
 
1124
   procedure Initialize (Environment_Task : Task_Id) is
1125
      act       : aliased struct_sigaction;
1126
      old_act   : aliased struct_sigaction;
1127
      Tmp_Set   : aliased sigset_t;
1128
      Result    : Interfaces.C.int;
1129
 
1130
      function State
1131
        (Int : System.Interrupt_Management.Interrupt_ID) return Character;
1132
      pragma Import (C, State, "__gnat_get_interrupt_state");
1133
      --  Get interrupt state. Defined in a-init.c. The input argument is
1134
      --  the interrupt number, and the result is one of the following:
1135
 
1136
      Default : constant Character := 's';
1137
      --    'n'   this interrupt not set by any Interrupt_State pragma
1138
      --    'u'   Interrupt_State pragma set state to User
1139
      --    'r'   Interrupt_State pragma set state to Runtime
1140
      --    's'   Interrupt_State pragma set state to System (use "default"
1141
      --           system handler)
1142
 
1143
   begin
1144
      Environment_Task_Id := Environment_Task;
1145
 
1146
      Interrupt_Management.Initialize;
1147
 
1148
      --  Initialize the lock used to synchronize chain of all ATCBs
1149
 
1150
      Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1151
 
1152
      Specific.Initialize (Environment_Task);
1153
 
1154
      Enter_Task (Environment_Task);
1155
 
1156
      --  Install the abort-signal handler
1157
 
1158
      if State (System.Interrupt_Management.Abort_Task_Interrupt)
1159
                                                     /= Default
1160
      then
1161
         act.sa_flags := 0;
1162
         act.sa_handler := Abort_Handler'Address;
1163
 
1164
         Result := sigemptyset (Tmp_Set'Access);
1165
         pragma Assert (Result = 0);
1166
         act.sa_mask := Tmp_Set;
1167
 
1168
         Result :=
1169
           sigaction (
1170
             Signal (System.Interrupt_Management.Abort_Task_Interrupt),
1171
             act'Unchecked_Access,
1172
             old_act'Unchecked_Access);
1173
         pragma Assert (Result = 0);
1174
      end if;
1175
   end Initialize;
1176
 
1177
   --  NOTE: Unlike other pthread implementations, we do *not* mask all
1178
   --  signals here since we handle signals using the process-wide primitive
1179
   --  signal, rather than using sigthreadmask and sigwait. The reason of
1180
   --  this difference is that sigwait doesn't work when some critical
1181
   --  signals (SIGABRT, SIGPIPE) are masked.
1182
 
1183
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.