[oden-js] Promise completion needs to be more robust

As predicted.
This commit is contained in:
John Doty 2023-06-30 06:26:16 -07:00
parent 44c39b1740
commit b77e7eba3e

View file

@ -175,37 +175,44 @@ impl Runtime {
/// Process all pending async jobs. This includes all promise resolutions.
fn process_promise_completions(&self) {
// TODO: This could be more robust if we buffered all the completed
// promise entries and then dropped the borrow of the state, so
// that we never invoked user code while borrowing our private
// state mutably.
let mut promises = vec![];
// First, gather all the completed promises into a temporary vector
// so that we only need to borrow our mutable state for a short
// period of time.
let mut state = unsafe { PrivateState::from_rt_mut(self.rt) };
while let Ok((handle, evt)) = state.promise_recv.try_recv() {
if let Some(entry) = state.promise_table.remove(&handle) {
let ctx = ContextRef::from_raw(entry.context);
let (callback, value) = match evt {
PromiseEvent::Resolved(v) => (entry.resolve, v),
PromiseEvent::Rejected(v) => (entry.reject, v),
};
// Convert the result into a JS value, which we can only
// really do while we are on this thread.
let value = value(&ctx).expect("Should be able to convert promise result to value");
// Call the particular callback and make sure it doesn't throw.
ctx.check_exception(unsafe {
let mut args = [value.val];
sys::JS_Call(
entry.context,
callback,
sys::JS_MakeUndefined(),
1,
args.as_mut_ptr(),
)
})
.expect("Exception thrown by promise callback");
promises.push((entry, evt));
}
}
drop(state); // Don't need our internal state anymore.
// Nowe we can complete all the promises.
for (entry, evt) in promises {
let ctx = ContextRef::from_raw(entry.context);
let (callback, value) = match evt {
PromiseEvent::Resolved(v) => (entry.resolve, v),
PromiseEvent::Rejected(v) => (entry.reject, v),
};
// Convert the result into a JS value, which we can only
// really do while we are on this thread.
let value = value(&ctx).expect("Should be able to convert promise result to value");
// Call the particular callback and make sure it doesn't throw.
ctx.check_exception(unsafe {
let mut args = [value.val];
sys::JS_Call(
entry.context,
callback,
sys::JS_MakeUndefined(),
1,
args.as_mut_ptr(),
)
})
.expect("Exception thrown by promise callback");
}
}
/// Process all pending async jobs. This includes all promise resolutions.