OSDN Git Service

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