OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [gcc/] [ada/] [s-taprop-solaris.adb] - Blame information for rev 12

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 12 jlechner
------------------------------------------------------------------------------
2
--                                                                          --
3
--                 GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS                 --
4
--                                                                          --
5
--     S Y S T E M . T A S K _ P R I M I T I V E S . O P E R A T I O N S    --
6
--                                                                          --
7
--                                  B o d y                                 --
8
--                                                                          --
9
--         Copyright (C) 1992-2005, Free Software Foundation, Inc.          --
10
--                                                                          --
11
-- GNARL is free software; you can  redistribute it  and/or modify it under --
12
-- terms of the  GNU General Public License as published  by the Free Soft- --
13
-- ware  Foundation;  either version 2,  or (at your option) any later ver- --
14
-- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
15
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16
-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17
-- for  more details.  You should have  received  a copy of the GNU General --
18
-- Public License  distributed with GNARL; see file COPYING.  If not, write --
19
-- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
20
-- Boston, MA 02110-1301, USA.                                              --
21
--                                                                          --
22
-- As a special exception,  if other files  instantiate  generics from this --
23
-- unit, or you link  this unit with other files  to produce an executable, --
24
-- this  unit  does not  by itself cause  the resulting  executable  to  be --
25
-- covered  by the  GNU  General  Public  License.  This exception does not --
26
-- however invalidate  any other reasons why  the executable file  might be --
27
-- covered by the  GNU Public License.                                      --
28
--                                                                          --
29
-- GNARL was developed by the GNARL team at Florida State University.       --
30
-- Extensive contributions were provided by Ada Core Technologies, Inc.     --
31
--                                                                          --
32
------------------------------------------------------------------------------
33
 
