OSDN Git Service

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