Merged with mainline at revision 128810.
[official-gcc.git] / gcc / ada / s-taprop-vms.adb
blob0647b21c981c09df07c0125b6eb55e91104f36c8
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
4 -- --
5 -- S Y S T E M . T A S K _ P R I M I T I V E S . O P E R A T I O N S --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2007, Free Software Foundation, Inc. --
10 -- --
11 -- GNARL is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 2, or (at your option) any later ver- --
14 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNARL; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
20 -- Boston, MA 02110-1301, USA. --
21 -- --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
28 -- --
29 -- GNARL was developed by the GNARL team at Florida State University. --
30 -- Extensive contributions were provided by Ada Core Technologies, Inc. --
31 -- --
32 ------------------------------------------------------------------------------
34 -- This is a OpenVMS/Alpha version of this package
36 -- This package contains all the GNULL primitives that interface directly
37 -- with the underlying OS.
39 pragma Polling (Off);
40 -- Turn off polling, we do not want ATC polling to take place during
41 -- tasking operations. It causes infinite loops and other problems.
43 with System.Tasking.Debug;
44 -- used for Known_Tasks
46 with System.OS_Primitives;
47 -- used for Delay_Modes
49 with Interfaces.C;
50 -- used for int
51 -- size_t
53 with System.Soft_Links;
54 -- used for Get_Exc_Stack_Addr
55 -- Abort_Defer/Undefer
57 with Ada.Unchecked_Conversion;
58 with Ada.Unchecked_Deallocation;
60 package body System.Task_Primitives.Operations is
62 use System.Tasking.Debug;
63 use System.Tasking;
64 use Interfaces.C;
65 use System.OS_Interface;
66 use System.Parameters;
67 use System.OS_Primitives;
68 use type System.OS_Primitives.OS_Time;
70 package SSL renames System.Soft_Links;
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 mainly in Single_Lock mode, but also to protect All_Tasks_List
84 ATCB_Key : aliased pthread_key_t;
85 -- Key used to find the Ada Task_Id associated with a thread
87 Environment_Task_Id : Task_Id;
88 -- A variable to hold Task_Id for the environment task
90 Time_Slice_Val : Integer;
91 pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
93 Dispatching_Policy : Character;
94 pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
96 Foreign_Task_Elaborated : aliased Boolean := True;
97 -- Used to identified fake tasks (i.e., non-Ada Threads)
99 --------------------
100 -- Local Packages --
101 --------------------
103 package Specific is
105 procedure Initialize (Environment_Task : Task_Id);
106 pragma Inline (Initialize);
107 -- Initialize various data needed by this package
109 function Is_Valid_Task return Boolean;
110 pragma Inline (Is_Valid_Task);
111 -- Does executing thread have a TCB?
113 procedure Set (Self_Id : Task_Id);
114 pragma Inline (Set);
115 -- Set the self id for the current task
117 function Self return Task_Id;
118 pragma Inline (Self);
119 -- Return a pointer to the Ada Task Control Block of the calling task
121 end Specific;
123 package body Specific is separate;
124 -- The body of this package is target specific
126 ---------------------------------
127 -- Support for foreign threads --
128 ---------------------------------
130 function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
131 -- Allocate and Initialize a new ATCB for the current Thread
133 function Register_Foreign_Thread
134 (Thread : Thread_Id) return Task_Id is separate;
136 -----------------------
137 -- Local Subprograms --
138 -----------------------
140 function To_Task_Id is
141 new Ada.Unchecked_Conversion (System.Address, Task_Id);
143 function To_Address is
144 new Ada.Unchecked_Conversion (Task_Id, System.Address);
146 function Get_Exc_Stack_Addr return Address;
147 -- Replace System.Soft_Links.Get_Exc_Stack_Addr_NT
149 procedure Timer_Sleep_AST (ID : Address);
150 -- Signal the condition variable when AST fires
152 procedure Timer_Sleep_AST (ID : Address) is
153 Result : Interfaces.C.int;
154 Self_ID : constant Task_Id := To_Task_Id (ID);
155 begin
156 Self_ID.Common.LL.AST_Pending := False;
157 Result := pthread_cond_signal_int_np (Self_ID.Common.LL.CV'Access);
158 pragma Assert (Result = 0);
159 end Timer_Sleep_AST;
161 -----------------
162 -- Stack_Guard --
163 -----------------
165 -- The underlying thread system sets a guard page at the bottom of a thread
166 -- stack, so nothing is needed.
167 -- ??? Check the comment above
169 procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is
170 pragma Unreferenced (T);
171 pragma Unreferenced (On);
172 begin
173 null;
174 end Stack_Guard;
176 --------------------
177 -- Get_Thread_Id --
178 --------------------
180 function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is
181 begin
182 return T.Common.LL.Thread;
183 end Get_Thread_Id;
185 ----------
186 -- Self --
187 ----------
189 function Self return Task_Id renames Specific.Self;
191 ---------------------
192 -- Initialize_Lock --
193 ---------------------
195 -- Note: mutexes and cond_variables needed per-task basis are initialized
196 -- in Initialize_TCB and the Storage_Error is handled. Other mutexes (such
197 -- as RTS_Lock, Memory_Lock...) used in RTS is initialized before any
198 -- status change of RTS. Therefore rasing Storage_Error in the following
199 -- routines should be able to be handled safely.
201 procedure Initialize_Lock
202 (Prio : System.Any_Priority;
203 L : not null access Lock)
205 Attributes : aliased pthread_mutexattr_t;
206 Result : Interfaces.C.int;
208 begin
209 Result := pthread_mutexattr_init (Attributes'Access);
210 pragma Assert (Result = 0 or else Result = ENOMEM);
212 if Result = ENOMEM then
213 raise Storage_Error;
214 end if;
216 L.Prio_Save := 0;
217 L.Prio := Interfaces.C.int (Prio);
219 Result := pthread_mutex_init (L.L'Access, Attributes'Access);
220 pragma Assert (Result = 0 or else Result = ENOMEM);
222 if Result = ENOMEM then
223 raise Storage_Error;
224 end if;
226 Result := pthread_mutexattr_destroy (Attributes'Access);
227 pragma Assert (Result = 0);
228 end Initialize_Lock;
230 procedure Initialize_Lock
231 (L : not null access RTS_Lock;
232 Level : Lock_Level)
234 pragma Unreferenced (Level);
236 Attributes : aliased pthread_mutexattr_t;
237 Result : Interfaces.C.int;
239 begin
240 Result := pthread_mutexattr_init (Attributes'Access);
241 pragma Assert (Result = 0 or else Result = ENOMEM);
243 if Result = ENOMEM then
244 raise Storage_Error;
245 end if;
247 -- Don't use, see comment in s-osinte.ads about ERRORCHECK mutexes???
248 -- Result := pthread_mutexattr_settype_np
249 -- (Attributes'Access, PTHREAD_MUTEX_ERRORCHECK_NP);
250 -- pragma Assert (Result = 0);
252 -- Result := pthread_mutexattr_setprotocol
253 -- (Attributes'Access, PTHREAD_PRIO_PROTECT);
254 -- pragma Assert (Result = 0);
256 -- Result := pthread_mutexattr_setprioceiling
257 -- (Attributes'Access, Interfaces.C.int (System.Any_Priority'Last));
258 -- pragma Assert (Result = 0);
260 Result := pthread_mutex_init (L, Attributes'Access);
262 pragma Assert (Result = 0 or else Result = ENOMEM);
264 if Result = ENOMEM then
265 raise Storage_Error;
266 end if;
268 Result := pthread_mutexattr_destroy (Attributes'Access);
269 pragma Assert (Result = 0);
270 end Initialize_Lock;
272 -------------------
273 -- Finalize_Lock --
274 -------------------
276 procedure Finalize_Lock (L : not null access Lock) is
277 Result : Interfaces.C.int;
278 begin
279 Result := pthread_mutex_destroy (L.L'Access);
280 pragma Assert (Result = 0);
281 end Finalize_Lock;
283 procedure Finalize_Lock (L : not null access RTS_Lock) is
284 Result : Interfaces.C.int;
285 begin
286 Result := pthread_mutex_destroy (L);
287 pragma Assert (Result = 0);
288 end Finalize_Lock;
290 ----------------
291 -- Write_Lock --
292 ----------------
294 procedure Write_Lock
295 (L : not null access Lock;
296 Ceiling_Violation : out Boolean)
298 Self_ID : constant Task_Id := Self;
299 All_Tasks_Link : constant Task_Id := Self.Common.All_Tasks_Link;
300 Current_Prio : System.Any_Priority;
301 Result : Interfaces.C.int;
303 begin
304 Current_Prio := Get_Priority (Self_ID);
306 -- If there is no other tasks, no need to check priorities
308 if All_Tasks_Link /= Null_Task
309 and then L.Prio < Interfaces.C.int (Current_Prio)
310 then
311 Ceiling_Violation := True;
312 return;
313 end if;
315 Result := pthread_mutex_lock (L.L'Access);
316 pragma Assert (Result = 0);
318 Ceiling_Violation := False;
319 -- Why is this commented out ???
320 -- L.Prio_Save := Interfaces.C.int (Current_Prio);
321 -- Set_Priority (Self_ID, System.Any_Priority (L.Prio));
322 end Write_Lock;
324 procedure Write_Lock
325 (L : not null access RTS_Lock;
326 Global_Lock : Boolean := False)
328 Result : Interfaces.C.int;
329 begin
330 if not Single_Lock or else Global_Lock then
331 Result := pthread_mutex_lock (L);
332 pragma Assert (Result = 0);
333 end if;
334 end Write_Lock;
336 procedure Write_Lock (T : Task_Id) is
337 Result : Interfaces.C.int;
338 begin
339 if not Single_Lock then
340 Result := pthread_mutex_lock (T.Common.LL.L'Access);
341 pragma Assert (Result = 0);
342 end if;
343 end Write_Lock;
345 ---------------
346 -- Read_Lock --
347 ---------------
349 procedure Read_Lock
350 (L : not null access Lock;
351 Ceiling_Violation : out Boolean)
353 begin
354 Write_Lock (L, Ceiling_Violation);
355 end Read_Lock;
357 ------------
358 -- Unlock --
359 ------------
361 procedure Unlock (L : not null access Lock) is
362 Result : Interfaces.C.int;
363 begin
364 Result := pthread_mutex_unlock (L.L'Access);
365 pragma Assert (Result = 0);
366 end Unlock;
368 procedure Unlock
369 (L : not null access RTS_Lock;
370 Global_Lock : Boolean := False)
372 Result : Interfaces.C.int;
373 begin
374 if not Single_Lock or else Global_Lock then
375 Result := pthread_mutex_unlock (L);
376 pragma Assert (Result = 0);
377 end if;
378 end Unlock;
380 procedure Unlock (T : Task_Id) is
381 Result : Interfaces.C.int;
382 begin
383 if not Single_Lock then
384 Result := pthread_mutex_unlock (T.Common.LL.L'Access);
385 pragma Assert (Result = 0);
386 end if;
387 end Unlock;
389 -----------------
390 -- Set_Ceiling --
391 -----------------
393 -- Dynamic priority ceilings are not supported by the underlying system
395 procedure Set_Ceiling
396 (L : not null access Lock;
397 Prio : System.Any_Priority)
399 pragma Unreferenced (L, Prio);
400 begin
401 null;
402 end Set_Ceiling;
404 -----------
405 -- Sleep --
406 -----------
408 procedure Sleep
409 (Self_ID : Task_Id;
410 Reason : System.Tasking.Task_States)
412 pragma Unreferenced (Reason);
413 Result : Interfaces.C.int;
415 begin
416 if Single_Lock then
417 Result :=
418 pthread_cond_wait
419 (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access);
420 else
421 Result :=
422 pthread_cond_wait
423 (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
424 end if;
426 -- EINTR is not considered a failure
428 pragma Assert (Result = 0 or else Result = EINTR);
430 if Self_ID.Deferral_Level = 0
431 and then Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
432 then
433 Unlock (Self_ID);
434 raise Standard'Abort_Signal;
435 end if;
436 end Sleep;
438 -----------------
439 -- Timed_Sleep --
440 -----------------
442 procedure Timed_Sleep
443 (Self_ID : Task_Id;
444 Time : Duration;
445 Mode : ST.Delay_Modes;
446 Reason : System.Tasking.Task_States;
447 Timedout : out Boolean;
448 Yielded : out Boolean)
450 pragma Unreferenced (Reason);
452 Sleep_Time : OS_Time;
453 Result : Interfaces.C.int;
454 Status : Cond_Value_Type;
456 -- The body below requires more comments ???
458 begin
459 Timedout := False;
460 Yielded := False;
462 Sleep_Time := To_OS_Time (Time, Mode);
464 if Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level then
465 return;
466 end if;
468 Self_ID.Common.LL.AST_Pending := True;
470 Sys_Setimr
471 (Status, 0, Sleep_Time,
472 Timer_Sleep_AST'Access, To_Address (Self_ID), 0);
474 if (Status and 1) /= 1 then
475 raise Storage_Error;
476 end if;
478 if Single_Lock then
479 Result :=
480 pthread_cond_wait
481 (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access);
482 pragma Assert (Result = 0);
484 else
485 Result :=
486 pthread_cond_wait
487 (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
488 pragma Assert (Result = 0);
489 end if;
491 Yielded := True;
493 if not Self_ID.Common.LL.AST_Pending then
494 Timedout := True;
495 else
496 Sys_Cantim (Status, To_Address (Self_ID), 0);
497 pragma Assert ((Status and 1) = 1);
498 end if;
499 end Timed_Sleep;
501 -----------------
502 -- Timed_Delay --
503 -----------------
505 procedure Timed_Delay
506 (Self_ID : Task_Id;
507 Time : Duration;
508 Mode : ST.Delay_Modes)
510 Sleep_Time : OS_Time;
511 Result : Interfaces.C.int;
512 Status : Cond_Value_Type;
513 Yielded : Boolean := False;
515 begin
516 if Single_Lock then
517 Lock_RTS;
518 end if;
520 -- More comments required in body below ???
522 Write_Lock (Self_ID);
524 if Time /= 0.0 or else Mode /= Relative then
525 Sleep_Time := To_OS_Time (Time, Mode);
527 if Mode = Relative or else OS_Clock < Sleep_Time then
528 Self_ID.Common.State := Delay_Sleep;
529 Self_ID.Common.LL.AST_Pending := True;
531 Sys_Setimr
532 (Status, 0, Sleep_Time,
533 Timer_Sleep_AST'Access, To_Address (Self_ID), 0);
535 -- Comment following test
537 if (Status and 1) /= 1 then
538 raise Storage_Error;
539 end if;
541 loop
542 if Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level then
543 Sys_Cantim (Status, To_Address (Self_ID), 0);
544 pragma Assert ((Status and 1) = 1);
545 exit;
546 end if;
548 if Single_Lock then
549 Result :=
550 pthread_cond_wait
551 (Self_ID.Common.LL.CV'Access,
552 Single_RTS_Lock'Access);
553 pragma Assert (Result = 0);
554 else
555 Result :=
556 pthread_cond_wait
557 (Self_ID.Common.LL.CV'Access,
558 Self_ID.Common.LL.L'Access);
559 pragma Assert (Result = 0);
560 end if;
562 Yielded := True;
564 exit when not Self_ID.Common.LL.AST_Pending;
565 end loop;
567 Self_ID.Common.State := Runnable;
568 end if;
569 end if;
571 Unlock (Self_ID);
573 if Single_Lock then
574 Unlock_RTS;
575 end if;
577 if not Yielded then
578 Result := sched_yield;
579 pragma Assert (Result = 0);
580 end if;
581 end Timed_Delay;
583 ---------------------
584 -- Monotonic_Clock --
585 ---------------------
587 function Monotonic_Clock return Duration
588 renames System.OS_Primitives.Monotonic_Clock;
590 -------------------
591 -- RT_Resolution --
592 -------------------
594 function RT_Resolution return Duration is
595 begin
596 -- Document origin of this magic constant ???
597 return 10#1.0#E-3;
598 end RT_Resolution;
600 ------------
601 -- Wakeup --
602 ------------
604 procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
605 pragma Unreferenced (Reason);
606 Result : Interfaces.C.int;
607 begin
608 Result := pthread_cond_signal (T.Common.LL.CV'Access);
609 pragma Assert (Result = 0);
610 end Wakeup;
612 -----------
613 -- Yield --
614 -----------
616 procedure Yield (Do_Yield : Boolean := True) is
617 Result : Interfaces.C.int;
618 pragma Unreferenced (Result);
619 begin
620 if Do_Yield then
621 Result := sched_yield;
622 end if;
623 end Yield;
625 ------------------
626 -- Set_Priority --
627 ------------------
629 procedure Set_Priority
630 (T : Task_Id;
631 Prio : System.Any_Priority;
632 Loss_Of_Inheritance : Boolean := False)
634 pragma Unreferenced (Loss_Of_Inheritance);
636 Result : Interfaces.C.int;
637 Param : aliased struct_sched_param;
639 function Get_Policy (Prio : System.Any_Priority) return Character;
640 pragma Import (C, Get_Policy, "__gnat_get_specific_dispatching");
641 -- Get priority specific dispatching policy
643 Priority_Specific_Policy : constant Character := Get_Policy (Prio);
644 -- Upper case first character of the policy name corresponding to the
645 -- task as set by a Priority_Specific_Dispatching pragma.
647 begin
648 T.Common.Current_Priority := Prio;
649 Param.sched_priority := Interfaces.C.int (Underlying_Priorities (Prio));
651 if Dispatching_Policy = 'R'
652 or else Priority_Specific_Policy = 'R'
653 or else Time_Slice_Val > 0
654 then
655 Result :=
656 pthread_setschedparam
657 (T.Common.LL.Thread, SCHED_RR, Param'Access);
659 elsif Dispatching_Policy = 'F'
660 or else Priority_Specific_Policy = 'F'
661 or else Time_Slice_Val = 0
662 then
663 Result :=
664 pthread_setschedparam
665 (T.Common.LL.Thread, SCHED_FIFO, Param'Access);
667 else
668 -- SCHED_OTHER priorities are restricted to the range 8 - 15.
669 -- Since the translation from Underlying priorities results
670 -- in a range of 16 - 31, dividing by 2 gives the correct result.
672 Param.sched_priority := Param.sched_priority / 2;
673 Result :=
674 pthread_setschedparam
675 (T.Common.LL.Thread, SCHED_OTHER, Param'Access);
676 end if;
678 pragma Assert (Result = 0);
679 end Set_Priority;
681 ------------------
682 -- Get_Priority --
683 ------------------
685 function Get_Priority (T : Task_Id) return System.Any_Priority is
686 begin
687 return T.Common.Current_Priority;
688 end Get_Priority;
690 ----------------
691 -- Enter_Task --
692 ----------------
694 procedure Enter_Task (Self_ID : Task_Id) is
695 begin
696 Self_ID.Common.LL.Thread := pthread_self;
698 Specific.Set (Self_ID);
700 Lock_RTS;
702 for J in Known_Tasks'Range loop
703 if Known_Tasks (J) = null then
704 Known_Tasks (J) := Self_ID;
705 Self_ID.Known_Tasks_Index := J;
706 exit;
707 end if;
708 end loop;
710 Unlock_RTS;
711 end Enter_Task;
713 --------------
714 -- New_ATCB --
715 --------------
717 function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
718 begin
719 return new Ada_Task_Control_Block (Entry_Num);
720 end New_ATCB;
722 -------------------
723 -- Is_Valid_Task --
724 -------------------
726 function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
728 -----------------------------
729 -- Register_Foreign_Thread --
730 -----------------------------
732 function Register_Foreign_Thread return Task_Id is
733 begin
734 if Is_Valid_Task then
735 return Self;
736 else
737 return Register_Foreign_Thread (pthread_self);
738 end if;
739 end Register_Foreign_Thread;
741 --------------------
742 -- Initialize_TCB --
743 --------------------
745 procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
746 Mutex_Attr : aliased pthread_mutexattr_t;
747 Result : Interfaces.C.int;
748 Cond_Attr : aliased pthread_condattr_t;
750 begin
751 -- More comments required in body below ???
753 if not Single_Lock then
754 Result := pthread_mutexattr_init (Mutex_Attr'Access);
755 pragma Assert (Result = 0 or else Result = ENOMEM);
757 if Result = 0 then
758 Result :=
759 pthread_mutex_init
760 (Self_ID.Common.LL.L'Access, Mutex_Attr'Access);
761 pragma Assert (Result = 0 or else Result = ENOMEM);
762 end if;
764 if Result /= 0 then
765 Succeeded := False;
766 return;
767 end if;
769 Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
770 pragma Assert (Result = 0);
771 end if;
773 Result := pthread_condattr_init (Cond_Attr'Access);
774 pragma Assert (Result = 0 or else Result = ENOMEM);
776 if Result = 0 then
777 Result :=
778 pthread_cond_init
779 (Self_ID.Common.LL.CV'Access, Cond_Attr'Access);
780 pragma Assert (Result = 0 or else Result = ENOMEM);
781 end if;
783 if Result = 0 then
784 Succeeded := True;
785 Self_ID.Common.LL.Exc_Stack_Ptr := new Exc_Stack_T;
787 else
788 if not Single_Lock then
789 Result := pthread_mutex_destroy (Self_ID.Common.LL.L'Access);
790 pragma Assert (Result = 0);
791 end if;
793 Succeeded := False;
794 end if;
796 Result := pthread_condattr_destroy (Cond_Attr'Access);
797 pragma Assert (Result = 0);
798 end Initialize_TCB;
800 ------------------------
801 -- Get_Exc_Stack_Addr --
802 ------------------------
804 function Get_Exc_Stack_Addr return Address is
805 begin
806 return Self.Common.LL.Exc_Stack_Ptr (Exc_Stack_T'Last)'Address;
807 end Get_Exc_Stack_Addr;
809 -----------------
810 -- Create_Task --
811 -----------------
813 procedure Create_Task
814 (T : Task_Id;
815 Wrapper : System.Address;
816 Stack_Size : System.Parameters.Size_Type;
817 Priority : System.Any_Priority;
818 Succeeded : out Boolean)
820 Attributes : aliased pthread_attr_t;
821 Result : Interfaces.C.int;
823 function Thread_Body_Access is new
824 Ada.Unchecked_Conversion (System.Address, Thread_Body);
826 begin
827 -- Since the initial signal mask of a thread is inherited from the
828 -- creator, we need to set our local signal mask mask all signals
829 -- during the creation operation, to make sure the new thread is
830 -- not disturbed by signals before it has set its own Task_Id.
832 Result := pthread_attr_init (Attributes'Access);
833 pragma Assert (Result = 0 or else Result = ENOMEM);
835 if Result /= 0 then
836 Succeeded := False;
837 return;
838 end if;
840 Result := pthread_attr_setdetachstate
841 (Attributes'Access, PTHREAD_CREATE_DETACHED);
842 pragma Assert (Result = 0);
844 Result := pthread_attr_setstacksize
845 (Attributes'Access, Interfaces.C.size_t (Stack_Size));
846 pragma Assert (Result = 0);
848 -- This call may be unnecessary, not sure. ???
850 Result :=
851 pthread_attr_setinheritsched
852 (Attributes'Access, PTHREAD_EXPLICIT_SCHED);
853 pragma Assert (Result = 0);
855 Result :=
856 pthread_create
857 (T.Common.LL.Thread'Access,
858 Attributes'Access,
859 Thread_Body_Access (Wrapper),
860 To_Address (T));
862 -- ENOMEM is a valid run-time error -- do not shut down
864 pragma Assert (Result = 0
865 or else Result = EAGAIN or else Result = ENOMEM);
867 Succeeded := Result = 0;
869 Result := pthread_attr_destroy (Attributes'Access);
870 pragma Assert (Result = 0);
872 if Succeeded then
873 Set_Priority (T, Priority);
874 end if;
875 end Create_Task;
877 ------------------
878 -- Finalize_TCB --
879 ------------------
881 procedure Finalize_TCB (T : Task_Id) is
882 Result : Interfaces.C.int;
883 Tmp : Task_Id := T;
884 Is_Self : constant Boolean := T = Self;
886 procedure Free is new
887 Ada.Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
889 procedure Free is new Ada.Unchecked_Deallocation
890 (Exc_Stack_T, Exc_Stack_Ptr_T);
892 begin
893 if not Single_Lock then
894 Result := pthread_mutex_destroy (T.Common.LL.L'Access);
895 pragma Assert (Result = 0);
896 end if;
898 Result := pthread_cond_destroy (T.Common.LL.CV'Access);
899 pragma Assert (Result = 0);
901 if T.Known_Tasks_Index /= -1 then
902 Known_Tasks (T.Known_Tasks_Index) := null;
903 end if;
905 Free (T.Common.LL.Exc_Stack_Ptr);
906 Free (Tmp);
908 if Is_Self then
909 Specific.Set (null);
910 end if;
911 end Finalize_TCB;
913 ---------------
914 -- Exit_Task --
915 ---------------
917 procedure Exit_Task is
918 begin
919 null;
920 end Exit_Task;
922 ----------------
923 -- Abort_Task --
924 ----------------
926 procedure Abort_Task (T : Task_Id) is
927 begin
928 -- Interrupt Server_Tasks may be waiting on an event flag
930 if T.Common.State = Interrupt_Server_Blocked_On_Event_Flag then
931 Wakeup (T, Interrupt_Server_Blocked_On_Event_Flag);
932 end if;
933 end Abort_Task;
935 ----------------
936 -- Initialize --
937 ----------------
939 procedure Initialize (S : in out Suspension_Object) is
940 Mutex_Attr : aliased pthread_mutexattr_t;
941 Cond_Attr : aliased pthread_condattr_t;
942 Result : Interfaces.C.int;
943 begin
944 -- Initialize internal state (always to False (D.10 (6)))
946 S.State := False;
947 S.Waiting := False;
949 -- Initialize internal mutex
951 Result := pthread_mutexattr_init (Mutex_Attr'Access);
952 pragma Assert (Result = 0 or else Result = ENOMEM);
954 if Result = ENOMEM then
955 raise Storage_Error;
956 end if;
958 Result := pthread_mutex_init (S.L'Access, Mutex_Attr'Access);
959 pragma Assert (Result = 0 or else Result = ENOMEM);
961 if Result = ENOMEM then
962 Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
963 pragma Assert (Result = 0);
965 raise Storage_Error;
966 end if;
968 Result := pthread_mutexattr_destroy (Mutex_Attr'Access);
969 pragma Assert (Result = 0);
971 -- Initialize internal condition variable
973 Result := pthread_condattr_init (Cond_Attr'Access);
974 pragma Assert (Result = 0 or else Result = ENOMEM);
976 if Result /= 0 then
977 Result := pthread_mutex_destroy (S.L'Access);
978 pragma Assert (Result = 0);
980 if Result = ENOMEM then
981 raise Storage_Error;
982 end if;
983 end if;
985 Result := pthread_cond_init (S.CV'Access, Cond_Attr'Access);
986 pragma Assert (Result = 0 or else Result = ENOMEM);
988 if Result /= 0 then
989 Result := pthread_mutex_destroy (S.L'Access);
990 pragma Assert (Result = 0);
992 if Result = ENOMEM then
993 Result := pthread_condattr_destroy (Cond_Attr'Access);
994 pragma Assert (Result = 0);
996 raise Storage_Error;
997 end if;
998 end if;
1000 Result := pthread_condattr_destroy (Cond_Attr'Access);
1001 pragma Assert (Result = 0);
1002 end Initialize;
1004 --------------
1005 -- Finalize --
1006 --------------
1008 procedure Finalize (S : in out Suspension_Object) is
1009 Result : Interfaces.C.int;
1011 begin
1012 -- Destroy internal mutex
1014 Result := pthread_mutex_destroy (S.L'Access);
1015 pragma Assert (Result = 0);
1017 -- Destroy internal condition variable
1019 Result := pthread_cond_destroy (S.CV'Access);
1020 pragma Assert (Result = 0);
1021 end Finalize;
1023 -------------------
1024 -- Current_State --
1025 -------------------
1027 function Current_State (S : Suspension_Object) return Boolean is
1028 begin
1029 -- We do not want to use lock on this read operation. State is marked
1030 -- as Atomic so that we ensure that the value retrieved is correct.
1032 return S.State;
1033 end Current_State;
1035 ---------------
1036 -- Set_False --
1037 ---------------
1039 procedure Set_False (S : in out Suspension_Object) is
1040 Result : Interfaces.C.int;
1042 begin
1043 SSL.Abort_Defer.all;
1045 Result := pthread_mutex_lock (S.L'Access);
1046 pragma Assert (Result = 0);
1048 S.State := False;
1050 Result := pthread_mutex_unlock (S.L'Access);
1051 pragma Assert (Result = 0);
1053 SSL.Abort_Undefer.all;
1054 end Set_False;
1056 --------------
1057 -- Set_True --
1058 --------------
1060 procedure Set_True (S : in out Suspension_Object) is
1061 Result : Interfaces.C.int;
1063 begin
1064 SSL.Abort_Defer.all;
1066 Result := pthread_mutex_lock (S.L'Access);
1067 pragma Assert (Result = 0);
1069 -- If there is already a task waiting on this suspension object then
1070 -- we resume it, leaving the state of the suspension object to False,
1071 -- as specified in (RM D.10(9)), otherwise leave state set to True.
1073 if S.Waiting then
1074 S.Waiting := False;
1075 S.State := False;
1077 Result := pthread_cond_signal (S.CV'Access);
1078 pragma Assert (Result = 0);
1080 else
1081 S.State := True;
1082 end if;
1084 Result := pthread_mutex_unlock (S.L'Access);
1085 pragma Assert (Result = 0);
1087 SSL.Abort_Undefer.all;
1088 end Set_True;
1090 ------------------------
1091 -- Suspend_Until_True --
1092 ------------------------
1094 procedure Suspend_Until_True (S : in out Suspension_Object) is
1095 Result : Interfaces.C.int;
1097 begin
1098 SSL.Abort_Defer.all;
1100 Result := pthread_mutex_lock (S.L'Access);
1101 pragma Assert (Result = 0);
1103 if S.Waiting then
1105 -- Program_Error must be raised upon calling Suspend_Until_True
1106 -- if another task is already waiting on that suspension object
1107 -- (RM D.10(10)).
1109 Result := pthread_mutex_unlock (S.L'Access);
1110 pragma Assert (Result = 0);
1112 SSL.Abort_Undefer.all;
1114 raise Program_Error;
1116 else
1117 -- Suspend the task if the state is False. Otherwise, the task
1118 -- continues its execution, and the state of the suspension object
1119 -- is set to False (ARM D.10 par. 9).
1121 if S.State then
1122 S.State := False;
1123 else
1124 S.Waiting := True;
1125 Result := pthread_cond_wait (S.CV'Access, S.L'Access);
1126 end if;
1128 Result := pthread_mutex_unlock (S.L'Access);
1129 pragma Assert (Result = 0);
1131 SSL.Abort_Undefer.all;
1132 end if;
1133 end Suspend_Until_True;
1135 ----------------
1136 -- Check_Exit --
1137 ----------------
1139 -- Dummy version
1141 function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1142 pragma Unreferenced (Self_ID);
1143 begin
1144 return True;
1145 end Check_Exit;
1147 --------------------
1148 -- Check_No_Locks --
1149 --------------------
1151 function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1152 pragma Unreferenced (Self_ID);
1153 begin
1154 return True;
1155 end Check_No_Locks;
1157 ----------------------
1158 -- Environment_Task --
1159 ----------------------
1161 function Environment_Task return Task_Id is
1162 begin
1163 return Environment_Task_Id;
1164 end Environment_Task;
1166 --------------
1167 -- Lock_RTS --
1168 --------------
1170 procedure Lock_RTS is
1171 begin
1172 Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
1173 end Lock_RTS;
1175 ----------------
1176 -- Unlock_RTS --
1177 ----------------
1179 procedure Unlock_RTS is
1180 begin
1181 Unlock (Single_RTS_Lock'Access, Global_Lock => True);
1182 end Unlock_RTS;
1184 ------------------
1185 -- Suspend_Task --
1186 ------------------
1188 function Suspend_Task
1189 (T : ST.Task_Id;
1190 Thread_Self : Thread_Id) return Boolean
1192 pragma Unreferenced (T);
1193 pragma Unreferenced (Thread_Self);
1194 begin
1195 return False;
1196 end Suspend_Task;
1198 -----------------
1199 -- Resume_Task --
1200 -----------------
1202 function Resume_Task
1203 (T : ST.Task_Id;
1204 Thread_Self : Thread_Id) return Boolean
1206 pragma Unreferenced (T);
1207 pragma Unreferenced (Thread_Self);
1208 begin
1209 return False;
1210 end Resume_Task;
1212 --------------------
1213 -- Stop_All_Tasks --
1214 --------------------
1216 procedure Stop_All_Tasks is
1217 begin
1218 null;
1219 end Stop_All_Tasks;
1221 ---------------
1222 -- Stop_Task --
1223 ---------------
1225 function Stop_Task (T : ST.Task_Id) return Boolean is
1226 pragma Unreferenced (T);
1227 begin
1228 return False;
1229 end Stop_Task;
1231 -------------------
1232 -- Continue_Task --
1233 -------------------
1235 function Continue_Task (T : ST.Task_Id) return Boolean is
1236 pragma Unreferenced (T);
1237 begin
1238 return False;
1239 end Continue_Task;
1241 ----------------
1242 -- Initialize --
1243 ----------------
1245 procedure Initialize (Environment_Task : Task_Id) is
1246 begin
1247 Environment_Task_Id := Environment_Task;
1249 SSL.Get_Exc_Stack_Addr := Get_Exc_Stack_Addr'Access;
1251 -- Initialize the lock used to synchronize chain of all ATCBs
1253 Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
1255 Specific.Initialize (Environment_Task);
1257 Enter_Task (Environment_Task);
1258 end Initialize;
1260 end System.Task_Primitives.Operations;