34
--  This is a Solaris (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.Interrupt_Management;
47
--  used for Keep_Unmasked
48
--           Abort_Task_Interrupt
49
--           Interrupt_ID
50
 
51
with System.OS_Primitives;
52
--  used for Delay_Modes
53
 
54
pragma Warnings (Off);
55
with GNAT.OS_Lib;
56
--  used for String_Access, Getenv
57
 
58
pragma Warnings (On);
59
 
60
with Interfaces.C;
61
--  used for int
62
--           size_t
63
 
64
with System.Parameters;
65
--  used for Size_Type
66
 
67
with System.Task_Info;
68
--  to initialize Task_Info for a C thread, in function Self
69
 
70
with Unchecked_Deallocation;
71
 
72
package body System.Task_Primitives.Operations is
73
 
74
   use System.Tasking.Debug;
75
   use System.Tasking;
76
   use Interfaces.C;
77
   use System.OS_Interface;
78
   use System.Parameters;
79
   use System.OS_Primitives;
80
 
81
   ----------------
82
   -- Local Data --
83
   ----------------
84
 
85
   --  The following are logically constants, but need to be initialized
86
   --  at run time.
87
 
88
   Environment_Task_Id : Task_Id;
89
   --  A variable to hold Task_Id for the environment task.
90
   --  If we use this variable to get the Task_Id, we need the following
91
   --  ATCB_Key only for non-Ada threads.
92
 
93
   Unblocked_Signal_Mask : aliased sigset_t;
94
   --  The set of signals that should unblocked in all tasks
95
 
96
   ATCB_Key : aliased thread_key_t;
97
   --  Key used to find the Ada Task_Id associated with a thread,
98
   --  at least for C threads unknown to the Ada run-time system.
99
 
100
   Single_RTS_Lock : aliased RTS_Lock;
101
   --  This is a lock to allow only one thread of control in the RTS at
102
   --  a time; it is used to execute in mutual exclusion from all other tasks.
103
   --  Used mainly in Single_Lock mode, but also to protect All_Tasks_List
104
 
105
   Next_Serial_Number : Task_Serial_Number := 100;
106
   --  We start at 100, to reserve some special values for
107
   --  using in error checking.
108
   --  The following are internal configuration constants needed.
109
 
110
   ----------------------
111
   -- Priority Support --
112
   ----------------------
113
 
114
   Priority_Ceiling_Emulation : constant Boolean := True;
115
   --  controls whether we emulate priority ceiling locking
116
 
117
   --  To get a scheduling close to annex D requirements, we use the real-time
118
   --  class provided for LWP's and map each task/thread to a specific and
119
   --  unique LWP (there is 1 thread per LWP, and 1 LWP per thread).
120
 
121
   --  The real time class can only be set when the process has root
122
   --  priviledges, so in the other cases, we use the normal thread scheduling
123
   --  and priority handling.
124
 
125
   Using_Real_Time_Class : Boolean := False;
126
   --  indicates wether the real time class is being used (i.e the process
127
   --  has root priviledges).
128
 
129
   Prio_Param : aliased struct_pcparms;
130
   --  Hold priority info (Real_Time) initialized during the package
131
   --  elaboration.
132
 
133
   -----------------------------------
134
   -- External Configuration Values --
135
   -----------------------------------
136
 
137
   Time_Slice_Val : Interfaces.C.long;
138
   pragma Import (C, Time_Slice_Val, "__gl_time_slice_val");
139
 
140
   Locking_Policy : Character;
141
   pragma Import (C, Locking_Policy, "__gl_locking_policy");
142
 
143
   Dispatching_Policy : Character;
144
   pragma Import (C, Dispatching_Policy, "__gl_task_dispatching_policy");
145
 
146
   Foreign_Task_Elaborated : aliased Boolean := True;
147
   --  Used to identified fake tasks (i.e., non-Ada Threads).
148
 
149
   -----------------------
150
   -- Local Subprograms --
151
   -----------------------
152
 
153
   function sysconf (name : System.OS_Interface.int) return processorid_t;
154
   pragma Import (C, sysconf, "sysconf");
155
 
156
   SC_NPROCESSORS_CONF : constant System.OS_Interface.int := 14;
157
 
158
   function Num_Procs
159
     (name : System.OS_Interface.int := SC_NPROCESSORS_CONF)
160
      return processorid_t renames sysconf;
161
 
162
   procedure Abort_Handler
163
     (Sig     : Signal;
164
      Code    : access siginfo_t;
165
      Context : access ucontext_t);
166
   --  Target-dependent binding of inter-thread Abort signal to
167
   --  the raising of the Abort_Signal exception.
168
   --  See also comments in 7staprop.adb
169
 
170
   ------------
171
   -- Checks --
172
   ------------
173
 
174
   function Check_Initialize_Lock
175
     (L     : Lock_Ptr;
176
      Level : Lock_Level) return Boolean;
177
   pragma Inline (Check_Initialize_Lock);
178
 
179
   function Check_Lock (L : Lock_Ptr) return Boolean;
180
   pragma Inline (Check_Lock);
181
 
182
   function Record_Lock (L : Lock_Ptr) return Boolean;
183
   pragma Inline (Record_Lock);
184
 
185
   function Check_Sleep (Reason : Task_States) return Boolean;
186
   pragma Inline (Check_Sleep);
187
 
188
   function Record_Wakeup
189
     (L      : Lock_Ptr;
190
      Reason : Task_States) return Boolean;
191
   pragma Inline (Record_Wakeup);
192
 
193
   function Check_Wakeup
194
     (T      : Task_Id;
195
      Reason : Task_States) return Boolean;
196
   pragma Inline (Check_Wakeup);
197
 
198
   function Check_Unlock (L : Lock_Ptr) return Boolean;
199
   pragma Inline (Check_Unlock);
200
 
201
   function Check_Finalize_Lock (L : Lock_Ptr) return Boolean;
202
   pragma Inline (Check_Finalize_Lock);
203
 
204
   --------------------
205
   -- Local Packages --
206
   --------------------
207
 
208
   package Specific is
209
 
210
      procedure Initialize (Environment_Task : Task_Id);
211
      pragma Inline (Initialize);
212
      --  Initialize various data needed by this package.
213
 
214
      function Is_Valid_Task return Boolean;
215
      pragma Inline (Is_Valid_Task);
216
      --  Does executing thread have a TCB?
217
 
218
      procedure Set (Self_Id : Task_Id);
219
      pragma Inline (Set);
220
      --  Set the self id for the current task.
221
 
222
      function Self return Task_Id;
223
      pragma Inline (Self);
224
      --  Return a pointer to the Ada Task Control Block of the calling task.
225
 
226
   end Specific;
227
 
228
   package body Specific is separate;
229
   --  The body of this package is target specific.
230
 
231
   ---------------------------------
232
   -- Support for foreign threads --
233
   ---------------------------------
234
 
235
   function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
236
   --  Allocate and Initialize a new ATCB for the current Thread.
237
 
238
   function Register_Foreign_Thread
239
     (Thread : Thread_Id) return Task_Id is separate;
240
 
241
   ------------
242
   -- Checks --
243
   ------------
244
 
245
   Check_Count  : Integer := 0;
246
   Lock_Count   : Integer := 0;
247
   Unlock_Count : Integer := 0;
248
 
249
   -------------------
250
   -- Abort_Handler --
251
   -------------------
252
 
253
   procedure Abort_Handler
254
     (Sig     : Signal;
255
      Code    : access siginfo_t;
256
      Context : access ucontext_t)
257
   is
258
      pragma Unreferenced (Sig);
259
      pragma Unreferenced (Code);
260
      pragma Unreferenced (Context);
261
 
262
      Self_ID : constant Task_Id := Self;
263
      Old_Set : aliased sigset_t;
264
 
265
      Result : Interfaces.C.int;
266
 
267
   begin
268
      --  It is not safe to raise an exception when using ZCX and the GCC
269
      --  exception handling mechanism.
270
 
271
      if ZCX_By_Default and then GCC_ZCX_Support then
272
         return;
273
      end if;
274
 
275
      if Self_ID.Deferral_Level = 0
276
        and then Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
277
        and then not Self_ID.Aborting
278
      then
279
         Self_ID.Aborting := True;
280
 
281
         --  Make sure signals used for RTS internal purpose are unmasked
282
 
283
         Result := thr_sigsetmask (SIG_UNBLOCK,
284
           Unblocked_Signal_Mask'Unchecked_Access, Old_Set'Unchecked_Access);
285
         pragma Assert (Result = 0);
286
 
287
         raise Standard'Abort_Signal;
288
      end if;
289
   end Abort_Handler;
290
 
291
   -----------------
292
   -- Stack_Guard --
293
   -----------------
294
 
295
   --  The underlying thread system sets a guard page at the
296
   --  bottom of a thread stack, so nothing is needed.
297
 
298
   procedure Stack_Guard (T : ST.Task_Id; On : Boolean) is
299
      pragma Unreferenced (T);
300
      pragma Unreferenced (On);
301
   begin
302
      null;
303
   end Stack_Guard;
304
 
305
   -------------------
306
   -- Get_Thread_Id --
307
   -------------------
308
 
309
   function Get_Thread_Id (T : ST.Task_Id) return OSI.Thread_Id is
310
   begin
311
      return T.Common.LL.Thread;
312
   end Get_Thread_Id;
313
 
314
   ----------------
315
   -- Initialize --
316
   ----------------
317
 
318
   procedure Initialize (Environment_Task : ST.Task_Id) is
319
      act     : aliased struct_sigaction;
320
      old_act : aliased struct_sigaction;
321
      Tmp_Set : aliased sigset_t;
322
      Result  : Interfaces.C.int;
323
 
324
      procedure Configure_Processors;
325
      --  Processors configuration
326
      --  The user can specify a processor which the program should run
327
      --  on to emulate a single-processor system. This can be easily
328
      --  done by setting environment variable GNAT_PROCESSOR to one of
329
      --  the following :
330
      --
331
      --    -2 : use the default configuration (run the program on all
332
      --         available processors) - this is the same as having
333
      --         GNAT_PROCESSOR unset
334
      --    -1 : let the RTS choose one processor and run the program on
335
      --         that processor
336
      --    0 .. Last_Proc : run the program on the specified processor
337
      --
338
      --  Last_Proc is equal to the value of the system variable
339
      --  _SC_NPROCESSORS_CONF, minus one.
340
 
341
      procedure Configure_Processors is
342
         Proc_Acc  : constant GNAT.OS_Lib.String_Access :=
343
                       GNAT.OS_Lib.Getenv ("GNAT_PROCESSOR");
344
         Proc      : aliased processorid_t;  --  User processor #
345
         Last_Proc : processorid_t;          --  Last processor #
346
 
347
      begin
348
         if Proc_Acc.all'Length /= 0 then
349
            --  Environment variable is defined
350
 
351
            Last_Proc := Num_Procs - 1;
352
 
353
            if Last_Proc /= -1 then
354
               Proc := processorid_t'Value (Proc_Acc.all);
355
 
356
               if Proc <= -2  or else Proc > Last_Proc then
357
                  --  Use the default configuration
358
                  null;
359
               elsif Proc = -1 then
360
                  --  Choose a processor
361
 
362
                  Result := 0;
363
 
364
                  while Proc < Last_Proc loop
365
                     Proc := Proc + 1;
366
                     Result := p_online (Proc, PR_STATUS);
367
                     exit when Result = PR_ONLINE;
368
                  end loop;
369
 
370
                  pragma Assert (Result = PR_ONLINE);
371
                  Result := processor_bind (P_PID, P_MYID, Proc, null);
372
                  pragma Assert (Result = 0);
373
 
374
               else
375
                  --  Use user processor
376
 
377
                  Result := processor_bind (P_PID, P_MYID, Proc, null);
378
                  pragma Assert (Result = 0);
379
               end if;
380
            end if;
381
         end if;
382
 
383
      exception
384
         when Constraint_Error =>
385
 
386
            --  Illegal environment variable GNAT_PROCESSOR - ignored
387
 
388
            null;
389
      end Configure_Processors;
390
 
391
      function State
392
        (Int : System.Interrupt_Management.Interrupt_ID) return Character;
393
      pragma Import (C, State, "__gnat_get_interrupt_state");
394
      --  Get interrupt state.  Defined in a-init.c
395
      --  The input argument is the interrupt number,
396
      --  and the result is one of the following:
397
 
398
      Default : constant Character := 's';
399
      --    'n'   this interrupt not set by any Interrupt_State pragma
400
      --    'u'   Interrupt_State pragma set state to User
401
      --    'r'   Interrupt_State pragma set state to Runtime
402
      --    's'   Interrupt_State pragma set state to System (use "default"
403
      --           system handler)
404
 
405
   --  Start of processing for Initialize
406
 
407
   begin
408
      Environment_Task_Id := Environment_Task;
409
 
410
      Interrupt_Management.Initialize;
411
 
412
      --  Prepare the set of signals that should unblocked in all tasks
413
 
414
      Result := sigemptyset (Unblocked_Signal_Mask'Access);
415
      pragma Assert (Result = 0);
416
 
417
      for J in Interrupt_Management.Interrupt_ID loop
418
         if System.Interrupt_Management.Keep_Unmasked (J) then
419
            Result := sigaddset (Unblocked_Signal_Mask'Access, Signal (J));
420
            pragma Assert (Result = 0);
421
         end if;
422
      end loop;
423
 
424
      if Dispatching_Policy = 'F' then
425
         declare
426
            Result      : Interfaces.C.long;
427
            Class_Info  : aliased struct_pcinfo;
428
            Secs, Nsecs : Interfaces.C.long;
429
 
430
         begin
431
            --  If a pragma Time_Slice is specified, takes the value in account
432
 
433
            if Time_Slice_Val > 0 then
434
               --  Convert Time_Slice_Val (microseconds) into seconds and
435
               --  nanoseconds
436
 
437
               Secs := Time_Slice_Val / 1_000_000;
438
               Nsecs := (Time_Slice_Val rem 1_000_000) * 1_000;
439
 
440
            --  Otherwise, default to no time slicing (i.e run until blocked)
441
 
442
            else
443
               Secs := RT_TQINF;
444
               Nsecs := RT_TQINF;
445
            end if;
446
 
447
            --  Get the real time class id.
448
 
449
            Class_Info.pc_clname (1) := 'R';
450
            Class_Info.pc_clname (2) := 'T';
451
            Class_Info.pc_clname (3) := ASCII.NUL;
452
 
453
            Result := priocntl (PC_VERSION, P_LWPID, P_MYID, PC_GETCID,
454
              Class_Info'Address);
455
 
456
            --  Request the real time class
457
 
458
            Prio_Param.pc_cid := Class_Info.pc_cid;
459
            Prio_Param.rt_pri := pri_t (Class_Info.rt_maxpri);
460
            Prio_Param.rt_tqsecs := Secs;
461
            Prio_Param.rt_tqnsecs := Nsecs;
462
 
463
            Result := priocntl (PC_VERSION, P_LWPID, P_MYID, PC_SETPARMS,
464
              Prio_Param'Address);
465
 
466
            Using_Real_Time_Class := Result /= -1;
467
         end;
468
      end if;
469
 
470
      Specific.Initialize (Environment_Task);
471
 
472
      --  The following is done in Enter_Task, but this is too late for the
473
      --  Environment Task, since we need to call Self in Check_Locks when
474
      --  the run time is compiled with assertions on.
475
 
476
      Specific.Set (Environment_Task);
477
 
478
      --  Initialize the lock used to synchronize chain of all ATCBs.
479
 
480
      Initialize_Lock (Single_RTS_Lock'Access, RTS_Lock_Level);
481
 
482
      Enter_Task (Environment_Task);
483
 
484
      --  Install the abort-signal handler
485
 
486
      if State (System.Interrupt_Management.Abort_Task_Interrupt)
487
        /= Default
488
      then
489
         --  Set sa_flags to SA_NODEFER so that during the handler execution
490
         --  we do not change the Signal_Mask to be masked for the Abort_Signal
491
         --  This is a temporary fix to the problem that the Signal_Mask is
492
         --  not restored after the exception (longjmp) from the handler.
493
         --  The right fix should be made in sigsetjmp so that we save
494
         --  the Signal_Set and restore it after a longjmp.
495
         --  In that case, this field should be changed back to 0. ???
496
 
497
         act.sa_flags := 16;
498
 
499
         act.sa_handler := Abort_Handler'Address;
500
         Result := sigemptyset (Tmp_Set'Access);
501
         pragma Assert (Result = 0);
502
         act.sa_mask := Tmp_Set;
503
 
504
         Result :=
505
           sigaction (
506
             Signal (System.Interrupt_Management.Abort_Task_Interrupt),
507
             act'Unchecked_Access,
508
             old_act'Unchecked_Access);
509
         pragma Assert (Result = 0);
510
      end if;
511
 
512
      Configure_Processors;
513
   end Initialize;
514
 
515
   ---------------------
516
   -- Initialize_Lock --
517
   ---------------------
518
 
519
   --  Note: mutexes and cond_variables needed per-task basis are
520
   --        initialized in Initialize_TCB and the Storage_Error is
521
   --        handled. Other mutexes (such as RTS_Lock, Memory_Lock...)
522
   --        used in RTS is initialized before any status change of RTS.
523
   --        Therefore rasing Storage_Error in the following routines
524
   --        should be able to be handled safely.
525
 
526
   procedure Initialize_Lock
527
     (Prio : System.Any_Priority;
528
      L    : access Lock)
529
   is
530
      Result : Interfaces.C.int;
531
 
532
   begin
533
      pragma Assert (Check_Initialize_Lock (Lock_Ptr (L), PO_Level));
534
 
535
      if Priority_Ceiling_Emulation then
536
         L.Ceiling := Prio;
537
      end if;
538
 
539
      Result := mutex_init (L.L'Access, USYNC_THREAD, System.Null_Address);
540
      pragma Assert (Result = 0 or else Result = ENOMEM);
541
 
542
      if Result = ENOMEM then
543
         raise Storage_Error with "Failed to allocate a lock";
544
      end if;
545
   end Initialize_Lock;
546
 
547
   procedure Initialize_Lock
548
     (L     : access RTS_Lock;
549
      Level : Lock_Level)
550
   is
551
      Result : Interfaces.C.int;
552
 
553
   begin
554
      pragma Assert (Check_Initialize_Lock
555
        (To_Lock_Ptr (RTS_Lock_Ptr (L)), Level));
556
      Result := mutex_init (L.L'Access, USYNC_THREAD, System.Null_Address);
557
      pragma Assert (Result = 0 or else Result = ENOMEM);
558
 
559
      if Result = ENOMEM then
560
         raise Storage_Error with "Failed to allocate a lock";
561
      end if;
562
   end Initialize_Lock;
563
 
564
   -------------------
565
   -- Finalize_Lock --
566
   -------------------
567
 
568
   procedure Finalize_Lock (L : access Lock) is
569
      Result : Interfaces.C.int;
570
 
571
   begin
572
      pragma Assert (Check_Finalize_Lock (Lock_Ptr (L)));
573
      Result := mutex_destroy (L.L'Access);
574
      pragma Assert (Result = 0);
575
   end Finalize_Lock;
576
 
577
   procedure Finalize_Lock (L : access RTS_Lock) is
578
      Result : Interfaces.C.int;
579
 
580
   begin
581
      pragma Assert (Check_Finalize_Lock (To_Lock_Ptr (RTS_Lock_Ptr (L))));
582
      Result := mutex_destroy (L.L'Access);
583
      pragma Assert (Result = 0);
584
   end Finalize_Lock;
585
 
586
   ----------------
587
   -- Write_Lock --
588
   ----------------
589
 
590
   procedure Write_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
591
      Result : Interfaces.C.int;
592
 
593
   begin
594
      pragma Assert (Check_Lock (Lock_Ptr (L)));
595
 
596
      if Priority_Ceiling_Emulation and then Locking_Policy = 'C' then
597
         declare
598
            Self_Id        : constant Task_Id := Self;
599
            Saved_Priority : System.Any_Priority;
600
 
601
         begin
602
            if Self_Id.Common.LL.Active_Priority > L.Ceiling then
603
               Ceiling_Violation := True;
604
               return;
605
            end if;
606
 
607
            Saved_Priority := Self_Id.Common.LL.Active_Priority;
608
 
609
            if Self_Id.Common.LL.Active_Priority < L.Ceiling then
610
               Set_Priority (Self_Id, L.Ceiling);
611
            end if;
612
 
613
            Result := mutex_lock (L.L'Access);
614
            pragma Assert (Result = 0);
615
            Ceiling_Violation := False;
616
 
617
            L.Saved_Priority := Saved_Priority;
618
         end;
619
 
620
      else
621
         Result := mutex_lock (L.L'Access);
622
         pragma Assert (Result = 0);
623
         Ceiling_Violation := False;
624
      end if;
625
 
626
      pragma Assert (Record_Lock (Lock_Ptr (L)));
627
   end Write_Lock;
628
 
629
   procedure Write_Lock
630
     (L          : access RTS_Lock;
631
     Global_Lock : Boolean := False)
632
   is
633
      Result : Interfaces.C.int;
634
 
635
   begin
636
      if not Single_Lock or else Global_Lock then
637
         pragma Assert (Check_Lock (To_Lock_Ptr (RTS_Lock_Ptr (L))));
638
         Result := mutex_lock (L.L'Access);
639
         pragma Assert (Result = 0);
640
         pragma Assert (Record_Lock (To_Lock_Ptr (RTS_Lock_Ptr (L))));
641
      end if;
642
   end Write_Lock;
643
 
644
   procedure Write_Lock (T : Task_Id) is
645
      Result : Interfaces.C.int;
646
 
647
   begin
648
      if not Single_Lock then
649
         pragma Assert (Check_Lock (To_Lock_Ptr (T.Common.LL.L'Access)));
650
         Result := mutex_lock (T.Common.LL.L.L'Access);
651
         pragma Assert (Result = 0);
652
         pragma Assert (Record_Lock (To_Lock_Ptr (T.Common.LL.L'Access)));
653
      end if;
654
   end Write_Lock;
655
 
656
   ---------------
657
   -- Read_Lock --
658
   ---------------
659
 
660
   procedure Read_Lock (L : access Lock; Ceiling_Violation : out Boolean) is
661
   begin
662
      Write_Lock (L, Ceiling_Violation);
663
   end Read_Lock;
664
 
665
   ------------
666
   -- Unlock --
667
   ------------
668
 
669
   procedure Unlock (L : access Lock) is
670
      Result  : Interfaces.C.int;
671
 
672
   begin
673
      pragma Assert (Check_Unlock (Lock_Ptr (L)));
674
 
675
      if Priority_Ceiling_Emulation and then Locking_Policy = 'C' then
676
         declare
677
            Self_Id : constant Task_Id := Self;
678
 
679
         begin
680
            Result := mutex_unlock (L.L'Access);
681
            pragma Assert (Result = 0);
682
 
683
            if Self_Id.Common.LL.Active_Priority > L.Saved_Priority then
684
               Set_Priority (Self_Id, L.Saved_Priority);
685
            end if;
686
         end;
687
      else
688
         Result := mutex_unlock (L.L'Access);
689
         pragma Assert (Result = 0);
690
      end if;
691
   end Unlock;
692
 
693
   procedure Unlock (L : access RTS_Lock; Global_Lock : Boolean := False) is
694
      Result : Interfaces.C.int;
695
 
696
   begin
697
      if not Single_Lock or else Global_Lock then
698
         pragma Assert (Check_Unlock (To_Lock_Ptr (RTS_Lock_Ptr (L))));
699
         Result := mutex_unlock (L.L'Access);
700
         pragma Assert (Result = 0);
701
      end if;
702
   end Unlock;
703
 
704
   procedure Unlock (T : Task_Id) is
705
      Result : Interfaces.C.int;
706
 
707
   begin
708
      if not Single_Lock then
709
         pragma Assert (Check_Unlock (To_Lock_Ptr (T.Common.LL.L'Access)));
710
         Result := mutex_unlock (T.Common.LL.L.L'Access);
711
         pragma Assert (Result = 0);
712
      end if;
713
   end Unlock;
714
 
715
   --  For the time delay implementation, we need to make sure we
716
   --  achieve following criteria:
717
 
718
   --  1) We have to delay at least for the amount requested.
719
   --  2) We have to give up CPU even though the actual delay does not
720
   --     result in blocking.
721
   --  3) Except for restricted run-time systems that do not support
722
   --     ATC or task abort, the delay must be interrupted by the
723
   --     abort_task operation.
724
   --  4) The implementation has to be efficient so that the delay overhead
725
   --     is relatively cheap.
726
   --  (1)-(3) are Ada requirements. Even though (2) is an Annex-D
727
   --     requirement we still want to provide the effect in all cases.
728
   --     The reason is that users may want to use short delays to implement
729
   --     their own scheduling effect in the absence of language provided
730
   --     scheduling policies.
731
 
732
   ---------------------
733
   -- Monotonic_Clock --
734
   ---------------------
735
 
736
   function Monotonic_Clock return Duration is
737
      TS     : aliased timespec;
738
      Result : Interfaces.C.int;
739
   begin
740
      Result := clock_gettime (CLOCK_REALTIME, TS'Unchecked_Access);
741
      pragma Assert (Result = 0);
742
      return To_Duration (TS);
743
   end Monotonic_Clock;
744
 
745
   -------------------
746
   -- RT_Resolution --
747
   -------------------
748
 
749
   function RT_Resolution return Duration is
750
   begin
751
      return 10#1.0#E-6;
752
   end RT_Resolution;
753
 
754
   -----------
755
   -- Yield --
756
   -----------
757
 
758
   procedure Yield (Do_Yield : Boolean := True) is
759
   begin
760
      if Do_Yield then
761
         System.OS_Interface.thr_yield;
762
      end if;
763
   end Yield;
764
 
765
   -----------
766
   -- Self ---
767
   -----------
768
 
769
   function Self return Task_Id renames Specific.Self;
770
 
771
   ------------------
772
   -- Set_Priority --
773
   ------------------
774
 
775
   procedure Set_Priority
776
     (T                   : Task_Id;
777
      Prio                : System.Any_Priority;
778
      Loss_Of_Inheritance : Boolean := False)
779
   is
780
      pragma Unreferenced (Loss_Of_Inheritance);
781
 
782
      Result : Interfaces.C.int;
783
      pragma Unreferenced (Result);
784
 
785
      Param   : aliased struct_pcparms;
786
 
787
      use Task_Info;
788
 
789
   begin
790
      T.Common.Current_Priority := Prio;
791
 
792
      if Priority_Ceiling_Emulation then
793
         T.Common.LL.Active_Priority := Prio;
794
      end if;
795
 
796
      if Using_Real_Time_Class then
797
         Param.pc_cid := Prio_Param.pc_cid;
798
         Param.rt_pri := pri_t (Prio);
799
         Param.rt_tqsecs := Prio_Param.rt_tqsecs;
800
         Param.rt_tqnsecs := Prio_Param.rt_tqnsecs;
801
 
802
         Result := Interfaces.C.int (
803
           priocntl (PC_VERSION, P_LWPID, T.Common.LL.LWP, PC_SETPARMS,
804
             Param'Address));
805
 
806
      else
807
         if T.Common.Task_Info /= null
808
           and then not T.Common.Task_Info.Bound_To_LWP
809
         then
810
            --  The task is not bound to a LWP, so use thr_setprio
811
 
812
            Result :=
813
              thr_setprio (T.Common.LL.Thread, Interfaces.C.int (Prio));
814
 
815
         else
816
 
817
            --  The task is bound to a LWP, use priocntl
818
            --  ??? TBD
819
 
820
            null;
821
         end if;
822
      end if;
823
   end Set_Priority;
824
 
825
   ------------------
826
   -- Get_Priority --
827
   ------------------
828
 
829
   function Get_Priority (T : Task_Id) return System.Any_Priority is
830
   begin
831
      return T.Common.Current_Priority;
832
   end Get_Priority;
833
 
834
   ----------------
835
   -- Enter_Task --
836
   ----------------
837
 
838
   procedure Enter_Task (Self_ID : Task_Id) is
839
      Result    : Interfaces.C.int;
840
      Proc      : processorid_t;  --  User processor #
841
      Last_Proc : processorid_t;  --  Last processor #
842
 
843
      use System.Task_Info;
844
   begin
845
      Self_ID.Common.LL.Thread := thr_self;
846
 
847
      Self_ID.Common.LL.LWP := lwp_self;
848
 
849
      if Self_ID.Common.Task_Info /= null then
850
         if Self_ID.Common.Task_Info.New_LWP
851
           and then Self_ID.Common.Task_Info.CPU /= CPU_UNCHANGED
852
         then
853
            Last_Proc := Num_Procs - 1;
854
 
855
            if Self_ID.Common.Task_Info.CPU = ANY_CPU then
856
               Result := 0;
857
               Proc := 0;
858
 
859
               while Proc < Last_Proc loop
860
                  Result := p_online (Proc, PR_STATUS);
861
                  exit when Result = PR_ONLINE;
862
                  Proc := Proc + 1;
863
               end loop;
864
 
865
               Result := processor_bind (P_LWPID, P_MYID, Proc, null);
866
               pragma Assert (Result = 0);
867
 
868
            else
869
               --  Use specified processor
870
 
871
               if Self_ID.Common.Task_Info.CPU < 0
872
                 or else Self_ID.Common.Task_Info.CPU > Last_Proc
873
               then
874
                  raise Invalid_CPU_Number;
875
               end if;
876
 
877
               Result := processor_bind
878
                 (P_LWPID, P_MYID, Self_ID.Common.Task_Info.CPU, null);
879
               pragma Assert (Result = 0);
880
            end if;
881
         end if;
882
      end if;
883
 
884
      Specific.Set (Self_ID);
885
 
886
      --  We need the above code even if we do direct fetch of Task_Id in Self
887
      --  for the main task on Sun, x86 Solaris and for gcc 2.7.2.
888
 
889
      Lock_RTS;
890
 
891
      for J in Known_Tasks'Range loop
892
         if Known_Tasks (J) = null then
893
            Known_Tasks (J) := Self_ID;
894
            Self_ID.Known_Tasks_Index := J;
895
            exit;
896
         end if;
897
      end loop;
898
 
899
      Unlock_RTS;
900
   end Enter_Task;
901
 
902
   --------------
903
   -- New_ATCB --
904
   --------------
905
 
906
   function New_ATCB (Entry_Num : Task_Entry_Index) return Task_Id is
907
   begin
908
      return new Ada_Task_Control_Block (Entry_Num);
909
   end New_ATCB;
910
 
911
   -------------------
912
   -- Is_Valid_Task --
913
   -------------------
914
 
915
   function Is_Valid_Task return Boolean renames Specific.Is_Valid_Task;
916
 
917
   -----------------------------
918
   -- Register_Foreign_Thread --
919
   -----------------------------
920
 
921
   function Register_Foreign_Thread return Task_Id is
922
   begin
923
      if Is_Valid_Task then
924
         return Self;
925
      else
926
         return Register_Foreign_Thread (thr_self);
927
      end if;
928
   end Register_Foreign_Thread;
929
 
930
   --------------------
931
   -- Initialize_TCB --
932
   --------------------
933
 
934
   procedure Initialize_TCB (Self_ID : Task_Id; Succeeded : out Boolean) is
935
      Result : Interfaces.C.int := 0;
936
 
937
   begin
938
      --  Give the task a unique serial number.
939
 
940
      Self_ID.Serial_Number := Next_Serial_Number;
941
      Next_Serial_Number := Next_Serial_Number + 1;
942
      pragma Assert (Next_Serial_Number /= 0);
943
 
944
      Self_ID.Common.LL.Thread := To_thread_t (-1);
945
 
946
      if not Single_Lock then
947
         Result := mutex_init
948
           (Self_ID.Common.LL.L.L'Access, USYNC_THREAD, System.Null_Address);
949
         Self_ID.Common.LL.L.Level :=
950
           Private_Task_Serial_Number (Self_ID.Serial_Number);
951
         pragma Assert (Result = 0 or else Result = ENOMEM);
952
      end if;
953
 
954
      if Result = 0 then
955
         Result := cond_init (Self_ID.Common.LL.CV'Access, USYNC_THREAD, 0);
956
         pragma Assert (Result = 0 or else Result = ENOMEM);
957
      end if;
958
 
959
      if Result = 0 then
960
         Succeeded := True;
961
      else
962
         if not Single_Lock then
963
            Result := mutex_destroy (Self_ID.Common.LL.L.L'Access);
964
            pragma Assert (Result = 0);
965
         end if;
966
 
967
         Succeeded := False;
968
      end if;
969
   end Initialize_TCB;
970
 
971
   -----------------
972
   -- Create_Task --
973
   -----------------
974
 
975
   procedure Create_Task
976
     (T          : Task_Id;
977
      Wrapper    : System.Address;
978
      Stack_Size : System.Parameters.Size_Type;
979
      Priority   : System.Any_Priority;
980
      Succeeded  : out Boolean)
981
   is
982
      pragma Unreferenced (Priority);
983
 
984
      Result     : Interfaces.C.int;
985
      Adjusted_Stack_Size : Interfaces.C.size_t;
986
      Opts       : Interfaces.C.int := THR_DETACHED;
987
 
988
      Page_Size  : constant System.Parameters.Size_Type := 4096;
989
      --  This constant is for reserving extra space at the
990
      --  end of the stack, which can be used by the stack
991
      --  checking as guard page. The idea is that we need
992
      --  to have at least Stack_Size bytes available for
993
      --  actual use.
994
 
995
      use System.Task_Info;
996
 
997
   begin
998
      if Stack_Size = System.Parameters.Unspecified_Size then
999
         Adjusted_Stack_Size :=
1000
           Interfaces.C.size_t (Default_Stack_Size + Page_Size);
1001
 
1002
      elsif Stack_Size < Minimum_Stack_Size then
1003
         Adjusted_Stack_Size :=
1004
           Interfaces.C.size_t (Minimum_Stack_Size + Page_Size);
1005
 
1006
      else
1007
         Adjusted_Stack_Size :=
1008
           Interfaces.C.size_t (Stack_Size + Page_Size);
1009
      end if;
1010
 
1011
      --  Since the initial signal mask of a thread is inherited from the
1012
      --  creator, and the Environment task has all its signals masked, we
1013
      --  do not need to manipulate caller's signal mask at this point.
1014
      --  All tasks in RTS will have All_Tasks_Mask initially.
1015
 
1016
      if T.Common.Task_Info /= null then
1017
         if T.Common.Task_Info.New_LWP then
1018
            Opts := Opts + THR_NEW_LWP;
1019
         end if;
1020
 
1021
         if T.Common.Task_Info.Bound_To_LWP then
1022
            Opts := Opts + THR_BOUND;
1023
         end if;
1024
 
1025
      else
1026
         Opts := THR_DETACHED + THR_BOUND;
1027
      end if;
1028
 
1029
      Result := thr_create
1030
        (System.Null_Address,
1031
         Adjusted_Stack_Size,
1032
         Thread_Body_Access (Wrapper),
1033
         To_Address (T),
1034
         Opts,
1035
         T.Common.LL.Thread'Access);
1036
 
1037
      Succeeded := Result = 0;
1038
      pragma Assert
1039
        (Result = 0
1040
          or else Result = ENOMEM
1041
          or else Result = EAGAIN);
1042
   end Create_Task;
1043
 
1044
   ------------------
1045
   -- Finalize_TCB --
1046
   ------------------
1047
 
1048
   procedure Finalize_TCB (T : Task_Id) is
1049
      Result : Interfaces.C.int;
1050
      Tmp    : Task_Id := T;
1051
      Is_Self : constant Boolean := T = Self;
1052
 
1053
      procedure Free is new
1054
        Unchecked_Deallocation (Ada_Task_Control_Block, Task_Id);
1055
 
1056
   begin
1057
      T.Common.LL.Thread := To_thread_t (0);
1058
 
1059
      if not Single_Lock then
1060
         Result := mutex_destroy (T.Common.LL.L.L'Access);
1061
         pragma Assert (Result = 0);
1062
      end if;
1063
 
1064
      Result := cond_destroy (T.Common.LL.CV'Access);
1065
      pragma Assert (Result = 0);
1066
 
1067
      if T.Known_Tasks_Index /= -1 then
1068
         Known_Tasks (T.Known_Tasks_Index) := null;
1069
      end if;
1070
 
1071
      Free (Tmp);
1072
 
1073
      if Is_Self then
1074
         Specific.Set (null);
1075
      end if;
1076
   end Finalize_TCB;
1077
 
1078
   ---------------
1079
   -- Exit_Task --
1080
   ---------------
1081
 
1082
   --  This procedure must be called with abort deferred.
1083
   --  It can no longer call Self or access
1084
   --  the current task's ATCB, since the ATCB has been deallocated.
1085
 
1086
   procedure Exit_Task is
1087
   begin
1088
      Specific.Set (null);
1089
   end Exit_Task;
1090
 
1091
   ----------------
1092
   -- Abort_Task --
1093
   ----------------
1094
 
1095
   procedure Abort_Task (T : Task_Id) is
1096
      Result : Interfaces.C.int;
1097
   begin
1098
      pragma Assert (T /= Self);
1099
 
1100
      Result := thr_kill (T.Common.LL.Thread,
1101
        Signal (System.Interrupt_Management.Abort_Task_Interrupt));
1102
      pragma Assert (Result = 0);
1103
   end Abort_Task;
1104
 
1105
   -----------
1106
   -- Sleep --
1107
   -----------
1108
 
1109
   procedure Sleep
1110
     (Self_ID : Task_Id;
1111
      Reason  : Task_States)
1112
   is
1113
      Result : Interfaces.C.int;
1114
 
1115
   begin
1116
      pragma Assert (Check_Sleep (Reason));
1117
 
1118
      if Dynamic_Priority_Support
1119
        and then Self_ID.Pending_Priority_Change
1120
      then
1121
         Self_ID.Pending_Priority_Change := False;
1122
         Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
1123
         Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
1124
      end if;
1125
 
1126
      if Single_Lock then
1127
         Result := cond_wait
1128
           (Self_ID.Common.LL.CV'Access, Single_RTS_Lock.L'Access);
1129
      else
1130
         Result := cond_wait
1131
           (Self_ID.Common.LL.CV'Access, Self_ID.Common.LL.L.L'Access);
1132
      end if;
1133
 
1134
      pragma Assert (Record_Wakeup
1135
        (To_Lock_Ptr (Self_ID.Common.LL.L'Access), Reason));
1136
      pragma Assert (Result = 0 or else Result = EINTR);
1137
   end Sleep;
1138
 
1139
   --  Note that we are relying heaviliy here on the GNAT feature
1140
   --  that Calendar.Time, System.Real_Time.Time, Duration, and
1141
   --  System.Real_Time.Time_Span are all represented in the same
1142
   --  way, i.e., as a 64-bit count of nanoseconds.
1143
 
1144
   --  This allows us to always pass the timeout value as a Duration.
1145
 
1146
   --  ???
1147
   --  We are taking liberties here with the semantics of the delays.
1148
   --  That is, we make no distinction between delays on the Calendar clock
1149
   --  and delays on the Real_Time clock. That is technically incorrect, if
1150
   --  the Calendar clock happens to be reset or adjusted.
1151
   --  To solve this defect will require modification to the compiler
1152
   --  interface, so that it can pass through more information, to tell
1153
   --  us here which clock to use!
1154
 
1155
   --  cond_timedwait will return if any of the following happens:
1156
   --  1) some other task did cond_signal on this condition variable
1157
   --     In this case, the return value is 0
1158
   --  2) the call just returned, for no good reason
1159
   --     This is called a "spurious wakeup".
1160
   --     In this case, the return value may also be 0.
1161
   --  3) the time delay expires
1162
   --     In this case, the return value is ETIME
1163
   --  4) this task received a signal, which was handled by some
1164
   --     handler procedure, and now the thread is resuming execution
1165
   --     UNIX calls this an "interrupted" system call.
1166
   --     In this case, the return value is EINTR
1167
 
1168
   --  If the cond_timedwait returns 0 or EINTR, it is still
1169
   --  possible that the time has actually expired, and by chance
1170
   --  a signal or cond_signal occurred at around the same time.
1171
 
1172
   --  We have also observed that on some OS's the value ETIME
1173
   --  will be returned, but the clock will show that the full delay
1174
   --  has not yet expired.
1175
 
1176
   --  For these reasons, we need to check the clock after return
1177
   --  from cond_timedwait.  If the time has expired, we will set
1178
   --  Timedout = True.
1179
 
1180
   --  This check might be omitted for systems on which the
1181
   --  cond_timedwait() never returns early or wakes up spuriously.
1182
 
1183
   --  Annex D requires that completion of a delay cause the task
1184
   --  to go to the end of its priority queue, regardless of whether
1185
   --  the task actually was suspended by the delay. Since
1186
   --  cond_timedwait does not do this on Solaris, we add a call
1187
   --  to thr_yield at the end. We might do this at the beginning,
1188
   --  instead, but then the round-robin effect would not be the
1189
   --  same; the delayed task would be ahead of other tasks of the
1190
   --  same priority that awoke while it was sleeping.
1191
 
1192
   --  For Timed_Sleep, we are expecting possible cond_signals
1193
   --  to indicate other events (e.g., completion of a RV or
1194
   --  completion of the abortable part of an async. select),
1195
   --  we want to always return if interrupted. The caller will
1196
   --  be responsible for checking the task state to see whether
1197
   --  the wakeup was spurious, and to go back to sleep again
1198
   --  in that case.  We don't need to check for pending abort
1199
   --  or priority change on the way in our out; that is the
1200
   --  caller's responsibility.
1201
 
1202
   --  For Timed_Delay, we are not expecting any cond_signals or
1203
   --  other interruptions, except for priority changes and aborts.
1204
   --  Therefore, we don't want to return unless the delay has
1205
   --  actually expired, or the call has been aborted. In this
1206
   --  case, since we want to implement the entire delay statement
1207
   --  semantics, we do need to check for pending abort and priority
1208
   --  changes. We can quietly handle priority changes inside the
1209
   --  procedure, since there is no entry-queue reordering involved.
1210
 
1211
   -----------------
1212
   -- Timed_Sleep --
1213
   -----------------
1214
 
1215
   procedure Timed_Sleep
1216
     (Self_ID  : Task_Id;
1217
      Time     : Duration;
1218
      Mode     : ST.Delay_Modes;
1219
      Reason   : System.Tasking.Task_States;
1220
      Timedout : out Boolean;
1221
      Yielded  : out Boolean)
1222
   is
1223
      Check_Time : constant Duration := Monotonic_Clock;
1224
      Abs_Time   : Duration;
1225
      Request    : aliased timespec;
1226
      Result     : Interfaces.C.int;
1227
 
1228
   begin
1229
      pragma Assert (Check_Sleep (Reason));
1230
      Timedout := True;
1231
      Yielded := False;
1232
 
1233
      if Mode = Relative then
1234
         Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
1235
      else
1236
         Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
1237
      end if;
1238
 
1239
      if Abs_Time > Check_Time then
1240
         Request := To_Timespec (Abs_Time);
1241
 
1242
         loop
1243
            exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level
1244
              or else (Dynamic_Priority_Support and then
1245
                Self_ID.Pending_Priority_Change);
1246
 
1247
            if Single_Lock then
1248
               Result := cond_timedwait (Self_ID.Common.LL.CV'Access,
1249
                 Single_RTS_Lock.L'Access, Request'Access);
1250
            else
1251
               Result := cond_timedwait (Self_ID.Common.LL.CV'Access,
1252
                 Self_ID.Common.LL.L.L'Access, Request'Access);
1253
            end if;
1254
 
1255
            Yielded := True;
1256
 
1257
            exit when Abs_Time <= Monotonic_Clock;
1258
 
1259
            if Result = 0 or Result = EINTR then
1260
 
1261
               --  Somebody may have called Wakeup for us
1262
 
1263
               Timedout := False;
1264
               exit;
1265
            end if;
1266
 
1267
            pragma Assert (Result = ETIME);
1268
         end loop;
1269
      end if;
1270
 
1271
      pragma Assert (Record_Wakeup
1272
        (To_Lock_Ptr (Self_ID.Common.LL.L'Access), Reason));
1273
   end Timed_Sleep;
1274
 
1275
   -----------------
1276
   -- Timed_Delay --
1277
   -----------------
1278
 
1279
   procedure Timed_Delay
1280
     (Self_ID  : Task_Id;
1281
      Time     : Duration;
1282
      Mode     : ST.Delay_Modes)
1283
   is
1284
      Check_Time : constant Duration := Monotonic_Clock;
1285
      Abs_Time   : Duration;
1286
      Request    : aliased timespec;
1287
      Result     : Interfaces.C.int;
1288
      Yielded    : Boolean := False;
1289
 
1290
   begin
1291
      if Single_Lock then
1292
         Lock_RTS;
1293
      end if;
1294
 
1295
      Write_Lock (Self_ID);
1296
 
1297
      if Mode = Relative then
1298
         Abs_Time := Time + Check_Time;
1299
      else
1300
         Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
1301
      end if;
1302
 
1303
      if Abs_Time > Check_Time then
1304
         Request := To_Timespec (Abs_Time);
1305
         Self_ID.Common.State := Delay_Sleep;
1306
 
1307
         pragma Assert (Check_Sleep (Delay_Sleep));
1308
 
1309
         loop
1310
            if Dynamic_Priority_Support and then
1311
              Self_ID.Pending_Priority_Change then
1312
               Self_ID.Pending_Priority_Change := False;
1313
               Self_ID.Common.Base_Priority := Self_ID.New_Base_Priority;
1314
               Set_Priority (Self_ID, Self_ID.Common.Base_Priority);
1315
            end if;
1316
 
1317
            exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
1318
 
1319
            if Single_Lock then
1320
               Result := cond_timedwait (Self_ID.Common.LL.CV'Access,
1321
                 Single_RTS_Lock.L'Access, Request'Access);
1322
            else
1323
               Result := cond_timedwait (Self_ID.Common.LL.CV'Access,
1324
                 Self_ID.Common.LL.L.L'Access, Request'Access);
1325
            end if;
1326
 
1327
            Yielded := True;
1328
 
1329
            exit when Abs_Time <= Monotonic_Clock;
1330
 
1331
            pragma Assert (Result = 0 or else
1332
              Result = ETIME or else
1333
              Result = EINTR);
1334
         end loop;
1335
 
1336
         pragma Assert (Record_Wakeup
1337
           (To_Lock_Ptr (Self_ID.Common.LL.L'Access), Delay_Sleep));
1338
 
1339
         Self_ID.Common.State := Runnable;
1340
      end if;
1341
 
1342
      Unlock (Self_ID);
1343
 
1344
      if Single_Lock then
1345
         Unlock_RTS;
1346
      end if;
1347
 
1348
      if not Yielded then
1349
         thr_yield;
1350
      end if;
1351
   end Timed_Delay;
1352
 
1353
   ------------
1354
   -- Wakeup --
1355
   ------------
1356
 
1357
   procedure Wakeup
1358
     (T : Task_Id;
1359
      Reason : Task_States)
1360
   is
1361
      Result : Interfaces.C.int;
1362
 
1363
   begin
1364
      pragma Assert (Check_Wakeup (T, Reason));
1365
      Result := cond_signal (T.Common.LL.CV'Access);
1366
      pragma Assert (Result = 0);
1367
   end Wakeup;
1368
 
1369
   ---------------------------
1370
   -- Check_Initialize_Lock --
1371
   ---------------------------
1372
 
1373
   --  The following code is intended to check some of the invariant
1374
   --  assertions related to lock usage, on which we depend.
1375
 
1376
   function Check_Initialize_Lock
1377
     (L     : Lock_Ptr;
1378
      Level : Lock_Level) return Boolean
1379
   is
1380
      Self_ID : constant Task_Id := Self;
1381
 
1382
   begin
1383
      --  Check that caller is abort-deferred
1384
 
1385
      if Self_ID.Deferral_Level = 0 then
1386
         return False;
1387
      end if;
1388
 
1389
      --  Check that the lock is not yet initialized
1390
 
1391
      if L.Level /= 0 then
1392
         return False;
1393
      end if;
1394
 
1395
      L.Level := Lock_Level'Pos (Level) + 1;
1396
      return True;
1397
   end Check_Initialize_Lock;
1398
 
1399
   ----------------
1400
   -- Check_Lock --
1401
   ----------------
1402
 
1403
   function Check_Lock (L : Lock_Ptr) return Boolean is
1404
      Self_ID : constant Task_Id := Self;
1405
      P       : Lock_Ptr;
1406
 
1407
   begin
1408
      --  Check that the argument is not null
1409
 
1410
      if L = null then
1411
         return False;
1412
      end if;
1413
 
1414
      --  Check that L is not frozen
1415
 
1416
      if L.Frozen then
1417
         return False;
1418
      end if;
1419
 
1420
      --  Check that caller is abort-deferred
1421
 
1422
      if Self_ID.Deferral_Level = 0 then
1423
         return False;
1424
      end if;
1425
 
1426
      --  Check that caller is not holding this lock already
1427
 
1428
      if L.Owner = To_Owner_ID (To_Address (Self_ID)) then
1429
         return False;
1430
      end if;
1431
 
1432
      if Single_Lock then
1433
         return True;
1434
      end if;
1435
 
1436
      --  Check that TCB lock order rules are satisfied
1437
 
1438
      P := Self_ID.Common.LL.Locks;
1439
      if P /= null then
1440
         if P.Level >= L.Level
1441
           and then (P.Level > 2 or else L.Level > 2)
1442
         then
1443
            return False;
1444
         end if;
1445
      end if;
1446
 
1447
      return True;
1448
   end Check_Lock;
1449
 
1450
   -----------------
1451
   -- Record_Lock --
1452
   -----------------
1453
 
1454
   function Record_Lock (L : Lock_Ptr) return Boolean is
1455
      Self_ID : constant Task_Id := Self;
1456
      P       : Lock_Ptr;
1457
 
1458
   begin
1459
      Lock_Count := Lock_Count + 1;
1460
 
1461
      --  There should be no owner for this lock at this point
1462
 
1463
      if L.Owner /= null then
1464
         return False;
1465
      end if;
1466
 
1467
      --  Record new owner
1468
 
1469
      L.Owner := To_Owner_ID (To_Address (Self_ID));
1470
 
1471
      if Single_Lock then
1472
         return True;
1473
      end if;
1474
 
1475
      --  Check that TCB lock order rules are satisfied
1476
 
1477
      P := Self_ID.Common.LL.Locks;
1478
 
1479
      if P /= null then
1480
         L.Next := P;
1481
      end if;
1482
 
1483
      Self_ID.Common.LL.Locking := null;
1484
      Self_ID.Common.LL.Locks := L;
1485
      return True;
1486
   end Record_Lock;
1487
 
1488
   -----------------
1489
   -- Check_Sleep --
1490
   -----------------
1491
 
1492
   function Check_Sleep (Reason : Task_States) return Boolean is
1493
      pragma Unreferenced (Reason);
1494
 
1495
      Self_ID : constant Task_Id := Self;
1496
      P       : Lock_Ptr;
1497
 
1498
   begin
1499
      --  Check that caller is abort-deferred
1500
 
1501
      if Self_ID.Deferral_Level = 0 then
1502
         return False;
1503
      end if;
1504
 
1505
      if Single_Lock then
1506
         return True;
1507
      end if;
1508
 
1509
      --  Check that caller is holding own lock, on top of list
1510
 
1511
      if Self_ID.Common.LL.Locks /=
1512
        To_Lock_Ptr (Self_ID.Common.LL.L'Access)
1513
      then
1514
         return False;
1515
      end if;
1516
 
1517
      --  Check that TCB lock order rules are satisfied
1518
 
1519
      if Self_ID.Common.LL.Locks.Next /= null then
1520
         return False;
1521
      end if;
1522
 
1523
      Self_ID.Common.LL.L.Owner := null;
1524
      P := Self_ID.Common.LL.Locks;
1525
      Self_ID.Common.LL.Locks := Self_ID.Common.LL.Locks.Next;
1526
      P.Next := null;
1527
      return True;
1528
   end Check_Sleep;
1529
 
1530
   -------------------
1531
   -- Record_Wakeup --
1532
   -------------------
1533
 
1534
   function Record_Wakeup
1535
     (L      : Lock_Ptr;
1536
      Reason : Task_States) return Boolean
1537
   is
1538
      pragma Unreferenced (Reason);
1539
 
1540
      Self_ID : constant Task_Id := Self;
1541
      P       : Lock_Ptr;
1542
 
1543
   begin
1544
      --  Record new owner
1545
 
1546
      L.Owner := To_Owner_ID (To_Address (Self_ID));
1547
 
1548
      if Single_Lock then
1549
         return True;
1550
      end if;
1551
 
1552
      --  Check that TCB lock order rules are satisfied
1553
 
1554
      P := Self_ID.Common.LL.Locks;
1555
 
1556
      if P /= null then
1557
         L.Next := P;
1558
      end if;
1559
 
1560
      Self_ID.Common.LL.Locking := null;
1561
      Self_ID.Common.LL.Locks := L;
1562
      return True;
1563
   end Record_Wakeup;
1564
 
1565
   ------------------
1566
   -- Check_Wakeup --
1567
   ------------------
1568
 
1569
   function Check_Wakeup
1570
     (T      : Task_Id;
1571
      Reason : Task_States) return Boolean
1572
   is
1573
      Self_ID : constant Task_Id := Self;
1574
 
1575
   begin
1576
      --  Is caller holding T's lock?
1577
 
1578
      if T.Common.LL.L.Owner /= To_Owner_ID (To_Address (Self_ID)) then
1579
         return False;
1580
      end if;
1581
 
1582
      --  Are reasons for wakeup and sleep consistent?
1583
 
1584
      if T.Common.State /= Reason then
1585
         return False;
1586
      end if;
1587
 
1588
      return True;
1589
   end Check_Wakeup;
1590
 
1591
   ------------------
1592
   -- Check_Unlock --
1593
   ------------------
1594
 
1595
   function Check_Unlock (L : Lock_Ptr) return Boolean is
1596
      Self_ID : constant Task_Id := Self;
1597
      P       : Lock_Ptr;
1598
 
1599
   begin
1600
      Unlock_Count := Unlock_Count + 1;
1601
 
1602
      if L = null then
1603
         return False;
1604
      end if;
1605
 
1606
      if L.Buddy /= null then
1607
         return False;
1608
      end if;
1609
 
1610
      if L.Level = 4 then
1611
         Check_Count := Unlock_Count;
1612
      end if;
1613
 
1614
      if Unlock_Count - Check_Count > 1000 then
1615
         Check_Count := Unlock_Count;
1616
      end if;
1617
 
1618
      --  Check that caller is abort-deferred
1619
 
1620
      if Self_ID.Deferral_Level = 0 then
1621
         return False;
1622
      end if;
1623
 
1624
      --  Check that caller is holding this lock, on top of list
1625
 
1626
      if Self_ID.Common.LL.Locks /= L then
1627
         return False;
1628
      end if;
1629
 
1630
      --  Record there is no owner now
1631
 
1632
      L.Owner := null;
1633
      P := Self_ID.Common.LL.Locks;
1634
      Self_ID.Common.LL.Locks := Self_ID.Common.LL.Locks.Next;
1635
      P.Next := null;
1636
      return True;
1637
   end Check_Unlock;
1638
 
1639
   --------------------
1640
   -- Check_Finalize --
1641
   --------------------
1642
 
1643
   function Check_Finalize_Lock (L : Lock_Ptr) return Boolean is
1644
      Self_ID : constant Task_Id := Self;
1645
 
1646
   begin
1647
      --  Check that caller is abort-deferred
1648
 
1649
      if Self_ID.Deferral_Level = 0 then
1650
         return False;
1651
      end if;
1652
 
1653
      --  Check that no one is holding this lock
1654
 
1655
      if L.Owner /= null then
1656
         return False;
1657
      end if;
1658
 
1659
      L.Frozen := True;
1660
      return True;
1661
   end Check_Finalize_Lock;
1662
 
1663
   ----------------
1664
   -- Initialize --
1665
   ----------------
1666
 
1667
   procedure Initialize (S : in out Suspension_Object) is
1668
      Result : Interfaces.C.int;
1669
   begin
1670
      --  Initialize internal state. It is always initialized to False (ARM
1671
      --  D.10 par. 6).
1672
 
1673
      S.State := False;
1674
      S.Waiting := False;
1675
 
1676
      --  Initialize internal mutex
1677
 
1678
      Result := mutex_init (S.L'Access, USYNC_THREAD, System.Null_Address);
1679
      pragma Assert (Result = 0 or else Result = ENOMEM);
1680
 
1681
      if Result = ENOMEM then
1682
         raise Storage_Error with "Failed to allocate a lock";
1683
      end if;
1684
 
1685
      --  Initialize internal condition variable
1686
 
1687
      Result := cond_init (S.CV'Access, USYNC_THREAD, 0);
1688
      pragma Assert (Result = 0 or else Result = ENOMEM);
1689
 
1690
      if Result /= 0 then
1691
         Result := mutex_destroy (S.L'Access);
1692
         pragma Assert (Result = 0);
1693
 
1694
         if Result = ENOMEM then
1695
            raise Storage_Error;
1696
         end if;
1697
      end if;
1698
   end Initialize;
1699
 
1700
   --------------
1701
   -- Finalize --
1702
   --------------
1703
 
1704
   procedure Finalize (S : in out Suspension_Object) is
1705
      Result  : Interfaces.C.int;
1706
   begin
1707
      --  Destroy internal mutex
1708
 
1709
      Result := mutex_destroy (S.L'Access);
1710
      pragma Assert (Result = 0);
1711
 
1712
      --  Destroy internal condition variable
1713
 
1714
      Result := cond_destroy (S.CV'Access);
1715
      pragma Assert (Result = 0);
1716
   end Finalize;
1717
 
1718
   -------------------
1719
   -- Current_State --
1720
   -------------------
1721
 
1722
   function Current_State (S : Suspension_Object) return Boolean is
1723
   begin
1724
      --  We do not want to use lock on this read operation. State is marked
1725
      --  as Atomic so that we ensure that the value retrieved is correct.
1726
 
1727
      return S.State;
1728
   end Current_State;
1729
 
1730
   ---------------
1731
   -- Set_False --
1732
   ---------------
1733
 
1734
   procedure Set_False (S : in out Suspension_Object) is
1735
      Result  : Interfaces.C.int;
1736
   begin
1737
      Result := mutex_lock (S.L'Access);
1738
      pragma Assert (Result = 0);
1739
 
1740
      S.State := False;
1741
 
1742
      Result := mutex_unlock (S.L'Access);
1743
      pragma Assert (Result = 0);
1744
   end Set_False;
1745
 
1746
   --------------
1747
   -- Set_True --
1748
   --------------
1749
 
1750
   procedure Set_True (S : in out Suspension_Object) is
1751
      Result : Interfaces.C.int;
1752
   begin
1753
      Result := mutex_lock (S.L'Access);
1754
      pragma Assert (Result = 0);
1755
 
1756
      --  If there is already a task waiting on this suspension object then
1757
      --  we resume it, leaving the state of the suspension object to False,
1758
      --  as it is specified in ARM D.10 par. 9. Otherwise, it just leaves
1759
      --  the state to True.
1760
 
1761
      if S.Waiting then
1762
         S.Waiting := False;
1763
         S.State := False;
1764
 
1765
         Result := cond_signal (S.CV'Access);
1766
         pragma Assert (Result = 0);
1767
      else
1768
         S.State := True;
1769
      end if;
1770
 
1771
      Result := mutex_unlock (S.L'Access);
1772
      pragma Assert (Result = 0);
1773
   end Set_True;
1774
 
1775
   ------------------------
1776
   -- Suspend_Until_True --
1777
   ------------------------
1778
 
1779
   procedure Suspend_Until_True (S : in out Suspension_Object) is
1780
      Result : Interfaces.C.int;
1781
   begin
1782
      Result := mutex_lock (S.L'Access);
1783
      pragma Assert (Result = 0);
1784
 
1785
      if S.Waiting then
1786
         --  Program_Error must be raised upon calling Suspend_Until_True
1787
         --  if another task is already waiting on that suspension object
1788
         --  (ARM D.10 par. 10).
1789
 
1790
         Result := mutex_unlock (S.L'Access);
1791
         pragma Assert (Result = 0);
1792
 
1793
         raise Program_Error;
1794
      else
1795
         --  Suspend the task if the state is False. Otherwise, the task
1796
         --  continues its execution, and the state of the suspension object
1797
         --  is set to False (ARM D.10 par. 9).
1798
 
1799
         if S.State then
1800
            S.State := False;
1801
         else
1802
            S.Waiting := True;
1803
            Result := cond_wait (S.CV'Access, S.L'Access);
1804
         end if;
1805
      end if;
1806
 
1807
      Result := mutex_unlock (S.L'Access);
1808
      pragma Assert (Result = 0);
1809
   end Suspend_Until_True;
1810
 
1811
   ----------------
1812
   -- Check_Exit --
1813
   ----------------
1814
 
1815
   function Check_Exit (Self_ID : Task_Id) return Boolean is
1816
   begin
1817
      --  Check that caller is just holding Global_Task_Lock
1818
      --  and no other locks
1819
 
1820
      if Self_ID.Common.LL.Locks = null then
1821
         return False;
1822
      end if;
1823
 
1824
      --  2 = Global_Task_Level
1825
 
1826
      if Self_ID.Common.LL.Locks.Level /= 2 then
1827
         return False;
1828
      end if;
1829
 
1830
      if Self_ID.Common.LL.Locks.Next /= null then
1831
         return False;
1832
      end if;
1833
 
1834
      --  Check that caller is abort-deferred
1835
 
1836
      if Self_ID.Deferral_Level = 0 then
1837
         return False;
1838
      end if;
1839
 
1840
      return True;
1841
   end Check_Exit;
1842
 
1843
   --------------------
1844
   -- Check_No_Locks --
1845
   --------------------
1846
 
1847
   function Check_No_Locks (Self_ID : Task_Id) return Boolean is
1848
   begin
1849
      return Self_ID.Common.LL.Locks = null;
1850
   end Check_No_Locks;
1851
 
1852
   ----------------------
1853
   -- Environment_Task --
1854
   ----------------------
1855
 
1856
   function Environment_Task return Task_Id is
1857
   begin
1858
      return Environment_Task_Id;
1859
   end Environment_Task;
1860
 
1861
   --------------
1862
   -- Lock_RTS --
1863
   --------------
1864
 
1865
   procedure Lock_RTS is
1866
   begin
1867
      Write_Lock (Single_RTS_Lock'Access, Global_Lock => True);
1868
   end Lock_RTS;
1869
 
1870
   ----------------
1871
   -- Unlock_RTS --
1872
   ----------------
1873
 
1874
   procedure Unlock_RTS is
1875
   begin
1876
      Unlock (Single_RTS_Lock'Access, Global_Lock => True);
1877
   end Unlock_RTS;
1878
 
1879
   ------------------
1880
   -- Suspend_Task --
1881
   ------------------
1882
 
1883
   function Suspend_Task
1884
     (T           : ST.Task_Id;
1885
      Thread_Self : Thread_Id) return Boolean
1886
   is
1887
   begin
1888
      if T.Common.LL.Thread /= Thread_Self then
1889
         return thr_suspend (T.Common.LL.Thread) = 0;
1890
      else
1891
         return True;
1892
      end if;
1893
   end Suspend_Task;
1894
 
1895
   -----------------
1896
   -- Resume_Task --
1897
   -----------------
1898
 
1899
   function Resume_Task
1900
     (T           : ST.Task_Id;
1901
      Thread_Self : Thread_Id) return Boolean
1902
   is
1903
   begin
1904
      if T.Common.LL.Thread /= Thread_Self then
1905
         return thr_continue (T.Common.LL.Thread) = 0;
1906
      else
1907
         return True;
1908
      end if;
1909
   end Resume_Task;
1910
 
1911
end System.Task_Primitives.Operations;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.