Fix Buffer Mapping Deadlock (#5518)

This commit is contained in:
Connor Fitzgerald 2024-04-17 20:41:51 -04:00 committed by GitHub
parent 1735968969
commit 152fd0930a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -808,29 +808,33 @@ impl<A: HalApi> LifetimeTracker<A> {
*buffer.map_state.lock() = resource::BufferMapState::Idle; *buffer.map_state.lock() = resource::BufferMapState::Idle;
log::trace!("Buffer ready to map {tracker_index:?} is not tracked anymore"); log::trace!("Buffer ready to map {tracker_index:?} is not tracked anymore");
} else { } else {
let mapping = match std::mem::replace( // This _cannot_ be inlined into the match. If it is, the lock will be held
// open through the whole match, resulting in a deadlock when we try to re-lock
// the buffer back to active.
let mapping = std::mem::replace(
&mut *buffer.map_state.lock(), &mut *buffer.map_state.lock(),
resource::BufferMapState::Idle, resource::BufferMapState::Idle,
) { );
let pending_mapping = match mapping {
resource::BufferMapState::Waiting(pending_mapping) => pending_mapping, resource::BufferMapState::Waiting(pending_mapping) => pending_mapping,
// Mapping cancelled // Mapping cancelled
resource::BufferMapState::Idle => continue, resource::BufferMapState::Idle => continue,
// Mapping queued at least twice by map -> unmap -> map // Mapping queued at least twice by map -> unmap -> map
// and was already successfully mapped below // and was already successfully mapped below
active @ resource::BufferMapState::Active { .. } => { resource::BufferMapState::Active { .. } => {
*buffer.map_state.lock() = active; *buffer.map_state.lock() = mapping;
continue; continue;
} }
_ => panic!("No pending mapping."), _ => panic!("No pending mapping."),
}; };
let status = if mapping.range.start != mapping.range.end { let status = if pending_mapping.range.start != pending_mapping.range.end {
log::debug!("Buffer {tracker_index:?} map state -> Active"); log::debug!("Buffer {tracker_index:?} map state -> Active");
let host = mapping.op.host; let host = pending_mapping.op.host;
let size = mapping.range.end - mapping.range.start; let size = pending_mapping.range.end - pending_mapping.range.start;
match super::map_buffer( match super::map_buffer(
raw, raw,
&buffer, &buffer,
mapping.range.start, pending_mapping.range.start,
size, size,
host, host,
snatch_guard, snatch_guard,
@ -838,7 +842,8 @@ impl<A: HalApi> LifetimeTracker<A> {
Ok(ptr) => { Ok(ptr) => {
*buffer.map_state.lock() = resource::BufferMapState::Active { *buffer.map_state.lock() = resource::BufferMapState::Active {
ptr, ptr,
range: mapping.range.start..mapping.range.start + size, range: pending_mapping.range.start
..pending_mapping.range.start + size,
host, host,
}; };
Ok(()) Ok(())
@ -851,12 +856,12 @@ impl<A: HalApi> LifetimeTracker<A> {
} else { } else {
*buffer.map_state.lock() = resource::BufferMapState::Active { *buffer.map_state.lock() = resource::BufferMapState::Active {
ptr: std::ptr::NonNull::dangling(), ptr: std::ptr::NonNull::dangling(),
range: mapping.range, range: pending_mapping.range,
host: mapping.op.host, host: pending_mapping.op.host,
}; };
Ok(()) Ok(())
}; };
pending_callbacks.push((mapping.op, status)); pending_callbacks.push((pending_mapping.op, status));
} }
} }
pending_callbacks pending_callbacks