use super::CudaBufferPoolInner;
use crate::{
error::{select_resource_release_error, CudaError},
execution::completion::select_uncertain_completion_error,
};
use std::sync::Arc;
#[derive(Debug)]
pub(crate) struct CudaBufferPoolReuseGuard {
pub(super) pool: Arc<CudaBufferPoolInner>,
pub(super) active: bool,
}
impl CudaBufferPoolReuseGuard {
pub(crate) fn release(mut self) -> Result<(), CudaError> {
if let Err(error) = self.release_inner() {
if self.active {
std::mem::forget(self);
}
return Err(error);
}
Ok(())
}
pub(crate) fn synchronize_pool_context(&self) -> crate::execution::CudaSynchronizationOutcome {
self.pool.context.synchronize_for_resource_release()
}
pub(crate) fn synchronize_and_release(self) -> Result<(), CudaError> {
let outcome = self.synchronize_pool_context();
if !outcome.completion_established() {
let result = outcome.into_result();
self.abandon();
return result;
}
self.release()
}
pub(crate) fn synchronize_then_error<T>(self, error: CudaError) -> Result<T, CudaError> {
if self.pool.context.inner.resource_lifetimes_poisoned() {
self.abandon();
return Err(select_uncertain_completion_error(error, None));
}
if let Err(completion_error) = self.synchronize_pool_context().into_result() {
self.abandon();
return Err(select_uncertain_completion_error(
error,
Some(completion_error),
));
}
match self.release() {
Ok(()) => Err(error),
Err(release_error) => Err(select_resource_release_error(error, release_error)),
}
}
pub(crate) fn release_after_recoverable_operation_error<T>(
self,
primary_error: CudaError,
) -> Result<T, CudaError> {
if self.pool.context.inner.resource_lifetimes_poisoned() {
self.abandon();
return Err(primary_error);
}
match self.release() {
Ok(()) => Err(primary_error),
Err(release_error) => Err(select_resource_release_error(primary_error, release_error)),
}
}
pub(crate) fn abandon(self) {
std::mem::forget(self);
}
fn release_inner(&mut self) -> Result<(), CudaError> {
if !self.active {
return Ok(());
}
match self.pool.release_reuse_hold() {
Ok(()) => {
self.active = false;
Ok(())
}
Err(error @ CudaError::HostAllocationFailed { .. }) => {
self.active = false;
Err(error)
}
Err(error) => Err(error),
}
}
}
impl Drop for CudaBufferPoolReuseGuard {
fn drop(&mut self) {
if self.active {
let outcome = self.pool.context.synchronize_for_resource_release();
if outcome.completion_established() {
if self.release_inner().is_err() && self.active {
std::mem::forget(self.pool.clone());
}
} else {
std::mem::forget(self.pool.clone());
}
}
}
}