File : s-bbtime.adb


   1 ------------------------------------------------------------------------------
   2 --                                                                          --
   3 --                  GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS                --
   4 --                                                                          --
   5 --                         S Y S T E M . B B . T I M E                      --
   6 --                                                                          --
   7 --                                  B o d y                                 --
   8 --                                                                          --
   9 --        Copyright (C) 1999-2002 Universidad Politecnica de Madrid         --
  10 --             Copyright (C) 2003-2005 The European Space Agency            --
  11 --                     Copyright (C) 2003-2015, AdaCore                     --
  12 --                                                                          --
  13 -- GNARL is free software; you can  redistribute it  and/or modify it under --
  14 -- terms of the  GNU General Public License as published  by the Free Soft- --
  15 -- ware  Foundation;  either version 3,  or (at your option) any later ver- --
  16 -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
  17 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18 -- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
  19 --                                                                          --
  20 --                                                                          --
  21 --                                                                          --
  22 --                                                                          --
  23 --                                                                          --
  24 -- You should have received a copy of the GNU General Public License and    --
  25 -- a copy of the GCC Runtime Library Exception along with this program;     --
  26 -- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
  27 -- <http://www.gnu.org/licenses/>.                                          --
  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 -- The port of GNARL to bare board targets was initially developed by the   --
  33 -- Real-Time Systems Group at the Technical University of Madrid.           --
  34 --                                                                          --
  35 ------------------------------------------------------------------------------
  36 
  37 pragma Restrictions (No_Elaboration_Code);
  38 
  39 with System.BB.Interrupts;
  40 with System.BB.Board_Support;
  41 with System.BB.Protection;
  42 with System.BB.Parameters;
  43 with System.BB.Threads.Queues;
  44 with System.BB.Timing_Events;
  45 with System.BB.CPU_Primitives.Multiprocessors;
  46 with System.Multiprocessors.Fair_Locks;
  47 with System.Multiprocessors.Spin_Locks;
  48 
  49 package body System.BB.Time is
  50 
  51    use Board_Support;
  52    use Parameters;
  53    use CPU_Primitives.Multiprocessors;
  54    use System.Multiprocessors;
  55    use System.Multiprocessors.Fair_Locks;
  56    use System.Multiprocessors.Spin_Locks;
  57    use Threads, Threads.Queues;
  58 
  59    -----------------------
  60    -- Local definitions --
  61    -----------------------
  62 
  63    Alarm_Lock : Fair_Lock := (Spinning => (others => False),
  64                               Lock     => (Flag   => 0));
  65    --  Used to protect access to shared alarm resources
  66    --  (Timer configuration and Pending_Alarm variable)
  67 
  68    subtype Clock_Interval is Timer_Interval;
  69 
  70    type Clock_Periods is mod 2 ** 32;
  71    for Clock_Periods'Size use 32;
  72 
  73    function "&" (Left : Clock_Periods; Right : Clock_Interval) return Time is
  74      (Time (Left) * (Time (Max_Timer_Interval) + 1) + Time (Right));
  75    --  Combine MSP and LSP of clock to form time
  76 
  77    Update_In_Progress : constant Clock_Periods := 0;
  78    Periods_In_Epoch   : constant Clock_Periods := 1;
  79    --  Special value to signify Last_Clock_Update is going on, so on
  80    --  multiprocessor systems can avoid race conditions during updates.
  81    --  Choose 0, and have epoch start at 1, so Unsynchronized_Clock can
  82    --  ignore updates and just return an early time instead.
  83 
  84    type Composite_Time is record
  85       MSP : Clock_Periods  := Periods_In_Epoch;
  86       pragma Atomic (MSP);
  87       LSP : Clock_Interval := 0;
  88       pragma Atomic (LSP);
  89    end record;
  90    --  Time representation used for the software clock, allowing concurrent
  91    --  updates and reads, see Update_Clock.
  92    --
  93    --  Include a default expression for component LSP, even when not needed, to
  94    --  prevent the need for elaboration code to initialize default-initialized
  95    --  objects of this type (note that this package has a restriction
  96    --  No_Elaboration_Code).
  97 
  98    Software_Clock : Composite_Time;
  99    --  Clock with same time-base as hardware clock, but allowing a larger
 100    --  range. This is always behind the actual time by less than one hardware
 101    --  clock period. See Update_Clock for read and update protocol.
 102 
 103    Pending_Alarm : Time := Time'Last;
 104    --  Time of the current alarm handled by the timer. Used to determine if a
 105    --  given alarm is before the current one, and so needs to re-configure the
 106    --  timer.
 107 
 108    Max_Sleep : Time := 0;
 109    --  The longest time we can sleep without updating the Software_Clock.
 110    --  Initialized by Initialize_Timers.
 111 
 112    -----------------------
 113    -- Local subprograms --
 114    -----------------------
 115 
 116    procedure Alarm_Handler (Interrupt : Interrupts.Interrupt_ID);
 117    --  Handler for the alarm interrupt
 118 
 119    procedure Update_Clock (Now : out Time);
 120    --  This procedure has to be executed at least once each period of the
 121    --  hardware clock. We also require that this procedure be called with
 122    --  interrupts disabled, to ensure no stale values will be written. Given
 123    --  that limitation, it is fine to do concurrent updates on SMP systems:
 124    --  no matter which update ultimately prevails, it can't be old. While, on
 125    --  SMP systems, the Period_Counter may not always be monotone, the time
 126    --  returned by Update_Clock and Clock is.
 127 
 128    -------------------
 129    -- Alarm_Handler --
 130    -------------------
 131 
 132    procedure Alarm_Handler (Interrupt : Interrupts.Interrupt_ID) is
 133       Now             : Time;
 134       Next_Alarm      : Time; -- Time
 135 
 136    begin
 137       --  Make sure we are handling the right interrupt and there is an alarm
 138       --  pending.
 139 
 140       pragma Assert
 141         (Pending_Alarm /= Time'Last
 142            and then Interrupt = Alarm_Interrupt_ID);
 143 
 144       Board_Support.Clear_Alarm_Interrupt;
 145 
 146       --  The access to the queues must be protected
 147 
 148       Protection.Enter_Kernel;
 149 
 150       --  Reset Pending_Alarm before computing the next alarm time, as other
 151       --  processors may set alarms concurrently, and these alarms would be
 152       --  ignored otherwise. The alarm lock must be held for this.
 153 
 154       if Multiprocessor then
 155          Lock (Alarm_Lock);
 156          Pending_Alarm := Time'Last;
 157          Unlock (Alarm_Lock);
 158 
 159       --  No need for lock if not on multiprocessor
 160 
 161       else
 162          Pending_Alarm := Time'Last;
 163       end if;
 164 
 165       Update_Clock (Now);
 166 
 167       --  Ensure alarms will keep going to keep the software clock up-to-date.
 168 
 169       Next_Alarm := Now + Max_Sleep;
 170 
 171       --  Multiprocessor case special processing
 172 
 173       if Parameters.Multiprocessor then
 174 
 175          --  This is the alarm CPU, we have to wake up the other CPUs with
 176          --  expired alarms.
 177 
 178          for CPU_Id in CPU loop
 179 
 180             if CPU_Id /= Current_CPU then
 181                declare
 182                   Alarm_Time : constant Time := Get_Next_Timeout (CPU_Id);
 183 
 184                begin
 185                   if Alarm_Time <= Now then
 186 
 187                      --  Alarm expired, wake up the CPU
 188 
 189                      Poke_CPU (CPU_Id);
 190 
 191                   else
 192                      --  Check if this is the next non-expired alarm of the
 193                      --  overall system.
 194 
 195                      if Alarm_Time < Next_Alarm then
 196                         Next_Alarm := Alarm_Time;
 197                      end if;
 198                   end if;
 199                end;
 200             end if;
 201          end loop;
 202       end if;
 203 
 204       --  Execute expired events of the current CPU
 205 
 206       Timing_Events.Execute_Expired_Timing_Events (Now);
 207 
 208       --  Wake up our alarms, and set any new alarm
 209 
 210       Wakeup_Expired_Alarms (Now);
 211 
 212       Next_Alarm := Time'Min (Get_Next_Timeout (Current_CPU), Next_Alarm);
 213       Update_Alarm (Next_Alarm);
 214 
 215       Protection.Leave_Kernel;
 216    end Alarm_Handler;
 217 
 218    -----------
 219    -- Clock --
 220    -----------
 221 
 222    function Clock return Time is
 223       First_MSP  : Clock_Periods;
 224       Before_MSP : Clock_Periods;
 225       Before_LSP : Clock_Interval;
 226       Now_LSP    : Clock_Interval;
 227       After_MSP  : Clock_Periods;
 228 
 229    begin
 230       --  Reading the clock needs to access to the software and the hardware
 231       --  clock. In a multiprocessor, masking interrupts is not enough because
 232       --  the software clock can be updated by another processor. Therefore, we
 233       --  keep reading until we get a consistent value (no updates of the
 234       --  software MSP while we read the hardware clock).
 235 
 236       --  We can limit the iterations in the loop to 3. In the worst case, if
 237       --  the MSP keeps increasing within the loop, it means that we are
 238       --  spending an extremely long time in this function (we get preempted
 239       --  all the time). If the first time we read 1, and then the MSP gets
 240       --  increased, we know that the time is between 1 & X and 2 & X (because
 241       --  the software clock can be behind the actual time by at most one
 242       --  hardware clock period). It means that the actual time when we entered
 243       --  this function was before 3 & 0. In the second iteration we can read
 244       --  2 and then get increased again. Hence actual time is between 2 & X
 245       --  and 3 & X. Hence, the actual time when we leave function clock is at
 246       --  least 2 & 0. However, we do not know when between 2 & 0 and 3 & 0.
 247       --  Hence we read a third time, and if we read 3 and then a change, it
 248       --  means that the actual time is between 3 & X and 4 & X (so at least
 249       --  3 & 0). Hence, at the end of the third iteration, we can return 3 & 0
 250       --  as a safe value that is between the beginning and end of the
 251       --  execution of this call to Clock.
 252 
 253       for Iteration in 1 .. 3 loop
 254 
 255          --  On multiprocessor systems there may be a concurrent update of the
 256          --  software clock (signaled with Update_In_Progress). Retry if this
 257          --  happens. On monoprocessors the loop is performed only once.
 258 
 259          loop
 260             Before_MSP := Software_Clock.MSP;
 261 
 262             exit when not Multiprocessor
 263               or else Before_MSP /= Update_In_Progress;
 264          end loop;
 265 
 266          --  After the loop, Before_MSP cannot be equal to Update_In_Progress.
 267          --  In the case of multiprocessors because of the exit condition, and
 268          --  in the case of monoprocessors because the update is done
 269          --  atomically.
 270 
 271          Before_LSP := Software_Clock.LSP;
 272 
 273          Now_LSP := Read_Clock;
 274 
 275          After_MSP := Software_Clock.MSP;
 276 
 277          --  If the MSP in Software_Clock has changed (or is changing), we
 278          --  do not know the time at which the software clock was updated. It
 279          --  is important to note that the implementation does not force the
 280          --  software clock to be updated at a time close to the LSP wraparound
 281          --  (it needs to be done at least once per hardware clock period, but
 282          --  we do not know when). Hence, returning (Before_MSP + 1) & 0 is
 283          --  not correct because the updated LSP in the Software_Clock does
 284          --  not need to be close to zero.
 285 
 286          --  Normal case, no updates in MSP
 287 
 288          if Before_MSP = After_MSP then
 289 
 290             --  If we know the value of the software clock at the time of the
 291             --  read of the hardware clock, we know the time of that read,
 292             --  because the software clock can never be more than one period
 293             --  behind. Hence, we build a Time value from two consecutive
 294             --  readings of the hardware clock (Before_LSP and Now_LSP) and one
 295             --  reading of the MSP from the Software_Clock (and we know that
 296             --  the MSP did not change between the two readings of Before_LSP
 297             --  and Now_LSP).
 298 
 299             return
 300               Before_MSP + (if Now_LSP < Before_LSP then 1 else 0) & Now_LSP;
 301 
 302          --  After the first unsuccessful iteration we store the first MSP
 303          --  value read to have a reference of the initial time when we entered
 304          --  the clock function (before First_MSP + 2 & 0).
 305 
 306          elsif Iteration = 1 then
 307             First_MSP := Before_MSP;
 308 
 309          --  During the second or third iteration, if the clock has been
 310          --  increased by two or more then Before_MSP & 0 is certainly within
 311          --  the beginning and end of the execution of this call to Clock.
 312 
 313          elsif Before_MSP - First_MSP >= 2 then
 314             exit;
 315          end if;
 316       end loop;
 317 
 318       pragma Assert (Before_MSP - First_MSP >= 2);
 319 
 320       return Before_MSP & 0;
 321    end Clock;
 322 
 323    -----------------
 324    -- Delay_Until --
 325    -----------------
 326 
 327    procedure Delay_Until (T : Time) is
 328       Now               : Time;
 329       Self              : Thread_Id;
 330       Inserted_As_First : Boolean;
 331 
 332    begin
 333       Protection.Enter_Kernel;
 334 
 335       Now := Clock;
 336 
 337       Self := Thread_Self;
 338 
 339       pragma Assert (Self.State = Runnable);
 340 
 341       --  Test if the alarm time is in the future
 342 
 343       if T > Now then
 344 
 345          --  Extract the thread from the ready queue. When a thread wants to
 346          --  wait for an alarm it becomes blocked.
 347 
 348          Self.State := Delayed;
 349 
 350          Extract (Self);
 351 
 352          --  Insert Thread_Id in the alarm queue (ordered by time) and if it
 353          --  was inserted at head then check if Alarm Time is closer than the
 354          --  next clock interrupt.
 355 
 356          Insert_Alarm (T, Self, Inserted_As_First);
 357 
 358          if Inserted_As_First then
 359             Update_Alarm (Get_Next_Timeout (Current_CPU));
 360          end if;
 361 
 362       else
 363          --  If alarm time is not in the future, the thread must yield the CPU
 364 
 365          Yield (Self);
 366       end if;
 367 
 368       Protection.Leave_Kernel;
 369    end Delay_Until;
 370 
 371    -----------
 372    -- Epoch --
 373    -----------
 374 
 375    function Epoch return Time is
 376    begin
 377       return Periods_In_Epoch & 0;
 378    end Epoch;
 379 
 380    ----------------------
 381    -- Get_Next_Timeout --
 382    ----------------------
 383 
 384    function Get_Next_Timeout (CPU_Id : CPU) return Time is
 385       Alarm_Time : constant Time := Get_Next_Alarm_Time (CPU_Id);
 386       Event_Time : constant Time := Timing_Events.Get_Next_Timeout (CPU_Id);
 387    begin
 388       return Time'Min (Alarm_Time, Event_Time);
 389    end Get_Next_Timeout;
 390 
 391    -----------------------
 392    -- Initialize_Timers --
 393    -----------------------
 394 
 395    procedure Initialize_Timers is
 396    begin
 397       --  There may never be more than Max_Timer_Interval clocks between
 398       --  updates of Software_Clock, or we lose track of time. Allow a 1/8th
 399       --  period safety for early wakeup. The alarm CPU should never have
 400       --  alarm interrupts disabled for longer than this, or we may miss
 401       --  clock updates.
 402 
 403       Max_Sleep := Time (Max_Timer_Interval / 8 * 7);
 404 
 405       --  Install alarm handler
 406 
 407       Interrupts.Attach_Handler
 408         (Alarm_Handler'Access,
 409          Alarm_Interrupt_ID,
 410          Priority_Of_Interrupt (Alarm_Interrupt_ID));
 411 
 412       --  It is important to initialize the software LSP with the value coming
 413       --  from the hardware. There is no guarantee that this hardware value is
 414       --  close to zero (it may have been initialized by monitor software with
 415       --  any value and at any moment in time). With this initialization we
 416       --  ensure that the first alarm is not too far (we need to ensure that
 417       --  the value in the software LSP is less than a period away from the
 418       --  actual value in hardware).
 419 
 420       Software_Clock.LSP := Read_Clock;
 421 
 422       --  Establish invariant that there always is a pending alarm at most
 423       --  Max_Sleep time in the future.
 424 
 425       Pending_Alarm := Clock + Max_Sleep;
 426       Board_Support.Set_Alarm (Clock_Interval (Max_Sleep));
 427    end Initialize_Timers;
 428 
 429    -------------------
 430    --  Update_Alarm --
 431    -------------------
 432 
 433    procedure Update_Alarm (Alarm : Time) is
 434       Now             : constant Time := Clock;
 435       Time_Difference : Time;
 436 
 437    begin
 438       --  On multiprocessors we want to do the entire procedure while holding
 439       --  the alarm lock, as we shouldn't read or update the Pending_Alarm
 440       --  variable, or program the alarm, concurrently with another update.
 441 
 442       if Parameters.Multiprocessor then
 443          Lock (Alarm_Lock);
 444       end if;
 445 
 446       if Alarm <= Now then
 447 
 448          --  If alarm is in the past, set the minimum timer value so the
 449          --  interrupt will be triggered as soon as possible.
 450 
 451          Time_Difference := 1;
 452 
 453       else
 454          Time_Difference := Alarm - Now;
 455       end if;
 456 
 457       Time_Difference := Time'Min (Time_Difference, Max_Sleep);
 458 
 459       --  If next alarm time is closer than the currently pending alarm,
 460       --  reprogram the alarm.
 461 
 462       if Alarm < Pending_Alarm then
 463          pragma Assert (Time_Difference in 1 .. Max_Sleep);
 464 
 465          Board_Support.Set_Alarm (Clock_Interval (Time_Difference));
 466          Pending_Alarm := Alarm;
 467       end if;
 468 
 469       if Parameters.Multiprocessor then
 470          Unlock (Alarm_Lock);
 471       end if;
 472    end Update_Alarm;
 473 
 474    ------------------
 475    -- Update_Clock --
 476    ------------------
 477 
 478    --  Must be called from within Kernel (interrupts disabled). Must only be
 479    --  called from one processor at a time.
 480 
 481    procedure Update_Clock (Now : out Time) is
 482       Update_MSP : constant Clock_Periods := Software_Clock.MSP;
 483       Update_LSP : constant Clock_Interval := Software_Clock.LSP;
 484       Now_LSP    : constant Clock_Interval := Read_Clock;
 485       Now_MSP    : Clock_Periods;
 486 
 487    begin
 488       if Now_LSP < Update_LSP then
 489          Now_MSP := Update_MSP + 1;
 490 
 491          --  Need to do "atomic" update of both parts of the clock
 492 
 493          --  Mark Software_Clock.MSP as invalid during updates. The read
 494          --  protocol is to read Software_Clock.MSP both before and after
 495          --  reading Software_Clock.LSP. Only consider the MSP as that
 496          --  belonging to the LSP if both values are the same and not equal
 497          --  to the special Update_In_Progress value.
 498 
 499          --  Because interrupts are disabled, this special read protocol is
 500          --  only necessary on multiprocessor systems.
 501 
 502          Software_Clock.MSP := Update_In_Progress;
 503          Software_Clock.LSP := Now_LSP;
 504          Software_Clock.MSP := Now_MSP;
 505 
 506       else
 507          Now_MSP := Update_MSP;
 508 
 509          --  Only need to change the LSP, so we can do this atomically
 510 
 511          Software_Clock.LSP := Now_LSP;
 512       end if;
 513 
 514       Now := Now_MSP & Now_LSP;
 515    end Update_Clock;
 516 end System.BB.Time;