[gcc]
[official-gcc.git] / gcc / ada / s-taprop-linux.adb
blob1d829de6ee023d45e5af11bd975ea98183a33e20
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNU ADA 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-2017, Free Software Foundation, Inc. --
10 -- --
11 -- GNARL is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
17 -- --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
21 -- --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
26 -- --
27 -- GNARL was developed by the GNARL team at Florida State University. --
28 -- Extensive contributions were provided by Ada Core Technologies, Inc. --
29 -- --
30 ------------------------------------------------------------------------------
32 -- This is a GNU/Linux (GNU/LinuxThreads) version of this package
34 -- This package contains all the GNULL primitives that interface directly with
35 -- the underlying OS.
37 pragma Polling (Off);
38 -- Turn off polling, we do not want ATC polling to take place during tasking
39 -- operations. It causes infinite loops and other problems.
41 with Interfaces.C; use Interfaces; use type Interfaces.C.int;
43 with System.Task_Info;
44 with System.Tasking.Debug;
45 with System.Interrupt_Management;
46 with System.OS_Constants;
47 with System.OS_Primitives;
48 with System.Multiprocessors;
50 with System.Soft_Links;
51 -- We use System.Soft_Links instead of System.Tasking.Initialization
52 -- because the later is a higher level package that we shouldn't depend on.
53 -- For example when using the restricted run time, it is replaced by
54 -- System.Tasking.Restricted.Stages.
56 package body System.Task_Primitives.Operations is
58 package OSC renames System.OS_Constants;
59 package SSL renames System.Soft_Links;
61 use System.Tasking.Debug;
62 use System.Tasking;
63 use System.OS_Interface;
64 use System.Parameters;
65 use System.OS_Primitives;
66 use System.Task_Info;
68 ----------------
69 -- Local Data --
70 ----------------
72 -- The followings are logically constants, but need to be initialized
73 -- at run time.
75 Single_RTS_Lock : aliased RTS_Lock;
76 -- This is a lock to allow only one thread of control in the RTS at
77 -- a time; it is used to execute in mutual exclusion from all other tasks.
78 -- Used mainly in Single_Lock mode, but also to protect All_Tasks_List
80 Environment_Task_Id : Task_Id;
81 -- A variable to hold Task_Id for the environment task
83 Unblocked_Signal_Mask : aliased sigset_t;
84 -- The set of signals that should be unblocked in all tasks
86 -- The followings are internal configuration constants needed
88 Next_Serial_Number : Task_Serial_Number := 100;
89 -- We start at 100 (reserve some special values for using in error checks)
91 Time_Slice_Val : Integer;
92 pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
94 Dispatching_Policy : Character;
95 pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
97 Locking_Policy : Character;
98 pragma Import (C, Locking_Policy, "__gl_locking_policy");
100 Foreign_Task_Elaborated : aliased Boolean := True;
101 -- Used to identified fake tasks (i.e., non-Ada Threads)
103 Use_Alternate_Stack : constant Boolean := Alternate_Stack_Size /= 0;
104 -- Whether to use an alternate signal stack for stack overflows
106 Abort_Handler_Installed : Boolean := False;
107 -- True if a handler for the abort signal is installed
109 Null_Thread_Id : constant pthread_t := pthread_t'Last;
110 -- Constant to indicate that the thread identifier has not yet been
111 -- initialized.
113 --------------------
114 -- Local Packages --
115 --------------------
117 package Specific is
119 procedure Initialize (Environment_Task : Task_Id);
120 pragma Inline (Initialize);
121 -- Initialize various data needed by this package
123 function Is_Valid_Task return Boolean;
124 pragma Inline (Is_Valid_Task);
125 -- Does executing thread have a TCB?
127 procedure Set (Self_Id : Task_Id);
128 pragma Inline (Set);
129 -- Set the self id for the current task
131 function Self return Task_Id;
132 pragma Inline (Self);
133 -- Return a pointer to the Ada Task Control Block of the calling task
135 end Specific;
137 package body Specific is separate;
138 -- The body of this package is target specific
140 ----------------------------------
141 -- ATCB allocation/deallocation --
142 ----------------------------------
144 package body ATCB_Allocation is separate;
145 -- The body of this package is shared across several targets
147 ---------------------------------
148 -- Support for foreign threads --
149 ---------------------------------
151 function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
152 -- Allocate and Initialize a new ATCB for the current Thread
154 function Register_Foreign_Thread
155 (Thread : Thread_Id) return Task_Id is separate;
157 -----------------------
158 -- Local Subprograms --
159 -----------------------
161 procedure Abort_Handler (signo : Signal);
163 function GNAT_pthread_condattr_setup
164 (attr : access pthread_condattr_t) return C.int;
165 pragma Import
166 (C, GNAT_pthread_condattr_setup, "__gnat_pthread_condattr_setup");
168 function Prio_To_Linux_Prio (Prio : Any_Priority) return C.int is
169 (C.int (Prio) + 1);
170 -- Convert Ada priority to Linux priority. Priorities are 1 .. 99 on
171 -- GNU/Linux, so we map 0 .. 98 to 1 .. 99.
173 function Get_Ceiling_Support return Boolean;
174 -- Get the value of the Ceiling_Support constant (see below).
175 -- ???For now, we're returning True only if running as superuser,
176 -- and ignore capabilities.
178 function Get_Ceiling_Support return Boolean is
179 Ceiling_Support : Boolean := False;
180 begin
181 if Locking_Policy = 'C' then
182 declare
183 function geteuid return Integer;
184 pragma Import (C, geteuid, "geteuid");
185 Superuser : constant Boolean := geteuid = 0;
186 begin
187 if Superuser then
188 Ceiling_Support := True;
189 end if;
190 end;
191 end if;
193 return Ceiling_Support;
194 end Get_Ceiling_Support;
196 pragma Warnings (Off, "non-static call not allowed in preelaborated unit");
197 Ceiling_Support : constant Boolean := Get_Ceiling_Support;
198 pragma Warnings (On, "non-static call not allowed in preelaborated unit");
199 -- True if the locking policy is Ceiling_Locking, and the current process
200 -- has permission to use this policy. The process has permission if it is
201 -- running as 'root', or if the capability was set by the setcap command,
202 -- as in "sudo /sbin/setcap cap_sys_nice=ep exe_file". If it doesn't have
203 -- permission, then a request for Ceiling_Locking is ignored.
205 type RTS_Lock_Ptr is not null access all RTS_Lock;
207 function Init_Mutex (L : RTS_Lock_Ptr; Prio : Any_Priority) return C.int;
208 -- Initialize the mutex L. If Ceiling_Support is True, then set the ceiling
209 -- to Prio. Returns 0 for success, or ENOMEM for out-of-memory.
211 -------------------
212 -- Abort_Handler --
213 -------------------
215 procedure Abort_Handler (signo : Signal) is
216 pragma Unreferenced (signo);
218 Self_Id : constant Task_Id := Self;
219 Result : C.int;
220 Old_Set : aliased sigset_t;
222 begin
223 -- It's not safe to raise an exception when using GCC ZCX mechanism.
224 -- Note that we still need to install a signal handler, since in some
225 -- cases (e.g. shutdown of the Server_Task in System.Interrupts) we
226 -- need to send the Abort signal to a task.
228 if ZCX_By_Default then
229 return;
230 end if;
232 if Self_Id.Deferral_Level = 0
233 and then Self_Id.Pending_ATC_Level < Self_Id.ATC_Nesting_Level
234 and then not Self_Id.Aborting
235 then
236 Self_Id.Aborting := True;
238 -- Make sure signals used for RTS internal purpose are unmasked
240 Result :=
241 pthread_sigmask
242 (SIG_UNBLOCK,
243 Unblocked_Signal_Mask'Access,
244 Old_Set'Access);
245 pragma Assert (Result = 0);
247 raise Standard'Abort_Signal;
248 end if;
249 end Abort_Handler;
251 --------------
252 -- Lock_RTS --
253 --------------
255 procedure Lock_RTS is
256 begin
257 Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
258 end Lock_RTS;
260 ----------------
261 -- Unlock_RTS --
262 ----------------
264 procedure Unlock_RTS is
265 begin
266 Unlock (Single_RTS_Lock'Access, Global_Lock => True);
267 end Unlock_RTS;
269 -----------------
270 -- Stack_Guard --
271 -----------------
273 -- The underlying thread system extends the memory (up to 2MB) when needed
275 procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is
276 pragma Unreferenced (T);
277 pragma Unreferenced (On);
278 begin
279 null;
280 end Stack_Guard;
282 --------------------
283 -- Get_Thread_Id --
284 --------------------
286 function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is
287 begin
288 return T.Common.LL.Thread;
289 end Get_Thread_Id;
291 ----------
292 -- Self --
293 ----------
295 function Self return Task_Id renames Specific.Self;
297 ----------------
298 -- Init_Mutex --
299 ----------------
301 function Init_Mutex (L : RTS_Lock_Ptr; Prio : Any_Priority) return C.int is
302 Mutex_Attr : aliased pthread_mutexattr_t;
303 Result, Result_2 : C.int;
305 begin
306 Result := pthread_mutexattr_init (Mutex_Attr'Access);
307 pragma Assert (Result in 0 | ENOMEM);
309 if Result = ENOMEM then
310 return Result;
311 end if;
313 if Ceiling_Support then
314 Result := pthread_mutexattr_setprotocol
315 (Mutex_Attr'Access, PTHREAD_PRIO_PROTECT);
316 pragma Assert (Result = 0);
318 Result := pthread_mutexattr_setprioceiling
319 (Mutex_Attr'Access, Prio_To_Linux_Prio (Prio));
320 pragma Assert (Result = 0);
322 elsif Locking_Policy = 'I' then
323 Result := pthread_mutexattr_setprotocol
324 (Mutex_Attr'Access, PTHREAD_PRIO_INHERIT);
325 pragma Assert (Result = 0);
326 end if;
328 Result := pthread_mutex_init (L, Mutex_Attr'Access);
329 pragma Assert (Result in 0 | ENOMEM);
331 Result_2 := pthread_mutexattr_destroy (Mutex_Attr'Access);
332 pragma Assert (Result_2 = 0);
333 return Result; -- of pthread_mutex_init, not pthread_mutexattr_destroy
334 end Init_Mutex;
336 ---------------------
337 -- Initialize_Lock --
338 ---------------------
340 -- Note: mutexes and cond_variables needed per-task basis are initialized
341 -- in Initialize_TCB and the Storage_Error is handled. Other mutexes (such
342 -- as RTS_Lock, Memory_Lock...) used in RTS is initialized before any
343 -- status change of RTS. Therefore raising Storage_Error in the following
344 -- routines should be able to be handled safely.
346 procedure Initialize_Lock
347 (Prio : Any_Priority;
348 L : not null access Lock)
350 begin
351 if Locking_Policy = 'R' then
352 declare
353 RWlock_Attr : aliased pthread_rwlockattr_t;
354 Result : C.int;
356 begin
357 -- Set the rwlock to prefer writer to avoid writers starvation
359 Result := pthread_rwlockattr_init (RWlock_Attr'Access);
360 pragma Assert (Result = 0);
362 Result := pthread_rwlockattr_setkind_np
363 (RWlock_Attr'Access,
364 PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
365 pragma Assert (Result = 0);
367 Result := pthread_rwlock_init (L.RW'Access, RWlock_Attr'Access);
369 pragma Assert (Result in 0 | ENOMEM);
371 if Result = ENOMEM then
372 raise Storage_Error with "Failed to allocate a lock";
373 end if;
374 end;
376 else
377 if Init_Mutex (L.WO'Access, Prio) = ENOMEM then
378 raise Storage_Error with "Failed to allocate a lock";
379 end if;
380 end if;
381 end Initialize_Lock;
383 procedure Initialize_Lock
384 (L : not null access RTS_Lock; Level : Lock_Level)
386 pragma Unreferenced (Level);
387 begin
388 if Init_Mutex (L.all'Access, Any_Priority'Last) = ENOMEM then
389 raise Storage_Error with "Failed to allocate a lock";
390 end if;
391 end Initialize_Lock;
393 -------------------
394 -- Finalize_Lock --
395 -------------------
397 procedure Finalize_Lock (L : not null access Lock) is
398 Result : C.int;
399 begin
400 if Locking_Policy = 'R' then
401 Result := pthread_rwlock_destroy (L.RW'Access);
402 else
403 Result := pthread_mutex_destroy (L.WO'Access);
404 end if;
405 pragma Assert (Result = 0);
406 end Finalize_Lock;
408 procedure Finalize_Lock (L : not null access RTS_Lock) is
409 Result : C.int;
410 begin
411 Result := pthread_mutex_destroy (L);
412 pragma Assert (Result = 0);
413 end Finalize_Lock;
415 ----------------
416 -- Write_Lock --
417 ----------------
419 procedure Write_Lock
420 (L : not null access Lock;
421 Ceiling_Violation : out Boolean)
423 Result : C.int;
424 begin
425 if Locking_Policy = 'R' then
426 Result := pthread_rwlock_wrlock (L.RW'Access);
427 else
428 Result := pthread_mutex_lock (L.WO'Access);
429 end if;
431 -- The cause of EINVAL is a priority ceiling violation
433 pragma Assert (Result in 0 | EINVAL);
434 Ceiling_Violation := Result = EINVAL;
435 end Write_Lock;
437 procedure Write_Lock
438 (L : not null access RTS_Lock;
439 Global_Lock : Boolean := False)
441 Result : C.int;
442 begin
443 if not Single_Lock or else Global_Lock then
444 Result := pthread_mutex_lock (L);
445 pragma Assert (Result = 0);
446 end if;
447 end Write_Lock;
449 procedure Write_Lock (T : Task_Id) is
450 Result : C.int;
451 begin
452 if not Single_Lock then
453 Result := pthread_mutex_lock (T.Common.LL.L'Access);
454 pragma Assert (Result = 0);
455 end if;
456 end Write_Lock;
458 ---------------
459 -- Read_Lock --
460 ---------------
462 procedure Read_Lock
463 (L : not null access Lock;
464 Ceiling_Violation : out Boolean)
466 Result : C.int;
467 begin
468 if Locking_Policy = 'R' then
469 Result := pthread_rwlock_rdlock (L.RW'Access);
470 else
471 Result := pthread_mutex_lock (L.WO'Access);
472 end if;
474 -- The cause of EINVAL is a priority ceiling violation
476 pragma Assert (Result in 0 | EINVAL);
477 Ceiling_Violation := Result = EINVAL;
478 end Read_Lock;
480 ------------
481 -- Unlock --
482 ------------
484 procedure Unlock (L : not null access Lock) is
485 Result : C.int;
486 begin
487 if Locking_Policy = 'R' then
488 Result := pthread_rwlock_unlock (L.RW'Access);
489 else
490 Result := pthread_mutex_unlock (L.WO'Access);
491 end if;
492 pragma Assert (Result = 0);
493 end Unlock;
495 procedure Unlock
496 (L : not null access RTS_Lock;
497 Global_Lock : Boolean := False)
499 Result : C.int;
500 begin
501 if not Single_Lock or else Global_Lock then
502 Result := pthread_mutex_unlock (L);
503 pragma Assert (Result = 0);
504 end if;
505 end Unlock;
507 procedure Unlock (T : Task_Id) is
508 Result : C.int;
509 begin
510 if not Single_Lock then
511 Result := pthread_mutex_unlock (T.Common.LL.L'Access);
512 pragma Assert (Result = 0);
513 end if;
514 end Unlock;
516 -----------------
517 -- Set_Ceiling --
518 -----------------
520 -- Dynamic priority ceilings are not supported by the underlying system
522 procedure Set_Ceiling
523 (L : not null access Lock;
524 Prio : Any_Priority)
526 pragma Unreferenced (L, Prio);
527 begin
528 null;
529 end Set_Ceiling;
531 -----------
532 -- Sleep --
533 -----------
535 procedure Sleep
536 (Self_ID : Task_Id;
537 Reason : System.Tasking.Task_States)
539 pragma Unreferenced (Reason);
541 Result : C.int;
543 begin
544 pragma Assert (Self_ID = Self);
546 Result :=
547 pthread_cond_wait
548 (cond => Self_ID.Common.LL.CV'Access,
549 mutex => (if Single_Lock
550 then Single_RTS_Lock'Access
551 else Self_ID.Common.LL.L'Access));
553 -- EINTR is not considered a failure
555 pragma Assert (Result in 0 | EINTR);
556 end Sleep;
558 -----------------
559 -- Timed_Sleep --
560 -----------------
562 -- This is for use within the run-time system, so abort is
563 -- assumed to be already deferred, and the caller should be
564 -- holding its own ATCB lock.
566 procedure Timed_Sleep
567 (Self_ID : Task_Id;
568 Time : Duration;
569 Mode : ST.Delay_Modes;
570 Reason : System.Tasking.Task_States;
571 Timedout : out Boolean;
572 Yielded : out Boolean)
574 pragma Unreferenced (Reason);
576 Base_Time : constant Duration := Monotonic_Clock;
577 Check_Time : Duration := Base_Time;
578 Abs_Time : Duration;
579 Request : aliased timespec;
580 Result : C.int;
582 begin
583 Timedout := True;
584 Yielded := False;
586 Abs_Time :=
587 (if Mode = Relative
588 then Duration'Min (Time, Max_Sensible_Delay) + Check_Time
589 else Duration'Min (Check_Time + Max_Sensible_Delay, Time));
591 if Abs_Time > Check_Time then
592 Request := To_Timespec (Abs_Time);
594 loop
595 exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
597 Result :=
598 pthread_cond_timedwait
599 (cond => Self_ID.Common.LL.CV'Access,
600 mutex => (if Single_Lock
601 then Single_RTS_Lock'Access
602 else Self_ID.Common.LL.L'Access),
603 abstime => Request'Access);
605 Check_Time := Monotonic_Clock;
606 exit when Abs_Time <= Check_Time or else Check_Time < Base_Time;
608 if Result in 0 | EINTR then
610 -- Somebody may have called Wakeup for us
612 Timedout := False;
613 exit;
614 end if;
616 pragma Assert (Result = ETIMEDOUT);
617 end loop;
618 end if;
619 end Timed_Sleep;
621 -----------------
622 -- Timed_Delay --
623 -----------------
625 -- This is for use in implementing delay statements, so we assume the
626 -- caller is abort-deferred but is holding no locks.
628 procedure Timed_Delay
629 (Self_ID : Task_Id;
630 Time : Duration;
631 Mode : ST.Delay_Modes)
633 Base_Time : constant Duration := Monotonic_Clock;
634 Check_Time : Duration := Base_Time;
635 Abs_Time : Duration;
636 Request : aliased timespec;
638 Result : C.int;
639 pragma Warnings (Off, Result);
641 begin
642 if Single_Lock then
643 Lock_RTS;
644 end if;
646 Write_Lock (Self_ID);
648 Abs_Time :=
649 (if Mode = Relative
650 then Time + Check_Time
651 else Duration'Min (Check_Time + Max_Sensible_Delay, Time));
653 if Abs_Time > Check_Time then
654 Request := To_Timespec (Abs_Time);
655 Self_ID.Common.State := Delay_Sleep;
657 loop
658 exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
660 Result :=
661 pthread_cond_timedwait
662 (cond => Self_ID.Common.LL.CV'Access,
663 mutex => (if Single_Lock
664 then Single_RTS_Lock'Access
665 else Self_ID.Common.LL.L'Access),
666 abstime => Request'Access);
668 Check_Time := Monotonic_Clock;
669 exit when Abs_Time <= Check_Time or else Check_Time < Base_Time;
671 pragma Assert (Result in 0 | ETIMEDOUT | EINTR);
672 end loop;
674 Self_ID.Common.State := Runnable;
675 end if;
677 Unlock (Self_ID);
679 if Single_Lock then
680 Unlock_RTS;
681 end if;
683 Result := sched_yield;
684 end Timed_Delay;
686 ---------------------
687 -- Monotonic_Clock --
688 ---------------------
690 function Monotonic_Clock return Duration is
691 TS : aliased timespec;
692 Result : C.int;
693 begin
694 Result := clock_gettime
695 (clock_id => OSC.CLOCK_RT_Ada, tp => TS'Unchecked_Access);
696 pragma Assert (Result = 0);
698 return To_Duration (TS);
699 end Monotonic_Clock;
701 -------------------
702 -- RT_Resolution --
703 -------------------
705 function RT_Resolution return Duration is
706 TS : aliased timespec;
707 Result : C.int;
709 begin
710 Result := clock_getres (OSC.CLOCK_REALTIME, TS'Unchecked_Access);
711 pragma Assert (Result = 0);
713 return To_Duration (TS);
714 end RT_Resolution;
716 ------------
717 -- Wakeup --
718 ------------
720 procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
721 pragma Unreferenced (Reason);
722 Result : C.int;
723 begin
724 Result := pthread_cond_signal (T.Common.LL.CV'Access);
725 pragma Assert (Result = 0);
726 end Wakeup;
728 -----------
729 -- Yield --
730 -----------
732 procedure Yield (Do_Yield : Boolean := True) is
733 Result : C.int;
734 pragma Unreferenced (Result);
735 begin
736 if Do_Yield then
737 Result := sched_yield;
738 end if;
739 end Yield;
741 ------------------
742 -- Set_Priority --
743 ------------------
745 procedure Set_Priority
746 (T : Task_Id;
747 Prio : Any_Priority;
748 Loss_Of_Inheritance : Boolean := False)
750 pragma Unreferenced (Loss_Of_Inheritance);
752 Result : C.int;
753 Param : aliased struct_sched_param;
755 function Get_Policy (Prio : Any_Priority) return Character;
756 pragma Import (C, Get_Policy, "__gnat_get_specific_dispatching");
757 -- Get priority specific dispatching policy
759 Priority_Specific_Policy : constant Character := Get_Policy (Prio);
760 -- Upper case first character of the policy name corresponding to the
761 -- task as set by a Priority_Specific_Dispatching pragma.
763 begin
764 T.Common.Current_Priority := Prio;
766 Param.sched_priority := Prio_To_Linux_Prio (Prio);
768 if Dispatching_Policy = 'R'
769 or else Priority_Specific_Policy = 'R'
770 or else Time_Slice_Val > 0
771 then
772 Result :=
773 pthread_setschedparam
774 (T.Common.LL.Thread, SCHED_RR, Param'Access);
776 elsif Dispatching_Policy = 'F'
777 or else Priority_Specific_Policy = 'F'
778 or else Time_Slice_Val = 0
779 then
780 Result :=
781 pthread_setschedparam
782 (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
784 else
785 Param.sched_priority := 0;
786 Result :=
787 pthread_setschedparam
788 (T.Common.LL.Thread,
789 SCHED_OTHER, Param'Access);
790 end if;
792 pragma Assert (Result in 0 | EPERM | EINVAL);
793 end Set_Priority;
795 ------------------
796 -- Get_Priority --
797 ------------------
799 function Get_Priority (T : Task_Id) return Any_Priority is
800 begin
801 return T.Common.Current_Priority;
802 end Get_Priority;
804 ----------------
805 -- Enter_Task --
806 ----------------
808 procedure Enter_Task (Self_ID : Task_Id) is
809 begin
810 if Self_ID.Common.Task_Info /= null
811 and then Self_ID.Common.Task_Info.CPU_Affinity = No_CPU
812 then
813 raise Invalid_CPU_Number;
814 end if;
816 Self_ID.Common.LL.Thread := pthread_self;
817 Self_ID.Common.LL.LWP := lwp_self;
819 -- Set thread name to ease debugging. If the name of the task is
820 -- "foreign thread" (as set by Register_Foreign_Thread) retrieve
821 -- the name of the thread and update the name of the task instead.
823 if Self_ID.Common.Task_Image_Len = 14
824 and then Self_ID.Common.Task_Image (1 .. 14) = "foreign thread"
825 then
826 declare
827 Thread_Name : String (1 .. 16);
828 -- PR_GET_NAME returns a string of up to 16 bytes
830 Len : Natural := 0;
831 -- Length of the task name contained in Task_Name
833 Result : C.int;
834 -- Result from the prctl call
835 begin
836 Result := prctl (PR_GET_NAME, unsigned_long (Thread_Name'Address));
837 pragma Assert (Result = 0);
839 -- Find the length of the given name
841 for J in Thread_Name'Range loop
842 if Thread_Name (J) /= ASCII.NUL then
843 Len := Len + 1;
844 else
845 exit;
846 end if;
847 end loop;
849 -- Cover the odd situation where someone decides to change
850 -- Parameters.Max_Task_Image_Length to less than 16 characters.
852 if Len > Parameters.Max_Task_Image_Length then
853 Len := Parameters.Max_Task_Image_Length;
854 end if;
856 -- Copy the name of the thread to the task's ATCB
858 Self_ID.Common.Task_Image (1 .. Len) := Thread_Name (1 .. Len);
859 Self_ID.Common.Task_Image_Len := Len;
860 end;
862 elsif Self_ID.Common.Task_Image_Len > 0 then
863 declare
864 Task_Name : String (1 .. Parameters.Max_Task_Image_Length + 1);
865 Result : C.int;
867 begin
868 Task_Name (1 .. Self_ID.Common.Task_Image_Len) :=
869 Self_ID.Common.Task_Image (1 .. Self_ID.Common.Task_Image_Len);
870 Task_Name (Self_ID.Common.Task_Image_Len + 1) := ASCII.NUL;
872 Result := prctl (PR_SET_NAME, unsigned_long (Task_Name'Address));
873 pragma Assert (Result = 0);
874 end;
875 end if;
877 Specific.Set (Self_ID);
879 if Use_Alternate_Stack
880 and then Self_ID.Common.Task_Alternate_Stack /= Null_Address
881 then
882 declare
883 Stack : aliased stack_t;
884 Result : C.int;
885 begin
886 Stack.ss_sp := Self_ID.Common.Task_Alternate_Stack;
887 Stack.ss_size := Alternate_Stack_Size;
888 Stack.ss_flags := 0;
889 Result := sigaltstack (Stack'Access, null);
890 pragma Assert (Result = 0);
891 end;
892 end if;
893 end Enter_Task;
895 -------------------
896 -- Is_Valid_Task --
897 -------------------
899 function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
901 -----------------------------
902 -- Register_Foreign_Thread --
903 -----------------------------
905 function Register_Foreign_Thread return Task_Id is
906 begin
907 if Is_Valid_Task then
908 return Self;
909 else
910 return Register_Foreign_Thread (pthread_self);
911 end if;
912 end Register_Foreign_Thread;
914 --------------------
915 -- Initialize_TCB --
916 --------------------
918 procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
919 Result : C.int;
920 Cond_Attr : aliased pthread_condattr_t;
922 begin
923 -- Give the task a unique serial number
925 Self_ID.Serial_Number := Next_Serial_Number;
926 Next_Serial_Number := Next_Serial_Number + 1;
927 pragma Assert (Next_Serial_Number /= 0);
929 Self_ID.Common.LL.Thread := Null_Thread_Id;
931 if not Single_Lock then
932 if Init_Mutex
933 (Self_ID.Common.LL.L'Access, Any_Priority'Last) /= 0
934 then
935 Succeeded := False;
936 return;
937 end if;
938 end if;
940 Result := pthread_condattr_init (Cond_Attr'Access);
941 pragma Assert (Result in 0 | ENOMEM);
943 if Result = 0 then
944 Result := GNAT_pthread_condattr_setup (Cond_Attr'Access);
945 pragma Assert (Result = 0);
947 Result :=
948 pthread_cond_init
949 (Self_ID.Common.LL.CV'Access, Cond_Attr'Access);
950 pragma Assert (Result in 0 | ENOMEM);
951 end if;
953 if Result = 0 then
954 Succeeded := True;
955 else
956 if not Single_Lock then
957 Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
958 pragma Assert (Result = 0);
959 end if;
961 Succeeded := False;
962 end if;
964 Result := pthread_condattr_destroy (Cond_Attr'Access);
965 pragma Assert (Result = 0);
966 end Initialize_TCB;
968 -----------------
969 -- Create_Task --
970 -----------------
972 procedure Create_Task
973 (T : Task_Id;
974 Wrapper : System.Address;
975 Stack_Size : System.Parameters.Size_Type;
976 Priority : Any_Priority;
977 Succeeded : out Boolean)
979 Thread_Attr : aliased pthread_attr_t;
980 Adjusted_Stack_Size : C.size_t;
981 Result : C.int;
983 use type Multiprocessors.CPU_Range, Interfaces.C.size_t;
985 begin
986 -- Check whether both Dispatching_Domain and CPU are specified for
987 -- the task, and the CPU value is not contained within the range of
988 -- processors for the domain.
990 if T.Common.Domain /= null
991 and then T.Common.Base_CPU /= Multiprocessors.Not_A_Specific_CPU
992 and then
993 (T.Common.Base_CPU not in T.Common.Domain'Range
994 or else not T.Common.Domain (T.Common.Base_CPU))
995 then
996 Succeeded := False;
997 return;
998 end if;
1000 Adjusted_Stack_Size := C.size_t (Stack_Size + Alternate_Stack_Size);
1002 Result := pthread_attr_init (Thread_Attr'Access);
1003 pragma Assert (Result in 0 | ENOMEM);
1005 if Result /= 0 then
1006 Succeeded := False;
1007 return;
1008 end if;
1010 Result :=
1011 pthread_attr_setstacksize (Thread_Attr'Access, Adjusted_Stack_Size);
1012 pragma Assert (Result = 0);
1014 Result :=
1015 pthread_attr_setdetachstate
1016 (Thread_Attr'Access, PTHREAD_CREATE_DETACHED);
1017 pragma Assert (Result = 0);
1019 -- Set the required attributes for the creation of the thread
1021 -- Note: Previously, we called pthread_setaffinity_np (after thread
1022 -- creation but before thread activation) to set the affinity but it was
1023 -- not behaving as expected. Setting the required attributes for the
1024 -- creation of the thread works correctly and it is more appropriate.
1026 -- Do nothing if required support not provided by the operating system
1028 if pthread_attr_setaffinity_np'Address = Null_Address then
1029 null;
1031 -- Support is available
1033 elsif T.Common.Base_CPU /= Multiprocessors.Not_A_Specific_CPU then
1034 declare
1035 CPUs : constant size_t :=
1036 C.size_t (Multiprocessors.Number_Of_CPUs);
1037 CPU_Set : constant cpu_set_t_ptr := CPU_ALLOC (CPUs);
1038 Size : constant size_t := CPU_ALLOC_SIZE (CPUs);
1040 begin
1041 CPU_ZERO (Size, CPU_Set);
1042 System.OS_Interface.CPU_SET
1043 (int (T.Common.Base_CPU), Size, CPU_Set);
1044 Result :=
1045 pthread_attr_setaffinity_np (Thread_Attr'Access, Size, CPU_Set);
1046 pragma Assert (Result = 0);
1048 CPU_FREE (CPU_Set);
1049 end;
1051 -- Handle Task_Info
1053 elsif T.Common.Task_Info /= null then
1054 Result :=
1055 pthread_attr_setaffinity_np
1056 (Thread_Attr'Access,
1057 CPU_SETSIZE / 8,
1058 T.Common.Task_Info.CPU_Affinity'Access);
1059 pragma Assert (Result = 0);
1061 -- Handle dispatching domains
1063 -- To avoid changing CPU affinities when not needed, we set the
1064 -- affinity only when assigning to a domain other than the default
1065 -- one, or when the default one has been modified.
1067 elsif T.Common.Domain /= null and then
1068 (T.Common.Domain /= ST.System_Domain
1069 or else T.Common.Domain.all /=
1070 (Multiprocessors.CPU'First ..
1071 Multiprocessors.Number_Of_CPUs => True))
1072 then
1073 declare
1074 CPUs : constant size_t :=
1075 C.size_t (Multiprocessors.Number_Of_CPUs);
1076 CPU_Set : constant cpu_set_t_ptr := CPU_ALLOC (CPUs);
1077 Size : constant size_t := CPU_ALLOC_SIZE (CPUs);
1079 begin
1080 CPU_ZERO (Size, CPU_Set);
1082 -- Set the affinity to all the processors belonging to the
1083 -- dispatching domain.
1085 for Proc in T.Common.Domain'Range loop
1086 if T.Common.Domain (Proc) then
1087 System.OS_Interface.CPU_SET (int (Proc), Size, CPU_Set);
1088 end if;
1089 end loop;
1091 Result :=
1092 pthread_attr_setaffinity_np (Thread_Attr'Access, Size, CPU_Set);
1093 pragma Assert (Result = 0);
1095 CPU_FREE (CPU_Set);
1096 end;
1097 end if;
1099 -- Since the initial signal mask of a thread is inherited from the
1100 -- creator, and the Environment task has all its signals masked, we
1101 -- do not need to manipulate caller's signal mask at this point.
1102 -- All tasks in RTS will have All_Tasks_Mask initially.
1104 -- Note: the use of Unrestricted_Access in the following call is needed
1105 -- because otherwise we have an error of getting a access-to-volatile
1106 -- value which points to a non-volatile object. But in this case it is
1107 -- safe to do this, since we know we have no problems with aliasing and
1108 -- Unrestricted_Access bypasses this check.
1110 Result := pthread_create
1111 (T.Common.LL.Thread'Unrestricted_Access,
1112 Thread_Attr'Access,
1113 Thread_Body_Access (Wrapper),
1114 To_Address (T));
1116 pragma Assert (Result in 0 | EAGAIN | ENOMEM);
1118 if Result /= 0 then
1119 Succeeded := False;
1120 Result := pthread_attr_destroy (Thread_Attr'Access);
1121 pragma Assert (Result = 0);
1122 return;
1123 end if;
1125 Succeeded := True;
1127 Result := pthread_attr_destroy (Thread_Attr'Access);
1128 pragma Assert (Result = 0);
1130 Set_Priority (T, Priority);
1131 end Create_Task;
1133 ------------------
1134 -- Finalize_TCB --
1135 ------------------
1137 procedure Finalize_TCB (T : Task_Id) is
1138 Result : C.int;
1140 begin
1141 if not Single_Lock then
1142 Result := pthread_mutex_destroy (T.Common.LL.L'Access);
1143 pragma Assert (Result = 0);
1144 end if;
1146 Result := pthread_cond_destroy (T.Common.LL.CV'Access);
1147 pragma Assert (Result = 0);
1149 if T.Known_Tasks_Index /= -1 then
1150 Known_Tasks (T.Known_Tasks_Index) := null;
1151 end if;
1153 ATCB_Allocation.Free_ATCB (T);
1154 end Finalize_TCB;
1156 ---------------
1157 -- Exit_Task --
1158 ---------------
1160 procedure Exit_Task is
1161 begin
1162 Specific.Set (null);
1163 end Exit_Task;
1165 ----------------
1166 -- Abort_Task --
1167 ----------------
1169 procedure Abort_Task (T : Task_Id) is
1170 Result : C.int;
1172 ESRCH : constant := 3; -- No such process
1173 -- It can happen that T has already vanished, in which case pthread_kill
1174 -- returns ESRCH, so we don't consider that to be an error.
1176 begin
1177 if Abort_Handler_Installed then
1178 Result :=
1179 pthread_kill
1180 (T.Common.LL.Thread,
1181 Signal (System.Interrupt_Management.Abort_Task_Interrupt));
1182 pragma Assert (Result in 0 | ESRCH);
1183 end if;
1184 end Abort_Task;
1186 ----------------
1187 -- Initialize --
1188 ----------------
1190 procedure Initialize (S : in out Suspension_Object) is
1191 Result : C.int;
1193 begin
1194 -- Initialize internal state (always to False (RM D.10(6)))
1196 S.State := False;
1197 S.Waiting := False;
1199 -- Initialize internal mutex
1201 Result := pthread_mutex_init (S.L'Access, null);
1203 pragma Assert (Result in 0 | ENOMEM);
1205 if Result = ENOMEM then
1206 raise Storage_Error;
1207 end if;
1209 -- Initialize internal condition variable
1211 Result := pthread_cond_init (S.CV'Access, null);
1213 pragma Assert (Result in 0 | ENOMEM);
1215 if Result /= 0 then
1216 Result := pthread_mutex_destroy (S.L'Access);
1217 pragma Assert (Result = 0);
1219 if Result = ENOMEM then
1220 raise Storage_Error;
1221 end if;
1222 end if;
1223 end Initialize;
1225 --------------
1226 -- Finalize --
1227 --------------
1229 procedure Finalize (S : in out Suspension_Object) is
1230 Result : C.int;
1232 begin
1233 -- Destroy internal mutex
1235 Result := pthread_mutex_destroy (S.L'Access);
1236 pragma Assert (Result = 0);
1238 -- Destroy internal condition variable
1240 Result := pthread_cond_destroy (S.CV'Access);
1241 pragma Assert (Result = 0);
1242 end Finalize;
1244 -------------------
1245 -- Current_State --
1246 -------------------
1248 function Current_State (S : Suspension_Object) return Boolean is
1249 begin
1250 -- We do not want to use lock on this read operation. State is marked
1251 -- as Atomic so that we ensure that the value retrieved is correct.
1253 return S.State;
1254 end Current_State;
1256 ---------------
1257 -- Set_False --
1258 ---------------
1260 procedure Set_False (S : in out Suspension_Object) is
1261 Result : C.int;
1263 begin
1264 SSL.Abort_Defer.all;
1266 Result := pthread_mutex_lock (S.L'Access);
1267 pragma Assert (Result = 0);
1269 S.State := False;
1271 Result := pthread_mutex_unlock (S.L'Access);
1272 pragma Assert (Result = 0);
1274 SSL.Abort_Undefer.all;
1275 end Set_False;
1277 --------------
1278 -- Set_True --
1279 --------------
1281 procedure Set_True (S : in out Suspension_Object) is
1282 Result : C.int;
1284 begin
1285 SSL.Abort_Defer.all;
1287 Result := pthread_mutex_lock (S.L'Access);
1288 pragma Assert (Result = 0);
1290 -- If there is already a task waiting on this suspension object then
1291 -- we resume it, leaving the state of the suspension object to False,
1292 -- as it is specified in ARM D.10 par. 9. Otherwise, it just leaves
1293 -- the state to True.
1295 if S.Waiting then
1296 S.Waiting := False;
1297 S.State := False;
1299 Result := pthread_cond_signal (S.CV'Access);
1300 pragma Assert (Result = 0);
1302 else
1303 S.State := True;
1304 end if;
1306 Result := pthread_mutex_unlock (S.L'Access);
1307 pragma Assert (Result = 0);
1309 SSL.Abort_Undefer.all;
1310 end Set_True;
1312 ------------------------
1313 -- Suspend_Until_True --
1314 ------------------------
1316 procedure Suspend_Until_True (S : in out Suspension_Object) is
1317 Result : C.int;
1319 begin
1320 SSL.Abort_Defer.all;
1322 Result := pthread_mutex_lock (S.L'Access);
1323 pragma Assert (Result = 0);
1325 if S.Waiting then
1327 -- Program_Error must be raised upon calling Suspend_Until_True
1328 -- if another task is already waiting on that suspension object
1329 -- (RM D.10(10)).
1331 Result := pthread_mutex_unlock (S.L'Access);
1332 pragma Assert (Result = 0);
1334 SSL.Abort_Undefer.all;
1336 raise Program_Error;
1338 else
1339 -- Suspend the task if the state is False. Otherwise, the task
1340 -- continues its execution, and the state of the suspension object
1341 -- is set to False (ARM D.10 par. 9).
1343 if S.State then
1344 S.State := False;
1345 else
1346 S.Waiting := True;
1348 loop
1349 -- Loop in case pthread_cond_wait returns earlier than expected
1350 -- (e.g. in case of EINTR caused by a signal). This should not
1351 -- happen with the current Linux implementation of pthread, but
1352 -- POSIX does not guarantee it so this may change in future.
1354 Result := pthread_cond_wait (S.CV'Access, S.L'Access);
1355 pragma Assert (Result in 0 | EINTR);
1357 exit when not S.Waiting;
1358 end loop;
1359 end if;
1361 Result := pthread_mutex_unlock (S.L'Access);
1362 pragma Assert (Result = 0);
1364 SSL.Abort_Undefer.all;
1365 end if;
1366 end Suspend_Until_True;
1368 ----------------
1369 -- Check_Exit --
1370 ----------------
1372 -- Dummy version
1374 function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1375 pragma Unreferenced (Self_ID);
1376 begin
1377 return True;
1378 end Check_Exit;
1380 --------------------
1381 -- Check_No_Locks --
1382 --------------------
1384 function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1385 pragma Unreferenced (Self_ID);
1386 begin
1387 return True;
1388 end Check_No_Locks;
1390 ----------------------
1391 -- Environment_Task --
1392 ----------------------
1394 function Environment_Task return Task_Id is
1395 begin
1396 return Environment_Task_Id;
1397 end Environment_Task;
1399 ------------------
1400 -- Suspend_Task --
1401 ------------------
1403 function Suspend_Task
1404 (T : ST.Task_Id;
1405 Thread_Self : Thread_Id) return Boolean
1407 begin
1408 if T.Common.LL.Thread /= Thread_Self then
1409 return pthread_kill (T.Common.LL.Thread, SIGSTOP) = 0;
1410 else
1411 return True;
1412 end if;
1413 end Suspend_Task;
1415 -----------------
1416 -- Resume_Task --
1417 -----------------
1419 function Resume_Task
1420 (T : ST.Task_Id;
1421 Thread_Self : Thread_Id) return Boolean
1423 begin
1424 if T.Common.LL.Thread /= Thread_Self then
1425 return pthread_kill (T.Common.LL.Thread, SIGCONT) = 0;
1426 else
1427 return True;
1428 end if;
1429 end Resume_Task;
1431 --------------------
1432 -- Stop_All_Tasks --
1433 --------------------
1435 procedure Stop_All_Tasks is
1436 begin
1437 null;
1438 end Stop_All_Tasks;
1440 ---------------
1441 -- Stop_Task --
1442 ---------------
1444 function Stop_Task (T : ST.Task_Id) return Boolean is
1445 pragma Unreferenced (T);
1446 begin
1447 return False;
1448 end Stop_Task;
1450 -------------------
1451 -- Continue_Task --
1452 -------------------
1454 function Continue_Task (T : ST.Task_Id) return Boolean is
1455 pragma Unreferenced (T);
1456 begin
1457 return False;
1458 end Continue_Task;
1460 ----------------
1461 -- Initialize --
1462 ----------------
1464 procedure Initialize (Environment_Task : Task_Id) is
1465 act : aliased struct_sigaction;
1466 old_act : aliased struct_sigaction;
1467 Tmp_Set : aliased sigset_t;
1468 Result : C.int;
1469 -- Whether to use an alternate signal stack for stack overflows
1471 function State
1472 (Int : System.Interrupt_Management.Interrupt_ID) return Character;
1473 pragma Import (C, State, "__gnat_get_interrupt_state");
1474 -- Get interrupt state. Defined in a-init.c
1475 -- The input argument is the interrupt number,
1476 -- and the result is one of the following:
1478 Default : constant Character := 's';
1479 -- 'n' this interrupt not set by any Interrupt_State pragma
1480 -- 'u' Interrupt_State pragma set state to User
1481 -- 'r' Interrupt_State pragma set state to Runtime
1482 -- 's' Interrupt_State pragma set state to System (use "default"
1483 -- system handler)
1485 begin
1486 Environment_Task_Id := Environment_Task;
1488 Interrupt_Management.Initialize;
1490 -- Prepare the set of signals that should be unblocked in all tasks
1492 Result := sigemptyset (Unblocked_Signal_Mask'Access);
1493 pragma Assert (Result = 0);
1495 for J in Interrupt_Management.Interrupt_ID loop
1496 if System.Interrupt_Management.Keep_Unmasked (J) then
1497 Result := sigaddset (Unblocked_Signal_Mask'Access, Signal (J));
1498 pragma Assert (Result = 0);
1499 end if;
1500 end loop;
1502 Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1504 -- Initialize the global RTS lock
1506 Specific.Initialize (Environment_Task);
1508 if Use_Alternate_Stack then
1509 Environment_Task.Common.Task_Alternate_Stack :=
1510 Alternate_Stack'Address;
1511 end if;
1513 -- Make environment task known here because it doesn't go through
1514 -- Activate_Tasks, which does it for all other tasks.
1516 Known_Tasks (Known_Tasks'First) := Environment_Task;
1517 Environment_Task.Known_Tasks_Index := Known_Tasks'First;
1519 Enter_Task (Environment_Task);
1521 if State
1522 (System.Interrupt_Management.Abort_Task_Interrupt) /= Default
1523 then
1524 act.sa_flags := 0;
1525 act.sa_handler := Abort_Handler'Address;
1527 Result := sigemptyset (Tmp_Set'Access);
1528 pragma Assert (Result = 0);
1529 act.sa_mask := Tmp_Set;
1531 Result :=
1532 sigaction
1533 (Signal (Interrupt_Management.Abort_Task_Interrupt),
1534 act'Unchecked_Access,
1535 old_act'Unchecked_Access);
1536 pragma Assert (Result = 0);
1537 Abort_Handler_Installed := True;
1538 end if;
1540 -- pragma CPU and dispatching domains for the environment task
1542 Set_Task_Affinity (Environment_Task);
1543 end Initialize;
1545 -----------------------
1546 -- Set_Task_Affinity --
1547 -----------------------
1549 procedure Set_Task_Affinity (T : ST.Task_Id) is
1550 use type Multiprocessors.CPU_Range;
1552 begin
1553 -- Do nothing if there is no support for setting affinities or the
1554 -- underlying thread has not yet been created. If the thread has not
1555 -- yet been created then the proper affinity will be set during its
1556 -- creation.
1558 if pthread_setaffinity_np'Address /= Null_Address
1559 and then T.Common.LL.Thread /= Null_Thread_Id
1560 then
1561 declare
1562 CPUs : constant size_t :=
1563 C.size_t (Multiprocessors.Number_Of_CPUs);
1564 CPU_Set : cpu_set_t_ptr := null;
1565 Size : constant size_t := CPU_ALLOC_SIZE (CPUs);
1567 Result : C.int;
1569 begin
1570 -- We look at the specific CPU (Base_CPU) first, then at the
1571 -- Task_Info field, and finally at the assigned dispatching
1572 -- domain, if any.
1574 if T.Common.Base_CPU /= Multiprocessors.Not_A_Specific_CPU then
1576 -- Set the affinity to an unique CPU
1578 CPU_Set := CPU_ALLOC (CPUs);
1579 System.OS_Interface.CPU_ZERO (Size, CPU_Set);
1580 System.OS_Interface.CPU_SET
1581 (int (T.Common.Base_CPU), Size, CPU_Set);
1583 -- Handle Task_Info
1585 elsif T.Common.Task_Info /= null then
1586 CPU_Set := T.Common.Task_Info.CPU_Affinity'Access;
1588 -- Handle dispatching domains
1590 elsif T.Common.Domain /= null and then
1591 (T.Common.Domain /= ST.System_Domain
1592 or else T.Common.Domain.all /=
1593 (Multiprocessors.CPU'First ..
1594 Multiprocessors.Number_Of_CPUs => True))
1595 then
1596 -- Set the affinity to all the processors belonging to the
1597 -- dispatching domain. To avoid changing CPU affinities when
1598 -- not needed, we set the affinity only when assigning to a
1599 -- domain other than the default one, or when the default one
1600 -- has been modified.
1602 CPU_Set := CPU_ALLOC (CPUs);
1603 System.OS_Interface.CPU_ZERO (Size, CPU_Set);
1605 for Proc in T.Common.Domain'Range loop
1606 if T.Common.Domain (Proc) then
1607 System.OS_Interface.CPU_SET (int (Proc), Size, CPU_Set);
1608 end if;
1609 end loop;
1610 end if;
1612 -- We set the new affinity if needed. Otherwise, the new task
1613 -- will inherit its creator's CPU affinity mask (according to
1614 -- the documentation of pthread_setaffinity_np), which is
1615 -- consistent with Ada's required semantics.
1617 if CPU_Set /= null then
1618 Result :=
1619 pthread_setaffinity_np (T.Common.LL.Thread, Size, CPU_Set);
1620 pragma Assert (Result = 0);
1622 CPU_FREE (CPU_Set);
1623 end if;
1624 end;
1625 end if;
1626 end Set_Task_Affinity;
1628 end System.Task_Primitives.Operations;