Skip to content

Instantly share code, notes, and snippets.

@fxn
Created November 6, 2022 20:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fxn/4e41a11ebefb2cc3c56fc93c9fead3bc to your computer and use it in GitHub Desktop.
Save fxn/4e41a11ebefb2cc3c56fc93c9fead3bc to your computer and use it in GitHub Desktop.
module Simulation
# Clocks in a Linux system
# ========================
#
# A Linux system has two clocks: The hardware clock, and the system clock.
#
# The hardware clock, also known as RTC or real-time clock, is a physical
# clock. This clock runs always, even when the system is shut down or
# unplugged the clock keeps running because it has an independent source of
# power, normally a lithium battery. See
#
# https://en.wikipedia.org/wiki/Real-time_clock
#
# You manage the RTC with the command `hwclock`.
#
# The system clock is a counter maintained by the kernel and driven by a
# periodic timer interrupt:
#
# http://www.science.unitn.it/~fiorella/guidelinux/tlk/node121.html
#
# Each time an interrupt happens, the kernel increments a variable called
# _jiffies_. This stores the number of clock ticks since last boot:
#
# http://www.makelinux.net/ldd3/chp-7-sect-1
#
# At boot time the hardware clock is checked to set the system time and from
# then on it can be changed without affecting the hardware clock. The command
# `date` allows management of the system clock. See:
#
# https://en.wikipedia.org/wiki/System_time
#
# The Linux kernel has a mode called "11 minutes mode" wherein it copies the
# system time to the hardware clock every 11 minutes. This needs a compile
# time option to be supported, and in such case the system has to be put in a
# synchronized state. The NTP daemon for example does this. It can also be
# turned off by running anything that sets the time the old-fashioned way,
# like `hwclock --hctosys`, but if `ntpd(1)` is running it will set the flag
# back the next time it synchronizes.
#
# Time wrapping in the simulator
# ==============================
#
# The simulator executes events and sets the system time to their
# corresponding timestamp. That way all external services are going to have a
# consistent time. If we emulated this only in Ruby with Timecop, for example
# any call to `NOW()` or default timestamp values set by the database would
# not match.
#
# For this reason, machines using the simulator cannot run ntpd(1).
# Moreover, Vagrant synchronizes the time of the guest with the one of the
# host, to run the simulator within Vagrant you need to execute
#
# VBoxManage setextradata $vm_name VBoxInternal/Devices/VMMDev/0/Config/GetHostTimeDisabled 1
#
# The runner wraps its main look in `wrap_time`, to ensure that no matter what
# we restore the system time after the simulation has finished (either
# successfully or aborted).
#
# The method `set_system_time` encapsulates the way the system time is set.
#
# Sleeping
# ========
#
# To have in mind.
#
# Sleeping is apparently implemented by a decreasing counter of CPU jiffies
# (the quantum of CPU time) and this ignores altogether system time. Because
# of this, if a process sleeps for 2 seconds and the simulation moves the
# system clock, the `sleep` call will wake up in two seconds of wall-clock
# time no matter where the system time is at that moment.
class TimeWrapper
def self.wrap_time
yield
ensure
# We reset the hardware clock to get a shell back with the current time.
#
# This doesn't work on the Docker containers of the simulator dedicated
# environment, but since they are ephemeral that is fine. That is why we
# redirect stderr, it is fine to err, and we want a clean output.
system "sudo hwclock -s 2>/dev/null"
end
def self.set_system_time(epoch)
system "sudo date -s '@#{epoch}' > /dev/null"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment