Refactor futex wait with timeout
This commit is contained in:
		
							parent
							
								
									b177eb2068
								
							
						
					
					
						commit
						e0b47b3a76
					
				| @ -109,6 +109,7 @@ fn wait_for_other_threads_to_exit(current_ref: &ThreadRef) { | |||||||
|     let timeout = FutexTimeout::new( |     let timeout = FutexTimeout::new( | ||||||
|         ClockID::CLOCK_MONOTONIC, |         ClockID::CLOCK_MONOTONIC, | ||||||
|         timespec_t::from(Duration::from_millis(50)), |         timespec_t::from(Duration::from_millis(50)), | ||||||
|  |         false, | ||||||
|     ); |     ); | ||||||
|     // Use calling process's pointer as futex value
 |     // Use calling process's pointer as futex value
 | ||||||
|     let futex_val = Arc::as_ptr(current_ref.process()) as *const i32; |     let futex_val = Arc::as_ptr(current_ref.process()) as *const i32; | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ use crate::time::{timespec_t, ClockID}; | |||||||
| /// `FutexOp`, `FutexFlags`, and `futex_op_and_flags_from_u32` are helper types and
 | /// `FutexOp`, `FutexFlags`, and `futex_op_and_flags_from_u32` are helper types and
 | ||||||
| /// functions for handling the versatile commands and arguments of futex system
 | /// functions for handling the versatile commands and arguments of futex system
 | ||||||
| /// call in a memory-safe way.
 | /// call in a memory-safe way.
 | ||||||
| 
 | #[derive(PartialEq)] | ||||||
| #[allow(non_camel_case_types)] | #[allow(non_camel_case_types)] | ||||||
| pub enum FutexOp { | pub enum FutexOp { | ||||||
|     FUTEX_WAIT = 0, |     FUTEX_WAIT = 0, | ||||||
| @ -77,11 +77,16 @@ const FUTEX_BITSET_MATCH_ANY: u32 = 0xFFFF_FFFF; | |||||||
| pub struct FutexTimeout { | pub struct FutexTimeout { | ||||||
|     clock_id: ClockID, |     clock_id: ClockID, | ||||||
|     ts: timespec_t, |     ts: timespec_t, | ||||||
|  |     absolute_time: bool, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl FutexTimeout { | impl FutexTimeout { | ||||||
|     pub fn new(clock_id: ClockID, ts: timespec_t) -> Self { |     pub fn new(clock_id: ClockID, ts: timespec_t, absolute_time: bool) -> Self { | ||||||
|         Self { clock_id, ts } |         Self { | ||||||
|  |             clock_id, | ||||||
|  |             ts, | ||||||
|  |             absolute_time, | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn clock_id(&self) -> &ClockID { |     pub fn clock_id(&self) -> &ClockID { | ||||||
| @ -91,6 +96,10 @@ impl FutexTimeout { | |||||||
|     pub fn ts(&self) -> ×pec_t { |     pub fn ts(&self) -> ×pec_t { | ||||||
|         &self.ts |         &self.ts | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     pub fn absolute_time(&self) -> bool { | ||||||
|  |         self.absolute_time | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Do futex wait
 | /// Do futex wait
 | ||||||
| @ -485,16 +494,20 @@ unsafe impl Sync for Waiter {} | |||||||
| fn wait_event_timeout(thread: *const c_void, timeout: &Option<FutexTimeout>) -> Result<()> { | fn wait_event_timeout(thread: *const c_void, timeout: &Option<FutexTimeout>) -> Result<()> { | ||||||
|     let mut ret: c_int = 0; |     let mut ret: c_int = 0; | ||||||
|     let mut sgx_ret: c_int = 0; |     let mut sgx_ret: c_int = 0; | ||||||
|     let (clockbit, ts_ptr) = timeout |     let (clockbit, ts_ptr, absolute_time) = timeout | ||||||
|         .as_ref() |         .as_ref() | ||||||
|         .map(|timeout| { |         .map(|timeout| { | ||||||
|             let clockbit = match timeout.clock_id() { |             let clockbit = match timeout.clock_id() { | ||||||
|                 ClockID::CLOCK_REALTIME => FutexFlags::FUTEX_CLOCK_REALTIME.bits() as i32, |                 ClockID::CLOCK_REALTIME => FutexFlags::FUTEX_CLOCK_REALTIME.bits() as i32, | ||||||
|                 _ => 0, |                 _ => 0, | ||||||
|             }; |             }; | ||||||
|             (clockbit, timeout.ts() as *const timespec_t) |             ( | ||||||
|  |                 clockbit, | ||||||
|  |                 timeout.ts() as *const timespec_t, | ||||||
|  |                 timeout.absolute_time() as i32, | ||||||
|  |             ) | ||||||
|         }) |         }) | ||||||
|         .unwrap_or((0, 0 as *const _)); |         .unwrap_or((0, 0 as *const _, 0)); | ||||||
|     let mut errno: c_int = 0; |     let mut errno: c_int = 0; | ||||||
|     unsafe { |     unsafe { | ||||||
|         sgx_ret = sgx_thread_wait_untrusted_event_timeout_ocall( |         sgx_ret = sgx_thread_wait_untrusted_event_timeout_ocall( | ||||||
| @ -502,6 +515,7 @@ fn wait_event_timeout(thread: *const c_void, timeout: &Option<FutexTimeout>) -> | |||||||
|             thread, |             thread, | ||||||
|             clockbit, |             clockbit, | ||||||
|             ts_ptr, |             ts_ptr, | ||||||
|  |             absolute_time, | ||||||
|             &mut errno as *mut c_int, |             &mut errno as *mut c_int, | ||||||
|         ); |         ); | ||||||
|         assert!(sgx_ret == 0); |         assert!(sgx_ret == 0); | ||||||
| @ -550,6 +564,7 @@ extern "C" { | |||||||
|         self_thread: *const c_void, |         self_thread: *const c_void, | ||||||
|         clockbit: i32, |         clockbit: i32, | ||||||
|         ts: *const timespec_t, |         ts: *const timespec_t, | ||||||
|  |         absolute_time: i32, | ||||||
|         errno: *mut c_int, |         errno: *mut c_int, | ||||||
|     ) -> c_int; |     ) -> c_int; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -282,6 +282,14 @@ pub fn do_futex( | |||||||
|         ts.validate()?; |         ts.validate()?; | ||||||
|         // TODO: use a secure clock to transfer the real time to monotonic time
 |         // TODO: use a secure clock to transfer the real time to monotonic time
 | ||||||
|         let clock_id = if futex_flags.contains(FutexFlags::FUTEX_CLOCK_REALTIME) { |         let clock_id = if futex_flags.contains(FutexFlags::FUTEX_CLOCK_REALTIME) { | ||||||
|  |             // FUTEX_WAIT can't work with FUTEX_CLOCK_REALTIME. This rule is applied by Linux. And we shall just obey it.
 | ||||||
|  |             // Reference: https://github.com/torvalds/linux/commit/4fbf5d6837bf81fd7a27d771358f4ee6c4f243f8
 | ||||||
|  |             if futex_op == FutexOp::FUTEX_WAIT { | ||||||
|  |                 return_errno!( | ||||||
|  |                     ENOSYS, | ||||||
|  |                     "FUTEX_CLOCK_REALTIME with this futex operation is not supported" | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|             ClockID::CLOCK_REALTIME |             ClockID::CLOCK_REALTIME | ||||||
|         } else { |         } else { | ||||||
|             ClockID::CLOCK_MONOTONIC |             ClockID::CLOCK_MONOTONIC | ||||||
| @ -291,24 +299,14 @@ pub fn do_futex( | |||||||
|         // for FUTEX_WAIT, timeout is interpreted as a relative value. This differs from other futex operations, where
 |         // for FUTEX_WAIT, timeout is interpreted as a relative value. This differs from other futex operations, where
 | ||||||
|         // timeout is interpreted as an absolute value. To obtain the equivalent of FUTEX_WAIT with an absolute timeout,
 |         // timeout is interpreted as an absolute value. To obtain the equivalent of FUTEX_WAIT with an absolute timeout,
 | ||||||
|         // employ FUTEX_WAIT_BITSET with val3 specified as FUTEX_BITSET_MATCH_ANY.
 |         // employ FUTEX_WAIT_BITSET with val3 specified as FUTEX_BITSET_MATCH_ANY.
 | ||||||
|         //
 |         let absolute_time = { | ||||||
|         // However, in Occlum, we prefer to use relative value for timeout for performance consideration because getting current time
 |             match futex_op { | ||||||
|         // requires an extra ocall.
 |                 FutexOp::FUTEX_WAIT => false, | ||||||
|         let ts = match futex_op { |                 _ => true, | ||||||
|             FutexOp::FUTEX_WAIT => ts, |  | ||||||
|             _ => { |  | ||||||
|                 let relative_ts = { |  | ||||||
|                     let absolute_ts = ts.as_duration(); |  | ||||||
|                     let current_ts = crate::time::do_clock_gettime(clock_id)?.as_duration(); |  | ||||||
|                     debug_assert!(current_ts <= absolute_ts); |  | ||||||
| 
 |  | ||||||
|                     timespec_t::from(absolute_ts - current_ts) |  | ||||||
|                 }; |  | ||||||
|                 relative_ts |  | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         Ok(Some(FutexTimeout::new(clock_id, ts))) |         Ok(Some(FutexTimeout::new(clock_id, ts, absolute_time))) | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     match futex_op { |     match futex_op { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user