66//! variable.
77
88use 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;
1014use core:: marker:: PhantomPinned ;
1115use macros:: pin_data;
1216
@@ -102,7 +106,12 @@ impl CondVar {
102106 } )
103107 }
104108
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 {
106115 let wait = Opaque :: < bindings:: wait_queue_entry > :: uninit ( ) ;
107116
108117 // SAFETY: `wait` points to valid memory.
@@ -113,11 +122,13 @@ impl CondVar {
113122 bindings:: prepare_to_wait_exclusive ( self . wait_list . get ( ) , wait. get ( ) , wait_state as _ )
114123 } ;
115124
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 ) } ) ;
118127
119128 // SAFETY: Both `wait` and `wait_list` point to valid memory.
120129 unsafe { bindings:: finish_wait ( self . wait_list . get ( ) , wait. get ( ) ) } ;
130+
131+ ret
121132 }
122133
123134 /// Releases the lock and waits for a notification in uninterruptible mode.
@@ -127,7 +138,7 @@ impl CondVar {
127138 /// [`CondVar::notify_one`] or [`CondVar::notify_all`]. Note that it may also wake up
128139 /// spuriously.
129140 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 ) ;
131142 }
132143
133144 /// Releases the lock and waits for a notification in interruptible mode.
@@ -138,10 +149,31 @@ impl CondVar {
138149 /// Returns whether there is a signal pending.
139150 #[ must_use = "wait_interruptible returns if a signal is pending, so the caller must check the return value" ]
140151 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 ) ;
142153 crate :: current!( ) . signal_pending ( )
143154 }
144155
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+
145177 /// Calls the kernel function to notify the appropriate number of threads with the given flags.
146178 fn notify ( & self , count : i32 , flags : u32 ) {
147179 // SAFETY: `wait_list` points to valid memory.
@@ -177,3 +209,19 @@ impl CondVar {
177209 self . notify ( 0 , 0 ) ;
178210 }
179211}
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