1
- use crate :: state:: tasks:: Task ;
2
- use std:: { fmt:: Debug , rc:: Rc } ;
1
+ use crate :: state:: tasks:: { Task , TaskState } ;
2
+ use std:: {
3
+ fmt:: Debug ,
4
+ rc:: Rc ,
5
+ time:: { Duration , SystemTime } ,
6
+ } ;
3
7
4
8
/// A warning for a particular type of monitored entity (e.g. task or resource).
5
9
///
6
10
/// This trait implements the logic for detecting a particular warning, and
7
11
/// generating a warning message describing it. The [`Linter`] type wraps an
8
12
/// instance of this trait to track active instances of the warning.
9
13
pub trait Warn < T > : Debug {
10
- /// Returns `true` if the warning applies to `val`.
11
- fn check ( & self , val : & T ) -> bool ;
14
+ /// Returns if the warning applies to `val`.
15
+ fn check ( & self , val : & T ) -> Warning ;
12
16
13
17
/// Formats a description of the warning detected for a *specific* `val`.
14
18
///
@@ -46,6 +50,19 @@ pub trait Warn<T>: Debug {
46
50
fn summary ( & self ) -> & str ;
47
51
}
48
52
53
+ /// A result for a warning check
54
+ pub enum Warning {
55
+ /// No warning for this entity.
56
+ Ok ,
57
+
58
+ /// A warning has been detected for this entity.
59
+ Warn ,
60
+
61
+ /// The warning should be rechecked as the conditions to allow for checking
62
+ /// are not satisfied yet
63
+ Recheck ,
64
+ }
65
+
49
66
#[ derive( Debug ) ]
50
67
pub ( crate ) struct Linter < T > ( Rc < dyn Warn < T > > ) ;
51
68
@@ -57,17 +74,12 @@ impl<T> Linter<T> {
57
74
Self ( Rc :: new ( warning) )
58
75
}
59
76
60
- /// Checks if the warning applies to a particular entity, returning a clone
61
- /// of `Self` if it does.
62
- ///
63
- /// The cloned instance of `Self` should be held by the entity that
64
- /// generated the warning, so that it can be formatted. Holding the clone of
65
- /// `Self` will increment the warning count for that entity.
66
- pub ( crate ) fn check ( & self , val : & T ) -> Option < Self > {
67
- if self . 0 . check ( val) {
68
- Some ( Self ( self . 0 . clone ( ) ) )
69
- } else {
70
- None
77
+ /// Checks if the warning applies to a particular entity
78
+ pub ( crate ) fn check ( & self , val : & T ) -> Lint < T > {
79
+ match self . 0 . check ( val) {
80
+ Warning :: Ok => Lint :: Ok ,
81
+ Warning :: Warn => Lint :: Warning ( Self ( self . 0 . clone ( ) ) ) ,
82
+ Warning :: Recheck => Lint :: Recheck ,
71
83
}
72
84
}
73
85
@@ -78,7 +90,7 @@ impl<T> Linter<T> {
78
90
79
91
pub ( crate ) fn format ( & self , val : & T ) -> String {
80
92
debug_assert ! (
81
- self . 0 . check( val) ,
93
+ matches! ( self . 0 . check( val) , Warning :: Warn ) ,
82
94
"tried to format a warning for a {} that did not have that warning!" ,
83
95
std:: any:: type_name:: <T >( )
84
96
) ;
@@ -90,6 +102,21 @@ impl<T> Linter<T> {
90
102
}
91
103
}
92
104
105
+ /// A result for a linter check
106
+ pub ( crate ) enum Lint < T > {
107
+ /// No warning applies to the entity
108
+ Ok ,
109
+
110
+ /// The cloned instance of `Self` should be held by the entity that
111
+ /// generated the warning, so that it can be formatted. Holding the clone of
112
+ /// `Self` will increment the warning count for that entity.
113
+ Warning ( Linter < T > ) ,
114
+
115
+ /// The lint should be rechecked as the conditions to allow for checking are
116
+ /// not satisfied yet
117
+ Recheck ,
118
+ }
119
+
93
120
#[ derive( Clone , Debug ) ]
94
121
pub ( crate ) struct SelfWakePercent {
95
122
min_percent : u64 ,
@@ -120,9 +147,13 @@ impl Warn<Task> for SelfWakePercent {
120
147
self . description . as_str ( )
121
148
}
122
149
123
- fn check ( & self , task : & Task ) -> bool {
150
+ fn check ( & self , task : & Task ) -> Warning {
124
151
let self_wakes = task. self_wake_percent ( ) ;
125
- self_wakes > self . min_percent
152
+ if self_wakes > self . min_percent {
153
+ Warning :: Warn
154
+ } else {
155
+ Warning :: Ok
156
+ }
126
157
}
127
158
128
159
fn format ( & self , task : & Task ) -> String {
@@ -142,11 +173,76 @@ impl Warn<Task> for LostWaker {
142
173
"tasks have lost their waker"
143
174
}
144
175
145
- fn check ( & self , task : & Task ) -> bool {
146
- !task. is_completed ( ) && task. waker_count ( ) == 0 && !task. is_running ( ) && !task. is_awakened ( )
176
+ fn check ( & self , task : & Task ) -> Warning {
177
+ if !task. is_completed ( )
178
+ && task. waker_count ( ) == 0
179
+ && !task. is_running ( )
180
+ && !task. is_awakened ( )
181
+ {
182
+ Warning :: Warn
183
+ } else {
184
+ Warning :: Ok
185
+ }
147
186
}
148
187
149
188
fn format ( & self , _: & Task ) -> String {
150
189
"This task has lost its waker, and will never be woken again." . into ( )
151
190
}
152
191
}
192
+
193
+ /// Warning for if a task has never yielded
194
+ #[ derive( Clone , Debug ) ]
195
+ pub ( crate ) struct NeverYielded {
196
+ min_duration : Duration ,
197
+ description : String ,
198
+ }
199
+
200
+ impl NeverYielded {
201
+ pub ( crate ) const DEFAULT_DURATION : Duration = Duration :: from_secs ( 1 ) ;
202
+ pub ( crate ) fn new ( min_duration : Duration ) -> Self {
203
+ Self {
204
+ min_duration,
205
+ description : format ! (
206
+ "tasks have never yielded (threshold {}ms)" ,
207
+ min_duration. as_millis( )
208
+ ) ,
209
+ }
210
+ }
211
+ }
212
+
213
+ impl Default for NeverYielded {
214
+ fn default ( ) -> Self {
215
+ Self :: new ( Self :: DEFAULT_DURATION )
216
+ }
217
+ }
218
+
219
+ impl Warn < Task > for NeverYielded {
220
+ fn summary ( & self ) -> & str {
221
+ self . description . as_str ( )
222
+ }
223
+
224
+ fn check ( & self , task : & Task ) -> Warning {
225
+ // Don't fire warning for tasks that are waiting to run
226
+ if task. state ( ) != TaskState :: Running {
227
+ return Warning :: Ok ;
228
+ }
229
+
230
+ if task. total_polls ( ) > 1 {
231
+ return Warning :: Ok ;
232
+ }
233
+
234
+ // Avoid short-lived task false positives
235
+ if task. busy ( SystemTime :: now ( ) ) >= self . min_duration {
236
+ Warning :: Warn
237
+ } else {
238
+ Warning :: Recheck
239
+ }
240
+ }
241
+
242
+ fn format ( & self , task : & Task ) -> String {
243
+ format ! (
244
+ "This task has never yielded ({:?})" ,
245
+ task. busy( SystemTime :: now( ) ) ,
246
+ )
247
+ }
248
+ }
0 commit comments