OSDN Git Service

PR fortran/23516
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-taprop-mingw.adb
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-2005, 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 ------------------------------------------------------------------------------
33
34 --  This is a NT (native) version of this package
35
36 --  This package contains all the GNULL primitives that interface directly
37 --  with the underlying OS.
38
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.
42
43 with System.Tasking.Debug;
44 --  used for Known_Tasks
45
46 with System.OS_Primitives;
47 --  used for Delay_Modes
48
49 with Interfaces.C;
50 --  used for int
51 --           size_t
52
53 with Interfaces.C.Strings;
54 --  used for Null_Ptr
55
56 with System.OS_Interface;
57 --  used for various type, constant, and operations
58
59 with System.Parameters;
60 --  used for Size_Type
61
62 with System.Task_Info;
63 --  used for Unspecified_Task_Info
64
65 with Unchecked_Deallocation;
66
67 package body System.Task_Primitives.Operations is
68
69    use System.Tasking.Debug;
70    use System.Tasking;
71    use Interfaces.C;
72    use Interfaces.C.Strings;
73    use System.OS_Interface;
74    use System.Parameters;
75    use System.OS_Primitives;
76
77    pragma Link_With ("-Xlinker --stack=0x800000,0x1000");
78    --  Change the stack size (8 MB) for tasking programs on Windows. This
79    --  permit to have more than 30 tasks running at the same time. Note that
80    --  we set the stack size for non tasking programs on System unit.
81
82    ----------------
83    -- Local Data --
84    ----------------
85
86    Environment_Task_Id : Task_Id;
87    --  A variable to hold Task_Id for the environment task
88
89    Single_RTS_Lock : aliased RTS_Lock;
90    --  This is a lock to allow only one thread of control in the RTS at
91    --  a time; it is used to execute in mutual exclusion from all other tasks.
92    --  Used mainly in Single_Lock mode, but also to protect All_Tasks_List
93
94    Time_Slice_Val : Integer;
95    pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
96
97    Dispatching_Policy : Character;
98    pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
99
100    Foreign_Task_Elaborated : aliased Boolean := True;
101    --  Used to identified fake tasks (i.e., non-Ada Threads)
102
103    ------------------------------------
104    -- The thread local storage index --
105    ------------------------------------
106
107    TlsIndex : DWORD;
108    pragma Export (Ada, TlsIndex);
109    --  To ensure that this variable won't be local to this package, since
110    --  in some cases, inlining forces this variable to be global anyway.
111
112    --------------------
113    -- Local Packages --
114    --------------------
115
116    package Specific is
117
118       function Is_Valid_Task return Boolean;
119       pragma Inline (Is_Valid_Task);
120       --  Does executing thread have a TCB?
121
122       procedure Set (Self_Id : Task_Id);
123       pragma Inline (Set);
124       --  Set the self id for the current task.
125
126    end Specific;
127
128    package body Specific is
129
130       function Is_Valid_Task return Boolean is
131       begin
132          return TlsGetValue (TlsIndex) /= System.Null_Address;
133       end Is_Valid_Task;
134
135       procedure Set (Self_Id : Task_Id) is
136          Succeeded : BOOL;
137       begin
138          Succeeded := TlsSetValue (TlsIndex, To_Address (Self_Id));
139          pragma Assert (Succeeded = True);
140       end Set;
141
142    end Specific;
143
144    ---------------------------------
145    -- Support for foreign threads --
146    ---------------------------------
147
148    function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
149    --  Allocate and Initialize a new ATCB for the current Thread.
150
151    function Register_Foreign_Thread
152      (Thread : Thread_Id) return Task_Id is separate;
153
154    ----------------------------------
155    -- Condition Variable Functions --
156    ----------------------------------
157
158    procedure Initialize_Cond (Cond : access Condition_Variable);
159    --  Initialize given condition variable Cond
160
161    procedure Finalize_Cond (Cond : access Condition_Variable);
162    --  Finalize given condition variable Cond.
163
164    procedure Cond_Signal (Cond : access Condition_Variable);
165    --  Signal condition variable Cond
166
167    procedure Cond_Wait
168      (Cond : access Condition_Variable;
169       L    : access RTS_Lock);
170    --  Wait on conditional variable Cond, using lock L
171
172    procedure Cond_Timed_Wait
173      (Cond      : access Condition_Variable;
174       L         : access RTS_Lock;
175       Rel_Time  : Duration;
176       Timed_Out : out Boolean;
177       Status    : out Integer);
178    --  Do timed wait on condition variable Cond using lock L. The duration
179    --  of the timed wait is given by Rel_Time. When the condition is
180    --  signalled, Timed_Out shows whether or not a time out occurred.
181    --  Status is only valid if Timed_Out is False, in which case it
182    --  shows whether Cond_Timed_Wait completed successfully.
183
184    ---------------------
185    -- Initialize_Cond --
186    ---------------------
187
188    procedure Initialize_Cond (Cond : access Condition_Variable) is
189       hEvent : HANDLE;
190
191    begin
192       hEvent := CreateEvent (null, True, False, Null_Ptr);
193       pragma Assert (hEvent /= 0);
194       Cond.all := Condition_Variable (hEvent);
195    end Initialize_Cond;
196
197    -------------------
198    -- Finalize_Cond --
199    -------------------
200
201    --  No such problem here, DosCloseEventSem has been derived.
202    --  What does such refer to in above comment???
203
204    procedure Finalize_Cond (Cond : access Condition_Variable) is
205       Result : BOOL;
206    begin
207       Result := CloseHandle (HANDLE (Cond.all));
208       pragma Assert (Result = True);
209    end Finalize_Cond;
210
211    -----------------
212    -- Cond_Signal --
213    -----------------
214
215    procedure Cond_Signal (Cond : access Condition_Variable) is
216       Result : BOOL;
217    begin
218       Result := SetEvent (HANDLE (Cond.all));
219       pragma Assert (Result = True);
220    end Cond_Signal;
221
222    ---------------
223    -- Cond_Wait --
224    ---------------
225
226    --  Pre-assertion: Cond is posted
227    --                 L is locked.
228
229    --  Post-assertion: Cond is posted
230    --                  L is locked.
231
232    procedure Cond_Wait
233      (Cond : access Condition_Variable;
234       L    : access RTS_Lock)
235    is
236       Result      : DWORD;
237       Result_Bool : BOOL;
238
239    begin
240       --  Must reset Cond BEFORE L is unlocked.
241
242       Result_Bool := ResetEvent (HANDLE (Cond.all));
243       pragma Assert (Result_Bool = True);
244       Unlock (L);
245
246       --  No problem if we are interrupted here: if the condition is signaled,
247       --  WaitForSingleObject will simply not block
248
249       Result := WaitForSingleObject (HANDLE (Cond.all), Wait_Infinite);
250       pragma Assert (Result = 0);
251
252       Write_Lock (L);
253    end Cond_Wait;
254
255    ---------------------
256    -- Cond_Timed_Wait --
257    ---------------------
258
259    --  Pre-assertion: Cond is posted
260    --                 L is locked.
261
262    --  Post-assertion: Cond is posted
263    --                  L is locked.
264
265    procedure Cond_Timed_Wait
266      (Cond      : access Condition_Variable;
267       L         : access RTS_Lock;
268       Rel_Time  : Duration;
269       Timed_Out : out Boolean;
270       Status    : out Integer)
271    is
272       Time_Out_Max : constant DWORD := 16#FFFF0000#;
273       --  NT 4 cannot handle timeout values that are too large,
274       --  e.g. DWORD'Last - 1
275
276       Time_Out     : DWORD;
277       Result       : BOOL;
278       Wait_Result  : DWORD;
279
280    begin
281       --  Must reset Cond BEFORE L is unlocked.
282
283       Result := ResetEvent (HANDLE (Cond.all));
284       pragma Assert (Result = True);
285       Unlock (L);
286
287       --  No problem if we are interrupted here: if the condition is signaled,
288       --  WaitForSingleObject will simply not block
289
290       if Rel_Time <= 0.0 then
291          Timed_Out := True;
292          Wait_Result := 0;
293
294       else
295          if Rel_Time >= Duration (Time_Out_Max) / 1000 then
296             Time_Out := Time_Out_Max;
297          else
298             Time_Out := DWORD (Rel_Time * 1000);
299          end if;
300
301          Wait_Result := WaitForSingleObject (HANDLE (Cond.all), Time_Out);
302
303          if Wait_Result = WAIT_TIMEOUT then
304             Timed_Out := True;
305             Wait_Result := 0;
306          else
307             Timed_Out := False;
308          end if;
309       end if;
310
311       Write_Lock (L);
312
313       --  Ensure post-condition
314
315       if Timed_Out then
316          Result := SetEvent (HANDLE (Cond.all));
317          pragma Assert (Result = True);
318       end if;
319
320       Status := Integer (Wait_Result);
321    end Cond_Timed_Wait;
322
323    ------------------
324    -- Stack_Guard  --
325    ------------------
326
327    --  The underlying thread system sets a guard page at the
328    --  bottom of a thread stack, so nothing is needed.
329    --  ??? Check the comment above
330
331    procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is
332       pragma Warnings (Off, T);
333       pragma Warnings (Off, On);
334
335    begin
336       null;
337    end Stack_Guard;
338
339    --------------------
340    -- Get_Thread_Id  --
341    --------------------
342
343    function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is
344    begin
345       return T.Common.LL.Thread;
346    end Get_Thread_Id;
347
348    ----------
349    -- Self --
350    ----------
351
352    function Self return Task_Id is
353       Self_Id : constant Task_Id := To_Task_Id (TlsGetValue (TlsIndex));
354    begin
355       if Self_Id = null then
356          return Register_Foreign_Thread (GetCurrentThread);
357       else
358          return Self_Id;
359       end if;
360    end Self;
361
362    ---------------------
363    -- Initialize_Lock --
364    ---------------------
365
366    --  Note: mutexes and cond_variables needed per-task basis are
367    --  initialized in Intialize_TCB and the Storage_Error is handled.
368    --  Other mutexes (such as RTS_Lock, Memory_Lock...) used in
369    --  the RTS is initialized before any status change of RTS.
370    --  Therefore raising Storage_Error in the following routines
371    --  should be able to be handled safely.
372
373    procedure Initialize_Lock
374      (Prio : System.Any_Priority;
375       L    : access Lock)
376    is
377    begin
378       InitializeCriticalSection (L.Mutex'Access);
379       L.Owner_Priority := 0;
380       L.Priority := Prio;
381    end Initialize_Lock;
382
383    procedure Initialize_Lock (L : access RTS_Lock; Level : Lock_Level) is
384       pragma Unreferenced (Level);
385    begin
386       InitializeCriticalSection (CRITICAL_SECTION (L.all)'Unrestricted_Access);
387    end Initialize_Lock;
388
389    -------------------
390    -- Finalize_Lock --
391    -------------------
392
393    procedure Finalize_Lock (L : access Lock) is
394    begin
395       DeleteCriticalSection (L.Mutex'Access);
396    end Finalize_Lock;
397
398    procedure Finalize_Lock (L : access RTS_Lock) is
399    begin
400       DeleteCriticalSection (CRITICAL_SECTION (L.all)'Unrestricted_Access);
401    end Finalize_Lock;
402
403    ----------------
404    -- Write_Lock --
405    ----------------
406
407    procedure Write_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
408    begin
409       L.Owner_Priority := Get_Priority (Self);
410
411       if L.Priority < L.Owner_Priority then
412          Ceiling_Violation := True;
413          return;
414       end if;
415
416       EnterCriticalSection (L.Mutex'Access);
417
418       Ceiling_Violation := False;
419    end Write_Lock;
420
421    procedure Write_Lock
422      (L           : access RTS_Lock;
423       Global_Lock : Boolean := False)
424    is
425    begin
426       if not Single_Lock or else Global_Lock then
427          EnterCriticalSection (CRITICAL_SECTION (L.all)'Unrestricted_Access);
428       end if;
429    end Write_Lock;
430
431    procedure Write_Lock (T : Task_Id) is
432    begin
433       if not Single_Lock then
434          EnterCriticalSection
435            (CRITICAL_SECTION (T.Common.LL.L)'Unrestricted_Access);
436       end if;
437    end Write_Lock;
438
439    ---------------
440    -- Read_Lock --
441    ---------------
442
443    procedure Read_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
444    begin
445       Write_Lock (L, Ceiling_Violation);
446    end Read_Lock;
447
448    ------------
449    -- Unlock --
450    ------------
451
452    procedure Unlock (L : access Lock) is
453    begin
454       LeaveCriticalSection (L.Mutex'Access);
455    end Unlock;
456
457    procedure Unlock (L : access RTS_Lock; Global_Lock : Boolean := False) is
458    begin
459       if not Single_Lock or else Global_Lock then
460          LeaveCriticalSection (CRITICAL_SECTION (L.all)'Unrestricted_Access);
461       end if;
462    end Unlock;
463
464    procedure Unlock (T : Task_Id) is
465    begin
466       if not Single_Lock then
467          LeaveCriticalSection
468            (CRITICAL_SECTION (T.Common.LL.L)'Unrestricted_Access);
469       end if;
470    end Unlock;
471
472    -----------
473    -- Sleep --
474    -----------
475
476    procedure Sleep
477      (Self_ID : Task_Id;
478       Reason  : System.Tasking.Task_States)
479    is
480       pragma Unreferenced (Reason);
481
482    begin
483       pragma Assert (Self_ID = Self);
484
485       if Single_Lock then
486          Cond_Wait (Self_ID.Common.LL.CV'Access, Single_RTS_Lock'Access);
487       else
488          Cond_Wait (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L'Access);
489       end if;
490
491       if Self_ID.Deferral_Level = 0
492         and then Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
493       then
494          Unlock (Self_ID);
495          raise Standard'Abort_Signal;
496       end if;
497    end Sleep;
498
499    -----------------
500    -- Timed_Sleep --
501    -----------------
502
503    --  This is for use within the run-time system, so abort is
504    --  assumed to be already deferred, and the caller should be
505    --  holding its own ATCB lock.
506
507    procedure Timed_Sleep
508      (Self_ID  : Task_Id;
509       Time     : Duration;
510       Mode     : ST.Delay_Modes;
511       Reason   : System.Tasking.Task_States;
512       Timedout : out Boolean;
513       Yielded  : out Boolean)
514    is
515       pragma Unreferenced (Reason);
516       Check_Time : Duration := Monotonic_Clock;
517       Rel_Time   : Duration;
518       Abs_Time   : Duration;
519       Result     : Integer;
520
521       Local_Timedout : Boolean;
522
523    begin
524       Timedout := True;
525       Yielded  := False;
526
527       if Mode = Relative then
528          Rel_Time := Time;
529          Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
530       else
531          Rel_Time := Time - Check_Time;
532          Abs_Time := Time;
533       end if;
534
535       if Rel_Time > 0.0 then
536          loop
537             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
538               or else Self_ID.Pending_Priority_Change;
539
540             if Single_Lock then
541                Cond_Timed_Wait (Self_ID.Common.LL.CV'Access,
542                  Single_RTS_Lock'Access, Rel_Time, Local_Timedout, Result);
543             else
544                Cond_Timed_Wait (Self_ID.Common.LL.CV'Access,
545                  Self_ID.Common.LL.L'Access, Rel_Time, Local_Timedout, Result);
546             end if;
547
548             Check_Time := Monotonic_Clock;
549             exit when Abs_Time <= Check_Time;
550
551             if not Local_Timedout then
552
553                --  Somebody may have called Wakeup for us
554
555                Timedout := False;
556                exit;
557             end if;
558
559             Rel_Time := Abs_Time - Check_Time;
560          end loop;
561       end if;
562    end Timed_Sleep;
563
564    -----------------
565    -- Timed_Delay --
566    -----------------
567
568    procedure Timed_Delay
569      (Self_ID  : Task_Id;
570       Time     : Duration;
571       Mode     : ST.Delay_Modes)
572    is
573       Check_Time : Duration := Monotonic_Clock;
574       Rel_Time   : Duration;
575       Abs_Time   : Duration;
576       Result     : Integer;
577       Timedout   : Boolean;
578
579    begin
580       if Single_Lock then
581          Lock_RTS;
582       end if;
583
584       Write_Lock (Self_ID);
585
586       if Mode = Relative then
587          Rel_Time := Time;
588          Abs_Time := Time + Check_Time;
589       else
590          Rel_Time := Time - Check_Time;
591          Abs_Time := Time;
592       end if;
593
594       if Rel_Time > 0.0 then
595          Self_ID.Common.State := Delay_Sleep;
596
597          loop
598             if Self_ID.Pending_Priority_Change then
599                Self_ID.Pending_Priority_Change := False;
600                Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
601                Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
602             end if;
603
604             exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
605
606             if Single_Lock then
607                Cond_Timed_Wait (Self_ID.Common.LL.CV'Access,
608                  Single_RTS_Lock'Access, Rel_Time, Timedout, Result);
609             else
610                Cond_Timed_Wait (Self_ID.Common.LL.CV'Access,
611                  Self_ID.Common.LL.L'Access, Rel_Time, Timedout, Result);
612             end if;
613
614             Check_Time := Monotonic_Clock;
615             exit when Abs_Time <= Check_Time;
616
617             Rel_Time := Abs_Time - Check_Time;
618          end loop;
619
620          Self_ID.Common.State := Runnable;
621       end if;
622
623       Unlock (Self_ID);
624
625       if Single_Lock then
626          Unlock_RTS;
627       end if;
628
629       Yield;
630    end Timed_Delay;
631
632    ------------
633    -- Wakeup --
634    ------------
635
636    procedure Wakeup (T : Task_Id; Reason : System.Tasking.Task_States) is
637       pragma Unreferenced (Reason);
638    begin
639       Cond_Signal (T.Common.LL.CV'Access);
640    end Wakeup;
641
642    -----------
643    -- Yield --
644    -----------
645
646    procedure Yield (Do_Yield : Boolean := True) is
647    begin
648       if Do_Yield then
649          Sleep (0);
650       end if;
651    end Yield;
652
653    ------------------
654    -- Set_Priority --
655    ------------------
656
657    type Prio_Array_Type is array (System.Any_Priority) of Integer;
658    pragma Atomic_Components (Prio_Array_Type);
659
660    Prio_Array : Prio_Array_Type;
661    --  Global array containing the id of the currently running task for
662    --  each priority.
663    --
664    --  Note: we assume that we are on a single processor with run-til-blocked
665    --  scheduling.
666
667    procedure Set_Priority
668      (T                   : Task_Id;
669       Prio                : System.Any_Priority;
670       Loss_Of_Inheritance : Boolean := False)
671    is
672       Res        : BOOL;
673       Array_Item : Integer;
674
675    begin
676       Res := SetThreadPriority
677         (T.Common.LL.Thread, Interfaces.C.int (Underlying_Priorities (Prio)));
678       pragma Assert (Res = True);
679
680       if Dispatching_Policy = 'F' then
681
682          --  Annex D requirement [RM D.2.2 par. 9]:
683          --    If the task drops its priority due to the loss of inherited
684          --    priority, it is added at the head of the ready queue for its
685          --    new active priority.
686
687          if Loss_Of_Inheritance
688            and then Prio < T.Common.Current_Priority
689          then
690             Array_Item := Prio_Array (T.Common.Base_Priority) + 1;
691             Prio_Array (T.Common.Base_Priority) := Array_Item;
692
693             loop
694                --  Let some processes a chance to arrive
695
696                Yield;
697
698                --  Then wait for our turn to proceed
699
700                exit when Array_Item = Prio_Array (T.Common.Base_Priority)
701                  or else Prio_Array (T.Common.Base_Priority) = 1;
702             end loop;
703
704             Prio_Array (T.Common.Base_Priority) :=
705               Prio_Array (T.Common.Base_Priority) - 1;
706          end if;
707       end if;
708
709       T.Common.Current_Priority := Prio;
710    end Set_Priority;
711
712    ------------------
713    -- Get_Priority --
714    ------------------
715
716    function Get_Priority (T : Task_Id) return System.Any_Priority is
717    begin
718       return T.Common.Current_Priority;
719    end Get_Priority;
720
721    ----------------
722    -- Enter_Task --
723    ----------------
724
725    --  There were two paths were we needed to call Enter_Task :
726    --  1) from System.Task_Primitives.Operations.Initialize
727    --  2) from System.Tasking.Stages.Task_Wrapper
728    --
729    --  The thread initialisation has to be done only for the first case.
730    --
731    --  This is because the GetCurrentThread NT call does not return the
732    --  real thread handler but only a "pseudo" one. It is not possible to
733    --  release the thread handle and free the system ressources from this
734    --  "pseudo" handle. So we really want to keep the real thread handle
735    --  set in System.Task_Primitives.Operations.Create_Task during the
736    --  thread creation.
737
738    procedure Enter_Task (Self_ID : Task_Id) is
739       procedure Init_Float;
740       pragma Import (C, Init_Float, "__gnat_init_float");
741       --  Properly initializes the FPU for x86 systems.
742
743    begin
744       Specific.Set (Self_ID);
745       Init_Float;
746
747       Self_ID.Common.LL.Thread_Id := GetCurrentThreadId;
748
749       Lock_RTS;
750
751       for J in Known_Tasks'Range loop
752          if Known_Tasks (J) = null then
753             Known_Tasks (J) := Self_ID;
754             Self_ID.Known_Tasks_Index := J;
755             exit;
756          end if;
757       end loop;
758
759       Unlock_RTS;
760    end Enter_Task;
761
762    --------------
763    -- New_ATCB --
764    --------------
765
766    function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
767    begin
768       return new Ada_Task_Control_Block (Entry_Num);
769    end New_ATCB;
770
771    -------------------
772    -- Is_Valid_Task --
773    -------------------
774
775    function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
776
777    -----------------------------
778    -- Register_Foreign_Thread --
779    -----------------------------
780
781    function Register_Foreign_Thread return Task_Id is
782    begin
783       if Is_Valid_Task then
784          return Self;
785       else
786          return Register_Foreign_Thread (GetCurrentThread);
787       end if;
788    end Register_Foreign_Thread;
789
790    --------------------
791    -- Initialize_TCB --
792    --------------------
793
794    procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
795    begin
796       --  Initialize thread ID to 0, this is needed to detect threads that
797       --  are not yet activated.
798
799       Self_ID.Common.LL.Thread := 0;
800
801       Initialize_Cond (Self_ID.Common.LL.CV'Access);
802
803       if not Single_Lock then
804          Initialize_Lock (Self_ID.Common.LL.L'Access, ATCB_Level);
805       end if;
806
807       Succeeded := True;
808    end Initialize_TCB;
809
810    -----------------
811    -- Create_Task --
812    -----------------
813
814    procedure Create_Task
815      (T          : Task_Id;
816       Wrapper    : System.Address;
817       Stack_Size : System.Parameters.Size_Type;
818       Priority   : System.Any_Priority;
819       Succeeded  : out Boolean)
820    is
821       pragma Unreferenced (Stack_Size);
822
823       Initial_Stack_Size : constant := 1024;
824       --  We set the initial stack size to 1024. On Windows there is no way to
825       --  fix a task stack size. Only the initial stack size can be set, the
826       --  operating system will raise the task stack size if needed.
827
828       hTask          : HANDLE;
829       TaskId         : aliased DWORD;
830       pTaskParameter : System.OS_Interface.PVOID;
831       Result         : DWORD;
832       Entry_Point    : PTHREAD_START_ROUTINE;
833
834    begin
835       pTaskParameter := To_Address (T);
836
837       Entry_Point := To_PTHREAD_START_ROUTINE (Wrapper);
838
839       hTask := CreateThread
840          (null,
841           Initial_Stack_Size,
842           Entry_Point,
843           pTaskParameter,
844           DWORD (Create_Suspended),
845           TaskId'Unchecked_Access);
846
847       --  Step 1: Create the thread in blocked mode
848
849       if hTask = 0 then
850          raise Storage_Error;
851       end if;
852
853       --  Step 2: set its TCB
854
855       T.Common.LL.Thread := hTask;
856
857       --  Step 3: set its priority (child has inherited priority from parent)
858
859       Set_Priority (T, Priority);
860
861       if Time_Slice_Val = 0 or else Dispatching_Policy = 'F' then
862          --  Here we need Annex E semantics so we disable the NT priority
863          --  boost. A priority boost is temporarily given by the system to a
864          --  thread when it is taken out of a wait state.
865
866          SetThreadPriorityBoost (hTask, DisablePriorityBoost => True);
867       end if;
868
869       --  Step 4: Now, start it for good:
870
871       Result := ResumeThread (hTask);
872       pragma Assert (Result = 1);
873
874       Succeeded := Result = 1;
875    end Create_Task;
876
877    ------------------
878    -- Finalize_TCB --
879    ------------------
880
881    procedure Finalize_TCB (T : Task_Id) is
882       Self_ID   : Task_Id := T;
883       Result    : DWORD;
884       Succeeded : BOOL;
885       Is_Self   : constant Boolean := T = Self;
886
887       procedure Free is new
888         Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
889
890    begin
891       if not Single_Lock then
892          Finalize_Lock (T.Common.LL.L'Access);
893       end if;
894
895       Finalize_Cond (T.Common.LL.CV'Access);
896
897       if T.Known_Tasks_Index /= -1 then
898          Known_Tasks (T.Known_Tasks_Index) := null;
899       end if;
900
901       if Self_ID.Common.LL.Thread /= 0 then
902
903          --  This task has been activated. Wait for the thread to terminate
904          --  then close it. this is needed to release system ressources.
905
906          Result := WaitForSingleObject (T.Common.LL.Thread, Wait_Infinite);
907          pragma Assert (Result /= WAIT_FAILED);
908          Succeeded := CloseHandle (T.Common.LL.Thread);
909          pragma Assert (Succeeded = True);
910       end if;
911
912       Free (Self_ID);
913
914       if Is_Self then
915          Specific.Set (null);
916       end if;
917    end Finalize_TCB;
918
919    ---------------
920    -- Exit_Task --
921    ---------------
922
923    procedure Exit_Task is
924    begin
925       Specific.Set (null);
926    end Exit_Task;
927
928    ----------------
929    -- Abort_Task --
930    ----------------
931
932    procedure Abort_Task (T : Task_Id) is
933       pragma Unreferenced (T);
934    begin
935       null;
936    end Abort_Task;
937
938    ----------------------
939    -- Environment_Task --
940    ----------------------
941
942    function Environment_Task return Task_Id is
943    begin
944       return Environment_Task_Id;
945    end Environment_Task;
946
947    --------------
948    -- Lock_RTS --
949    --------------
950
951    procedure Lock_RTS is
952    begin
953       Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
954    end Lock_RTS;
955
956    ----------------
957    -- Unlock_RTS --
958    ----------------
959
960    procedure Unlock_RTS is
961    begin
962       Unlock (Single_RTS_Lock'Access, Global_Lock => True);
963    end Unlock_RTS;
964
965    ----------------
966    -- Initialize --
967    ----------------
968
969    procedure Initialize (Environment_Task : Task_Id) is
970       Discard : BOOL;
971       pragma Unreferenced (Discard);
972
973    begin
974       Environment_Task_Id := Environment_Task;
975       OS_Primitives.Initialize;
976
977       if Time_Slice_Val = 0 or else Dispatching_Policy = 'F' then
978
979          --  Here we need Annex D semantics, switch the current process to the
980          --  High_Priority_Class.
981
982          Discard :=
983            OS_Interface.SetPriorityClass
984              (GetCurrentProcess, High_Priority_Class);
985
986          --  ??? In theory it should be possible to use the priority class
987          --  Realtime_Prioriry_Class but we suspect a bug in the NT scheduler
988          --  which prevents (in some obscure cases) a thread to get on top of
989          --  the running queue by another thread of lower priority. For
990          --  example cxd8002 ACATS test freeze.
991       end if;
992
993       TlsIndex := TlsAlloc;
994
995       --  Initialize the lock used to synchronize chain of all ATCBs.
996
997       Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
998
999       Environment_Task.Common.LL.Thread := GetCurrentThread;
1000       Enter_Task (Environment_Task);
1001    end Initialize;
1002
1003    ---------------------
1004    -- Monotonic_Clock --
1005    ---------------------
1006
1007    function Monotonic_Clock return Duration
1008      renames System.OS_Primitives.Monotonic_Clock;
1009
1010    -------------------
1011    -- RT_Resolution --
1012    -------------------
1013
1014    function RT_Resolution return Duration is
1015    begin
1016       return 0.000_001; --  1 micro-second
1017    end RT_Resolution;
1018
1019    ----------------
1020    -- Initialize --
1021    ----------------
1022
1023    procedure Initialize (S : in out Suspension_Object) is
1024    begin
1025       --  Initialize internal state. It is always initialized to False (ARM
1026       --  D.10 par. 6).
1027
1028       S.State := False;
1029       S.Waiting := False;
1030
1031       --  Initialize internal mutex
1032
1033       InitializeCriticalSection (S.L'Access);
1034
1035       --  Initialize internal condition variable
1036
1037       S.CV := CreateEvent (null, True, False, Null_Ptr);
1038       pragma Assert (S.CV /= 0);
1039    end Initialize;
1040
1041    --------------
1042    -- Finalize --
1043    --------------
1044
1045    procedure Finalize (S : in out Suspension_Object) is
1046       Result : BOOL;
1047    begin
1048       --  Destroy internal mutex
1049
1050       DeleteCriticalSection (S.L'Access);
1051
1052       --  Destroy internal condition variable
1053
1054       Result := CloseHandle (S.CV);
1055       pragma Assert (Result = True);
1056    end Finalize;
1057
1058    -------------------
1059    -- Current_State --
1060    -------------------
1061
1062    function Current_State (S : Suspension_Object) return Boolean is
1063    begin
1064       --  We do not want to use lock on this read operation. State is marked
1065       --  as Atomic so that we ensure that the value retrieved is correct.
1066
1067       return S.State;
1068    end Current_State;
1069
1070    ---------------
1071    -- Set_False --
1072    ---------------
1073
1074    procedure Set_False (S : in out Suspension_Object) is
1075    begin
1076       EnterCriticalSection (S.L'Access);
1077
1078       S.State := False;
1079
1080       LeaveCriticalSection (S.L'Access);
1081    end Set_False;
1082
1083    --------------
1084    -- Set_True --
1085    --------------
1086
1087    procedure Set_True (S : in out Suspension_Object) is
1088       Result : BOOL;
1089    begin
1090       EnterCriticalSection (S.L'Access);
1091
1092       --  If there is already a task waiting on this suspension object then
1093       --  we resume it, leaving the state of the suspension object to False,
1094       --  as it is specified in ARM D.10 par. 9. Otherwise, it just leaves
1095       --  the state to True.
1096
1097       if S.Waiting then
1098          S.Waiting := False;
1099          S.State := False;
1100
1101          Result := SetEvent (S.CV);
1102          pragma Assert (Result = True);
1103       else
1104          S.State := True;
1105       end if;
1106
1107       LeaveCriticalSection (S.L'Access);
1108    end Set_True;
1109
1110    ------------------------
1111    -- Suspend_Until_True --
1112    ------------------------
1113
1114    procedure Suspend_Until_True (S : in out Suspension_Object) is
1115       Result      : DWORD;
1116       Result_Bool : BOOL;
1117    begin
1118       EnterCriticalSection (S.L'Access);
1119
1120       if S.Waiting then
1121          --  Program_Error must be raised upon calling Suspend_Until_True
1122          --  if another task is already waiting on that suspension object
1123          --  (ARM D.10 par. 10).
1124
1125          LeaveCriticalSection (S.L'Access);
1126
1127          raise Program_Error;
1128       else
1129          --  Suspend the task if the state is False. Otherwise, the task
1130          --  continues its execution, and the state of the suspension object
1131          --  is set to False (ARM D.10 par. 9).
1132
1133          if S.State then
1134             S.State := False;
1135
1136             LeaveCriticalSection (S.L'Access);
1137          else
1138             S.Waiting := True;
1139
1140             --  Must reset CV BEFORE L is unlocked.
1141
1142             Result_Bool := ResetEvent (S.CV);
1143             pragma Assert (Result_Bool = True);
1144
1145             LeaveCriticalSection (S.L'Access);
1146
1147             Result := WaitForSingleObject (S.CV, Wait_Infinite);
1148             pragma Assert (Result = 0);
1149          end if;
1150       end if;
1151    end Suspend_Until_True;
1152
1153    ----------------
1154    -- Check_Exit --
1155    ----------------
1156
1157    --  Dummy versions.  The only currently working versions is for solaris
1158    --  (native).
1159
1160    function Check_Exit (Self_ID : ST.Task_Id) return Boolean is
1161       pragma Unreferenced (Self_ID);
1162    begin
1163       return True;
1164    end Check_Exit;
1165
1166    --------------------
1167    -- Check_No_Locks --
1168    --------------------
1169
1170    function Check_No_Locks (Self_ID : ST.Task_Id) return Boolean is
1171       pragma Unreferenced (Self_ID);
1172    begin
1173       return True;
1174    end Check_No_Locks;
1175
1176    ------------------
1177    -- Suspend_Task --
1178    ------------------
1179
1180    function Suspend_Task
1181      (T           : ST.Task_Id;
1182       Thread_Self : Thread_Id) return Boolean
1183    is
1184    begin
1185       if T.Common.LL.Thread /= Thread_Self then
1186          return SuspendThread (T.Common.LL.Thread) = NO_ERROR;
1187       else
1188          return True;
1189       end if;
1190    end Suspend_Task;
1191
1192    -----------------
1193    -- Resume_Task --
1194    -----------------
1195
1196    function Resume_Task
1197      (T           : ST.Task_Id;
1198       Thread_Self : Thread_Id) return Boolean
1199    is
1200    begin
1201       if T.Common.LL.Thread /= Thread_Self then
1202          return ResumeThread (T.Common.LL.Thread) = NO_ERROR;
1203       else
1204          return True;
1205       end if;
1206    end Resume_Task;
1207
1208 end System.Task_Primitives.Operations;