hppa: Fix LO_SUM DLTIND14R address support in PRINT_OPERAND_ADDRESS
[official-gcc.git] / gcc / ada / libgnarl / s-taprop__qnx.adb
blob8b98af7284e3dab0f4feb7c8970fac6e9e12ec4c
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-2024, 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 POSIX-like version of this package
34 -- This package contains all the GNULL primitives that interface directly with
35 -- the underlying OS.
37 -- Note: this file can only be used for POSIX compliant systems that implement
38 -- SCHED_FIFO and Ceiling Locking correctly.
40 -- For configurations where SCHED_FIFO and priority ceiling are not a
41 -- requirement, this file can also be used (e.g AiX threads)
43 with Ada.Unchecked_Conversion;
45 with Interfaces.C;
47 with System.Tasking.Debug;
48 with System.Interrupt_Management;
49 with System.OS_Constants;
50 with System.OS_Primitives;
51 with System.Task_Info;
52 with System.Multiprocessors;
54 with System.Soft_Links;
55 -- We use System.Soft_Links instead of System.Tasking.Initialization
56 -- because the later is a higher level package that we shouldn't depend on.
57 -- For example when using the restricted run time, it is replaced by
58 -- System.Tasking.Restricted.Stages.
60 package body System.Task_Primitives.Operations is
62 package OSC renames System.OS_Constants;
63 package SSL renames System.Soft_Links;
65 use System.Tasking.Debug;
66 use System.Tasking;
67 use Interfaces.C;
68 use System.OS_Interface;
69 use System.Parameters;
70 use System.OS_Primitives;
72 ----------------
73 -- Local Data --
74 ----------------
76 -- The followings are logically constants, but need to be initialized
77 -- at run time.
79 Single_RTS_Lock : aliased RTS_Lock;
80 -- This is a lock to allow only one thread of control in the RTS at
81 -- a time; it is used to execute in mutual exclusion from all other tasks.
82 -- Used to protect All_Tasks_List
84 Environment_Task_Id : Task_Id;
85 -- A variable to hold Task_Id for the environment task
87 Locking_Policy : constant Character;
88 pragma Import (C, Locking_Policy, "__gl_locking_policy");
89 -- Value of the pragma Locking_Policy:
90 -- 'C' for Ceiling_Locking
91 -- 'I' for Inherit_Locking
92 -- ' ' for none.
94 Unblocked_Signal_Mask : aliased sigset_t;
95 -- The set of signals that should unblocked in all tasks
97 -- The followings are internal configuration constants needed
99 Next_Serial_Number : Task_Serial_Number := 100;
100 -- We start at 100, to reserve some special values for
101 -- using in error checking.
103 Time_Slice_Val : constant Integer;
104 pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
106 Dispatching_Policy : constant Character;
107 pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
109 Foreign_Task_Elaborated : aliased Boolean := True;
110 -- Used to identified fake tasks (i.e., non-Ada Threads)
112 Use_Alternate_Stack : constant Boolean := Alternate_Stack_Size /= 0;
113 -- Whether to use an alternate signal stack for stack overflows
115 Abort_Handler_Installed : Boolean := False;
116 -- True if a handler for the abort signal is installed
118 type RTS_Lock_Ptr is not null access all RTS_Lock;
120 function Init_Mutex (L : RTS_Lock_Ptr; Prio : Any_Priority) return int;
121 -- Initialize the mutex L. If Ceiling_Support is True, then set the ceiling
122 -- to Prio. Returns 0 for success, or ENOMEM for out-of-memory.
124 function Get_Policy (Prio : System.Any_Priority) return Character;
125 pragma Import (C, Get_Policy, "__gnat_get_specific_dispatching");
126 -- Get priority specific dispatching policy
128 --------------------
129 -- Local Packages --
130 --------------------
132 package Specific is
134 procedure Initialize (Environment_Task : Task_Id);
135 pragma Inline (Initialize);
136 -- Initialize various data needed by this package
138 function Is_Valid_Task return Boolean;
139 pragma Inline (Is_Valid_Task);
140 -- Does executing thread have a TCB?
142 procedure Set (Self_Id : Task_Id);
143 pragma Inline (Set);
144 -- Set the self id for the current task
146 function Self return Task_Id;
147 pragma Inline (Self);
148 -- Return a pointer to the Ada Task Control Block of the calling task
150 end Specific;
152 package body Specific is separate;
153 -- The body of this package is target specific
155 package Monotonic is
157 function Monotonic_Clock return Duration;
158 pragma Inline (Monotonic_Clock);
159 -- Returns an absolute time, represented as an offset relative to some
160 -- unspecified starting point, typically system boot time. This clock
161 -- is not affected by discontinuous jumps in the system time.
163 function RT_Resolution return Duration;
164 pragma Inline (RT_Resolution);
165 -- Returns resolution of the underlying clock used to implement RT_Clock
167 procedure Timed_Sleep
168 (Self_ID : ST.Task_Id;
169 Time : Duration;
170 Mode : ST.Delay_Modes;
171 Reason : System.Tasking.Task_States;
172 Timedout : out Boolean;
173 Yielded : out Boolean);
174 -- Combination of Sleep (above) and Timed_Delay
176 procedure Timed_Delay
177 (Self_ID : ST.Task_Id;
178 Time : Duration;
179 Mode : ST.Delay_Modes);
180 -- Implement the semantics of the delay statement.
181 -- The caller should be abort-deferred and should not hold any locks.
183 end Monotonic;
185 package body Monotonic is separate;
187 ----------------------------------
188 -- ATCB allocation/deallocation --
189 ----------------------------------
191 package body ATCB_Allocation is separate;
192 -- The body of this package is shared across several targets
194 ---------------------------------
195 -- Support for foreign threads --
196 ---------------------------------
198 function Register_Foreign_Thread
199 (Thread : Thread_Id;
200 Sec_Stack_Size : Size_Type := Unspecified_Size) return Task_Id;
201 -- Allocate and initialize a new ATCB for the current Thread. The size of
202 -- the secondary stack can be optionally specified.
204 function Register_Foreign_Thread
205 (Thread : Thread_Id;
206 Sec_Stack_Size : Size_Type := Unspecified_Size)
207 return Task_Id is separate;
209 -----------------------
210 -- Local Subprograms --
211 -----------------------
213 procedure Abort_Handler (Sig : Signal);
214 -- Signal handler used to implement asynchronous abort.
215 -- See also comment before body, below.
217 function To_Address is
218 new Ada.Unchecked_Conversion (Task_Id, System.Address);
220 function GNAT_pthread_condattr_setup
221 (attr : access pthread_condattr_t) return int;
222 pragma Import (C,
223 GNAT_pthread_condattr_setup, "__gnat_pthread_condattr_setup");
225 -------------------
226 -- Abort_Handler --
227 -------------------
229 -- Target-dependent binding of inter-thread Abort signal to the raising of
230 -- the Abort_Signal exception.
232 -- The technical issues and alternatives here are essentially the
233 -- same as for raising exceptions in response to other signals
234 -- (e.g. Storage_Error). See code and comments in the package body
235 -- System.Interrupt_Management.
237 -- Some implementations may not allow an exception to be propagated out of
238 -- a handler, and others might leave the signal or interrupt that invoked
239 -- this handler masked after the exceptional return to the application
240 -- code.
242 -- GNAT exceptions are originally implemented using setjmp()/longjmp(). On
243 -- most UNIX systems, this will allow transfer out of a signal handler,
244 -- which is usually the only mechanism available for implementing
245 -- asynchronous handlers of this kind. However, some systems do not
246 -- restore the signal mask on longjmp(), leaving the abort signal masked.
248 procedure Abort_Handler (Sig : Signal) is
249 pragma Unreferenced (Sig);
251 T : constant Task_Id := Self;
252 Old_Set : aliased sigset_t;
254 Result : Interfaces.C.int;
255 pragma Warnings (Off, Result);
257 begin
258 -- It's not safe to raise an exception when using GCC ZCX mechanism.
259 -- Note that we still need to install a signal handler, since in some
260 -- cases (e.g. shutdown of the Server_Task in System.Interrupts) we
261 -- need to send the Abort signal to a task.
263 if ZCX_By_Default then
264 return;
265 end if;
267 if T.Deferral_Level = 0
268 and then T.Pending_ATC_Level < T.ATC_Nesting_Level and then
269 not T.Aborting
270 then
271 T.Aborting := True;
273 -- Make sure signals used for RTS internal purpose are unmasked
275 Result := pthread_sigmask (SIG_UNBLOCK,
276 Unblocked_Signal_Mask'Access, Old_Set'Access);
277 pragma Assert (Result = 0);
279 raise Standard'Abort_Signal;
280 end if;
281 end Abort_Handler;
283 -----------------
284 -- Stack_Guard --
285 -----------------
287 procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is
288 Stack_Base : constant Address := Get_Stack_Base (T.Common.LL.Thread);
289 Page_Size : Address;
290 Res : Interfaces.C.int;
292 begin
293 if Stack_Base_Available then
295 -- Compute the guard page address
297 Page_Size := Address (Get_Page_Size);
298 Res :=
299 mprotect
300 (Stack_Base - (Stack_Base mod Page_Size) + Page_Size,
301 size_t (Page_Size),
302 prot => (if On then PROT_ON else PROT_OFF));
303 pragma Assert (Res = 0);
304 end if;
305 end Stack_Guard;
307 --------------------
308 -- Get_Thread_Id --
309 --------------------
311 function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is
312 begin
313 return T.Common.LL.Thread;
314 end Get_Thread_Id;
316 ----------
317 -- Self --
318 ----------
320 function Self return Task_Id renames Specific.Self;
322 ----------------
323 -- Init_Mutex --
324 ----------------
326 function Init_Mutex (L : RTS_Lock_Ptr; Prio : Any_Priority) return int
328 Attributes : aliased pthread_mutexattr_t;
329 Result : int;
330 Result_2 : aliased int;
332 begin
333 Result := pthread_mutexattr_init (Attributes'Access);
334 pragma Assert (Result = 0 or else Result = ENOMEM);
336 if Result = ENOMEM then
337 return Result;
338 end if;
340 if Locking_Policy = 'C' then
341 Result := pthread_mutexattr_setprotocol
342 (Attributes'Access, PTHREAD_PRIO_PROTECT);
343 pragma Assert (Result = 0);
345 Result := pthread_mutexattr_getprotocol
346 (Attributes'Access, Result_2'Access);
347 if Result_2 /= PTHREAD_PRIO_PROTECT then
348 raise Program_Error with "setprotocol failed";
349 end if;
351 Result := pthread_mutexattr_setprioceiling
352 (Attributes'Access, To_Target_Priority (Prio));
353 pragma Assert (Result = 0);
355 elsif Locking_Policy = 'I' then
356 Result := pthread_mutexattr_setprotocol
357 (Attributes'Access, PTHREAD_PRIO_INHERIT);
358 pragma Assert (Result = 0);
359 end if;
361 Result := pthread_mutex_init (L, Attributes'Access);
362 pragma Assert (Result = 0 or else Result = ENOMEM);
364 Result_2 := pthread_mutexattr_destroy (Attributes'Access);
365 pragma Assert (Result_2 = 0);
367 return Result;
368 end Init_Mutex;
370 ---------------------
371 -- Initialize_Lock --
372 ---------------------
374 -- Note: mutexes and cond_variables needed per-task basis are initialized
375 -- in Initialize_TCB and the Storage_Error is handled. Other mutexes (such
376 -- as RTS_Lock, Memory_Lock...) used in RTS is initialized before any
377 -- status change of RTS. Therefore raising Storage_Error in the following
378 -- routines should be able to be handled safely.
380 procedure Initialize_Lock
381 (Prio : System.Any_Priority;
382 L : not null access Lock)
384 begin
385 if Init_Mutex (L.WO'Access, Prio) = ENOMEM then
386 raise Storage_Error with "Failed to allocate a lock";
387 end if;
388 end Initialize_Lock;
390 procedure Initialize_Lock
391 (L : not null access RTS_Lock; Level : Lock_Level)
393 pragma Unreferenced (Level);
395 begin
396 if Init_Mutex (L.all'Access, Any_Priority'Last) = ENOMEM then
397 raise Storage_Error with "Failed to allocate a lock";
398 end if;
399 end Initialize_Lock;
401 -------------------
402 -- Finalize_Lock --
403 -------------------
405 procedure Finalize_Lock (L : not null access Lock) is
406 Result : Interfaces.C.int;
407 begin
408 Result := pthread_mutex_destroy (L.WO'Access);
409 pragma Assert (Result = 0);
410 end Finalize_Lock;
412 procedure Finalize_Lock (L : not null access RTS_Lock) is
413 Result : Interfaces.C.int;
414 begin
415 Result := pthread_mutex_destroy (L);
416 pragma Assert (Result = 0);
417 end Finalize_Lock;
419 ----------------
420 -- Write_Lock --
421 ----------------
423 procedure Write_Lock
424 (L : not null access Lock; Ceiling_Violation : out Boolean)
426 Self : constant pthread_t := pthread_self;
427 Result : int;
428 Policy : aliased int;
429 Ceiling : aliased int;
430 Sched : aliased struct_sched_param;
432 begin
433 Result := pthread_mutex_lock (L.WO'Access);
435 -- The cause of EINVAL is a priority ceiling violation
437 Ceiling_Violation := Result = EINVAL;
438 pragma Assert (Result = 0 or else Ceiling_Violation);
440 -- Workaround bug in QNX on ceiling locks: tasks with priority higher
441 -- than the ceiling priority don't receive EINVAL upon trying to lock.
442 if Result = 0 and then Locking_Policy = 'C' then
443 Result := pthread_getschedparam (Self, Policy'Access, Sched'Access);
444 pragma Assert (Result = 0);
445 Result := pthread_mutex_getprioceiling (L.WO'Access, Ceiling'Access);
446 pragma Assert (Result = 0);
448 -- Ceiling < current priority means Ceiling violation
449 -- (otherwise the current priority == ceiling)
450 if Ceiling < Sched.sched_curpriority then
451 Ceiling_Violation := True;
452 Result := pthread_mutex_unlock (L.WO'Access);
453 pragma Assert (Result = 0);
454 end if;
455 end if;
456 end Write_Lock;
458 procedure Write_Lock (L : not null access RTS_Lock) is
459 Result : Interfaces.C.int;
460 begin
461 Result := pthread_mutex_lock (L);
462 pragma Assert (Result = 0);
463 end Write_Lock;
465 procedure Write_Lock (T : Task_Id) is
466 Result : Interfaces.C.int;
467 begin
468 Result := pthread_mutex_lock (T.Common.LL.L'Access);
469 pragma Assert (Result = 0);
470 end Write_Lock;
472 ---------------
473 -- Read_Lock --
474 ---------------
476 procedure Read_Lock
477 (L : not null access Lock; Ceiling_Violation : out Boolean) is
478 begin
479 Write_Lock (L, Ceiling_Violation);
480 end Read_Lock;
482 ------------
483 -- Unlock --
484 ------------
486 procedure Unlock (L : not null access Lock) is
487 Result : Interfaces.C.int;
488 begin
489 Result := pthread_mutex_unlock (L.WO'Access);
490 pragma Assert (Result = 0);
491 end Unlock;
493 procedure Unlock (L : not null access RTS_Lock) is
494 Result : Interfaces.C.int;
495 begin
496 Result := pthread_mutex_unlock (L);
497 pragma Assert (Result = 0);
498 end Unlock;
500 procedure Unlock (T : Task_Id) is
501 Result : Interfaces.C.int;
502 begin
503 Result := pthread_mutex_unlock (T.Common.LL.L'Access);
504 pragma Assert (Result = 0);
505 end Unlock;
507 -----------------
508 -- Set_Ceiling --
509 -----------------
511 procedure Set_Ceiling
512 (L : not null access Lock;
513 Prio : System.Any_Priority)
515 Result : Interfaces.C.int;
516 begin
517 Result := pthread_mutex_setprioceiling
518 (L.WO'Access, To_Target_Priority (Prio), null);
519 pragma Assert (Result = 0);
520 end Set_Ceiling;
522 -----------
523 -- Sleep --
524 -----------
526 procedure Sleep
527 (Self_ID : Task_Id;
528 Reason : System.Tasking.Task_States)
530 pragma Unreferenced (Reason);
532 Result : Interfaces.C.int;
534 begin
535 Result :=
536 pthread_cond_wait
537 (cond => Self_ID.Common.LL.CV'Access,
538 mutex => Self_ID.Common.LL.L'Access);
540 -- EINTR is not considered a failure
542 pragma Assert (Result = 0 or else Result = EINTR);
543 end Sleep;
545 -----------------
546 -- Timed_Sleep --
547 -----------------
549 -- This is for use within the run-time system, so abort is
550 -- assumed to be already deferred, and the caller should be
551 -- holding its own ATCB lock.
553 procedure Timed_Sleep
554 (Self_ID : Task_Id;
555 Time : Duration;
556 Mode : ST.Delay_Modes;
557 Reason : Task_States;
558 Timedout : out Boolean;
559 Yielded : out Boolean) renames Monotonic.Timed_Sleep;
561 -----------------
562 -- Timed_Delay --
563 -----------------
565 -- This is for use in implementing delay statements, so we assume the
566 -- caller is abort-deferred but is holding no locks.
568 procedure Timed_Delay
569 (Self_ID : Task_Id;
570 Time : Duration;
571 Mode : ST.Delay_Modes) renames Monotonic.Timed_Delay;
573 ---------------------
574 -- Monotonic_Clock --
575 ---------------------
577 function Monotonic_Clock return Duration renames Monotonic.Monotonic_Clock;
579 -------------------
580 -- RT_Resolution --
581 -------------------
583 function RT_Resolution return Duration renames Monotonic.RT_Resolution;
585 ------------
586 -- Wakeup --
587 ------------
589 procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
590 pragma Unreferenced (Reason);
591 Result : Interfaces.C.int;
592 begin
593 Result := pthread_cond_signal (T.Common.LL.CV'Access);
594 pragma Assert (Result = 0);
595 end Wakeup;
597 -----------
598 -- Yield --
599 -----------
601 procedure Yield (Do_Yield : Boolean := True) is
602 Result : Interfaces.C.int;
603 pragma Unreferenced (Result);
604 begin
605 if Do_Yield then
606 Result := sched_yield;
607 end if;
608 end Yield;
610 ------------------
611 -- Set_Priority --
612 ------------------
614 procedure Set_Priority
615 (T : Task_Id;
616 Prio : System.Any_Priority;
617 Loss_Of_Inheritance : Boolean := False)
619 pragma Unreferenced (Loss_Of_Inheritance);
620 Result : Interfaces.C.int;
621 Old : constant System.Any_Priority := T.Common.Current_Priority;
623 begin
624 T.Common.Current_Priority := Prio;
625 Result := pthread_setschedprio
626 (T.Common.LL.Thread, To_Target_Priority (Prio));
627 pragma Assert (Result = 0);
629 if T.Common.LL.Thread = pthread_self
630 and then Old > Prio
631 then
632 -- When lowering the priority via a pthread_setschedprio, QNX ensures
633 -- that the running thread remains in the head of the FIFO for tne
634 -- new priority. Annex D expects the thread to be requeued so let's
635 -- yield to the other threads of the same priority.
636 Result := sched_yield;
637 pragma Assert (Result = 0);
638 end if;
639 end Set_Priority;
641 ------------------
642 -- Get_Priority --
643 ------------------
645 function Get_Priority (T : Task_Id) return System.Any_Priority is
646 begin
647 return T.Common.Current_Priority;
648 end Get_Priority;
650 ----------------
651 -- Enter_Task --
652 ----------------
654 procedure Enter_Task (Self_ID : Task_Id) is
655 begin
656 Self_ID.Common.LL.Thread := pthread_self;
657 Self_ID.Common.LL.LWP := lwp_self;
659 Specific.Set (Self_ID);
661 if Use_Alternate_Stack then
662 declare
663 Stack : aliased stack_t;
664 Result : Interfaces.C.int;
665 begin
666 Stack.ss_sp := Self_ID.Common.Task_Alternate_Stack;
667 Stack.ss_size := Alternate_Stack_Size;
668 Stack.ss_flags := 0;
669 Result := sigaltstack (Stack'Access, null);
670 pragma Assert (Result = 0);
671 end;
672 end if;
673 end Enter_Task;
675 -------------------
676 -- Is_Valid_Task --
677 -------------------
679 function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
681 -----------------------------
682 -- Register_Foreign_Thread --
683 -----------------------------
685 function Register_Foreign_Thread return Task_Id is
686 begin
687 if Is_Valid_Task then
688 return Self;
689 else
690 return Register_Foreign_Thread (pthread_self);
691 end if;
692 end Register_Foreign_Thread;
694 --------------------
695 -- Initialize_TCB --
696 --------------------
698 procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
699 Result : Interfaces.C.int;
700 Cond_Attr : aliased pthread_condattr_t;
702 begin
703 -- Give the task a unique serial number
705 Self_ID.Serial_Number := Next_Serial_Number;
706 Next_Serial_Number := Next_Serial_Number + 1;
707 pragma Assert (Next_Serial_Number /= 0);
709 Result := Init_Mutex (Self_ID.Common.LL.L'Access, Any_Priority'Last);
710 pragma Assert (Result = 0);
712 if Result /= 0 then
713 Succeeded := False;
714 return;
715 end if;
717 Result := pthread_condattr_init (Cond_Attr'Access);
718 pragma Assert (Result = 0 or else Result = ENOMEM);
720 if Result = 0 then
721 Result := GNAT_pthread_condattr_setup (Cond_Attr'Access);
722 pragma Assert (Result = 0);
724 Result :=
725 pthread_cond_init
726 (Self_ID.Common.LL.CV'Access, Cond_Attr'Access);
727 pragma Assert (Result = 0 or else Result = ENOMEM);
728 end if;
730 if Result = 0 then
731 Succeeded := True;
732 else
733 Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
734 pragma Assert (Result = 0);
736 Succeeded := False;
737 end if;
739 Result := pthread_condattr_destroy (Cond_Attr'Access);
740 pragma Assert (Result = 0);
741 end Initialize_TCB;
743 -----------------
744 -- Create_Task --
745 -----------------
747 procedure Create_Task
748 (T : Task_Id;
749 Wrapper : System.Address;
750 Stack_Size : System.Parameters.Size_Type;
751 Priority : System.Any_Priority;
752 Succeeded : out Boolean)
754 Attributes : aliased pthread_attr_t;
755 Adjusted_Stack_Size : Interfaces.C.size_t;
756 Page_Size : constant Interfaces.C.size_t :=
757 Interfaces.C.size_t (Get_Page_Size);
758 Sched_Param : aliased struct_sched_param;
759 Result : Interfaces.C.int;
761 Priority_Specific_Policy : constant Character := Get_Policy (Priority);
762 -- Upper case first character of the policy name corresponding to the
763 -- task as set by a Priority_Specific_Dispatching pragma.
765 function Thread_Body_Access is new
766 Ada.Unchecked_Conversion (System.Address, Thread_Body);
768 begin
769 Adjusted_Stack_Size :=
770 Interfaces.C.size_t (Stack_Size + Alternate_Stack_Size);
772 if Stack_Base_Available then
774 -- If Stack Checking is supported then allocate 2 additional pages:
776 -- In the worst case, stack is allocated at something like
777 -- N * Get_Page_Size - epsilon, we need to add the size for 2 pages
778 -- to be sure the effective stack size is greater than what
779 -- has been asked.
781 Adjusted_Stack_Size := Adjusted_Stack_Size + 2 * Page_Size;
782 end if;
784 -- Round stack size as this is required by some OSes (Darwin)
786 Adjusted_Stack_Size := Adjusted_Stack_Size + Page_Size - 1;
787 Adjusted_Stack_Size :=
788 Adjusted_Stack_Size - Adjusted_Stack_Size mod Page_Size;
790 Result := pthread_attr_init (Attributes'Access);
791 pragma Assert (Result = 0 or else Result = ENOMEM);
793 if Result /= 0 then
794 Succeeded := False;
795 return;
796 end if;
798 Result :=
799 pthread_attr_setdetachstate
800 (Attributes'Access, PTHREAD_CREATE_DETACHED);
801 pragma Assert (Result = 0);
803 Result :=
804 pthread_attr_setstacksize
805 (Attributes'Access, Adjusted_Stack_Size);
806 pragma Assert (Result = 0);
808 -- Set thread priority
809 T.Common.Current_Priority := Priority;
810 Sched_Param.sched_priority := To_Target_Priority (Priority);
812 Result := pthread_attr_setinheritsched
813 (Attributes'Access, PTHREAD_EXPLICIT_SCHED);
814 pragma Assert (Result = 0);
816 Result := pthread_attr_setschedparam
817 (Attributes'Access, Sched_Param'Access);
818 pragma Assert (Result = 0);
820 if Time_Slice_Supported
821 and then (Dispatching_Policy = 'R'
822 or else Priority_Specific_Policy = 'R'
823 or else Time_Slice_Val > 0)
824 then
825 Result := pthread_attr_setschedpolicy
826 (Attributes'Access, SCHED_RR);
828 elsif Dispatching_Policy = 'F'
829 or else Priority_Specific_Policy = 'F'
830 or else Time_Slice_Val = 0
831 then
832 Result := pthread_attr_setschedpolicy
833 (Attributes'Access, SCHED_FIFO);
835 else
836 Result := pthread_attr_setschedpolicy
837 (Attributes'Access, SCHED_OTHER);
838 end if;
840 pragma Assert (Result = 0);
842 -- Since the initial signal mask of a thread is inherited from the
843 -- creator, and the Environment task has all its signals masked, we
844 -- do not need to manipulate caller's signal mask at this point.
845 -- All tasks in RTS will have All_Tasks_Mask initially.
847 -- Note: the use of Unrestricted_Access in the following call is needed
848 -- because otherwise we have an error of getting a access-to-volatile
849 -- value which points to a non-volatile object. But in this case it is
850 -- safe to do this, since we know we have no problems with aliasing and
851 -- Unrestricted_Access bypasses this check.
853 Result := pthread_create
854 (T.Common.LL.Thread'Unrestricted_Access,
855 Attributes'Access,
856 Thread_Body_Access (Wrapper),
857 To_Address (T));
858 pragma Assert (Result = 0 or else Result = EAGAIN);
860 Succeeded := Result = 0;
862 Result := pthread_attr_destroy (Attributes'Access);
863 pragma Assert (Result = 0);
864 end Create_Task;
866 ------------------
867 -- Finalize_TCB --
868 ------------------
870 procedure Finalize_TCB (T : Task_Id) is
871 Result : Interfaces.C.int;
873 begin
874 Result := pthread_mutex_destroy (T.Common.LL.L'Access);
875 pragma Assert (Result = 0);
877 Result := pthread_cond_destroy (T.Common.LL.CV'Access);
878 pragma Assert (Result = 0);
880 if T.Known_Tasks_Index /= -1 then
881 Known_Tasks (T.Known_Tasks_Index) := null;
882 end if;
884 ATCB_Allocation.Free_ATCB (T);
885 end Finalize_TCB;
887 ---------------
888 -- Exit_Task --
889 ---------------
891 procedure Exit_Task is
892 begin
893 -- Mark this task as unknown, so that if Self is called, it won't
894 -- return a dangling pointer.
896 Specific.Set (null);
897 end Exit_Task;
899 ----------------
900 -- Abort_Task --
901 ----------------
903 procedure Abort_Task (T : Task_Id) is
904 Result : Interfaces.C.int;
905 begin
906 if Abort_Handler_Installed then
907 Result :=
908 pthread_kill
909 (T.Common.LL.Thread,
910 Signal (System.Interrupt_Management.Abort_Task_Interrupt));
911 pragma Assert (Result = 0);
912 end if;
913 end Abort_Task;
915 ----------------
916 -- Initialize --
917 ----------------
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 begin
925 -- Initialize internal state (always to False (RM D.10 (6)))
927 S.State := False;
928 S.Waiting := False;
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
936 raise Storage_Error;
937 end if;
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);
946 raise Storage_Error;
947 end if;
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);
957 if Result /= 0 then
958 Result := pthread_mutex_destroy (S.L'Access);
959 pragma Assert (Result = 0);
961 -- Storage_Error is propagated as intended if the allocation of the
962 -- underlying OS entities fails.
964 raise Storage_Error;
966 else
967 Result := GNAT_pthread_condattr_setup (Cond_Attr'Access);
968 pragma Assert (Result = 0);
969 end if;
971 Result := pthread_cond_init (S.CV'Access, Cond_Attr'Access);
972 pragma Assert (Result = 0 or else Result = ENOMEM);
974 if Result /= 0 then
975 Result := pthread_mutex_destroy (S.L'Access);
976 pragma Assert (Result = 0);
978 Result := pthread_condattr_destroy (Cond_Attr'Access);
979 pragma Assert (Result = 0);
981 -- Storage_Error is propagated as intended if the allocation of the
982 -- underlying OS entities fails.
984 raise Storage_Error;
985 end if;
987 Result := pthread_condattr_destroy (Cond_Attr'Access);
988 pragma Assert (Result = 0);
989 end Initialize;
991 --------------
992 -- Finalize --
993 --------------
995 procedure Finalize (S : in out Suspension_Object) is
996 Result : Interfaces.C.int;
998 begin
999 -- Destroy internal mutex
1001 Result := pthread_mutex_destroy (S.L'Access);
1002 pragma Assert (Result = 0);
1004 -- Destroy internal condition variable
1006 Result := pthread_cond_destroy (S.CV'Access);
1007 pragma Assert (Result = 0);
1008 end Finalize;
1010 -------------------
1011 -- Current_State --
1012 -------------------
1014 function Current_State (S : Suspension_Object) return Boolean is
1015 begin
1016 -- We do not want to use lock on this read operation. State is marked
1017 -- as Atomic so that we ensure that the value retrieved is correct.
1019 return S.State;
1020 end Current_State;
1022 ---------------
1023 -- Set_False --
1024 ---------------
1026 procedure Set_False (S : in out Suspension_Object) is
1027 Result : Interfaces.C.int;
1029 begin
1030 SSL.Abort_Defer.all;
1032 Result := pthread_mutex_lock (S.L'Access);
1033 pragma Assert (Result = 0);
1035 S.State := False;
1037 Result := pthread_mutex_unlock (S.L'Access);
1038 pragma Assert (Result = 0);
1040 SSL.Abort_Undefer.all;
1041 end Set_False;
1043 --------------
1044 -- Set_True --
1045 --------------
1047 procedure Set_True (S : in out Suspension_Object) is
1048 Result : Interfaces.C.int;
1050 begin
1051 SSL.Abort_Defer.all;
1053 Result := pthread_mutex_lock (S.L'Access);
1054 pragma Assert (Result = 0);
1056 -- If there is already a task waiting on this suspension object then
1057 -- we resume it, leaving the state of the suspension object to False,
1058 -- as it is specified in (RM D.10(9)). Otherwise, it just leaves
1059 -- the state to True.
1061 if S.Waiting then
1062 S.Waiting := False;
1063 S.State := False;
1065 Result := pthread_cond_signal (S.CV'Access);
1066 pragma Assert (Result = 0);
1068 else
1069 S.State := True;
1070 end if;
1072 Result := pthread_mutex_unlock (S.L'Access);
1073 pragma Assert (Result = 0);
1075 SSL.Abort_Undefer.all;
1076 end Set_True;
1078 ------------------------
1079 -- Suspend_Until_True --
1080 ------------------------
1082 procedure Suspend_Until_True (S : in out Suspension_Object) is
1083 Result : Interfaces.C.int;
1085 begin
1086 SSL.Abort_Defer.all;
1088 Result := pthread_mutex_lock (S.L'Access);
1089 pragma Assert (Result = 0);
1091 if S.Waiting then
1093 -- Program_Error must be raised upon calling Suspend_Until_True
1094 -- if another task is already waiting on that suspension object
1095 -- (RM D.10(10)).
1097 Result := pthread_mutex_unlock (S.L'Access);
1098 pragma Assert (Result = 0);
1100 SSL.Abort_Undefer.all;
1102 raise Program_Error;
1104 else
1105 -- Suspend the task if the state is False. Otherwise, the task
1106 -- continues its execution, and the state of the suspension object
1107 -- is set to False (ARM D.10 par. 9).
1109 if S.State then
1110 S.State := False;
1111 else
1112 S.Waiting := True;
1114 loop
1115 -- Loop in case pthread_cond_wait returns earlier than expected
1116 -- (e.g. in case of EINTR caused by a signal).
1118 Result := pthread_cond_wait (S.CV'Access, S.L'Access);
1119 pragma Assert (Result = 0 or else Result = EINTR);
1121 exit when not S.Waiting;
1122 end loop;
1123 end if;
1125 Result := pthread_mutex_unlock (S.L'Access);
1126 pragma Assert (Result = 0);
1128 SSL.Abort_Undefer.all;
1129 end if;
1130 end Suspend_Until_True;
1132 ----------------
1133 -- Check_Exit --
1134 ----------------
1136 -- Dummy version
1138 function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1139 pragma Unreferenced (Self_ID);
1140 begin
1141 return True;
1142 end Check_Exit;
1144 --------------------
1145 -- Check_No_Locks --
1146 --------------------
1148 function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1149 pragma Unreferenced (Self_ID);
1150 begin
1151 return True;
1152 end Check_No_Locks;
1154 ----------------------
1155 -- Environment_Task --
1156 ----------------------
1158 function Environment_Task return Task_Id is
1159 begin
1160 return Environment_Task_Id;
1161 end Environment_Task;
1163 --------------
1164 -- Lock_RTS --
1165 --------------
1167 procedure Lock_RTS is
1168 begin
1169 Write_Lock (Single_RTS_Lock'Access);
1170 end Lock_RTS;
1172 ----------------
1173 -- Unlock_RTS --
1174 ----------------
1176 procedure Unlock_RTS is
1177 begin
1178 Unlock (Single_RTS_Lock'Access);
1179 end Unlock_RTS;
1181 ------------------
1182 -- Suspend_Task --
1183 ------------------
1185 function Suspend_Task
1186 (T : ST.Task_Id;
1187 Thread_Self : Thread_Id) return Boolean
1189 pragma Unreferenced (T, Thread_Self);
1190 begin
1191 return False;
1192 end Suspend_Task;
1194 -----------------
1195 -- Resume_Task --
1196 -----------------
1198 function Resume_Task
1199 (T : ST.Task_Id;
1200 Thread_Self : Thread_Id) return Boolean
1202 pragma Unreferenced (T, Thread_Self);
1203 begin
1204 return False;
1205 end Resume_Task;
1207 --------------------
1208 -- Stop_All_Tasks --
1209 --------------------
1211 procedure Stop_All_Tasks is
1212 begin
1213 null;
1214 end Stop_All_Tasks;
1216 ---------------
1217 -- Stop_Task --
1218 ---------------
1220 function Stop_Task (T : ST.Task_Id) return Boolean is
1221 pragma Unreferenced (T);
1222 begin
1223 return False;
1224 end Stop_Task;
1226 -------------------
1227 -- Continue_Task --
1228 -------------------
1230 function Continue_Task (T : ST.Task_Id) return Boolean is
1231 pragma Unreferenced (T);
1232 begin
1233 return False;
1234 end Continue_Task;
1236 ----------------
1237 -- Initialize --
1238 ----------------
1240 procedure Initialize (Environment_Task : Task_Id) is
1241 act : aliased struct_sigaction;
1242 old_act : aliased struct_sigaction;
1243 Tmp_Set : aliased sigset_t;
1244 Result : Interfaces.C.int;
1246 function State
1247 (Int : System.Interrupt_Management.Interrupt_ID) return Character;
1248 pragma Import (C, State, "__gnat_get_interrupt_state");
1249 -- Get interrupt state. Defined in a-init.c
1250 -- The input argument is the interrupt number,
1251 -- and the result is one of the following:
1253 Default : constant Character := 's';
1254 -- 'n' this interrupt not set by any Interrupt_State pragma
1255 -- 'u' Interrupt_State pragma set state to User
1256 -- 'r' Interrupt_State pragma set state to Runtime
1257 -- 's' Interrupt_State pragma set state to System (use "default"
1258 -- system handler)
1260 begin
1261 Environment_Task_Id := Environment_Task;
1263 Interrupt_Management.Initialize;
1265 -- Prepare the set of signals that should unblocked in all tasks
1267 Result := sigemptyset (Unblocked_Signal_Mask'Access);
1268 pragma Assert (Result = 0);
1270 for J in Interrupt_Management.Interrupt_ID loop
1271 if System.Interrupt_Management.Keep_Unmasked (J) then
1272 Result := sigaddset (Unblocked_Signal_Mask'Access, Signal (J));
1273 pragma Assert (Result = 0);
1274 end if;
1275 end loop;
1277 -- Initialize the lock used to synchronize chain of all ATCBs
1279 Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1281 Specific.Initialize (Environment_Task);
1283 if Use_Alternate_Stack then
1284 Environment_Task.Common.Task_Alternate_Stack :=
1285 Alternate_Stack'Address;
1286 end if;
1288 -- Make environment task known here because it doesn't go through
1289 -- Activate_Tasks, which does it for all other tasks.
1291 Known_Tasks (Known_Tasks'First) := Environment_Task;
1292 Environment_Task.Known_Tasks_Index := Known_Tasks'First;
1294 Enter_Task (Environment_Task);
1296 if State
1297 (System.Interrupt_Management.Abort_Task_Interrupt) /= Default
1298 then
1299 act.sa_flags := 0;
1300 act.sa_handler := Abort_Handler'Address;
1302 Result := sigemptyset (Tmp_Set'Access);
1303 pragma Assert (Result = 0);
1304 act.sa_mask := Tmp_Set;
1306 Result :=
1307 sigaction
1308 (Signal (System.Interrupt_Management.Abort_Task_Interrupt),
1309 act'Unchecked_Access,
1310 old_act'Unchecked_Access);
1311 pragma Assert (Result = 0);
1312 Abort_Handler_Installed := True;
1313 end if;
1314 end Initialize;
1316 -----------------------
1317 -- Set_Task_Affinity --
1318 -----------------------
1320 procedure Set_Task_Affinity (T : ST.Task_Id) is
1321 use type Multiprocessors.CPU_Range;
1323 function Thread_Ctl_Ext
1324 (Pid : pid_t;
1325 Tid : Thread_Id;
1326 Command : Interfaces.C.unsigned;
1327 Runmask : Interfaces.C.size_t) return Interfaces.C.int
1328 with
1329 Import, Convention => C, External_Name => "ThreadCtlExt";
1330 -- Thread_Ctl_Ext is a generic thread control function in QNX.
1331 -- It is defined locally because in the C API its second
1332 -- argument is a void pointer that takes different actual
1333 -- pointer types or values depending on the command. This
1334 -- particular instance of this function only accepts the
1335 -- NTO_TCTL_RUNMASK command. The void * pointer in the C
1336 -- interface is interpreted as bitmask for this command.
1337 -- In the binding size_t is used as an integer type that
1338 -- always has the same size as a pointer.
1340 NTO_TCTL_RUNMASK : constant := 4;
1341 -- Command for Thread_Ctl. Using this command in Thread_Ctl
1342 -- allows the caller to pass a bitmask that describes on
1343 -- which CPU the current thread is allowed to run on.
1345 Pid : constant pid_t := getpid;
1346 Result : Interfaces.C.int;
1347 Runmask : Interfaces.C.size_t;
1348 -- Each set bit in runmask represents a processor that the thread
1349 -- can run on. If all bits are set to one the thread can run on any CPU.
1350 begin
1351 if T.Common.Base_CPU = Multiprocessors.Not_A_Specific_CPU then
1352 Runmask := Interfaces.C.size_t'Last;
1353 else
1354 Runmask :=
1355 Interfaces.C.size_t
1356 (2 ** Natural (T.Common.Base_CPU - Multiprocessors.CPU'First));
1357 end if;
1358 Result :=
1359 Thread_Ctl_Ext (Pid, Get_Thread_Id (T), NTO_TCTL_RUNMASK, Runmask);
1360 pragma Assert (Result = 0);
1361 end Set_Task_Affinity;
1363 end System.Task_Primitives.Operations;