Skip to content

Commit 6d29ef0

Browse files
authored
Merge pull request #23046 from linusg/uefi-time
Three time-related fixes for UEFI
2 parents 00a8742 + 3bea478 commit 6d29ef0

File tree

2 files changed

+52
-42
lines changed

2 files changed

+52
-42
lines changed

Diff for: lib/std/os/uefi.zig

+19-11
Original file line numberDiff line numberDiff line change
@@ -113,31 +113,39 @@ pub const Time = extern struct {
113113
/// 0 - 59
114114
second: u8,
115115

116+
_pad1: u8,
117+
116118
/// 0 - 999999999
117119
nanosecond: u32,
118120

119121
/// The time's offset in minutes from UTC.
120122
/// Allowed values are -1440 to 1440 or unspecified_timezone
121123
timezone: i16,
122-
daylight: packed struct {
123-
_pad1: u6,
124-
124+
daylight: packed struct(u8) {
125125
/// If true, the time has been adjusted for daylight savings time.
126126
in_daylight: bool,
127127

128128
/// If true, the time is affected by daylight savings time.
129129
adjust_daylight: bool,
130+
131+
_: u6,
130132
},
131133

134+
_pad2: u8,
135+
136+
comptime {
137+
std.debug.assert(@sizeOf(Time) == 16);
138+
}
139+
132140
/// Time is to be interpreted as local time
133141
pub const unspecified_timezone: i16 = 0x7ff;
134142

135-
fn daysInYear(year: u16, maxMonth: u4) u32 {
136-
const leapYear: std.time.epoch.YearLeapKind = if (std.time.epoch.isLeapYear(year)) .leap else .not_leap;
137-
var days: u32 = 0;
143+
fn daysInYear(year: u16, max_month: u4) u9 {
144+
const leap_year: std.time.epoch.YearLeapKind = if (std.time.epoch.isLeapYear(year)) .leap else .not_leap;
145+
var days: u9 = 0;
138146
var month: u4 = 0;
139-
while (month < maxMonth) : (month += 1) {
140-
days += std.time.epoch.getDaysInMonth(leapYear, @enumFromInt(month + 1));
147+
while (month < max_month) : (month += 1) {
148+
days += std.time.epoch.getDaysInMonth(leap_year, @enumFromInt(month + 1));
141149
}
142150
return days;
143151
}
@@ -151,9 +159,9 @@ pub const Time = extern struct {
151159
}
152160

153161
days += daysInYear(self.year, @as(u4, @intCast(self.month)) - 1) + self.day;
154-
const hours = self.hour + (days * 24);
155-
const minutes = self.minute + (hours * 60);
156-
const seconds = self.second + (minutes * std.time.s_per_min);
162+
const hours: u64 = self.hour + (days * 24);
163+
const minutes: u64 = self.minute + (hours * 60);
164+
const seconds: u64 = self.second + (minutes * std.time.s_per_min);
157165
return self.nanosecond + (seconds * std.time.ns_per_s);
158166
}
159167
};

Diff for: lib/std/time.zig

+33-31
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ pub const Instant = struct {
135135
const clock_id = switch (builtin.os.tag) {
136136
.windows => {
137137
// QPC on windows doesn't fail on >= XP/2000 and includes time suspended.
138-
return Instant{ .timestamp = windows.QueryPerformanceCounter() };
138+
return .{ .timestamp = windows.QueryPerformanceCounter() };
139139
},
140140
.wasi => {
141141
var ns: std.os.wasi.timestamp_t = undefined;
@@ -147,7 +147,7 @@ pub const Instant = struct {
147147
var value: std.os.uefi.Time = undefined;
148148
const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
149149
if (status != .success) return error.Unsupported;
150-
return Instant{ .timestamp = value.toEpoch() };
150+
return .{ .timestamp = value.toEpoch() };
151151
},
152152
// On darwin, use UPTIME_RAW instead of MONOTONIC as it ticks while
153153
// suspended.
@@ -185,36 +185,38 @@ pub const Instant = struct {
185185
/// This assumes that the `earlier` Instant represents a moment in time before or equal to `self`.
186186
/// This also assumes that the time that has passed between both Instants fits inside a u64 (~585 yrs).
187187
pub fn since(self: Instant, earlier: Instant) u64 {
188-
if (builtin.os.tag == .windows) {
189-
// We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA
190-
// (a read-only page of info updated and mapped by the kernel to all processes):
191-
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data
192-
// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
193-
const qpc = self.timestamp - earlier.timestamp;
194-
const qpf = windows.QueryPerformanceFrequency();
195-
196-
// 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it.
197-
// https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701
198-
const common_qpf = 10_000_000;
199-
if (qpf == common_qpf) {
200-
return qpc * (ns_per_s / common_qpf);
201-
}
202-
203-
// Convert to ns using fixed point.
204-
const scale = @as(u64, std.time.ns_per_s << 32) / @as(u32, @intCast(qpf));
205-
const result = (@as(u96, qpc) * scale) >> 32;
206-
return @as(u64, @truncate(result));
207-
}
208-
209-
// WASI timestamps are directly in nanoseconds
210-
if (builtin.os.tag == .wasi) {
211-
return self.timestamp - earlier.timestamp;
188+
switch (builtin.os.tag) {
189+
.windows => {
190+
// We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA
191+
// (a read-only page of info updated and mapped by the kernel to all processes):
192+
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data
193+
// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
194+
const qpc = self.timestamp - earlier.timestamp;
195+
const qpf = windows.QueryPerformanceFrequency();
196+
197+
// 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it.
198+
// https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701
199+
const common_qpf = 10_000_000;
200+
if (qpf == common_qpf) {
201+
return qpc * (ns_per_s / common_qpf);
202+
}
203+
204+
// Convert to ns using fixed point.
205+
const scale = @as(u64, std.time.ns_per_s << 32) / @as(u32, @intCast(qpf));
206+
const result = (@as(u96, qpc) * scale) >> 32;
207+
return @as(u64, @truncate(result));
208+
},
209+
.uefi, .wasi => {
210+
// UEFI and WASI timestamps are directly in nanoseconds
211+
return self.timestamp - earlier.timestamp;
212+
},
213+
else => {
214+
// Convert timespec diff to ns
215+
const seconds = @as(u64, @intCast(self.timestamp.sec - earlier.timestamp.sec));
216+
const elapsed = (seconds * ns_per_s) + @as(u32, @intCast(self.timestamp.nsec));
217+
return elapsed - @as(u32, @intCast(earlier.timestamp.nsec));
218+
},
212219
}
213-
214-
// Convert timespec diff to ns
215-
const seconds = @as(u64, @intCast(self.timestamp.sec - earlier.timestamp.sec));
216-
const elapsed = (seconds * ns_per_s) + @as(u32, @intCast(self.timestamp.nsec));
217-
return elapsed - @as(u32, @intCast(earlier.timestamp.nsec));
218220
}
219221
};
220222

0 commit comments

Comments
 (0)