OSDN Git Service

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