1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
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 --
9 -- Copyright (C) 1992-2006, Free Software Foundation, Inc. --
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. --
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. --
29 -- GNARL was developed by the GNARL team at Florida State University. --
30 -- Extensive contributions were provided by Ada Core Technologies, Inc. --
32 ------------------------------------------------------------------------------
34 -- This is a IRIX (pthread library) version of this package
36 -- This package contains all the GNULL primitives that interface directly
37 -- with the underlying OS.
40 -- Turn off polling, we do not want ATC polling to take place during
41 -- tasking operations. It causes infinite loops and other problems.
47 with System
.Task_Info
;
49 with System
.Tasking
.Debug
;
50 -- used for Known_Tasks
52 with System
.Interrupt_Management
;
53 -- used for Keep_Unmasked
54 -- Abort_Task_Interrupt
57 with System
.OS_Primitives
;
58 -- used for Delay_Modes
63 with Unchecked_Conversion
;
64 with Unchecked_Deallocation
;
66 package body System
.Task_Primitives
.Operations
is
69 use System
.Tasking
.Debug
;
71 use System
.OS_Interface
;
72 use System
.OS_Primitives
;
73 use System
.Parameters
;
79 -- The followings are logically constants, but need to be initialized
82 Single_RTS_Lock
: aliased RTS_Lock
;
83 -- This is a lock to allow only one thread of control in the RTS at
84 -- a time; it is used to execute in mutual exclusion from all other tasks.
85 -- Used mainly in Single_Lock mode, but also to protect All_Tasks_List
87 ATCB_Key
: aliased pthread_key_t
;
88 -- Key used to find the Ada Task_Id associated with a thread
90 Environment_Task_Id
: Task_Id
;
91 -- A variable to hold Task_Id for the environment task
93 Locking_Policy
: Character;
94 pragma Import
(C
, Locking_Policy
, "__gl_locking_policy");
96 Real_Time_Clock_Id
: constant clockid_t
:= CLOCK_REALTIME
;
98 Unblocked_Signal_Mask
: aliased sigset_t
;
100 Foreign_Task_Elaborated
: aliased Boolean := True;
101 -- Used to identified fake tasks (i.e., non-Ada Threads)
109 procedure Initialize
(Environment_Task
: Task_Id
);
110 pragma Inline
(Initialize
);
111 -- Initialize various data needed by this package
113 function Is_Valid_Task
return Boolean;
114 pragma Inline
(Is_Valid_Task
);
115 -- Does executing thread have a TCB?
117 procedure Set
(Self_Id
: Task_Id
);
119 -- Set the self id for the current task
121 function Self
return Task_Id
;
122 pragma Inline
(Self
);
123 -- Return a pointer to the Ada Task Control Block of the calling task
127 package body Specific
is separate;
128 -- The body of this package is target specific
130 ---------------------------------
131 -- Support for foreign threads --
132 ---------------------------------
134 function Register_Foreign_Thread
(Thread
: Thread_Id
) return Task_Id
;
135 -- Allocate and Initialize a new ATCB for the current Thread
137 function Register_Foreign_Thread
138 (Thread
: Thread_Id
) return Task_Id
is separate;
140 -----------------------
141 -- Local Subprograms --
142 -----------------------
144 function To_Address
is new Unchecked_Conversion
(Task_Id
, System
.Address
);
146 procedure Abort_Handler
(Sig
: Signal
);
147 -- Signal handler used to implement asynchronous abort
153 procedure Abort_Handler
(Sig
: Signal
) is
154 pragma Unreferenced
(Sig
);
156 T
: constant Task_Id
:= Self
;
157 Result
: Interfaces
.C
.int
;
158 Old_Set
: aliased sigset_t
;
161 -- It is not safe to raise an exception when using ZCX and the GCC
162 -- exception handling mechanism.
164 if ZCX_By_Default
and then GCC_ZCX_Support
then
168 if T
.Deferral_Level
= 0
169 and then T
.Pending_ATC_Level
< T
.ATC_Nesting_Level
171 -- Make sure signals used for RTS internal purpose are unmasked
173 Result
:= pthread_sigmask
175 Unblocked_Signal_Mask
'Unchecked_Access,
176 Old_Set
'Unchecked_Access);
177 pragma Assert
(Result
= 0);
179 raise Standard
'Abort_Signal;
187 -- The underlying thread system sets a guard page at the
188 -- bottom of a thread stack, so nothing is needed.
190 procedure Stack_Guard
(T
: ST
.Task_Id
; On
: Boolean) is
191 pragma Unreferenced
(On
);
192 pragma Unreferenced
(T
);
201 function Get_Thread_Id
(T
: ST
.Task_Id
) return OSI
.Thread_Id
is
203 return T
.Common
.LL
.Thread
;
210 function Self
return Task_Id
renames Specific
.Self
;
212 ---------------------
213 -- Initialize_Lock --
214 ---------------------
216 -- Note: mutexes and cond_variables needed per-task basis are
217 -- initialized in Initialize_TCB and the Storage_Error is
218 -- handled. Other mutexes (such as RTS_Lock, Memory_Lock...)
219 -- used in RTS is initialized before any status change of RTS.
220 -- Therefore rasing Storage_Error in the following routines
221 -- should be able to be handled safely.
223 procedure Initialize_Lock
224 (Prio
: System
.Any_Priority
;
227 Attributes
: aliased pthread_mutexattr_t
;
228 Result
: Interfaces
.C
.int
;
231 Result
:= pthread_mutexattr_init
(Attributes
'Access);
232 pragma Assert
(Result
= 0 or else Result
= ENOMEM
);
234 if Result
= ENOMEM
then
238 if Locking_Policy
= 'C' then
239 Result
:= pthread_mutexattr_setprotocol
240 (Attributes
'Access, PTHREAD_PRIO_PROTECT
);
241 pragma Assert
(Result
= 0);
243 Result
:= pthread_mutexattr_setprioceiling
244 (Attributes
'Access, Interfaces
.C
.int
(Prio
));
245 pragma Assert
(Result
= 0);
248 Result
:= pthread_mutex_init
(L
, Attributes
'Access);
249 pragma Assert
(Result
= 0 or else Result
= ENOMEM
);
251 if Result
= ENOMEM
then
252 Result
:= pthread_mutexattr_destroy
(Attributes
'Access);
256 Result
:= pthread_mutexattr_destroy
(Attributes
'Access);
257 pragma Assert
(Result
= 0);
260 procedure Initialize_Lock
(L
: access RTS_Lock
; Level
: Lock_Level
) is
261 pragma Unreferenced
(Level
);
263 Attributes
: aliased pthread_mutexattr_t
;
264 Result
: Interfaces
.C
.int
;
267 Result
:= pthread_mutexattr_init
(Attributes
'Access);
268 pragma Assert
(Result
= 0 or else Result
= ENOMEM
);
270 if Result
= ENOMEM
then
274 if Locking_Policy
= 'C' then
275 Result
:= pthread_mutexattr_setprotocol
276 (Attributes
'Access, PTHREAD_PRIO_PROTECT
);
277 pragma Assert
(Result
= 0);
279 Result
:= pthread_mutexattr_setprioceiling
280 (Attributes
'Access, Interfaces
.C
.int
(System
.Any_Priority
'Last));
281 pragma Assert
(Result
= 0);
284 Result
:= pthread_mutex_init
(L
, Attributes
'Access);
286 pragma Assert
(Result
= 0 or else Result
= ENOMEM
);
288 if Result
= ENOMEM
then
289 Result
:= pthread_mutexattr_destroy
(Attributes
'Access);
293 Result
:= pthread_mutexattr_destroy
(Attributes
'Access);
300 procedure Finalize_Lock
(L
: access Lock
) is
301 Result
: Interfaces
.C
.int
;
303 Result
:= pthread_mutex_destroy
(L
);
304 pragma Assert
(Result
= 0);
307 procedure Finalize_Lock
(L
: access RTS_Lock
) is
308 Result
: Interfaces
.C
.int
;
310 Result
:= pthread_mutex_destroy
(L
);
311 pragma Assert
(Result
= 0);
318 procedure Write_Lock
(L
: access Lock
; Ceiling_Violation
: out Boolean) is
319 Result
: Interfaces
.C
.int
;
321 Result
:= pthread_mutex_lock
(L
);
322 Ceiling_Violation
:= Result
= EINVAL
;
324 -- Assumes the cause of EINVAL is a priority ceiling violation
326 pragma Assert
(Result
= 0 or else Result
= EINVAL
);
330 (L
: access RTS_Lock
;
331 Global_Lock
: Boolean := False)
333 Result
: Interfaces
.C
.int
;
335 if not Single_Lock
or else Global_Lock
then
336 Result
:= pthread_mutex_lock
(L
);
337 pragma Assert
(Result
= 0);
341 procedure Write_Lock
(T
: Task_Id
) is
342 Result
: Interfaces
.C
.int
;
344 if not Single_Lock
then
345 Result
:= pthread_mutex_lock
(T
.Common
.LL
.L
'Access);
346 pragma Assert
(Result
= 0);
354 procedure Read_Lock
(L
: access Lock
; Ceiling_Violation
: out Boolean) is
356 Write_Lock
(L
, Ceiling_Violation
);
363 procedure Unlock
(L
: access Lock
) is
364 Result
: Interfaces
.C
.int
;
366 Result
:= pthread_mutex_unlock
(L
);
367 pragma Assert
(Result
= 0);
370 procedure Unlock
(L
: access RTS_Lock
; Global_Lock
: Boolean := False) is
371 Result
: Interfaces
.C
.int
;
374 if not Single_Lock
or else Global_Lock
then
375 Result
:= pthread_mutex_unlock
(L
);
376 pragma Assert
(Result
= 0);
380 procedure Unlock
(T
: Task_Id
) is
381 Result
: Interfaces
.C
.int
;
384 if not Single_Lock
then
385 Result
:= pthread_mutex_unlock
(T
.Common
.LL
.L
'Access);
386 pragma Assert
(Result
= 0);
395 (Self_ID
: ST
.Task_Id
;
396 Reason
: System
.Tasking
.Task_States
)
398 pragma Unreferenced
(Reason
);
400 Result
: Interfaces
.C
.int
;
404 Result
:= pthread_cond_wait
405 (Self_ID
.Common
.LL
.CV
'Access, Single_RTS_Lock
'Access);
407 Result
:= pthread_cond_wait
408 (Self_ID
.Common
.LL
.CV
'Access, Self_ID
.Common
.LL
.L
'Access);
411 -- EINTR is not considered a failure
413 pragma Assert
(Result
= 0 or else Result
= EINTR
);
420 procedure Timed_Sleep
423 Mode
: ST
.Delay_Modes
;
424 Reason
: Task_States
;
425 Timedout
: out Boolean;
426 Yielded
: out Boolean)
428 pragma Unreferenced
(Reason
);
430 Check_Time
: constant Duration := Monotonic_Clock
;
432 Request
: aliased timespec
;
433 Result
: Interfaces
.C
.int
;
439 if Mode
= Relative
then
440 Abs_Time
:= Duration'Min (Time
, Max_Sensible_Delay
) + Check_Time
;
442 Abs_Time
:= Duration'Min (Check_Time
+ Max_Sensible_Delay
, Time
);
445 if Abs_Time
> Check_Time
then
446 Request
:= To_Timespec
(Abs_Time
);
449 exit when Self_ID
.Pending_ATC_Level
< Self_ID
.ATC_Nesting_Level
450 or else Self_ID
.Pending_Priority_Change
;
453 Result
:= pthread_cond_timedwait
454 (Self_ID
.Common
.LL
.CV
'Access, Single_RTS_Lock
'Access,
458 Result
:= pthread_cond_timedwait
459 (Self_ID
.Common
.LL
.CV
'Access, Self_ID
.Common
.LL
.L
'Access,
463 exit when Abs_Time
<= Monotonic_Clock
;
465 if Result
= 0 or else errno
= EINTR
then
477 -- This is for use in implementing delay statements, so we assume
478 -- the caller is abort-deferred but is holding no locks.
480 procedure Timed_Delay
483 Mode
: ST
.Delay_Modes
)
485 Check_Time
: constant Duration := Monotonic_Clock
;
487 Request
: aliased timespec
;
488 Result
: Interfaces
.C
.int
;
495 Write_Lock
(Self_ID
);
497 if Mode
= Relative
then
498 Abs_Time
:= Time
+ Check_Time
;
500 Abs_Time
:= Duration'Min (Check_Time
+ Max_Sensible_Delay
, Time
);
503 if Abs_Time
> Check_Time
then
504 Request
:= To_Timespec
(Abs_Time
);
505 Self_ID
.Common
.State
:= Delay_Sleep
;
508 if Self_ID
.Pending_Priority_Change
then
509 Self_ID
.Pending_Priority_Change
:= False;
510 Self_ID
.Common
.Base_Priority
:= Self_ID
.New_Base_Priority
;
511 Set_Priority
(Self_ID
, Self_ID
.Common
.Base_Priority
);
514 exit when Self_ID
.Pending_ATC_Level
< Self_ID
.ATC_Nesting_Level
;
516 Result
:= pthread_cond_timedwait
(Self_ID
.Common
.LL
.CV
'Access,
517 Self_ID
.Common
.LL
.L
'Access, Request
'Access);
518 exit when Abs_Time
<= Monotonic_Clock
;
520 pragma Assert
(Result
= 0
521 or else Result
= ETIMEDOUT
522 or else Result
= EINTR
);
525 Self_ID
.Common
.State
:= Runnable
;
537 ---------------------
538 -- Monotonic_Clock --
539 ---------------------
541 function Monotonic_Clock
return Duration is
542 TS
: aliased timespec
;
543 Result
: Interfaces
.C
.int
;
545 Result
:= clock_gettime
(Real_Time_Clock_Id
, TS
'Unchecked_Access);
546 pragma Assert
(Result
= 0);
547 return To_Duration
(TS
);
554 function RT_Resolution
return Duration is
556 -- The clock_getres (Real_Time_Clock_Id) function appears to return
557 -- the interrupt resolution of the realtime clock and not the actual
558 -- resolution of reading the clock. Even though this last value is
559 -- only guaranteed to be 100 Hz, at least the Origin 200 appears to
560 -- have a microsecond resolution or better.
562 -- ??? We should figure out a method to return the right value on
572 procedure Wakeup
(T
: ST
.Task_Id
; Reason
: System
.Tasking
.Task_States
) is
573 pragma Unreferenced
(Reason
);
574 Result
: Interfaces
.C
.int
;
576 Result
:= pthread_cond_signal
(T
.Common
.LL
.CV
'Access);
577 pragma Assert
(Result
= 0);
584 procedure Yield
(Do_Yield
: Boolean := True) is
585 Result
: Interfaces
.C
.int
;
586 pragma Unreferenced
(Result
);
589 Result
:= sched_yield
;
597 procedure Set_Priority
599 Prio
: System
.Any_Priority
;
600 Loss_Of_Inheritance
: Boolean := False)
602 pragma Unreferenced
(Loss_Of_Inheritance
);
604 Result
: Interfaces
.C
.int
;
605 Param
: aliased struct_sched_param
;
606 Sched_Policy
: Interfaces
.C
.int
;
608 use type System
.Task_Info
.Task_Info_Type
;
610 function To_Int
is new Unchecked_Conversion
611 (System
.Task_Info
.Thread_Scheduling_Policy
, Interfaces
.C
.int
);
614 T
.Common
.Current_Priority
:= Prio
;
615 Param
.sched_priority
:= Interfaces
.C
.int
(Prio
);
617 if T
.Common
.Task_Info
/= null then
618 Sched_Policy
:= To_Int
(T
.Common
.Task_Info
.Policy
);
620 Sched_Policy
:= SCHED_FIFO
;
623 Result
:= pthread_setschedparam
(T
.Common
.LL
.Thread
, Sched_Policy
,
625 pragma Assert
(Result
= 0);
632 function Get_Priority
(T
: Task_Id
) return System
.Any_Priority
is
634 return T
.Common
.Current_Priority
;
641 procedure Enter_Task
(Self_ID
: Task_Id
) is
642 Result
: Interfaces
.C
.int
;
644 function To_Int
is new Unchecked_Conversion
645 (System
.Task_Info
.CPU_Number
, Interfaces
.C
.int
);
647 use System
.Task_Info
;
650 Self_ID
.Common
.LL
.Thread
:= pthread_self
;
651 Specific
.Set
(Self_ID
);
653 if Self_ID
.Common
.Task_Info
/= null
654 and then Self_ID
.Common
.Task_Info
.Scope
= PTHREAD_SCOPE_SYSTEM
655 and then Self_ID
.Common
.Task_Info
.Runon_CPU
/= ANY_CPU
657 Result
:= pthread_setrunon_np
658 (To_Int
(Self_ID
.Common
.Task_Info
.Runon_CPU
));
659 pragma Assert
(Result
= 0);
664 for J
in Known_Tasks
'Range loop
665 if Known_Tasks
(J
) = null then
666 Known_Tasks
(J
) := Self_ID
;
667 Self_ID
.Known_Tasks_Index
:= J
;
679 function New_ATCB
(Entry_Num
: Task_Entry_Index
) return Task_Id
is
681 return new Ada_Task_Control_Block
(Entry_Num
);
688 function Is_Valid_Task
return Boolean renames Specific
.Is_Valid_Task
;
690 -----------------------------
691 -- Register_Foreign_Thread --
692 -----------------------------
694 function Register_Foreign_Thread
return Task_Id
is
696 if Is_Valid_Task
then
699 return Register_Foreign_Thread
(pthread_self
);
701 end Register_Foreign_Thread
;
707 procedure Initialize_TCB
(Self_ID
: Task_Id
; Succeeded
: out Boolean) is
708 Result
: Interfaces
.C
.int
;
709 Cond_Attr
: aliased pthread_condattr_t
;
712 if not Single_Lock
then
713 Initialize_Lock
(Self_ID
.Common
.LL
.L
'Access, ATCB_Level
);
716 Result
:= pthread_condattr_init
(Cond_Attr
'Access);
717 pragma Assert
(Result
= 0 or else Result
= ENOMEM
);
720 Result
:= pthread_cond_init
(Self_ID
.Common
.LL
.CV
'Access,
722 pragma Assert
(Result
= 0 or else Result
= ENOMEM
);
728 if not Single_Lock
then
729 Result
:= pthread_mutex_destroy
(Self_ID
.Common
.LL
.L
'Access);
730 pragma Assert
(Result
= 0);
736 Result
:= pthread_condattr_destroy
(Cond_Attr
'Access);
737 pragma Assert
(Result
= 0);
744 procedure Create_Task
746 Wrapper
: System
.Address
;
747 Stack_Size
: System
.Parameters
.Size_Type
;
748 Priority
: System
.Any_Priority
;
749 Succeeded
: out Boolean)
751 use System
.Task_Info
;
753 Attributes
: aliased pthread_attr_t
;
754 Sched_Param
: aliased struct_sched_param
;
755 Result
: Interfaces
.C
.int
;
757 function Thread_Body_Access
is new
758 Unchecked_Conversion
(System
.Address
, Thread_Body
);
760 function To_Int
is new Unchecked_Conversion
761 (System
.Task_Info
.Thread_Scheduling_Scope
, Interfaces
.C
.int
);
762 function To_Int
is new Unchecked_Conversion
763 (System
.Task_Info
.Thread_Scheduling_Inheritance
, Interfaces
.C
.int
);
764 function To_Int
is new Unchecked_Conversion
765 (System
.Task_Info
.Thread_Scheduling_Policy
, Interfaces
.C
.int
);
768 Result
:= pthread_attr_init
(Attributes
'Access);
769 pragma Assert
(Result
= 0 or else Result
= ENOMEM
);
776 Result
:= pthread_attr_setdetachstate
777 (Attributes
'Access, PTHREAD_CREATE_DETACHED
);
778 pragma Assert
(Result
= 0);
780 Result
:= pthread_attr_setstacksize
781 (Attributes
'Access, Interfaces
.C
.size_t
(Stack_Size
));
782 pragma Assert
(Result
= 0);
784 if T
.Common
.Task_Info
/= null then
785 Result
:= pthread_attr_setscope
786 (Attributes
'Access, To_Int
(T
.Common
.Task_Info
.Scope
));
787 pragma Assert
(Result
= 0);
789 Result
:= pthread_attr_setinheritsched
790 (Attributes
'Access, To_Int
(T
.Common
.Task_Info
.Inheritance
));
791 pragma Assert
(Result
= 0);
793 Result
:= pthread_attr_setschedpolicy
794 (Attributes
'Access, To_Int
(T
.Common
.Task_Info
.Policy
));
795 pragma Assert
(Result
= 0);
797 Sched_Param
.sched_priority
:=
798 Interfaces
.C
.int
(T
.Common
.Task_Info
.Priority
);
800 Result
:= pthread_attr_setschedparam
801 (Attributes
'Access, Sched_Param
'Access);
802 pragma Assert
(Result
= 0);
805 -- Since the initial signal mask of a thread is inherited from the
806 -- creator, and the Environment task has all its signals masked, we
807 -- do not need to manipulate caller's signal mask at this point.
808 -- All tasks in RTS will have All_Tasks_Mask initially.
810 Result
:= pthread_create
811 (T
.Common
.LL
.Thread
'Access,
813 Thread_Body_Access
(Wrapper
),
817 and then T
.Common
.Task_Info
/= null
818 and then T
.Common
.Task_Info
.Scope
= PTHREAD_SCOPE_SYSTEM
820 -- The pthread_create call may have failed because we
821 -- asked for a system scope pthread and none were
822 -- available (probably because the program was not executed
823 -- by the superuser). Let's try for a process scope pthread
824 -- instead of raising Tasking_Error.
827 ("Request for PTHREAD_SCOPE_SYSTEM in Task_Info pragma for task");
828 System
.IO
.Put
("""");
829 System
.IO
.Put
(T
.Common
.Task_Image
(1 .. T
.Common
.Task_Image_Len
));
830 System
.IO
.Put_Line
(""" could not be honored. ");
831 System
.IO
.Put_Line
("Scope changed to PTHREAD_SCOPE_PROCESS");
833 T
.Common
.Task_Info
.Scope
:= PTHREAD_SCOPE_PROCESS
;
834 Result
:= pthread_attr_setscope
835 (Attributes
'Access, To_Int
(T
.Common
.Task_Info
.Scope
));
836 pragma Assert
(Result
= 0);
838 Result
:= pthread_create
839 (T
.Common
.LL
.Thread
'Access,
841 Thread_Body_Access
(Wrapper
),
845 pragma Assert
(Result
= 0 or else Result
= EAGAIN
);
847 Succeeded
:= Result
= 0;
849 -- The following needs significant commenting ???
851 if T
.Common
.Task_Info
/= null then
852 T
.Common
.Base_Priority
:= T
.Common
.Task_Info
.Priority
;
853 Set_Priority
(T
, T
.Common
.Task_Info
.Priority
);
855 Set_Priority
(T
, Priority
);
858 Result
:= pthread_attr_destroy
(Attributes
'Access);
859 pragma Assert
(Result
= 0);
866 procedure Finalize_TCB
(T
: Task_Id
) is
867 Result
: Interfaces
.C
.int
;
869 Is_Self
: constant Boolean := T
= Self
;
871 procedure Free
is new
872 Unchecked_Deallocation
(Ada_Task_Control_Block
, Task_Id
);
875 if not Single_Lock
then
876 Result
:= pthread_mutex_destroy
(T
.Common
.LL
.L
'Access);
877 pragma Assert
(Result
= 0);
880 Result
:= pthread_cond_destroy
(T
.Common
.LL
.CV
'Access);
881 pragma Assert
(Result
= 0);
883 if T
.Known_Tasks_Index
/= -1 then
884 Known_Tasks
(T
.Known_Tasks_Index
) := null;
898 procedure Exit_Task
is
907 procedure Abort_Task
(T
: Task_Id
) is
908 Result
: Interfaces
.C
.int
;
910 Result
:= pthread_kill
(T
.Common
.LL
.Thread
,
911 Signal
(System
.Interrupt_Management
.Abort_Task_Interrupt
));
912 pragma Assert
(Result
= 0);
919 procedure Initialize
(S
: in out Suspension_Object
) is
920 Mutex_Attr
: aliased pthread_mutexattr_t
;
921 Cond_Attr
: aliased pthread_condattr_t
;
922 Result
: Interfaces
.C
.int
;
924 -- Initialize internal state. It is always initialized to False (ARM
930 -- Initialize internal mutex
932 Result
:= pthread_mutexattr_init
(Mutex_Attr
'Access);
933 pragma Assert
(Result
= 0 or else Result
= ENOMEM
);
935 if Result
= ENOMEM
then
939 Result
:= pthread_mutex_init
(S
.L
'Access, Mutex_Attr
'Access);
940 pragma Assert
(Result
= 0 or else Result
= ENOMEM
);
942 if Result
= ENOMEM
then
943 Result
:= pthread_mutexattr_destroy
(Mutex_Attr
'Access);
944 pragma Assert
(Result
= 0);
949 Result
:= pthread_mutexattr_destroy
(Mutex_Attr
'Access);
950 pragma Assert
(Result
= 0);
952 -- Initialize internal condition variable
954 Result
:= pthread_condattr_init
(Cond_Attr
'Access);
955 pragma Assert
(Result
= 0 or else Result
= ENOMEM
);
958 Result
:= pthread_mutex_destroy
(S
.L
'Access);
959 pragma Assert
(Result
= 0);
961 if Result
= ENOMEM
then
966 Result
:= pthread_cond_init
(S
.CV
'Access, Cond_Attr
'Access);
967 pragma Assert
(Result
= 0 or else Result
= ENOMEM
);
970 Result
:= pthread_mutex_destroy
(S
.L
'Access);
971 pragma Assert
(Result
= 0);
973 if Result
= ENOMEM
then
974 Result
:= pthread_condattr_destroy
(Cond_Attr
'Access);
975 pragma Assert
(Result
= 0);
981 Result
:= pthread_condattr_destroy
(Cond_Attr
'Access);
982 pragma Assert
(Result
= 0);
989 procedure Finalize
(S
: in out Suspension_Object
) is
990 Result
: Interfaces
.C
.int
;
992 -- Destroy internal mutex
994 Result
:= pthread_mutex_destroy
(S
.L
'Access);
995 pragma Assert
(Result
= 0);
997 -- Destroy internal condition variable
999 Result
:= pthread_cond_destroy
(S
.CV
'Access);
1000 pragma Assert
(Result
= 0);
1007 function Current_State
(S
: Suspension_Object
) return Boolean is
1009 -- We do not want to use lock on this read operation. State is marked
1010 -- as Atomic so that we ensure that the value retrieved is correct.
1019 procedure Set_False
(S
: in out Suspension_Object
) is
1020 Result
: Interfaces
.C
.int
;
1022 Result
:= pthread_mutex_lock
(S
.L
'Access);
1023 pragma Assert
(Result
= 0);
1027 Result
:= pthread_mutex_unlock
(S
.L
'Access);
1028 pragma Assert
(Result
= 0);
1035 procedure Set_True
(S
: in out Suspension_Object
) is
1036 Result
: Interfaces
.C
.int
;
1038 Result
:= pthread_mutex_lock
(S
.L
'Access);
1039 pragma Assert
(Result
= 0);
1041 -- If there is already a task waiting on this suspension object then
1042 -- we resume it, leaving the state of the suspension object to False,
1043 -- as it is specified in ARM D.10 par. 9. Otherwise, it just leaves
1044 -- the state to True.
1050 Result
:= pthread_cond_signal
(S
.CV
'Access);
1051 pragma Assert
(Result
= 0);
1056 Result
:= pthread_mutex_unlock
(S
.L
'Access);
1057 pragma Assert
(Result
= 0);
1060 ------------------------
1061 -- Suspend_Until_True --
1062 ------------------------
1064 procedure Suspend_Until_True
(S
: in out Suspension_Object
) is
1065 Result
: Interfaces
.C
.int
;
1067 Result
:= pthread_mutex_lock
(S
.L
'Access);
1068 pragma Assert
(Result
= 0);
1071 -- Program_Error must be raised upon calling Suspend_Until_True
1072 -- if another task is already waiting on that suspension object
1073 -- (ARM D.10 par. 10).
1075 Result
:= pthread_mutex_unlock
(S
.L
'Access);
1076 pragma Assert
(Result
= 0);
1078 raise Program_Error
;
1080 -- Suspend the task if the state is False. Otherwise, the task
1081 -- continues its execution, and the state of the suspension object
1082 -- is set to False (ARM D.10 par. 9).
1088 Result
:= pthread_cond_wait
(S
.CV
'Access, S
.L
'Access);
1092 Result
:= pthread_mutex_unlock
(S
.L
'Access);
1093 pragma Assert
(Result
= 0);
1094 end Suspend_Until_True
;
1102 function Check_Exit
(Self_ID
: ST
.Task_Id
) return Boolean is
1103 pragma Unreferenced
(Self_ID
);
1108 --------------------
1109 -- Check_No_Locks --
1110 --------------------
1112 function Check_No_Locks
(Self_ID
: ST
.Task_Id
) return Boolean is
1113 pragma Unreferenced
(Self_ID
);
1118 ----------------------
1119 -- Environment_Task --
1120 ----------------------
1122 function Environment_Task
return Task_Id
is
1124 return Environment_Task_Id
;
1125 end Environment_Task
;
1131 procedure Lock_RTS
is
1133 Write_Lock
(Single_RTS_Lock
'Access, Global_Lock
=> True);
1140 procedure Unlock_RTS
is
1142 Unlock
(Single_RTS_Lock
'Access, Global_Lock
=> True);
1149 function Suspend_Task
1151 Thread_Self
: Thread_Id
) return Boolean
1153 pragma Unreferenced
(T
);
1154 pragma Unreferenced
(Thread_Self
);
1163 function Resume_Task
1165 Thread_Self
: Thread_Id
) return Boolean
1167 pragma Unreferenced
(T
);
1168 pragma Unreferenced
(Thread_Self
);
1177 procedure Initialize
(Environment_Task
: Task_Id
) is
1178 act
: aliased struct_sigaction
;
1179 old_act
: aliased struct_sigaction
;
1180 Tmp_Set
: aliased sigset_t
;
1181 Result
: Interfaces
.C
.int
;
1184 (Int
: System
.Interrupt_Management
.Interrupt_ID
) return Character;
1185 pragma Import
(C
, State
, "__gnat_get_interrupt_state");
1186 -- Get interrupt state. Defined in a-init.c. The input argument is
1187 -- the interrupt number, and the result is one of the following:
1189 Default
: constant Character := 's';
1190 -- 'n' this interrupt not set by any Interrupt_State pragma
1191 -- 'u' Interrupt_State pragma set state to User
1192 -- 'r' Interrupt_State pragma set state to Runtime
1193 -- 's' Interrupt_State pragma set state to System (use "default"
1197 Environment_Task_Id
:= Environment_Task
;
1199 Interrupt_Management
.Initialize
;
1201 -- Initialize the lock used to synchronize chain of all ATCBs.
1203 Initialize_Lock
(Single_RTS_Lock
'Access, RTS_Lock_Level
);
1205 Specific
.Initialize
(Environment_Task
);
1207 Enter_Task
(Environment_Task
);
1209 -- Prepare the set of signals that should unblocked in all tasks
1211 Result
:= sigemptyset
(Unblocked_Signal_Mask
'Access);
1212 pragma Assert
(Result
= 0);
1214 for J
in Interrupt_Management
.Interrupt_ID
loop
1215 if System
.Interrupt_Management
.Keep_Unmasked
(J
) then
1216 Result
:= sigaddset
(Unblocked_Signal_Mask
'Access, Signal
(J
));
1217 pragma Assert
(Result
= 0);
1221 -- Install the abort-signal handler
1223 if State
(System
.Interrupt_Management
.Abort_Task_Interrupt
)
1227 act
.sa_handler
:= Abort_Handler
'Address;
1229 Result
:= sigemptyset
(Tmp_Set
'Access);
1230 pragma Assert
(Result
= 0);
1231 act
.sa_mask
:= Tmp_Set
;
1235 Signal
(System
.Interrupt_Management
.Abort_Task_Interrupt
),
1236 act
'Unchecked_Access,
1237 old_act
'Unchecked_Access);
1238 pragma Assert
(Result
= 0);
1242 end System
.Task_Primitives
.Operations
;