|
13 | 13 | use kyron_foundation::prelude::*; |
14 | 14 | use kyron_foundation::{not_recoverable_error, prelude::CommonErrors}; |
15 | 15 |
|
| 16 | +use crate::scheduler::context::ctx_set_running_task; |
16 | 17 | use crate::{ |
17 | 18 | futures::{FutureInternalReturn, FutureState}, |
18 | 19 | TaskRef, |
@@ -74,34 +75,52 @@ impl<T: Send + 'static> Future for JoinHandle<T> { |
74 | 75 | if was_set { |
75 | 76 | FutureInternalReturn::default() |
76 | 77 | } else { |
| 78 | + // Check whether there is safety error for the completed task |
| 79 | + let task_hdr = TaskRef::into_raw(self.for_task.clone()); |
| 80 | + if unsafe { (*task_hdr).get_safety_error() } { |
| 81 | + // Change the running task to safety task to schedule the current task into safety worker |
| 82 | + ctx_set_running_task(task_hdr); |
| 83 | + waker.wake_by_ref(); |
| 84 | + FutureInternalReturn::polled() |
| 85 | + } else { |
| 86 | + let mut ret: Result<T, CommonErrors> = Err(CommonErrors::NoData); |
| 87 | + let ret_as_ptr = &mut ret as *mut _; |
| 88 | + self.for_task.get_return_val(ret_as_ptr as *mut u8); |
| 89 | + |
| 90 | + match ret { |
| 91 | + Ok(v) => FutureInternalReturn::ready(Ok(v)), |
| 92 | + Err(CommonErrors::OperationAborted) => FutureInternalReturn::ready(Err(CommonErrors::OperationAborted)), |
| 93 | + Err(e) => { |
| 94 | + not_recoverable_error!(with e, "There has been an error in a task that is not recoverable ({})!"); |
| 95 | + } |
| 96 | + } |
| 97 | + } |
| 98 | + } |
| 99 | + } |
| 100 | + FutureState::Polled => { |
| 101 | + let waker = cx.waker(); |
| 102 | + |
| 103 | + // Set the waker, return values tells what have happen and took care about correct synchronization |
| 104 | + let was_set = self.for_task.set_join_handle_waker(waker.clone()); |
| 105 | + |
| 106 | + if was_set { |
| 107 | + FutureInternalReturn::default() |
| 108 | + } else { |
| 109 | + // Safety belows forms AqrRel so waker is really written before we do marking |
77 | 110 | let mut ret: Result<T, CommonErrors> = Err(CommonErrors::NoData); |
78 | 111 | let ret_as_ptr = &mut ret as *mut _; |
79 | 112 | self.for_task.get_return_val(ret_as_ptr as *mut u8); |
80 | 113 |
|
81 | 114 | match ret { |
82 | 115 | Ok(v) => FutureInternalReturn::ready(Ok(v)), |
| 116 | + Err(CommonErrors::NoData) => FutureInternalReturn::polled(), |
83 | 117 | Err(CommonErrors::OperationAborted) => FutureInternalReturn::ready(Err(CommonErrors::OperationAborted)), |
84 | 118 | Err(e) => { |
85 | 119 | not_recoverable_error!(with e, "There has been an error in a task that is not recoverable ({})!"); |
86 | 120 | } |
87 | 121 | } |
88 | 122 | } |
89 | 123 | } |
90 | | - FutureState::Polled => { |
91 | | - // Safety belows forms AqrRel so waker is really written before we do marking |
92 | | - let mut ret: Result<T, CommonErrors> = Err(CommonErrors::NoData); |
93 | | - let ret_as_ptr = &mut ret as *mut _; |
94 | | - self.for_task.get_return_val(ret_as_ptr as *mut u8); |
95 | | - |
96 | | - match ret { |
97 | | - Ok(v) => FutureInternalReturn::ready(Ok(v)), |
98 | | - Err(CommonErrors::NoData) => FutureInternalReturn::polled(), |
99 | | - Err(CommonErrors::OperationAborted) => FutureInternalReturn::ready(Err(CommonErrors::OperationAborted)), |
100 | | - Err(e) => { |
101 | | - not_recoverable_error!(with e, "There has been an error in a task that is not recoverable ({})!"); |
102 | | - } |
103 | | - } |
104 | | - } |
105 | 124 | FutureState::Finished => { |
106 | 125 | not_recoverable_error!("Future polled after it finished!"); |
107 | 126 | } |
@@ -130,6 +149,7 @@ mod tests { |
130 | 149 | use kyron_testing::prelude::*; |
131 | 150 |
|
132 | 151 | #[test] |
| 152 | + #[cfg(not(miri))] |
133 | 153 | fn test_join_handler_ready_task_get_correct_result_to_handle() { |
134 | 154 | let scheduler = create_mock_scheduler(); |
135 | 155 |
|
@@ -175,6 +195,7 @@ mod tests { |
175 | 195 | } |
176 | 196 |
|
177 | 197 | #[test] |
| 198 | + #[cfg(not(miri))] |
178 | 199 | fn test_join_handler_aborted_task_produce_handle_abort_result() { |
179 | 200 | let scheduler = create_mock_scheduler(); |
180 | 201 |
|
@@ -205,6 +226,7 @@ mod tests { |
205 | 226 | } |
206 | 227 |
|
207 | 228 | #[test] |
| 229 | + #[cfg(not(miri))] |
208 | 230 | #[should_panic] |
209 | 231 | fn test_join_handler_panics_when_fetched_data_and_repolled() { |
210 | 232 | let scheduler = create_mock_scheduler(); |
@@ -256,6 +278,40 @@ mod tests { |
256 | 278 | assert_eq!(poller.poll(), ::core::task::Poll::Ready(Ok(0))); |
257 | 279 | } |
258 | 280 | } |
| 281 | + |
| 282 | + #[test] |
| 283 | + fn test_join_handle_waker_is_set_in_polled_state_also() { |
| 284 | + let scheduler = create_mock_scheduler(); |
| 285 | + |
| 286 | + { |
| 287 | + // Data is present before first poll of join handle |
| 288 | + let task = ArcInternal::new(AsyncTask::new(box_future(test_function::<u32>()), 1, scheduler.clone())); |
| 289 | + |
| 290 | + let handle = JoinHandle::<u32>::new(TaskRef::new(task.clone())); |
| 291 | + |
| 292 | + let mut poller = TestingFuturePoller::new(handle); |
| 293 | + |
| 294 | + let waker_mock1 = TrackableWaker::new(); |
| 295 | + let waker1 = waker_mock1.get_waker(); |
| 296 | + |
| 297 | + let waker_mock2 = TrackableWaker::new(); |
| 298 | + let waker2 = waker_mock2.get_waker(); |
| 299 | + |
| 300 | + let _ = poller.poll_with_waker(&waker1); |
| 301 | + // Now in polled state, poll again with waker2 |
| 302 | + let _ = poller.poll_with_waker(&waker2); |
| 303 | + { |
| 304 | + let waker = noop_waker(); |
| 305 | + let mut cx = Context::from_waker(&waker); |
| 306 | + task.poll(&mut cx); // task done |
| 307 | + } |
| 308 | + |
| 309 | + assert!(!waker_mock1.was_waked()); |
| 310 | + // this should be TRUE |
| 311 | + assert!(waker_mock2.was_waked()); |
| 312 | + assert_eq!(poller.poll(), ::core::task::Poll::Ready(Ok(0))); |
| 313 | + } |
| 314 | + } |
259 | 315 | } |
260 | 316 |
|
261 | 317 | #[cfg(test)] |
|
0 commit comments