Merged with mainline at revision 128810.
[official-gcc.git] / gcc / ada / s-taprop-lynxos.adb
blob8693fed7ced7243f669df05bcd60ee1e68236578
1 ------------------------------------------------------------------------------
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-2007, 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 ------------------------------------------------------------------------------
34 -- This is a LynxOS version of this file, adapted to make
35 -- SCHED_FIFO and ceiling locking (Annex D compliance) work properly
37 -- This package contains all the GNULL primitives that interface directly
38 -- with the underlying OS.
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.
44 with System.Tasking.Debug;
45 -- used for Known_Tasks
47 with System.Interrupt_Management;
48 -- used for Keep_Unmasked
49 -- Abort_Task_Interrupt
50 -- Interrupt_ID
52 with System.OS_Primitives;
53 -- used for Delay_Modes
55 with System.Task_Info;
56 -- used for Task_Info_Type
58 with Interfaces.C;
59 -- used for int
60 -- size_t
62 with System.Soft_Links;
63 -- used for Abort_Defer/Undefer
65 -- We use System.Soft_Links instead of System.Tasking.Initialization
66 -- because the later is a higher level package that we shouldn't depend on.
67 -- For example when using the restricted run time, it is replaced by
68 -- System.Tasking.Restricted.Stages.
70 with Ada.Unchecked_Deallocation;
72 package body System.Task_Primitives.Operations is
74 package SSL renames System.Soft_Links;
76 use System.Tasking.Debug;
77 use System.Tasking;
78 use Interfaces.C;
79 use System.OS_Interface;
80 use System.Parameters;
81 use System.OS_Primitives;
83 ----------------
84 -- Local Data --
85 ----------------
87 -- The followings are logically constants, but need to be initialized
88 -- at run time.
90 Single_RTS_Lock : aliased RTS_Lock;
91 -- This is a lock to allow only one thread of control in the RTS at
92 -- a time; it is used to execute in mutual exclusion from all other tasks.
93 -- Used mainly in Single_Lock mode, but also to protect All_Tasks_List
95 ATCB_Key : aliased pthread_key_t;
96 -- Key used to find the Ada Task_Id associated with a thread
98 Environment_Task_Id : Task_Id;
99 -- A variable to hold Task_Id for the environment task
101 Locking_Policy : Character;
102 pragma Import (C, Locking_Policy, "__gl_locking_policy");
103 -- Value of the pragma Locking_Policy:
104 -- 'C' for Ceiling_Locking
105 -- 'I' for Inherit_Locking
106 -- ' ' for none.
108 Unblocked_Signal_Mask : aliased sigset_t;
109 -- The set of signals that should unblocked in all tasks
111 -- The followings are internal configuration constants needed
113 Next_Serial_Number : Task_Serial_Number := 100;
114 -- We start at 100, to reserve some special values for
115 -- using in error checking.
117 Time_Slice_Val : Integer;
118 pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
120 Dispatching_Policy : Character;
121 pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
123 Foreign_Task_Elaborated : aliased Boolean := True;
124 -- Used to identified fake tasks (i.e., non-Ada Threads)
126 --------------------
127 -- Local Packages --
128 --------------------
130 package Specific is
132 procedure Initialize (Environment_Task : Task_Id);
133 pragma Inline (Initialize);
134 -- Initialize various data needed by this package
136 function Is_Valid_Task return Boolean;
137 pragma Inline (Is_Valid_Task);
138 -- Does the current thread have an ATCB?
140 procedure Set (Self_Id : Task_Id);
141 pragma Inline (Set);
142 -- Set the self id for the current task
144 function Self return Task_Id;
145 pragma Inline (Self);
146 -- Return a pointer to the Ada Task Control Block of the calling task
148 end Specific;
150 package body Specific is separate;
151 -- The body of this package is target specific
153 ---------------------------------
154 -- Support for foreign threads --
155 ---------------------------------
157 function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
158 -- Allocate and Initialize a new ATCB for the current Thread
160 function Register_Foreign_Thread
161 (Thread : Thread_Id) return Task_Id is separate;
163 -----------------------
164 -- Local Subprograms --
165 -----------------------
167 procedure Abort_Handler (Sig : Signal);
168 -- Signal handler used to implement asynchronous abort
170 procedure Set_OS_Priority (T : Task_Id; Prio : System.Any_Priority);
171 -- This procedure calls the scheduler of the OS to set thread's priority
173 -------------------
174 -- Abort_Handler --
175 -------------------
177 procedure Abort_Handler (Sig : Signal) is
178 pragma Unreferenced (Sig);
180 T : constant Task_Id := Self;
181 Result : Interfaces.C.int;
182 Old_Set : aliased sigset_t;
184 begin
185 -- It is not safe to raise an exception when using ZCX and the GCC
186 -- exception handling mechanism.
188 if ZCX_By_Default and then GCC_ZCX_Support then
189 return;
190 end if;
192 if T.Deferral_Level = 0
193 and then T.Pending_ATC_Level < T.ATC_Nesting_Level
194 and then not T.Aborting
195 then
196 T.Aborting := True;
198 -- Make sure signals used for RTS internal purpose are unmasked
200 Result :=
201 pthread_sigmask
202 (SIG_UNBLOCK,
203 Unblocked_Signal_Mask'Unchecked_Access,
204 Old_Set'Unchecked_Access);
205 pragma Assert (Result = 0);
207 raise Standard'Abort_Signal;
208 end if;
209 end Abort_Handler;
211 -----------------
212 -- Stack_Guard --
213 -----------------
215 procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is
216 Stack_Base : constant Address := Get_Stack_Base (T.Common.LL.Thread);
217 Guard_Page_Address : Address;
219 Res : Interfaces.C.int;
221 begin
222 if Stack_Base_Available then
224 -- Compute the guard page address
226 Guard_Page_Address :=
227 Stack_Base - (Stack_Base mod Get_Page_Size) + Get_Page_Size;
229 if On then
230 Res := mprotect (Guard_Page_Address, Get_Page_Size, PROT_ON);
231 else
232 Res := mprotect (Guard_Page_Address, Get_Page_Size, PROT_OFF);
233 end if;
235 pragma Assert (Res = 0);
236 end if;
237 end Stack_Guard;
239 --------------------
240 -- Get_Thread_Id --
241 --------------------
243 function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is
244 begin
245 return T.Common.LL.Thread;
246 end Get_Thread_Id;
248 ----------
249 -- Self --
250 ----------
252 function Self return Task_Id renames Specific.Self;
254 ---------------------
255 -- Initialize_Lock --
256 ---------------------
258 procedure Initialize_Lock
259 (Prio : System.Any_Priority;
260 L : not null access Lock)
262 Attributes : aliased pthread_mutexattr_t;
263 Result : Interfaces.C.int;
265 begin
266 Result := pthread_mutexattr_init (Attributes'Access);
267 pragma Assert (Result = 0 or else Result = ENOMEM);
269 if Result = ENOMEM then
270 raise Storage_Error;
271 end if;
273 if Locking_Policy = 'C' then
274 L.Ceiling := Prio;
275 end if;
277 Result := pthread_mutex_init (L.Mutex'Access, Attributes'Access);
278 pragma Assert (Result = 0 or else Result = ENOMEM);
280 if Result = ENOMEM then
281 raise Storage_Error;
282 end if;
284 Result := pthread_mutexattr_destroy (Attributes'Access);
285 pragma Assert (Result = 0);
286 end Initialize_Lock;
288 procedure Initialize_Lock
289 (L : not null access RTS_Lock;
290 Level : Lock_Level)
292 pragma Unreferenced (Level);
294 Attributes : aliased pthread_mutexattr_t;
295 Result : Interfaces.C.int;
297 begin
298 Result := pthread_mutexattr_init (Attributes'Access);
299 pragma Assert (Result = 0 or else Result = ENOMEM);
301 if Result = ENOMEM then
302 raise Storage_Error;
303 end if;
305 Result := pthread_mutex_init (L, Attributes'Access);
306 pragma Assert (Result = 0 or else Result = ENOMEM);
308 if Result = ENOMEM then
309 Result := pthread_mutexattr_destroy (Attributes'Access);
310 raise Storage_Error;
311 end if;
313 Result := pthread_mutexattr_destroy (Attributes'Access);
314 pragma Assert (Result = 0);
315 end Initialize_Lock;
317 -------------------
318 -- Finalize_Lock --
319 -------------------
321 procedure Finalize_Lock (L : not null access Lock) is
322 Result : Interfaces.C.int;
323 begin
324 Result := pthread_mutex_destroy (L.Mutex'Access);
325 pragma Assert (Result = 0);
326 end Finalize_Lock;
328 procedure Finalize_Lock (L : not null access RTS_Lock) is
329 Result : Interfaces.C.int;
330 begin
331 Result := pthread_mutex_destroy (L);
332 pragma Assert (Result = 0);
333 end Finalize_Lock;
335 ----------------
336 -- Write_Lock --
337 ----------------
339 procedure Write_Lock
340 (L : not null access Lock;
341 Ceiling_Violation : out Boolean)
343 Result : Interfaces.C.int;
344 T : constant Task_Id := Self;
346 begin
347 if Locking_Policy = 'C' then
348 if T.Common.Current_Priority > L.Ceiling then
349 Ceiling_Violation := True;
350 return;
351 end if;
353 L.Saved_Priority := T.Common.Current_Priority;
355 if T.Common.Current_Priority < L.Ceiling then
356 Set_OS_Priority (T, L.Ceiling);
357 end if;
358 end if;
360 Result := pthread_mutex_lock (L.Mutex'Access);
362 -- Assume that the cause of EINVAL is a priority ceiling violation
364 Ceiling_Violation := (Result = EINVAL);
365 pragma Assert (Result = 0 or else Result = EINVAL);
366 end Write_Lock;
368 -- No tricks on RTS_Locks
370 procedure Write_Lock
371 (L : not null access RTS_Lock;
372 Global_Lock : Boolean := False)
374 Result : Interfaces.C.int;
375 begin
376 if not Single_Lock or else Global_Lock then
377 Result := pthread_mutex_lock (L);
378 pragma Assert (Result = 0);
379 end if;
380 end Write_Lock;
382 procedure Write_Lock (T : Task_Id) is
383 Result : Interfaces.C.int;
384 begin
385 if not Single_Lock then
386 Result := pthread_mutex_lock (T.Common.LL.L'Access);
387 pragma Assert (Result = 0);
388 end if;
389 end Write_Lock;
391 ---------------
392 -- Read_Lock --
393 ---------------
395 procedure Read_Lock
396 (L : not null access Lock;
397 Ceiling_Violation : out Boolean)
399 begin
400 Write_Lock (L, Ceiling_Violation);
401 end Read_Lock;
403 ------------
404 -- Unlock --
405 ------------
407 procedure Unlock (L : not null access Lock) is
408 Result : Interfaces.C.int;
409 T : constant Task_Id := Self;
411 begin
412 Result := pthread_mutex_unlock (L.Mutex'Access);
413 pragma Assert (Result = 0);
415 if Locking_Policy = 'C' then
416 if T.Common.Current_Priority > L.Saved_Priority then
417 Set_OS_Priority (T, L.Saved_Priority);
418 end if;
419 end if;
420 end Unlock;
422 procedure Unlock
423 (L : not null access RTS_Lock;
424 Global_Lock : Boolean := False)
426 Result : Interfaces.C.int;
427 begin
428 if not Single_Lock or else Global_Lock then
429 Result := pthread_mutex_unlock (L);
430 pragma Assert (Result = 0);
431 end if;
432 end Unlock;
434 procedure Unlock (T : Task_Id) is
435 Result : Interfaces.C.int;
436 begin
437 if not Single_Lock then
438 Result := pthread_mutex_unlock (T.Common.LL.L'Access);
439 pragma Assert (Result = 0);
440 end if;
441 end Unlock;
443 -----------------
444 -- Set_Ceiling --
445 -----------------
447 -- Dynamic priority ceilings are not supported by the underlying system
449 procedure Set_Ceiling
450 (L : not null access Lock;
451 Prio : System.Any_Priority)
453 pragma Unreferenced (L, Prio);
454 begin
455 null;
456 end Set_Ceiling;
458 -----------
459 -- Sleep --
460 -----------
462 procedure Sleep
463 (Self_ID : Task_Id;
464 Reason : System.Tasking.Task_States)
466 pragma Unreferenced (Reason);
467 Result : Interfaces.C.int;
469 begin
470 if Single_Lock then
471 Result :=
472 pthread_cond_wait
473 (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access);
474 else
475 Result :=
476 pthread_cond_wait
477 (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
478 end if;
480 -- EINTR is not considered a failure
482 pragma Assert (Result = 0 or else Result = EINTR);
483 end Sleep;
485 -----------------
486 -- Timed_Sleep --
487 -----------------
489 -- This is for use within the run-time system, so abort is
490 -- assumed to be already deferred, and the caller should be
491 -- holding its own ATCB lock.
493 procedure Timed_Sleep
494 (Self_ID : Task_Id;
495 Time : Duration;
496 Mode : ST.Delay_Modes;
497 Reason : Task_States;
498 Timedout : out Boolean;
499 Yielded : out Boolean)
501 pragma Unreferenced (Reason);
503 Base_Time : constant Duration := Monotonic_Clock;
504 Check_Time : Duration := Base_Time;
505 Rel_Time : Duration;
506 Abs_Time : Duration;
507 Request : aliased timespec;
508 Result : Interfaces.C.int;
510 begin
511 Timedout := True;
512 Yielded := False;
514 if Mode = Relative then
515 Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
517 if Relative_Timed_Wait then
518 Rel_Time := Duration'Min (Max_Sensible_Delay, Time);
519 end if;
521 else
522 Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
524 if Relative_Timed_Wait then
525 Rel_Time := Duration'Min (Max_Sensible_Delay, Time - Check_Time);
526 end if;
527 end if;
529 if Abs_Time > Check_Time then
530 if Relative_Timed_Wait then
531 Request := To_Timespec (Rel_Time);
532 else
533 Request := To_Timespec (Abs_Time);
534 end if;
536 loop
537 exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
539 if Single_Lock then
540 Result :=
541 pthread_cond_timedwait
542 (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access,
543 Request'Access);
545 else
546 Result :=
547 pthread_cond_timedwait
548 (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access,
549 Request'Access);
550 end if;
552 Check_Time := Monotonic_Clock;
553 exit when Abs_Time <= Check_Time or else Check_Time < Base_Time;
555 if Result = 0 or Result = EINTR then
557 -- Somebody may have called Wakeup for us
559 Timedout := False;
560 exit;
561 end if;
563 pragma Assert (Result = ETIMEDOUT);
564 end loop;
565 end if;
566 end Timed_Sleep;
568 -----------------
569 -- Timed_Delay --
570 -----------------
572 -- This is for use in implementing delay statements, so we assume
573 -- the caller is abort-deferred but is holding no locks.
575 procedure Timed_Delay
576 (Self_ID : Task_Id;
577 Time : Duration;
578 Mode : ST.Delay_Modes)
580 Base_Time : constant Duration := Monotonic_Clock;
581 Check_Time : Duration := Base_Time;
582 Abs_Time : Duration;
583 Rel_Time : Duration;
584 Request : aliased timespec;
586 Result : Interfaces.C.int;
587 pragma Warnings (Off, Result);
589 begin
590 if Single_Lock then
591 Lock_RTS;
592 end if;
594 -- Comments needed in code below ???
596 Write_Lock (Self_ID);
598 if Mode = Relative then
599 Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
601 if Relative_Timed_Wait then
602 Rel_Time := Duration'Min (Max_Sensible_Delay, Time);
603 end if;
605 else
606 Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
608 if Relative_Timed_Wait then
609 Rel_Time := Duration'Min (Max_Sensible_Delay, Time - Check_Time);
610 end if;
611 end if;
613 if Abs_Time > Check_Time then
614 if Relative_Timed_Wait then
615 Request := To_Timespec (Rel_Time);
616 else
617 Request := To_Timespec (Abs_Time);
618 end if;
620 Self_ID.Common.State := Delay_Sleep;
622 loop
623 exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
625 if Single_Lock then
626 Result :=
627 pthread_cond_timedwait
628 (Self_ID.Common.LL.CV'Access,
629 Single_RTS_Lock'Access,
630 Request'Access);
631 else
632 Result :=
633 pthread_cond_timedwait
634 (Self_ID.Common.LL.CV'Access,
635 Self_ID.Common.LL.L'Access,
636 Request'Access);
637 end if;
639 Check_Time := Monotonic_Clock;
640 exit when Abs_Time <= Check_Time or else Check_Time < Base_Time;
642 pragma Assert (Result = 0 or else
643 Result = ETIMEDOUT or else
644 Result = EINTR);
645 end loop;
647 Self_ID.Common.State := Runnable;
648 end if;
650 Unlock (Self_ID);
652 if Single_Lock then
653 Unlock_RTS;
654 end if;
656 Result := sched_yield;
657 end Timed_Delay;
659 ---------------------
660 -- Monotonic_Clock --
661 ---------------------
663 function Monotonic_Clock return Duration is
664 TS : aliased timespec;
665 Result : Interfaces.C.int;
666 begin
667 Result :=
668 clock_gettime
669 (clock_id => CLOCK_REALTIME, tp => TS'Unchecked_Access);
670 pragma Assert (Result = 0);
671 return To_Duration (TS);
672 end Monotonic_Clock;
674 -------------------
675 -- RT_Resolution --
676 -------------------
678 function RT_Resolution return Duration is
679 Res : aliased timespec;
680 Result : Interfaces.C.int;
681 begin
682 Result :=
683 clock_getres
684 (clock_id => CLOCK_REALTIME, Res => Res'Unchecked_Access);
685 pragma Assert (Result = 0);
686 return To_Duration (Res);
687 end RT_Resolution;
689 ------------
690 -- Wakeup --
691 ------------
693 procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
694 pragma Unreferenced (Reason);
695 Result : Interfaces.C.int;
696 begin
697 Result := pthread_cond_signal (T.Common.LL.CV'Access);
698 pragma Assert (Result = 0);
699 end Wakeup;
701 -----------
702 -- Yield --
703 -----------
705 procedure Yield (Do_Yield : Boolean := True) is
706 Result : Interfaces.C.int;
707 pragma Unreferenced (Result);
708 begin
709 if Do_Yield then
710 Result := sched_yield;
711 end if;
712 end Yield;
714 ------------------
715 -- Set_Priority --
716 ------------------
718 procedure Set_OS_Priority (T : Task_Id; Prio : System.Any_Priority) is
719 Result : Interfaces.C.int;
720 Param : aliased struct_sched_param;
722 function Get_Policy (Prio : System.Any_Priority) return Character;
723 pragma Import (C, Get_Policy, "__gnat_get_specific_dispatching");
724 -- Get priority specific dispatching policy
726 Priority_Specific_Policy : constant Character := Get_Policy (Prio);
727 -- Upper case first character of the policy name corresponding to the
728 -- task as set by a Priority_Specific_Dispatching pragma.
730 begin
731 Param.sched_priority := Interfaces.C.int (Prio);
733 if Time_Slice_Supported
734 and then (Dispatching_Policy = 'R'
735 or else Priority_Specific_Policy = 'R'
736 or else Time_Slice_Val > 0)
737 then
738 Result :=
739 pthread_setschedparam
740 (T.Common.LL.Thread, SCHED_RR, Param'Access);
742 elsif Dispatching_Policy = 'F'
743 or else Priority_Specific_Policy = 'F'
744 or else Time_Slice_Val = 0
745 then
746 Result :=
747 pthread_setschedparam
748 (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
750 else
751 Result :=
752 pthread_setschedparam
753 (T.Common.LL.Thread, SCHED_OTHER, Param'Access);
754 end if;
756 pragma Assert (Result = 0);
757 end Set_OS_Priority;
759 type Prio_Array_Type is array (System.Any_Priority) of Integer;
760 pragma Atomic_Components (Prio_Array_Type);
761 Prio_Array : Prio_Array_Type;
762 -- Comments needed for these declarations ???
764 procedure Set_Priority
765 (T : Task_Id;
766 Prio : System.Any_Priority;
767 Loss_Of_Inheritance : Boolean := False)
769 Array_Item : Integer;
771 begin
772 Set_OS_Priority (T, Prio);
774 if Locking_Policy = 'C' then
776 -- Annex D requirements: loss of inheritance puts task at the start
777 -- of the queue for that prio; copied from 5ztaprop (VxWorks).
779 if Loss_Of_Inheritance
780 and then Prio < T.Common.Current_Priority then
782 Array_Item := Prio_Array (T.Common.Base_Priority) + 1;
783 Prio_Array (T.Common.Base_Priority) := Array_Item;
785 loop
786 Yield;
787 exit when Array_Item = Prio_Array (T.Common.Base_Priority)
788 or else Prio_Array (T.Common.Base_Priority) = 1;
789 end loop;
791 Prio_Array (T.Common.Base_Priority) :=
792 Prio_Array (T.Common.Base_Priority) - 1;
793 end if;
794 end if;
796 T.Common.Current_Priority := Prio;
797 end Set_Priority;
799 ------------------
800 -- Get_Priority --
801 ------------------
803 function Get_Priority (T : Task_Id) return System.Any_Priority is
804 begin
805 return T.Common.Current_Priority;
806 end Get_Priority;
808 ----------------
809 -- Enter_Task --
810 ----------------
812 procedure Enter_Task (Self_ID : Task_Id) is
813 begin
814 Self_ID.Common.LL.Thread := pthread_self;
815 Self_ID.Common.LL.LWP := lwp_self;
817 Specific.Set (Self_ID);
819 Lock_RTS;
821 for J in Known_Tasks'Range loop
822 if Known_Tasks (J) = null then
823 Known_Tasks (J) := Self_ID;
824 Self_ID.Known_Tasks_Index := J;
825 exit;
826 end if;
827 end loop;
829 Unlock_RTS;
830 end Enter_Task;
832 --------------
833 -- New_ATCB --
834 --------------
836 function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
837 begin
838 return new Ada_Task_Control_Block (Entry_Num);
839 end New_ATCB;
841 -------------------
842 -- Is_Valid_Task --
843 -------------------
845 function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
847 -----------------------------
848 -- Register_Foreign_Thread --
849 -----------------------------
851 function Register_Foreign_Thread return Task_Id is
852 begin
853 if Is_Valid_Task then
854 return Self;
855 else
856 return Register_Foreign_Thread (pthread_self);
857 end if;
858 end Register_Foreign_Thread;
860 --------------------
861 -- Initialize_TCB --
862 --------------------
864 procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
865 Mutex_Attr : aliased pthread_mutexattr_t;
866 Result : Interfaces.C.int;
867 Cond_Attr : aliased pthread_condattr_t;
869 begin
870 -- Give the task a unique serial number
872 Self_ID.Serial_Number := Next_Serial_Number;
873 Next_Serial_Number := Next_Serial_Number + 1;
874 pragma Assert (Next_Serial_Number /= 0);
876 if not Single_Lock then
877 Result := pthread_mutexattr_init (Mutex_Attr'Access);
878 pragma Assert (Result = 0 or else Result = ENOMEM);
880 if Result = 0 then
881 Result :=
882 pthread_mutex_init
883 (Self_ID.Common.LL.L'Access, Mutex_Attr'Access);
884 pragma Assert (Result = 0 or else Result = ENOMEM);
885 end if;
887 if Result /= 0 then
888 Succeeded := False;
889 return;
890 end if;
892 Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
893 pragma Assert (Result = 0);
894 end if;
896 Result := pthread_condattr_init (Cond_Attr'Access);
897 pragma Assert (Result = 0 or else Result = ENOMEM);
899 if Result = 0 then
900 Result :=
901 pthread_cond_init (Self_ID.Common.LL.CV'Access, Cond_Attr'Access);
902 pragma Assert (Result = 0 or else Result = ENOMEM);
903 end if;
905 if Result = 0 then
906 Succeeded := True;
907 else
908 if not Single_Lock then
909 Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
910 pragma Assert (Result = 0);
911 end if;
913 Succeeded := False;
914 end if;
916 Result := pthread_condattr_destroy (Cond_Attr'Access);
917 pragma Assert (Result = 0);
918 end Initialize_TCB;
920 -----------------
921 -- Create_Task --
922 -----------------
924 procedure Create_Task
925 (T : Task_Id;
926 Wrapper : System.Address;
927 Stack_Size : System.Parameters.Size_Type;
928 Priority : System.Any_Priority;
929 Succeeded : out Boolean)
931 Attributes : aliased pthread_attr_t;
932 Adjusted_Stack_Size : Interfaces.C.size_t;
933 Result : Interfaces.C.int;
935 use System.Task_Info;
937 begin
938 Adjusted_Stack_Size := Interfaces.C.size_t (Stack_Size);
940 if Stack_Base_Available then
942 -- If Stack Checking is supported then allocate 2 additional pages:
944 -- In the worst case, stack is allocated at something like
945 -- N * Get_Page_Size - epsilon, we need to add the size for 2 pages
946 -- to be sure the effective stack size is greater than what
947 -- has been asked.
949 Adjusted_Stack_Size := Adjusted_Stack_Size + 2 * Get_Page_Size;
950 end if;
952 Result := pthread_attr_init (Attributes'Access);
953 pragma Assert (Result = 0 or else Result = ENOMEM);
955 if Result /= 0 then
956 Succeeded := False;
957 return;
958 end if;
960 Result :=
961 pthread_attr_setdetachstate
962 (Attributes'Access, PTHREAD_CREATE_DETACHED);
963 pragma Assert (Result = 0);
965 Result :=
966 pthread_attr_setstacksize
967 (Attributes'Access, Adjusted_Stack_Size);
968 pragma Assert (Result = 0);
970 if T.Common.Task_Info /= Default_Scope then
972 -- We are assuming that Scope_Type has the same values than the
973 -- corresponding C macros
975 Result :=
976 pthread_attr_setscope
977 (Attributes'Access, Task_Info_Type'Pos (T.Common.Task_Info));
978 pragma Assert (Result = 0);
979 end if;
981 -- Since the initial signal mask of a thread is inherited from the
982 -- creator, and the Environment task has all its signals masked, we
983 -- do not need to manipulate caller's signal mask at this point.
984 -- All tasks in RTS will have All_Tasks_Mask initially.
986 Result :=
987 pthread_create
988 (T.Common.LL.Thread'Access,
989 Attributes'Access,
990 Thread_Body_Access (Wrapper),
991 To_Address (T));
992 pragma Assert (Result = 0 or else Result = EAGAIN);
994 Succeeded := Result = 0;
996 Result := pthread_attr_destroy (Attributes'Access);
997 pragma Assert (Result = 0);
999 Set_Priority (T, Priority);
1000 end Create_Task;
1002 ------------------
1003 -- Finalize_TCB --
1004 ------------------
1006 procedure Finalize_TCB (T : Task_Id) is
1007 Result : Interfaces.C.int;
1008 Tmp : Task_Id := T;
1009 Is_Self : constant Boolean := T = Self;
1011 procedure Free is new
1012 Ada.Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
1014 begin
1015 if not Single_Lock then
1016 Result := pthread_mutex_destroy (T.Common.LL.L'Access);
1017 pragma Assert (Result = 0);
1018 end if;
1020 Result := pthread_cond_destroy (T.Common.LL.CV'Access);
1021 pragma Assert (Result = 0);
1023 if T.Known_Tasks_Index /= -1 then
1024 Known_Tasks (T.Known_Tasks_Index) := null;
1025 end if;
1027 Free (Tmp);
1029 if Is_Self then
1030 Result := st_setspecific (ATCB_Key, System.Null_Address);
1031 pragma Assert (Result = 0);
1032 end if;
1033 end Finalize_TCB;
1035 ---------------
1036 -- Exit_Task --
1037 ---------------
1039 procedure Exit_Task is
1040 begin
1041 Specific.Set (null);
1042 end Exit_Task;
1044 ----------------
1045 -- Abort_Task --
1046 ----------------
1048 procedure Abort_Task (T : Task_Id) is
1049 Result : Interfaces.C.int;
1050 begin
1051 Result :=
1052 pthread_kill
1053 (T.Common.LL.Thread,
1054 Signal (System.Interrupt_Management.Abort_Task_Interrupt));
1055 pragma Assert (Result = 0);
1056 end Abort_Task;
1058 ----------------
1059 -- Initialize --
1060 ----------------
1062 procedure Initialize (S : in out Suspension_Object) is
1063 Mutex_Attr : aliased pthread_mutexattr_t;
1064 Cond_Attr : aliased pthread_condattr_t;
1065 Result : Interfaces.C.int;
1067 begin
1068 -- Initialize internal state (always to False (RM D.10(6)))
1070 S.State := False;
1071 S.Waiting := False;
1073 -- Initialize internal mutex
1075 Result := pthread_mutexattr_init (Mutex_Attr'Access);
1076 pragma Assert (Result = 0 or else Result = ENOMEM);
1078 if Result = ENOMEM then
1079 raise Storage_Error;
1080 end if;
1082 Result := pthread_mutex_init (S.L'Access, Mutex_Attr'Access);
1083 pragma Assert (Result = 0 or else Result = ENOMEM);
1085 if Result = ENOMEM then
1086 Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
1087 pragma Assert (Result = 0);
1089 raise Storage_Error;
1090 end if;
1092 Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
1093 pragma Assert (Result = 0);
1095 -- Initialize internal condition variable
1097 Result := pthread_condattr_init (Cond_Attr'Access);
1098 pragma Assert (Result = 0 or else Result = ENOMEM);
1100 if Result /= 0 then
1101 Result := pthread_mutex_destroy (S.L'Access);
1102 pragma Assert (Result = 0);
1104 if Result = ENOMEM then
1105 raise Storage_Error;
1106 end if;
1107 end if;
1109 Result := pthread_cond_init (S.CV'Access, Cond_Attr'Access);
1110 pragma Assert (Result = 0 or else Result = ENOMEM);
1112 if Result /= 0 then
1113 Result := pthread_mutex_destroy (S.L'Access);
1114 pragma Assert (Result = 0);
1116 if Result = ENOMEM then
1117 Result := pthread_condattr_destroy (Cond_Attr'Access);
1118 pragma Assert (Result = 0);
1120 raise Storage_Error;
1121 end if;
1122 end if;
1124 Result := pthread_condattr_destroy (Cond_Attr'Access);
1125 pragma Assert (Result = 0);
1126 end Initialize;
1128 --------------
1129 -- Finalize --
1130 --------------
1132 procedure Finalize (S : in out Suspension_Object) is
1133 Result : Interfaces.C.int;
1135 begin
1136 -- Destroy internal mutex
1138 Result := pthread_mutex_destroy (S.L'Access);
1139 pragma Assert (Result = 0);
1141 -- Destroy internal condition variable
1143 Result := pthread_cond_destroy (S.CV'Access);
1144 pragma Assert (Result = 0);
1145 end Finalize;
1147 -------------------
1148 -- Current_State --
1149 -------------------
1151 function Current_State (S : Suspension_Object) return Boolean is
1152 begin
1153 -- We do not want to use lock on this read operation. State is marked
1154 -- as Atomic so that we ensure that the value retrieved is correct.
1156 return S.State;
1157 end Current_State;
1159 ---------------
1160 -- Set_False --
1161 ---------------
1163 procedure Set_False (S : in out Suspension_Object) is
1164 Result : Interfaces.C.int;
1166 begin
1167 SSL.Abort_Defer.all;
1169 Result := pthread_mutex_lock (S.L'Access);
1170 pragma Assert (Result = 0);
1172 S.State := False;
1174 Result := pthread_mutex_unlock (S.L'Access);
1175 pragma Assert (Result = 0);
1177 SSL.Abort_Undefer.all;
1178 end Set_False;
1180 --------------
1181 -- Set_True --
1182 --------------
1184 procedure Set_True (S : in out Suspension_Object) is
1185 Result : Interfaces.C.int;
1187 begin
1188 SSL.Abort_Defer.all;
1190 Result := pthread_mutex_lock (S.L'Access);
1191 pragma Assert (Result = 0);
1193 -- If there is already a task waiting on this suspension object then
1194 -- we resume it, leaving the state of the suspension object to False,
1195 -- as specified in (RM D.10(9)). Otherwise, just leave state set True.
1197 if S.Waiting then
1198 S.Waiting := False;
1199 S.State := False;
1201 Result := pthread_cond_signal (S.CV'Access);
1202 pragma Assert (Result = 0);
1204 else
1205 S.State := True;
1206 end if;
1208 Result := pthread_mutex_unlock (S.L'Access);
1209 pragma Assert (Result = 0);
1211 SSL.Abort_Undefer.all;
1212 end Set_True;
1214 ------------------------
1215 -- Suspend_Until_True --
1216 ------------------------
1218 procedure Suspend_Until_True (S : in out Suspension_Object) is
1219 Result : Interfaces.C.int;
1221 begin
1222 SSL.Abort_Defer.all;
1224 Result := pthread_mutex_lock (S.L'Access);
1225 pragma Assert (Result = 0);
1227 if S.Waiting then
1229 -- Program_Error must be raised upon calling Suspend_Until_True
1230 -- if another task is already waiting on that suspension object
1231 -- (RM D.10 (10)).
1233 Result := pthread_mutex_unlock (S.L'Access);
1234 pragma Assert (Result = 0);
1236 SSL.Abort_Undefer.all;
1238 raise Program_Error;
1240 else
1241 -- Suspend the task if the state is False. Otherwise, the task
1242 -- continues its execution, and the state of the suspension object
1243 -- is set to False (RM D.10(9)).
1245 if S.State then
1246 S.State := False;
1247 else
1248 S.Waiting := True;
1249 Result := pthread_cond_wait (S.CV'Access, S.L'Access);
1250 end if;
1252 Result := pthread_mutex_unlock (S.L'Access);
1253 pragma Assert (Result = 0);
1255 SSL.Abort_Undefer.all;
1256 end if;
1257 end Suspend_Until_True;
1259 ----------------
1260 -- Check_Exit --
1261 ----------------
1263 -- Dummy version
1265 function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1266 pragma Unreferenced (Self_ID);
1267 begin
1268 return True;
1269 end Check_Exit;
1271 --------------------
1272 -- Check_No_Locks --
1273 --------------------
1275 function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1276 pragma Unreferenced (Self_ID);
1277 begin
1278 return True;
1279 end Check_No_Locks;
1281 ----------------------
1282 -- Environment_Task --
1283 ----------------------
1285 function Environment_Task return Task_Id is
1286 begin
1287 return Environment_Task_Id;
1288 end Environment_Task;
1290 --------------
1291 -- Lock_RTS --
1292 --------------
1294 procedure Lock_RTS is
1295 begin
1296 Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
1297 end Lock_RTS;
1299 ----------------
1300 -- Unlock_RTS --
1301 ----------------
1303 procedure Unlock_RTS is
1304 begin
1305 Unlock (Single_RTS_Lock'Access, Global_Lock => True);
1306 end Unlock_RTS;
1308 ------------------
1309 -- Suspend_Task --
1310 ------------------
1312 function Suspend_Task
1313 (T : ST.Task_Id;
1314 Thread_Self : Thread_Id) return Boolean
1316 pragma Unreferenced (T);
1317 pragma Unreferenced (Thread_Self);
1318 begin
1319 return False;
1320 end Suspend_Task;
1322 -----------------
1323 -- Resume_Task --
1324 -----------------
1326 function Resume_Task
1327 (T : ST.Task_Id;
1328 Thread_Self : Thread_Id) return Boolean
1330 pragma Unreferenced (T);
1331 pragma Unreferenced (Thread_Self);
1332 begin
1333 return False;
1334 end Resume_Task;
1336 --------------------
1337 -- Stop_All_Tasks --
1338 --------------------
1340 procedure Stop_All_Tasks is
1341 begin
1342 null;
1343 end Stop_All_Tasks;
1345 ---------------
1346 -- Stop_Task --
1347 ---------------
1349 function Stop_Task (T : ST.Task_Id) return Boolean is
1350 pragma Unreferenced (T);
1351 begin
1352 return False;
1353 end Stop_Task;
1355 -------------------
1356 -- Continue_Task --
1357 -------------------
1359 function Continue_Task (T : ST.Task_Id) return Boolean is
1360 pragma Unreferenced (T);
1361 begin
1362 return False;
1363 end Continue_Task;
1365 ----------------
1366 -- Initialize --
1367 ----------------
1369 procedure Initialize (Environment_Task : Task_Id) is
1370 act : aliased struct_sigaction;
1371 old_act : aliased struct_sigaction;
1372 Tmp_Set : aliased sigset_t;
1373 Result : Interfaces.C.int;
1375 function State
1376 (Int : System.Interrupt_Management.Interrupt_ID) return Character;
1377 pragma Import (C, State, "__gnat_get_interrupt_state");
1378 -- Get interrupt state. Defined in a-init.c
1379 -- The input argument is the interrupt number,
1380 -- and the result is one of the following:
1382 Default : constant Character := 's';
1383 -- 'n' this interrupt not set by any Interrupt_State pragma
1384 -- 'u' Interrupt_State pragma set state to User
1385 -- 'r' Interrupt_State pragma set state to Runtime
1386 -- 's' Interrupt_State pragma set state to System (use "default"
1387 -- system handler)
1389 begin
1390 Environment_Task_Id := Environment_Task;
1392 Interrupt_Management.Initialize;
1394 -- Prepare the set of signals that should unblocked in all tasks
1396 Result := sigemptyset (Unblocked_Signal_Mask'Access);
1397 pragma Assert (Result = 0);
1399 for J in Interrupt_Management.Interrupt_ID loop
1400 if System.Interrupt_Management.Keep_Unmasked (J) then
1401 Result := sigaddset (Unblocked_Signal_Mask'Access, Signal (J));
1402 pragma Assert (Result = 0);
1403 end if;
1404 end loop;
1406 -- Initialize the lock used to synchronize chain of all ATCBs
1408 Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1410 Specific.Initialize (Environment_Task);
1412 Enter_Task (Environment_Task);
1414 -- Install the abort-signal handler
1416 if State
1417 (System.Interrupt_Management.Abort_Task_Interrupt) /= Default
1418 then
1419 act.sa_flags := 0;
1420 act.sa_handler := Abort_Handler'Address;
1422 Result := sigemptyset (Tmp_Set'Access);
1423 pragma Assert (Result = 0);
1424 act.sa_mask := Tmp_Set;
1426 Result :=
1427 sigaction
1428 (Signal (System.Interrupt_Management.Abort_Task_Interrupt),
1429 act'Unchecked_Access,
1430 old_act'Unchecked_Access);
1432 pragma Assert (Result = 0);
1433 end if;
1434 end Initialize;
1436 end System.Task_Primitives.Operations;