| ... | @@ -126,6 +126,21 @@ pub const Node = struct { | ... | @@ -126,6 +126,21 @@ pub const Node = struct { |
| 126 | } | 126 | } |
| 127 | } | 127 | } |
| 128 | | 128 | |
| | 129 | /// Thread-safe. |
| | 130 | pub fn setName(self: *Node, name: []const u8) void { |
| | 131 | const progress = self.context; |
| | 132 | progress.update_mutex.lock(); |
| | 133 | defer progress.update_mutex.unlock(); |
| | 134 | self.name = name; |
| | 135 | if (self.parent) |parent| { |
| | 136 | @atomicStore(?*Node, &parent.recently_updated_child, self, .Release); |
| | 137 | if (parent.parent) |grand_parent| { |
| | 138 | @atomicStore(?*Node, &grand_parent.recently_updated_child, parent, .Release); |
| | 139 | } |
| | 140 | if (progress.timer) |*timer| progress.maybeRefreshWithHeldLock(timer); |
| | 141 | } |
| | 142 | } |
| | 143 | |
| 129 | /// Thread-safe. 0 means unknown. | 144 | /// Thread-safe. 0 means unknown. |
| 130 | pub fn setEstimatedTotalItems(self: *Node, count: usize) void { | 145 | pub fn setEstimatedTotalItems(self: *Node, count: usize) void { |
| 131 | @atomicStore(usize, &self.unprotected_estimated_total_items, count, .Monotonic); | 146 | @atomicStore(usize, &self.unprotected_estimated_total_items, count, .Monotonic); |
| ... | @@ -174,16 +189,20 @@ pub fn maybeRefresh(self: *Progress) void { | ... | @@ -174,16 +189,20 @@ pub fn maybeRefresh(self: *Progress) void { |
| 174 | if (self.timer) |*timer| { | 189 | if (self.timer) |*timer| { |
| 175 | if (!self.update_mutex.tryLock()) return; | 190 | if (!self.update_mutex.tryLock()) return; |
| 176 | defer self.update_mutex.unlock(); | 191 | defer self.update_mutex.unlock(); |
| 177 | const now = timer.read(); | 192 | maybeRefreshWithHeldLock(self, timer); |
| 178 | if (now < self.initial_delay_ns) return; | | |
| 179 | // TODO I have observed this to happen sometimes. I think we need to follow Rust's | | |
| 180 | // lead and guarantee monotonically increasing times in the std lib itself. | | |
| 181 | if (now < self.prev_refresh_timestamp) return; | | |
| 182 | if (now - self.prev_refresh_timestamp < self.refresh_rate_ns) return; | | |
| 183 | return self.refreshWithHeldLock(); | | |
| 184 | } | 193 | } |
| 185 | } | 194 | } |
| 186 | | 195 | |
| | 196 | fn maybeRefreshWithHeldLock(self: *Progress, timer: *std.time.Timer) void { |
| | 197 | const now = timer.read(); |
| | 198 | if (now < self.initial_delay_ns) return; |
| | 199 | // TODO I have observed this to happen sometimes. I think we need to follow Rust's |
| | 200 | // lead and guarantee monotonically increasing times in the std lib itself. |
| | 201 | if (now < self.prev_refresh_timestamp) return; |
| | 202 | if (now - self.prev_refresh_timestamp < self.refresh_rate_ns) return; |
| | 203 | return self.refreshWithHeldLock(); |
| | 204 | } |
| | 205 | |
| 187 | /// Updates the terminal and resets `self.next_refresh_timestamp`. Thread-safe. | 206 | /// Updates the terminal and resets `self.next_refresh_timestamp`. Thread-safe. |
| 188 | pub fn refresh(self: *Progress) void { | 207 | pub fn refresh(self: *Progress) void { |
| 189 | if (!self.update_mutex.tryLock()) return; | 208 | if (!self.update_mutex.tryLock()) return; |