use crate::ibverbs::completion_queue::CompletionQueue;
use crate::ibverbs::device::{Device, IB_PORT};
use crate::ibverbs::error::{IbvError, IbvResult};
use crate::ibverbs::protection_domain::ProtectionDomain;
use ibverbs_sys::*;
use std::io;
use std::sync::Arc;
#[doc(alias = "ibv_context")]
#[doc(alias = "ibv_open_device")]
#[derive(Debug, Clone)]
pub struct Context {
pub(crate) inner: Arc<ContextInner>,
}
impl Context {
pub fn create_cq(&self, min_cq_entries: u32) -> IbvResult<CompletionQueue> {
CompletionQueue::create(self, min_cq_entries)
}
pub fn allocate_pd(&self) -> IbvResult<ProtectionDomain> {
ProtectionDomain::allocate(self)
}
}
impl Context {
pub fn from_device(dev: &Device) -> IbvResult<Self> {
let ibv_ctx = unsafe { ibv_open_device(dev.device_ptr) };
if ibv_ctx.is_null() {
return Err(IbvError::from_errno_with_msg(
io::Error::last_os_error()
.raw_os_error()
.expect("ibv_open_device should set errno on error"),
"Failed to open device context",
));
}
let context = Self {
inner: Arc::new(ContextInner { ctx: ibv_ctx }),
};
context.inner.query_port()?;
log::debug!("Context opened");
Ok(context)
}
pub fn device(&self) -> Device<'_> {
unsafe { Device::from_ptr((&*self.inner.ctx).device) }
}
}
pub(crate) struct ContextInner {
pub(crate) ctx: *mut ibv_context,
}
unsafe impl Sync for ContextInner {}
unsafe impl Send for ContextInner {}
impl Drop for ContextInner {
fn drop(&mut self) {
log::debug!("Context closed");
if unsafe { ibv_close_device(self.ctx) } != 0 {
let error = IbvError::from_errno_with_msg(
io::Error::last_os_error()
.raw_os_error()
.expect("ibv_close_device should set errno on error"),
"Failed to close context",
);
log::error!("{error}");
}
}
}
impl std::fmt::Debug for ContextInner {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Context")
.field("device", &unsafe { Device::from_ptr((&*self.ctx).device) })
.finish()
}
}
impl ContextInner {
pub(crate) fn query_port(&self) -> IbvResult<ibv_port_attr> {
let mut port_attr = ibv_port_attr::default();
let errno = unsafe {
ibv_query_port(
self.ctx,
IB_PORT,
&mut port_attr as *mut ibv_port_attr as *mut _,
)
};
if errno != 0 {
return Err(IbvError::from_errno_with_msg(errno, "Failed to query port"));
}
match port_attr.state {
ibv_port_state::IBV_PORT_ACTIVE | ibv_port_state::IBV_PORT_ARMED => Ok(port_attr),
state => Err(IbvError::Resource(format!(
"Port is in state {:?} (expected ACTIVE or ARMED)",
state
))),
}
}
}