6
6
//! variable.
7
7
8
8
use super :: { lock:: Backend , lock:: Guard , LockClassKey } ;
9
- use crate :: { bindings, init:: PinInit , pin_init, str:: CStr , types:: Opaque } ;
9
+ use crate :: {
10
+ bindings, init:: PinInit , pin_init, str:: CStr , task:: MAX_SCHEDULE_TIMEOUT , time:: Jiffies ,
11
+ types:: Opaque ,
12
+ } ;
13
+ use core:: ffi:: c_long;
10
14
use core:: marker:: PhantomPinned ;
11
15
use macros:: pin_data;
12
16
@@ -102,7 +106,12 @@ impl CondVar {
102
106
} )
103
107
}
104
108
105
- fn wait_internal < T : ?Sized , B : Backend > ( & self , wait_state : u32 , guard : & mut Guard < ' _ , T , B > ) {
109
+ fn wait_internal < T : ?Sized , B : Backend > (
110
+ & self ,
111
+ wait_state : u32 ,
112
+ guard : & mut Guard < ' _ , T , B > ,
113
+ timeout_in_jiffies : c_long ,
114
+ ) -> c_long {
106
115
let wait = Opaque :: < bindings:: wait_queue_entry > :: uninit ( ) ;
107
116
108
117
// SAFETY: `wait` points to valid memory.
@@ -113,11 +122,13 @@ impl CondVar {
113
122
bindings:: prepare_to_wait_exclusive ( self . wait_list . get ( ) , wait. get ( ) , wait_state as _ )
114
123
} ;
115
124
116
- // SAFETY: No arguments, switches to another thread.
117
- guard. do_unlocked ( || unsafe { bindings:: schedule ( ) } ) ;
125
+ // SAFETY: Switches to another thread. The timeout can be any number .
126
+ let ret = guard. do_unlocked ( || unsafe { bindings:: schedule_timeout ( timeout_in_jiffies ) } ) ;
118
127
119
128
// SAFETY: Both `wait` and `wait_list` point to valid memory.
120
129
unsafe { bindings:: finish_wait ( self . wait_list . get ( ) , wait. get ( ) ) } ;
130
+
131
+ ret
121
132
}
122
133
123
134
/// Releases the lock and waits for a notification in uninterruptible mode.
@@ -127,7 +138,7 @@ impl CondVar {
127
138
/// [`CondVar::notify_one`] or [`CondVar::notify_all`]. Note that it may also wake up
128
139
/// spuriously.
129
140
pub fn wait < T : ?Sized , B : Backend > ( & self , guard : & mut Guard < ' _ , T , B > ) {
130
- self . wait_internal ( bindings:: TASK_UNINTERRUPTIBLE , guard) ;
141
+ self . wait_internal ( bindings:: TASK_UNINTERRUPTIBLE , guard, MAX_SCHEDULE_TIMEOUT ) ;
131
142
}
132
143
133
144
/// Releases the lock and waits for a notification in interruptible mode.
@@ -138,10 +149,31 @@ impl CondVar {
138
149
/// Returns whether there is a signal pending.
139
150
#[ must_use = "wait_interruptible returns if a signal is pending, so the caller must check the return value" ]
140
151
pub fn wait_interruptible < T : ?Sized , B : Backend > ( & self , guard : & mut Guard < ' _ , T , B > ) -> bool {
141
- self . wait_internal ( bindings:: TASK_INTERRUPTIBLE , guard) ;
152
+ self . wait_internal ( bindings:: TASK_INTERRUPTIBLE , guard, MAX_SCHEDULE_TIMEOUT ) ;
142
153
crate :: current!( ) . signal_pending ( )
143
154
}
144
155
156
+ /// Releases the lock and waits for a notification in interruptible mode.
157
+ ///
158
+ /// Atomically releases the given lock (whose ownership is proven by the guard) and puts the
159
+ /// thread to sleep. It wakes up when notified by [`CondVar::notify_one`] or
160
+ /// [`CondVar::notify_all`], or when a timeout occurs, or when the thread receives a signal.
161
+ #[ must_use = "wait_interruptible_timeout returns if a signal is pending, so the caller must check the return value" ]
162
+ pub fn wait_interruptible_timeout < T : ?Sized , B : Backend > (
163
+ & self ,
164
+ guard : & mut Guard < ' _ , T , B > ,
165
+ jiffies : Jiffies ,
166
+ ) -> CondVarTimeoutResult {
167
+ let jiffies = jiffies. try_into ( ) . unwrap_or ( MAX_SCHEDULE_TIMEOUT ) ;
168
+ let res = self . wait_internal ( bindings:: TASK_INTERRUPTIBLE , guard, jiffies) ;
169
+
170
+ match ( res as Jiffies , crate :: current!( ) . signal_pending ( ) ) {
171
+ ( jiffies, true ) => CondVarTimeoutResult :: Signal { jiffies } ,
172
+ ( 0 , false ) => CondVarTimeoutResult :: Timeout ,
173
+ ( jiffies, false ) => CondVarTimeoutResult :: Woken { jiffies } ,
174
+ }
175
+ }
176
+
145
177
/// Calls the kernel function to notify the appropriate number of threads with the given flags.
146
178
fn notify ( & self , count : i32 , flags : u32 ) {
147
179
// SAFETY: `wait_list` points to valid memory.
@@ -177,3 +209,19 @@ impl CondVar {
177
209
self . notify ( 0 , 0 ) ;
178
210
}
179
211
}
212
+
213
+ /// The return type of `wait_timeout`.
214
+ pub enum CondVarTimeoutResult {
215
+ /// The timeout was reached.
216
+ Timeout ,
217
+ /// Somebody woke us up.
218
+ Woken {
219
+ /// Remaining sleep duration.
220
+ jiffies : Jiffies ,
221
+ } ,
222
+ /// A signal occurred.
223
+ Signal {
224
+ /// Remaining sleep duration.
225
+ jiffies : Jiffies ,
226
+ } ,
227
+ }
0 commit comments