1 ------------------------------------------------------------------------------
3 -- GNU ADA 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 --
10 -- Copyright (C) 1992-2001, Free Software Foundation, Inc. --
12 -- GNARL is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNARL; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
21 -- MA 02111-1307, USA. --
23 -- As a special exception, if other files instantiate generics from this --
24 -- unit, or you link this unit with other files to produce an executable, --
25 -- this unit does not by itself cause the resulting executable to be --
26 -- covered by the GNU General Public License. This exception does not --
27 -- however invalidate any other reasons why the executable file might be --
28 -- covered by the GNU Public License. --
30 -- GNARL was developed by the GNARL team at Florida State University. It is --
31 -- now maintained by Ada Core Technologies, Inc. (http://www.gnat.com). --
33 ------------------------------------------------------------------------------
35 -- This is an Irix (old athread library) version of this package
37 -- This package contains all the GNULL primitives that interface directly
38 -- with the underlying OS.
41 -- Turn off polling, we do not want ATC polling to take place during
42 -- tasking operations. It causes infinite loops and other problems.
48 with System.Tasking.Debug;
49 -- used for Known_Tasks
51 with System.Task_Info;
53 with System.Interrupt_Management;
54 -- used for Keep_Unmasked
55 -- Abort_Task_Interrupt
58 with System.Parameters;
62 -- used for Ada_Task_Control_Block
65 with System.Program_Info;
66 -- used for Default_Task_Stack
69 -- Pthread_Sched_Signal
72 with System.Soft_Links;
73 -- used for Defer/Undefer_Abort
75 -- Note that we do not use System.Tasking.Initialization directly since
76 -- this is a higher level package that we shouldn't depend on. For example
77 -- when using the restricted run time, it is replaced by
78 -- System.Tasking.Restricted.Initialization
80 with System.OS_Primitives;
81 -- used for Delay_Modes
83 with System.Storage_Elements;
84 -- used for To_Address
86 with Unchecked_Conversion;
87 with Unchecked_Deallocation;
89 package body System.Task_Primitives.Operations is
91 use System.Tasking.Debug;
94 use System.OS_Interface;
95 use System.Parameters;
96 use System.OS_Primitives;
98 package SSL renames System.Soft_Links;
104 -- The followings are logically constants, but need to be initialized
107 Single_RTS_Lock : aliased RTS_Lock;
108 -- This is a lock to allow only one thread of control in the RTS at
109 -- a time; it is used to execute in mutual exclusion from all other tasks.
110 -- Used mainly in Single_Lock mode, but also to protect All_Tasks_List
112 Environment_Task_ID : Task_ID;
113 -- A variable to hold Task_ID for the environment task.
115 Locking_Policy : Character;
116 pragma Import (C, Locking_Policy, "__gl_locking_policy");
118 Clock_Address : constant System.Address :=
119 System.Storage_Elements.To_Address (16#200F90#);
121 RT_Clock_Id : clockid_t;
122 for RT_Clock_Id'Address use Clock_Address;
124 -----------------------
125 -- Local Subprograms --
126 -----------------------
128 procedure Initialize_Athread_Library;
130 function To_Task_ID is new Unchecked_Conversion (System.Address, Task_ID);
132 function To_Address is new Unchecked_Conversion (Task_ID, System.Address);
138 -- The underlying thread system sets a guard page at the
139 -- bottom of a thread stack, so nothing is needed.
140 -- ??? Check the comment above
142 procedure Stack_Guard (T : ST.Task_ID; On : Boolean) is
151 function Get_Thread_Id (T : ST.Task_ID) return OSI.Thread_Id is
153 return T.Common.LL.Thread;
160 function Self return Task_ID is
162 return To_Task_ID (pthread_get_current_ada_tcb);
165 ---------------------
166 -- Initialize_Lock --
167 ---------------------
169 -- Note: mutexes and cond_variables needed per-task basis are
170 -- initialized in Initialize_TCB and the Storage_Error is
171 -- handled. Other mutexes (such as RTS_Lock, Memory_Lock...)
172 -- used in RTS is initialized before any status change of RTS.
173 -- Therefore rasing Storage_Error in the following routines
174 -- should be able to be handled safely.
176 procedure Initialize_Lock
177 (Prio : System.Any_Priority;
180 Attributes : aliased pthread_mutexattr_t;
181 Result : Interfaces.C.int;
184 Result := pthread_mutexattr_init (Attributes'Access);
186 if Result = FUNC_ERR then
190 if Locking_Policy = 'C' then
192 Result := pthread_mutexattr_setqueueorder
193 (Attributes'Access, MUTEX_PRIORITY_CEILING);
195 pragma Assert (Result /= FUNC_ERR);
197 Result := pthread_mutexattr_setceilingprio
198 (Attributes'Access, Interfaces.C.int (Prio));
200 pragma Assert (Result /= FUNC_ERR);
203 Result := pthread_mutex_init (L, Attributes'Access);
205 if Result = FUNC_ERR then
206 Result := pthread_mutexattr_destroy (Attributes'Access);
210 Result := pthread_mutexattr_destroy (Attributes'Access);
213 procedure Initialize_Lock (L : access RTS_Lock; Level : Lock_Level) is
214 Attributes : aliased pthread_mutexattr_t;
215 Result : Interfaces.C.int;
217 Result := pthread_mutexattr_init (Attributes'Access);
219 if Result = FUNC_ERR then
223 if Locking_Policy = 'C' then
224 Result := pthread_mutexattr_setqueueorder
225 (Attributes'Access, MUTEX_PRIORITY_CEILING);
226 pragma Assert (Result /= FUNC_ERR);
228 Result := pthread_mutexattr_setceilingprio
229 (Attributes'Access, Interfaces.C.int (System.Any_Priority'Last));
230 pragma Assert (Result /= FUNC_ERR);
233 Result := pthread_mutex_init (L, Attributes'Access);
235 if Result = FUNC_ERR then
236 Result := pthread_mutexattr_destroy (Attributes'Access);
240 Result := pthread_mutexattr_destroy (Attributes'Access);
247 procedure Finalize_Lock (L : access Lock) is
248 Result : Interfaces.C.int;
251 Result := pthread_mutex_destroy (L);
252 pragma Assert (Result = 0);
255 procedure Finalize_Lock (L : access RTS_Lock) is
256 Result : Interfaces.C.int;
259 Result := pthread_mutex_destroy (L);
260 pragma Assert (Result = 0);
267 procedure Write_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
268 Result : Interfaces.C.int;
270 Result := pthread_mutex_lock (L);
272 Ceiling_Violation := Result = FUNC_ERR and then errno = EINVAL;
273 pragma Assert (Result /= FUNC_ERR);
277 (L : access RTS_Lock; Global_Lock : Boolean := False)
279 Result : Interfaces.C.int;
281 if not Single_Lock or else Global_Lock then
282 Result := pthread_mutex_lock (L);
283 pragma Assert (Result = 0);
287 procedure Write_Lock (T : Task_ID) is
288 Result : Interfaces.C.int;
290 if not Single_Lock then
291 Result := pthread_mutex_lock (T.Common.LL.L'Access);
292 pragma Assert (Result = 0);
300 procedure Read_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
302 Write_Lock (L, Ceiling_Violation);
309 procedure Unlock (L : access Lock) is
310 Result : Interfaces.C.int;
312 Result := pthread_mutex_unlock (L);
313 pragma Assert (Result = 0);
316 procedure Unlock (L : access RTS_Lock; Global_Lock : Boolean := False) is
317 Result : Interfaces.C.int;
319 if not Single_Lock or else Global_Lock then
320 Result := pthread_mutex_unlock (L);
321 pragma Assert (Result = 0);
325 procedure Unlock (T : Task_ID) is
326 Result : Interfaces.C.int;
328 if not Single_Lock then
329 Result := pthread_mutex_unlock (T.Common.LL.L'Access);
330 pragma Assert (Result = 0);
339 (Self_ID : ST.Task_ID;
340 Reason : System.Tasking.Task_States)
342 Result : Interfaces.C.int;
345 Result := pthread_cond_wait
346 (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access);
348 Result := pthread_cond_wait
349 (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
352 -- EINTR is not considered a failure.
353 pragma Assert (Result = 0 or else Result = EINTR);
360 procedure Timed_Sleep
363 Mode : ST.Delay_Modes;
364 Reason : System.Tasking.Task_States;
365 Timedout : out Boolean;
366 Yielded : out Boolean)
368 Check_Time : constant Duration := Monotonic_Clock;
370 Request : aliased struct_timeval;
371 Result : Interfaces.C.int;
376 if Mode = Relative then
377 Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
379 Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
382 if Abs_Time > Check_Time then
383 Request := To_Timeval (Abs_Time);
386 exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
387 or else Self_ID.Pending_Priority_Change;
390 Result := pthread_cond_timedwait
391 (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access,
395 Result := pthread_cond_timedwait
396 (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access,
400 exit when Abs_Time <= Monotonic_Clock;
402 if Result = 0 or Result = EINTR then
403 -- somebody may have called Wakeup for us
408 pragma Assert (Result = ETIMEDOUT
409 or else (Result = -1 and then errno = EAGAIN));
418 procedure Timed_Delay
421 Mode : ST.Delay_Modes)
423 Check_Time : constant Duration := Monotonic_Clock;
425 Request : aliased struct_timeval;
426 Result : Interfaces.C.int;
429 -- Only the little window between deferring abort and
430 -- locking Self_ID is the reason we need to
431 -- check for pending abort and priority change below! :(
439 Write_Lock (Self_ID);
441 if Mode = Relative then
442 Abs_Time := Time + Check_Time;
444 Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
447 if Abs_Time > Check_Time then
448 Request := To_Timeval (Abs_Time);
449 Self_ID.Common.State := Delay_Sleep;
452 if Self_ID.Pending_Priority_Change then
453 Self_ID.Pending_Priority_Change := False;
454 Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
455 Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
458 exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
461 Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
462 Single_RTS_Lock'Access, Request'Access);
464 Result := pthread_cond_timedwait (Self_ID.Common.LL.CV'Access,
465 Self_ID.Common.LL.L'Access, Request'Access);
468 exit when Abs_Time <= Monotonic_Clock;
470 pragma Assert (Result = 0 or else
471 Result = ETIMEDOUT or else
472 (Result = -1 and then errno = EAGAIN) or else
476 Self_ID.Common.State := Runnable;
486 SSL.Abort_Undefer.all;
489 ---------------------
490 -- Monotonic_Clock --
491 ---------------------
493 function Monotonic_Clock return Duration is
494 type timeval is record
498 pragma Convention (C, timeval);
500 tv : aliased timeval;
502 procedure gettimeofday (tp : access timeval);
503 pragma Import (C, gettimeofday, "gettimeofday", "gettimeofday");
506 gettimeofday (tv'Access);
507 return Duration (tv.tv_sec) + Duration (tv.tv_usec) / 1_000_000.0;
514 function RT_Resolution return Duration is
525 Reason : System.Tasking.Task_States)
527 Result : Interfaces.C.int;
529 Result := pthread_cond_signal (T.Common.LL.CV'Access);
530 pragma Assert (Result = 0);
537 procedure Yield (Do_Yield : Boolean := True) is
548 procedure Set_Priority
550 Prio : System.Any_Priority;
551 Loss_Of_Inheritance : Boolean := False)
553 Result : Interfaces.C.int;
555 T.Common.Current_Priority := Prio;
556 Result := pthread_setprio (T.Common.LL.Thread, Interfaces.C.int (Prio));
557 pragma Assert (Result /= FUNC_ERR);
565 function Get_Priority (T : Task_ID) return System.Any_Priority is
567 return T.Common.Current_Priority;
574 procedure Enter_Task (Self_ID : Task_ID) is
575 Result : Interfaces.C.int;
577 Self_ID.Common.LL.Thread := pthread_self;
578 Self_ID.Common.LL.LWP := sproc_self;
581 pthread_set_ada_tcb (Self_ID.Common.LL.Thread, To_Address (Self_ID));
583 pragma Assert (Result = 0);
587 for J in Known_Tasks'Range loop
588 if Known_Tasks (J) = null then
589 Known_Tasks (J) := Self_ID;
590 Self_ID.Known_Tasks_Index := J;
602 function New_ATCB (Entry_Num : Task_Entry_Index) return Task_ID is
604 return new Ada_Task_Control_Block (Entry_Num);
607 ----------------------
609 ----------------------
611 procedure Initialize_TCB (Self_ID : Task_ID; Succeeded : out Boolean) is
612 Result : Interfaces.C.int;
613 Cond_Attr : aliased pthread_condattr_t;
616 if not Single_Lock then
617 Initialize_Lock (Self_ID.Common.LL.L'Access, ATCB_Level);
620 Result := pthread_condattr_init (Cond_Attr'Access);
621 pragma Assert (Result = 0 or else Result = ENOMEM);
624 Result := pthread_cond_init (Self_ID.Common.LL.CV'Access,
626 pragma Assert (Result = 0 or else Result = ENOMEM);
632 if not Single_Lock then
633 Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
634 pragma Assert (Result = 0);
640 Result := pthread_condattr_destroy (Cond_Attr'Access);
641 pragma Assert (Result = 0);
648 procedure Create_Task
650 Wrapper : System.Address;
651 Stack_Size : System.Parameters.Size_Type;
652 Priority : System.Any_Priority;
653 Succeeded : out Boolean)
655 Attributes : aliased pthread_attr_t;
656 Adjusted_Stack_Size : Interfaces.C.size_t;
657 Result : Interfaces.C.int;
659 function Thread_Body_Access is new
660 Unchecked_Conversion (System.Address, start_addr);
662 function To_Resource_T is new Unchecked_Conversion
663 (System.Task_Info.Resource_Vector_T, System.OS_Interface.resource_t);
665 use System.Task_Info;
668 if Stack_Size = Unspecified_Size then
669 Adjusted_Stack_Size :=
670 Interfaces.C.size_t (System.Program_Info.Default_Task_Stack);
672 elsif Stack_Size < Minimum_Stack_Size then
673 Adjusted_Stack_Size := Interfaces.C.size_t (Minimum_Stack_Size);
676 Adjusted_Stack_Size := Interfaces.C.size_t (Stack_Size);
679 Result := pthread_attr_init (Attributes'Access);
680 pragma Assert (Result = 0 or else Result = ENOMEM);
687 Result := pthread_attr_setdetachstate (Attributes'Access, 1);
688 pragma Assert (Result = 0);
690 Result := pthread_attr_setstacksize
691 (Attributes'Access, Adjusted_Stack_Size);
692 pragma Assert (Result = 0);
694 if T.Common.Task_Info /= null then
695 Result := pthread_attr_setresources
697 To_Resource_T (T.Common.Task_Info.Thread_Resources));
698 pragma Assert (Result /= FUNC_ERR);
700 if T.Common.Task_Info.Thread_Timeslice /= 0.0 then
702 use System.OS_Interface;
704 Tv : aliased struct_timeval := To_Timeval
705 (T.Common.Task_Info.Thread_Timeslice);
707 Result := pthread_attr_set_tslice
708 (Attributes'Access, Tv'Access);
712 if T.Common.Task_Info.Bound_To_Sproc then
713 Result := pthread_attr_set_boundtosproc
714 (Attributes'Access, PTHREAD_BOUND);
715 Result := pthread_attr_set_bsproc
716 (Attributes'Access, T.Common.Task_Info.Sproc);
721 -- Since the initial signal mask of a thread is inherited from the
722 -- creator, and the Environment task has all its signals masked, we
723 -- do not need to manipulate caller's signal mask at this point.
724 -- All tasks in RTS will have All_Tasks_Mask initially.
726 Result := pthread_create
727 (T.Common.LL.Thread'Access,
729 Thread_Body_Access (Wrapper),
731 pragma Assert (Result = 0 or else Result = EAGAIN);
733 Succeeded := Result = 0;
735 Set_Priority (T, Priority);
737 Result := pthread_attr_destroy (Attributes'Access);
738 pragma Assert (Result /= FUNC_ERR);
745 procedure Finalize_TCB (T : Task_ID) is
746 procedure Free is new
747 Unchecked_Deallocation (Ada_Task_Control_Block, Task_ID);
749 Result : Interfaces.C.int;
753 if not Single_Lock then
754 Result := pthread_mutex_destroy (T.Common.LL.L'Access);
755 pragma Assert (Result = 0);
758 Result := pthread_cond_destroy (T.Common.LL.CV'Access);
759 pragma Assert (Result = 0);
761 if T.Known_Tasks_Index /= -1 then
762 Known_Tasks (T.Known_Tasks_Index) := null;
772 procedure Exit_Task is
774 pthread_exit (System.Null_Address);
781 procedure Abort_Task (T : Task_ID) is
782 Result : Interfaces.C.int;
784 Result := pthread_kill (T.Common.LL.Thread,
785 Interfaces.C.int (System.Interrupt_Management.Abort_Task_Interrupt));
786 pragma Assert (Result = 0);
793 -- Dummy versions. The only currently working versions is for solaris
796 function Check_Exit (Self_ID : ST.Task_ID) return Boolean is
805 function Check_No_Locks (Self_ID : ST.Task_ID) return Boolean is
810 ----------------------
811 -- Environment_Task --
812 ----------------------
814 function Environment_Task return Task_ID is
816 return Environment_Task_ID;
817 end Environment_Task;
823 procedure Lock_RTS is
825 Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
832 procedure Unlock_RTS is
834 Unlock (Single_RTS_Lock'Access, Global_Lock => True);
841 function Suspend_Task
843 Thread_Self : Thread_Id) return Boolean is
845 if T.Common.LL.Thread /= Thread_Self then
846 return pthread_suspend (T.Common.LL.Thread) = 0;
858 Thread_Self : Thread_Id) return Boolean is
860 if T.Common.LL.Thread /= Thread_Self then
861 return pthread_resume (T.Common.LL.Thread) = 0;
871 procedure Initialize (Environment_Task : Task_ID) is
873 Environment_Task_ID := Environment_Task;
875 Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
876 -- Initialize the lock used to synchronize chain of all ATCBs.
878 Enter_Task (Environment_Task);
880 Set_Priority (Environment_Task,
881 Environment_Task.Common.Current_Priority);
884 procedure Initialize_Athread_Library is
885 Result : Interfaces.C.int;
886 Init : aliased pthread_init_struct;
888 package PINF renames System.Program_Info;
889 package C renames Interfaces.C;
892 Init.conf_initsize := C.int (PINF.Pthread_Arena_Size);
893 Init.max_sproc_count := C.int (PINF.Max_Sproc_Count);
894 Init.sproc_stack_size := C.size_t (PINF.Sproc_Stack_Size);
895 Init.os_default_priority := C.int (PINF.Os_Default_Priority);
896 Init.os_sched_signal := C.int (PINF.Pthread_Sched_Signal);
897 Init.guard_pages := C.int (PINF.Stack_Guard_Pages);
898 Init.init_sproc_count := C.int (PINF.Initial_Sproc_Count);
900 Result := pthread_exec_begin (Init'Access);
901 pragma Assert (Result /= FUNC_ERR);
903 if Result = FUNC_ERR then
904 raise Storage_Error; -- Insufficient resources.
907 end Initialize_Athread_Library;
910 Initialize_Athread_Library;
911 end System.Task_Primitives.Operations;