diff options
Diffstat (limited to 'gcc-4.4.3/gcc/ada/s-taprop-mingw.adb')
-rw-r--r-- | gcc-4.4.3/gcc/ada/s-taprop-mingw.adb | 1337 |
1 files changed, 0 insertions, 1337 deletions
diff --git a/gcc-4.4.3/gcc/ada/s-taprop-mingw.adb b/gcc-4.4.3/gcc/ada/s-taprop-mingw.adb deleted file mode 100644 index 89e7dc138..000000000 --- a/gcc-4.4.3/gcc/ada/s-taprop-mingw.adb +++ /dev/null @@ -1,1337 +0,0 @@ ------------------------------------------------------------------------------- --- -- --- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS -- --- -- --- 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 -- --- -- --- B o d y -- --- -- --- Copyright (C) 1992-2009, Free Software Foundation, Inc. -- --- -- --- GNARL is free software; you can redistribute it and/or modify it under -- --- terms of the GNU General Public License as published by the Free Soft- -- --- ware Foundation; either version 3, or (at your option) any later ver- -- --- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- --- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- --- or FITNESS FOR A PARTICULAR PURPOSE. -- --- -- --- As a special exception under Section 7 of GPL version 3, you are granted -- --- additional permissions described in the GCC Runtime Library Exception, -- --- version 3.1, as published by the Free Software Foundation. -- --- -- --- You should have received a copy of the GNU General Public License and -- --- a copy of the GCC Runtime Library Exception along with this program; -- --- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- --- <http://www.gnu.org/licenses/>. -- --- -- --- GNARL was developed by the GNARL team at Florida State University. -- --- Extensive contributions were provided by Ada Core Technologies, Inc. -- --- -- ------------------------------------------------------------------------------- - --- This is a NT (native) version of this package - --- This package contains all the GNULL primitives that interface directly with --- the underlying OS. - -pragma Polling (Off); --- Turn off polling, we do not want ATC polling to take place during tasking --- operations. It causes infinite loops and other problems. - -with Ada.Unchecked_Deallocation; - -with Interfaces.C; -with Interfaces.C.Strings; - -with System.Tasking.Debug; -with System.OS_Primitives; -with System.Task_Info; -with System.Interrupt_Management; -with System.Win32.Ext; - -with System.Soft_Links; --- We use System.Soft_Links instead of System.Tasking.Initialization because --- the later is a higher level package that we shouldn't depend on. For --- example when using the restricted run time, it is replaced by --- System.Tasking.Restricted.Stages. - -package body System.Task_Primitives.Operations is - - package SSL renames System.Soft_Links; - - use System.Tasking.Debug; - use System.Tasking; - use Interfaces.C; - use Interfaces.C.Strings; - use System.OS_Interface; - use System.Parameters; - use System.OS_Primitives; - use System.Task_Info; - use System.Win32; - use System.Win32.Ext; - - pragma Link_With ("-Xlinker --stack=0x200000,0x1000"); - -- Change the default stack size (2 MB) for tasking programs on Windows. - -- This allows about 1000 tasks running at the same time. Note that - -- we set the stack size for non tasking programs on System unit. - -- Also note that under Windows XP, we use a Windows XP extension to - -- specify the stack size on a per task basis, as done under other OSes. - - --------------------- - -- Local Functions -- - --------------------- - - procedure InitializeCriticalSection (pCriticalSection : access RTS_Lock); - procedure InitializeCriticalSection - (pCriticalSection : access CRITICAL_SECTION); - pragma Import - (Stdcall, InitializeCriticalSection, "InitializeCriticalSection"); - - procedure EnterCriticalSection (pCriticalSection : access RTS_Lock); - procedure EnterCriticalSection - (pCriticalSection : access CRITICAL_SECTION); - pragma Import (Stdcall, EnterCriticalSection, "EnterCriticalSection"); - - procedure LeaveCriticalSection (pCriticalSection : access RTS_Lock); - procedure LeaveCriticalSection (pCriticalSection : access CRITICAL_SECTION); - pragma Import (Stdcall, LeaveCriticalSection, "LeaveCriticalSection"); - - procedure DeleteCriticalSection (pCriticalSection : access RTS_Lock); - procedure DeleteCriticalSection - (pCriticalSection : access CRITICAL_SECTION); - pragma Import (Stdcall, DeleteCriticalSection, "DeleteCriticalSection"); - - ---------------- - -- Local Data -- - ---------------- - - Environment_Task_Id : Task_Id; - -- A variable to hold Task_Id for the environment task - - Single_RTS_Lock : aliased RTS_Lock; - -- This is a lock to allow only one thread of control in the RTS at - -- a time; it is used to execute in mutual exclusion from all other tasks. - -- Used mainly in Single_Lock mode, but also to protect All_Tasks_List - - Time_Slice_Val : Integer; - pragma Import (C, Time_Slice_Val, "__gl_time_slice_val"); - - Dispatching_Policy : Character; - pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy"); - - function Get_Policy (Prio : System.Any_Priority) return Character; - pragma Import (C, Get_Policy, "__gnat_get_specific_dispatching"); - -- Get priority specific dispatching policy - - Foreign_Task_Elaborated : aliased Boolean := True; - -- Used to identified fake tasks (i.e., non-Ada Threads) - - Annex_D : Boolean := False; - -- Set to True if running with Annex-D semantics - - ------------------------------------ - -- The thread local storage index -- - ------------------------------------ - - TlsIndex : DWORD; - pragma Export (Ada, TlsIndex); - -- To ensure that this variable won't be local to this package, since - -- in some cases, inlining forces this variable to be global anyway. - - -------------------- - -- Local Packages -- - -------------------- - - package Specific is - - function Is_Valid_Task return Boolean; - pragma Inline (Is_Valid_Task); - -- Does executing thread have a TCB? - - procedure Set (Self_Id : Task_Id); - pragma Inline (Set); - -- Set the self id for the current task - - end Specific; - - package body Specific is - - function Is_Valid_Task return Boolean is - begin - return TlsGetValue (TlsIndex) /= System.Null_Address; - end Is_Valid_Task; - - procedure Set (Self_Id : Task_Id) is - Succeeded : BOOL; - begin - Succeeded := TlsSetValue (TlsIndex, To_Address (Self_Id)); - pragma Assert (Succeeded = Win32.TRUE); - end Set; - - end Specific; - - --------------------------------- - -- Support for foreign threads -- - --------------------------------- - - function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id; - -- Allocate and Initialize a new ATCB for the current Thread - - function Register_Foreign_Thread - (Thread : Thread_Id) return Task_Id is separate; - - ---------------------------------- - -- Condition Variable Functions -- - ---------------------------------- - - procedure Initialize_Cond (Cond : not null access Condition_Variable); - -- Initialize given condition variable Cond - - procedure Finalize_Cond (Cond : not null access Condition_Variable); - -- Finalize given condition variable Cond - - procedure Cond_Signal (Cond : not null access Condition_Variable); - -- Signal condition variable Cond - - procedure Cond_Wait - (Cond : not null access Condition_Variable; - L : not null access RTS_Lock); - -- Wait on conditional variable Cond, using lock L - - procedure Cond_Timed_Wait - (Cond : not null access Condition_Variable; - L : not null access RTS_Lock; - Rel_Time : Duration; - Timed_Out : out Boolean; - Status : out Integer); - -- Do timed wait on condition variable Cond using lock L. The duration - -- of the timed wait is given by Rel_Time. When the condition is - -- signalled, Timed_Out shows whether or not a time out occurred. - -- Status is only valid if Timed_Out is False, in which case it - -- shows whether Cond_Timed_Wait completed successfully. - - --------------------- - -- Initialize_Cond -- - --------------------- - - procedure Initialize_Cond (Cond : not null access Condition_Variable) is - hEvent : HANDLE; - begin - hEvent := CreateEvent (null, Win32.TRUE, Win32.FALSE, Null_Ptr); - pragma Assert (hEvent /= 0); - Cond.all := Condition_Variable (hEvent); - end Initialize_Cond; - - ------------------- - -- Finalize_Cond -- - ------------------- - - -- No such problem here, DosCloseEventSem has been derived. - -- What does such refer to in above comment??? - - procedure Finalize_Cond (Cond : not null access Condition_Variable) is - Result : BOOL; - begin - Result := CloseHandle (HANDLE (Cond.all)); - pragma Assert (Result = Win32.TRUE); - end Finalize_Cond; - - ----------------- - -- Cond_Signal -- - ----------------- - - procedure Cond_Signal (Cond : not null access Condition_Variable) is - Result : BOOL; - begin - Result := SetEvent (HANDLE (Cond.all)); - pragma Assert (Result = Win32.TRUE); - end Cond_Signal; - - --------------- - -- Cond_Wait -- - --------------- - - -- Pre-condition: Cond is posted - -- L is locked. - - -- Post-condition: Cond is posted - -- L is locked. - - procedure Cond_Wait - (Cond : not null access Condition_Variable; - L : not null access RTS_Lock) - is - Result : DWORD; - Result_Bool : BOOL; - - begin - -- Must reset Cond BEFORE L is unlocked - - Result_Bool := ResetEvent (HANDLE (Cond.all)); - pragma Assert (Result_Bool = Win32.TRUE); - Unlock (L, Global_Lock => True); - - -- No problem if we are interrupted here: if the condition is signaled, - -- WaitForSingleObject will simply not block - - Result := WaitForSingleObject (HANDLE (Cond.all), Wait_Infinite); - pragma Assert (Result = 0); - - Write_Lock (L, Global_Lock => True); - end Cond_Wait; - - --------------------- - -- Cond_Timed_Wait -- - --------------------- - - -- Pre-condition: Cond is posted - -- L is locked. - - -- Post-condition: Cond is posted - -- L is locked. - - procedure Cond_Timed_Wait - (Cond : not null access Condition_Variable; - L : not null access RTS_Lock; - Rel_Time : Duration; - Timed_Out : out Boolean; - Status : out Integer) - is - Time_Out_Max : constant DWORD := 16#FFFF0000#; - -- NT 4 can't handle excessive timeout values (e.g. DWORD'Last - 1) - - Time_Out : DWORD; - Result : BOOL; - Wait_Result : DWORD; - - begin - -- Must reset Cond BEFORE L is unlocked - - Result := ResetEvent (HANDLE (Cond.all)); - pragma Assert (Result = Win32.TRUE); - Unlock (L, Global_Lock => True); - - -- No problem if we are interrupted here: if the condition is signaled, - -- WaitForSingleObject will simply not block - - if Rel_Time <= 0.0 then - Timed_Out := True; - Wait_Result := 0; - - else - if Rel_Time >= Duration (Time_Out_Max) / 1000 then - Time_Out := Time_Out_Max; - else - Time_Out := DWORD (Rel_Time * 1000); - end if; - - Wait_Result := WaitForSingleObject (HANDLE (Cond.all), Time_Out); - - if Wait_Result = WAIT_TIMEOUT then - Timed_Out := True; - Wait_Result := 0; - else - Timed_Out := False; - end if; - end if; - - Write_Lock (L, Global_Lock => True); - - -- Ensure post-condition - - if Timed_Out then - Result := SetEvent (HANDLE (Cond.all)); - pragma Assert (Result = Win32.TRUE); - end if; - - Status := Integer (Wait_Result); - end Cond_Timed_Wait; - - ------------------ - -- Stack_Guard -- - ------------------ - - -- The underlying thread system sets a guard page at the bottom of a thread - -- stack, so nothing is needed. - -- ??? Check the comment above - - procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is - pragma Unreferenced (T, On); - begin - null; - end Stack_Guard; - - -------------------- - -- Get_Thread_Id -- - -------------------- - - function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is - begin - return T.Common.LL.Thread; - end Get_Thread_Id; - - ---------- - -- Self -- - ---------- - - function Self return Task_Id is - Self_Id : constant Task_Id := To_Task_Id (TlsGetValue (TlsIndex)); - begin - if Self_Id = null then - return Register_Foreign_Thread (GetCurrentThread); - else - return Self_Id; - end if; - end Self; - - --------------------- - -- Initialize_Lock -- - --------------------- - - -- Note: mutexes and cond_variables needed per-task basis are initialized - -- in Initialize_TCB and the Storage_Error is handled. Other mutexes (such - -- as RTS_Lock, Memory_Lock...) used in the RTS is initialized before any - -- status change of RTS. Therefore raising Storage_Error in the following - -- routines should be able to be handled safely. - - procedure Initialize_Lock - (Prio : System.Any_Priority; - L : not null access Lock) - is - begin - InitializeCriticalSection (L.Mutex'Access); - L.Owner_Priority := 0; - L.Priority := Prio; - end Initialize_Lock; - - procedure Initialize_Lock - (L : not null access RTS_Lock; Level : Lock_Level) - is - pragma Unreferenced (Level); - begin - InitializeCriticalSection (L); - end Initialize_Lock; - - ------------------- - -- Finalize_Lock -- - ------------------- - - procedure Finalize_Lock (L : not null access Lock) is - begin - DeleteCriticalSection (L.Mutex'Access); - end Finalize_Lock; - - procedure Finalize_Lock (L : not null access RTS_Lock) is - begin - DeleteCriticalSection (L); - end Finalize_Lock; - - ---------------- - -- Write_Lock -- - ---------------- - - procedure Write_Lock - (L : not null access Lock; Ceiling_Violation : out Boolean) is - begin - L.Owner_Priority := Get_Priority (Self); - - if L.Priority < L.Owner_Priority then - Ceiling_Violation := True; - return; - end if; - - EnterCriticalSection (L.Mutex'Access); - - Ceiling_Violation := False; - end Write_Lock; - - procedure Write_Lock - (L : not null access RTS_Lock; - Global_Lock : Boolean := False) - is - begin - if not Single_Lock or else Global_Lock then - EnterCriticalSection (L); - end if; - end Write_Lock; - - procedure Write_Lock (T : Task_Id) is - begin - if not Single_Lock then - EnterCriticalSection (T.Common.LL.L'Access); - end if; - end Write_Lock; - - --------------- - -- Read_Lock -- - --------------- - - procedure Read_Lock - (L : not null access Lock; Ceiling_Violation : out Boolean) is - begin - Write_Lock (L, Ceiling_Violation); - end Read_Lock; - - ------------ - -- Unlock -- - ------------ - - procedure Unlock (L : not null access Lock) is - begin - LeaveCriticalSection (L.Mutex'Access); - end Unlock; - - procedure Unlock - (L : not null access RTS_Lock; Global_Lock : Boolean := False) is - begin - if not Single_Lock or else Global_Lock then - LeaveCriticalSection (L); - end if; - end Unlock; - - procedure Unlock (T : Task_Id) is - begin - if not Single_Lock then - LeaveCriticalSection (T.Common.LL.L'Access); - end if; - end Unlock; - - ----------------- - -- Set_Ceiling -- - ----------------- - - -- Dynamic priority ceilings are not supported by the underlying system - - procedure Set_Ceiling - (L : not null access Lock; - Prio : System.Any_Priority) - is - pragma Unreferenced (L, Prio); - begin - null; - end Set_Ceiling; - - ----------- - -- Sleep -- - ----------- - - procedure Sleep - (Self_ID : Task_Id; - Reason : System.Tasking.Task_States) - is - pragma Unreferenced (Reason); - - begin - pragma Assert (Self_ID = Self); - - if Single_Lock then - Cond_Wait (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access); - else - Cond_Wait (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access); - end if; - - if Self_ID.Deferral_Level = 0 - and then Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level - then - Unlock (Self_ID); - raise Standard'Abort_Signal; - end if; - end Sleep; - - ----------------- - -- Timed_Sleep -- - ----------------- - - -- This is for use within the run-time system, so abort is assumed to be - -- already deferred, and the caller should be holding its own ATCB lock. - - procedure Timed_Sleep - (Self_ID : Task_Id; - Time : Duration; - Mode : ST.Delay_Modes; - Reason : System.Tasking.Task_States; - Timedout : out Boolean; - Yielded : out Boolean) - is - pragma Unreferenced (Reason); - Check_Time : Duration := Monotonic_Clock; - Rel_Time : Duration; - Abs_Time : Duration; - - Result : Integer; - pragma Unreferenced (Result); - - Local_Timedout : Boolean; - - begin - Timedout := True; - Yielded := False; - - if Mode = Relative then - Rel_Time := Time; - Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time; - else - Rel_Time := Time - Check_Time; - Abs_Time := Time; - end if; - - if Rel_Time > 0.0 then - loop - exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level; - - if Single_Lock then - Cond_Timed_Wait - (Self_ID.Common.LL.CV'Access, - Single_RTS_Lock'Access, - Rel_Time, Local_Timedout, Result); - else - Cond_Timed_Wait - (Self_ID.Common.LL.CV'Access, - Self_ID.Common.LL.L'Access, - Rel_Time, Local_Timedout, Result); - end if; - - Check_Time := Monotonic_Clock; - exit when Abs_Time <= Check_Time; - - if not Local_Timedout then - - -- Somebody may have called Wakeup for us - - Timedout := False; - exit; - end if; - - Rel_Time := Abs_Time - Check_Time; - end loop; - end if; - end Timed_Sleep; - - ----------------- - -- Timed_Delay -- - ----------------- - - procedure Timed_Delay - (Self_ID : Task_Id; - Time : Duration; - Mode : ST.Delay_Modes) - is - Check_Time : Duration := Monotonic_Clock; - Rel_Time : Duration; - Abs_Time : Duration; - - Timedout : Boolean; - Result : Integer; - pragma Unreferenced (Timedout, Result); - - begin - if Single_Lock then - Lock_RTS; - end if; - - Write_Lock (Self_ID); - - if Mode = Relative then - Rel_Time := Time; - Abs_Time := Time + Check_Time; - else - Rel_Time := Time - Check_Time; - Abs_Time := Time; - end if; - - if Rel_Time > 0.0 then - Self_ID.Common.State := Delay_Sleep; - - loop - exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level; - - if Single_Lock then - Cond_Timed_Wait - (Self_ID.Common.LL.CV'Access, - Single_RTS_Lock'Access, - Rel_Time, Timedout, Result); - else - Cond_Timed_Wait - (Self_ID.Common.LL.CV'Access, - Self_ID.Common.LL.L'Access, - Rel_Time, Timedout, Result); - end if; - - Check_Time := Monotonic_Clock; - exit when Abs_Time <= Check_Time; - - Rel_Time := Abs_Time - Check_Time; - end loop; - - Self_ID.Common.State := Runnable; - end if; - - Unlock (Self_ID); - - if Single_Lock then - Unlock_RTS; - end if; - - Yield; - end Timed_Delay; - - ------------ - -- Wakeup -- - ------------ - - procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is - pragma Unreferenced (Reason); - begin - Cond_Signal (T.Common.LL.CV'Access); - end Wakeup; - - ----------- - -- Yield -- - ----------- - - procedure Yield (Do_Yield : Boolean := True) is - begin - if Do_Yield then - SwitchToThread; - - elsif Annex_D then - -- If running with Annex-D semantics we need a delay - -- above 0 milliseconds here otherwise processes give - -- enough time to the other tasks to have a chance to - -- run. - -- - -- This makes cxd8002 ACATS pass on Windows. - - Sleep (1); - end if; - end Yield; - - ------------------ - -- Set_Priority -- - ------------------ - - type Prio_Array_Type is array (System.Any_Priority) of Integer; - pragma Atomic_Components (Prio_Array_Type); - - Prio_Array : Prio_Array_Type; - -- Global array containing the id of the currently running task for - -- each priority. - -- - -- Note: we assume that we are on a single processor with run-til-blocked - -- scheduling. - - procedure Set_Priority - (T : Task_Id; - Prio : System.Any_Priority; - Loss_Of_Inheritance : Boolean := False) - is - Res : BOOL; - Array_Item : Integer; - - begin - Res := SetThreadPriority - (T.Common.LL.Thread, Interfaces.C.int (Underlying_Priorities (Prio))); - pragma Assert (Res = Win32.TRUE); - - if Dispatching_Policy = 'F' or else Get_Policy (Prio) = 'F' then - - -- Annex D requirement [RM D.2.2 par. 9]: - -- If the task drops its priority due to the loss of inherited - -- priority, it is added at the head of the ready queue for its - -- new active priority. - - if Loss_Of_Inheritance - and then Prio < T.Common.Current_Priority - then - Array_Item := Prio_Array (T.Common.Base_Priority) + 1; - Prio_Array (T.Common.Base_Priority) := Array_Item; - - loop - -- Let some processes a chance to arrive - - Yield; - - -- Then wait for our turn to proceed - - exit when Array_Item = Prio_Array (T.Common.Base_Priority) - or else Prio_Array (T.Common.Base_Priority) = 1; - end loop; - - Prio_Array (T.Common.Base_Priority) := - Prio_Array (T.Common.Base_Priority) - 1; - end if; - end if; - - T.Common.Current_Priority := Prio; - end Set_Priority; - - ------------------ - -- Get_Priority -- - ------------------ - - function Get_Priority (T : Task_Id) return System.Any_Priority is - begin - return T.Common.Current_Priority; - end Get_Priority; - - ---------------- - -- Enter_Task -- - ---------------- - - -- There were two paths were we needed to call Enter_Task : - -- 1) from System.Task_Primitives.Operations.Initialize - -- 2) from System.Tasking.Stages.Task_Wrapper - - -- The thread initialisation has to be done only for the first case - - -- This is because the GetCurrentThread NT call does not return the real - -- thread handler but only a "pseudo" one. It is not possible to release - -- the thread handle and free the system resources from this "pseudo" - -- handle. So we really want to keep the real thread handle set in - -- System.Task_Primitives.Operations.Create_Task during thread creation. - - procedure Enter_Task (Self_ID : Task_Id) is - procedure Init_Float; - pragma Import (C, Init_Float, "__gnat_init_float"); - -- Properly initializes the FPU for x86 systems - - begin - Specific.Set (Self_ID); - Init_Float; - - if Self_ID.Common.Task_Info /= null - and then - Self_ID.Common.Task_Info.CPU >= CPU_Number (Number_Of_Processors) - then - raise Invalid_CPU_Number; - end if; - - Self_ID.Common.LL.Thread_Id := GetCurrentThreadId; - - Lock_RTS; - - for J in Known_Tasks'Range loop - if Known_Tasks (J) = null then - Known_Tasks (J) := Self_ID; - Self_ID.Known_Tasks_Index := J; - exit; - end if; - end loop; - - Unlock_RTS; - end Enter_Task; - - -------------- - -- New_ATCB -- - -------------- - - function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is - begin - return new Ada_Task_Control_Block (Entry_Num); - end New_ATCB; - - ------------------- - -- Is_Valid_Task -- - ------------------- - - function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task; - - ----------------------------- - -- Register_Foreign_Thread -- - ----------------------------- - - function Register_Foreign_Thread return Task_Id is - begin - if Is_Valid_Task then - return Self; - else - return Register_Foreign_Thread (GetCurrentThread); - end if; - end Register_Foreign_Thread; - - -------------------- - -- Initialize_TCB -- - -------------------- - - procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is - begin - -- Initialize thread ID to 0, this is needed to detect threads that - -- are not yet activated. - - Self_ID.Common.LL.Thread := 0; - - Initialize_Cond (Self_ID.Common.LL.CV'Access); - - if not Single_Lock then - Initialize_Lock (Self_ID.Common.LL.L'Access, ATCB_Level); - end if; - - Succeeded := True; - end Initialize_TCB; - - ----------------- - -- Create_Task -- - ----------------- - - procedure Create_Task - (T : Task_Id; - Wrapper : System.Address; - Stack_Size : System.Parameters.Size_Type; - Priority : System.Any_Priority; - Succeeded : out Boolean) - is - Initial_Stack_Size : constant := 1024; - -- We set the initial stack size to 1024. On Windows version prior to XP - -- there is no way to fix a task stack size. Only the initial stack size - -- can be set, the operating system will raise the task stack size if - -- needed. - - function Is_Windows_XP return Integer; - pragma Import (C, Is_Windows_XP, "__gnat_is_windows_xp"); - -- Returns 1 if running on Windows XP - - hTask : HANDLE; - TaskId : aliased DWORD; - pTaskParameter : Win32.PVOID; - Result : DWORD; - Entry_Point : PTHREAD_START_ROUTINE; - - begin - pTaskParameter := To_Address (T); - - Entry_Point := To_PTHREAD_START_ROUTINE (Wrapper); - - if Is_Windows_XP = 1 then - hTask := CreateThread - (null, - DWORD (Stack_Size), - Entry_Point, - pTaskParameter, - DWORD (Create_Suspended) or - DWORD (Stack_Size_Param_Is_A_Reservation), - TaskId'Unchecked_Access); - else - hTask := CreateThread - (null, - Initial_Stack_Size, - Entry_Point, - pTaskParameter, - DWORD (Create_Suspended), - TaskId'Unchecked_Access); - end if; - - -- Step 1: Create the thread in blocked mode - - if hTask = 0 then - Succeeded := False; - return; - end if; - - -- Step 2: set its TCB - - T.Common.LL.Thread := hTask; - - -- Step 3: set its priority (child has inherited priority from parent) - - Set_Priority (T, Priority); - - if Time_Slice_Val = 0 - or else Dispatching_Policy = 'F' - or else Get_Policy (Priority) = 'F' - then - -- Here we need Annex D semantics so we disable the NT priority - -- boost. A priority boost is temporarily given by the system to a - -- thread when it is taken out of a wait state. - - SetThreadPriorityBoost (hTask, DisablePriorityBoost => Win32.TRUE); - end if; - - -- Step 4: Handle Task_Info - - if T.Common.Task_Info /= null then - if T.Common.Task_Info.CPU /= Task_Info.Any_CPU then - Result := SetThreadIdealProcessor (hTask, T.Common.Task_Info.CPU); - pragma Assert (Result = 1); - end if; - end if; - - -- Step 5: Now, start it for good: - - Result := ResumeThread (hTask); - pragma Assert (Result = 1); - - Succeeded := Result = 1; - end Create_Task; - - ------------------ - -- Finalize_TCB -- - ------------------ - - procedure Finalize_TCB (T : Task_Id) is - Self_ID : Task_Id := T; - Result : DWORD; - Succeeded : BOOL; - Is_Self : constant Boolean := T = Self; - - procedure Free is new - Ada.Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id); - - begin - if not Single_Lock then - Finalize_Lock (T.Common.LL.L'Access); - end if; - - Finalize_Cond (T.Common.LL.CV'Access); - - if T.Known_Tasks_Index /= -1 then - Known_Tasks (T.Known_Tasks_Index) := null; - end if; - - if Self_ID.Common.LL.Thread /= 0 then - - -- This task has been activated. Wait for the thread to terminate - -- then close it. This is needed to release system resources. - - Result := WaitForSingleObject (T.Common.LL.Thread, Wait_Infinite); - pragma Assert (Result /= WAIT_FAILED); - Succeeded := CloseHandle (T.Common.LL.Thread); - pragma Assert (Succeeded = Win32.TRUE); - end if; - - Free (Self_ID); - - if Is_Self then - Specific.Set (null); - end if; - end Finalize_TCB; - - --------------- - -- Exit_Task -- - --------------- - - procedure Exit_Task is - begin - Specific.Set (null); - end Exit_Task; - - ---------------- - -- Abort_Task -- - ---------------- - - procedure Abort_Task (T : Task_Id) is - pragma Unreferenced (T); - begin - null; - end Abort_Task; - - ---------------------- - -- Environment_Task -- - ---------------------- - - function Environment_Task return Task_Id is - begin - return Environment_Task_Id; - end Environment_Task; - - -------------- - -- Lock_RTS -- - -------------- - - procedure Lock_RTS is - begin - Write_Lock (Single_RTS_Lock'Access, Global_Lock => True); - end Lock_RTS; - - ---------------- - -- Unlock_RTS -- - ---------------- - - procedure Unlock_RTS is - begin - Unlock (Single_RTS_Lock'Access, Global_Lock => True); - end Unlock_RTS; - - ---------------- - -- Initialize -- - ---------------- - - procedure Initialize (Environment_Task : Task_Id) is - Discard : BOOL; - pragma Unreferenced (Discard); - - begin - Environment_Task_Id := Environment_Task; - OS_Primitives.Initialize; - Interrupt_Management.Initialize; - - if Time_Slice_Val = 0 or else Dispatching_Policy = 'F' then - -- Here we need Annex D semantics, switch the current process to the - -- Realtime_Priority_Class. - - Discard := OS_Interface.SetPriorityClass - (GetCurrentProcess, Realtime_Priority_Class); - - Annex_D := True; - end if; - - TlsIndex := TlsAlloc; - - -- Initialize the lock used to synchronize chain of all ATCBs - - Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level); - - Environment_Task.Common.LL.Thread := GetCurrentThread; - Enter_Task (Environment_Task); - end Initialize; - - --------------------- - -- Monotonic_Clock -- - --------------------- - - function Monotonic_Clock return Duration - renames System.OS_Primitives.Monotonic_Clock; - - ------------------- - -- RT_Resolution -- - ------------------- - - function RT_Resolution return Duration is - begin - return 0.000_001; -- 1 micro-second - end RT_Resolution; - - ---------------- - -- Initialize -- - ---------------- - - procedure Initialize (S : in out Suspension_Object) is - begin - -- Initialize internal state. It is always initialized to False (ARM - -- D.10 par. 6). - - S.State := False; - S.Waiting := False; - - -- Initialize internal mutex - - InitializeCriticalSection (S.L'Access); - - -- Initialize internal condition variable - - S.CV := CreateEvent (null, Win32.TRUE, Win32.FALSE, Null_Ptr); - pragma Assert (S.CV /= 0); - end Initialize; - - -------------- - -- Finalize -- - -------------- - - procedure Finalize (S : in out Suspension_Object) is - Result : BOOL; - begin - -- Destroy internal mutex - - DeleteCriticalSection (S.L'Access); - - -- Destroy internal condition variable - - Result := CloseHandle (S.CV); - pragma Assert (Result = Win32.TRUE); - end Finalize; - - ------------------- - -- Current_State -- - ------------------- - - function Current_State (S : Suspension_Object) return Boolean is - begin - -- We do not want to use lock on this read operation. State is marked - -- as Atomic so that we ensure that the value retrieved is correct. - - return S.State; - end Current_State; - - --------------- - -- Set_False -- - --------------- - - procedure Set_False (S : in out Suspension_Object) is - begin - SSL.Abort_Defer.all; - - EnterCriticalSection (S.L'Access); - - S.State := False; - - LeaveCriticalSection (S.L'Access); - - SSL.Abort_Undefer.all; - end Set_False; - - -------------- - -- Set_True -- - -------------- - - procedure Set_True (S : in out Suspension_Object) is - Result : BOOL; - begin - SSL.Abort_Defer.all; - - EnterCriticalSection (S.L'Access); - - -- If there is already a task waiting on this suspension object then - -- we resume it, leaving the state of the suspension object to False, - -- as it is specified in ARM D.10 par. 9. Otherwise, it just leaves - -- the state to True. - - if S.Waiting then - S.Waiting := False; - S.State := False; - - Result := SetEvent (S.CV); - pragma Assert (Result = Win32.TRUE); - else - S.State := True; - end if; - - LeaveCriticalSection (S.L'Access); - - SSL.Abort_Undefer.all; - end Set_True; - - ------------------------ - -- Suspend_Until_True -- - ------------------------ - - procedure Suspend_Until_True (S : in out Suspension_Object) is - Result : DWORD; - Result_Bool : BOOL; - begin - SSL.Abort_Defer.all; - - EnterCriticalSection (S.L'Access); - - if S.Waiting then - -- Program_Error must be raised upon calling Suspend_Until_True - -- if another task is already waiting on that suspension object - -- (ARM D.10 par. 10). - - LeaveCriticalSection (S.L'Access); - - SSL.Abort_Undefer.all; - - raise Program_Error; - else - -- Suspend the task if the state is False. Otherwise, the task - -- continues its execution, and the state of the suspension object - -- is set to False (ARM D.10 par. 9). - - if S.State then - S.State := False; - - LeaveCriticalSection (S.L'Access); - - SSL.Abort_Undefer.all; - else - S.Waiting := True; - - -- Must reset CV BEFORE L is unlocked - - Result_Bool := ResetEvent (S.CV); - pragma Assert (Result_Bool = Win32.TRUE); - - LeaveCriticalSection (S.L'Access); - - SSL.Abort_Undefer.all; - - Result := WaitForSingleObject (S.CV, Wait_Infinite); - pragma Assert (Result = 0); - end if; - end if; - end Suspend_Until_True; - - ---------------- - -- Check_Exit -- - ---------------- - - -- Dummy versions. The only currently working versions is for solaris - -- (native). - - function Check_Exit (Self_ID : ST.Task_Id) return Boolean is - pragma Unreferenced (Self_ID); - begin - return True; - end Check_Exit; - - -------------------- - -- Check_No_Locks -- - -------------------- - - function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is - pragma Unreferenced (Self_ID); - begin - return True; - end Check_No_Locks; - - ------------------ - -- Suspend_Task -- - ------------------ - - function Suspend_Task - (T : ST.Task_Id; - Thread_Self : Thread_Id) return Boolean - is - begin - if T.Common.LL.Thread /= Thread_Self then - return SuspendThread (T.Common.LL.Thread) = NO_ERROR; - else - return True; - end if; - end Suspend_Task; - - ----------------- - -- Resume_Task -- - ----------------- - - function Resume_Task - (T : ST.Task_Id; - Thread_Self : Thread_Id) return Boolean - is - begin - if T.Common.LL.Thread /= Thread_Self then - return ResumeThread (T.Common.LL.Thread) = NO_ERROR; - else - return True; - end if; - end Resume_Task; - - -------------------- - -- Stop_All_Tasks -- - -------------------- - - procedure Stop_All_Tasks is - begin - null; - end Stop_All_Tasks; - - --------------- - -- Stop_Task -- - --------------- - - function Stop_Task (T : ST.Task_Id) return Boolean is - pragma Unreferenced (T); - begin - return False; - end Stop_Task; - - ------------------- - -- Continue_Task -- - ------------------- - - function Continue_Task (T : ST.Task_Id) return Boolean is - pragma Unreferenced (T); - begin - return False; - end Continue_Task; - -end System.Task_Primitives.Operations; |