1#![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)]
8#![warn(missing_debug_implementations)]
9
10use core::ffi::{c_char, c_int, c_uint, c_void};
11use std::sync::OnceLock;
12
13use baracuda_core::{Library, LoaderError};
14use baracuda_types::CudaStatus;
15
16#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
18#[repr(transparent)]
19pub struct CUfileOpError(pub i32);
20
21impl CUfileOpError {
22 pub const SUCCESS: Self = Self(0);
23 pub const INTERNAL: Self = Self(5001);
24 pub const DRIVER_NOT_INITIALIZED: Self = Self(5002);
25 pub const IO_NOT_SUPPORTED: Self = Self(5003);
26 pub const NOT_REGISTERED: Self = Self(5004);
27 pub const INVALID_FILE_HANDLE: Self = Self(5005);
28
29 pub const fn is_success(self) -> bool {
30 self.0 == 0
31 }
32}
33
34impl CudaStatus for CUfileOpError {
35 fn code(self) -> i32 {
36 self.0
37 }
38 fn name(self) -> &'static str {
39 match self.0 {
40 0 => "CU_FILE_SUCCESS",
41 5001 => "CU_FILE_INTERNAL_ERROR",
42 5002 => "CU_FILE_DRIVER_NOT_INITIALIZED",
43 5003 => "CU_FILE_IO_NOT_SUPPORTED",
44 5004 => "CU_FILE_NOT_REGISTERED",
45 5005 => "CU_FILE_INVALID_FILE_HANDLE",
46 _ => "CU_FILE_UNRECOGNIZED",
47 }
48 }
49 fn description(self) -> &'static str {
50 match self.0 {
51 0 => "success",
52 5002 => "cuFile driver not initialized — call cuFileDriverOpen first",
53 5003 => "I/O not supported on this file / filesystem",
54 _ => "unrecognized cuFile status code",
55 }
56 }
57 fn is_success(self) -> bool {
58 CUfileOpError::is_success(self)
59 }
60 fn library(self) -> &'static str {
61 "cufile"
62 }
63}
64
65#[repr(C)]
68#[derive(Copy, Clone, Debug)]
69pub struct CUfileError_t {
70 pub err: CUfileOpError,
71 pub cu_err: c_int, }
73
74pub type CUfileHandle_t = *mut c_void;
76
77#[repr(C)]
81#[derive(Copy, Clone, Debug)]
82pub struct CUfileDescr_t {
83 pub handle_type: c_int,
85 pub handle_fd: c_int,
86 pub _reserved: [u8; 40],
89 pub fs_ops: *mut c_void,
90}
91
92impl Default for CUfileDescr_t {
93 fn default() -> Self {
94 Self {
95 handle_type: 1, handle_fd: -1,
97 _reserved: [0; 40],
98 fs_ops: core::ptr::null_mut(),
99 }
100 }
101}
102
103pub type PFN_cuFileDriverOpen = unsafe extern "C" fn() -> CUfileError_t;
106pub type PFN_cuFileDriverClose = unsafe extern "C" fn() -> CUfileError_t;
107pub type PFN_cuFileDriverGetProperties = unsafe extern "C" fn(props: *mut c_void) -> CUfileError_t;
108pub type PFN_cuFileDriverSetPollMode =
109 unsafe extern "C" fn(poll: bool, poll_threshold_size: usize) -> CUfileError_t;
110
111pub type PFN_cuFileHandleRegister =
112 unsafe extern "C" fn(fh: *mut CUfileHandle_t, descr: *mut CUfileDescr_t) -> CUfileError_t;
113pub type PFN_cuFileHandleDeregister = unsafe extern "C" fn(fh: CUfileHandle_t);
114
115pub type PFN_cuFileBufRegister =
116 unsafe extern "C" fn(buf_ptr: *mut c_void, length: usize, flags: c_int) -> CUfileError_t;
117pub type PFN_cuFileBufDeregister = unsafe extern "C" fn(buf_ptr: *mut c_void) -> CUfileError_t;
118
119pub type PFN_cuFileRead = unsafe extern "C" fn(
120 fh: CUfileHandle_t,
121 buf_ptr: *mut c_void,
122 size: usize,
123 file_offset: i64,
124 buf_ptr_offset: i64,
125) -> isize;
126pub type PFN_cuFileWrite = unsafe extern "C" fn(
127 fh: CUfileHandle_t,
128 buf_ptr: *const c_void,
129 size: usize,
130 file_offset: i64,
131 buf_ptr_offset: i64,
132) -> isize;
133
134pub type PFN_cuFileGetVersion = unsafe extern "C" fn(version: *mut c_int) -> CUfileError_t;
135
136pub type PFN_cuFileOpStatusError = unsafe extern "C" fn(status: CUfileOpError) -> *const c_char;
137
138pub type PFN_cuFileReadAsync = unsafe extern "C" fn(
141 fh: CUfileHandle_t,
142 buf_ptr: *mut c_void,
143 size_p: *mut usize,
144 file_offset_p: *mut i64,
145 buf_ptr_offset_p: *mut i64,
146 bytes_read: *mut isize,
147 stream: *mut c_void,
148) -> CUfileError_t;
149
150pub type PFN_cuFileWriteAsync = unsafe extern "C" fn(
151 fh: CUfileHandle_t,
152 buf_ptr: *const c_void,
153 size_p: *mut usize,
154 file_offset_p: *mut i64,
155 buf_ptr_offset_p: *mut i64,
156 bytes_written: *mut isize,
157 stream: *mut c_void,
158) -> CUfileError_t;
159
160pub type PFN_cuFileStreamRegister =
161 unsafe extern "C" fn(stream: *mut c_void, flags: c_uint) -> CUfileError_t;
162
163pub type PFN_cuFileStreamDeregister = unsafe extern "C" fn(stream: *mut c_void) -> CUfileError_t;
164
165#[allow(non_snake_case)]
169pub mod CUfileOpcode {
170 pub const READ: i32 = 0;
171 pub const WRITE: i32 = 1;
172}
173
174#[repr(C)]
181#[derive(Copy, Clone, Debug)]
182pub struct CUfileIOParams_t {
183 pub mode: c_int, pub fh: CUfileHandle_t,
185 pub opcode: c_int,
186 pub cookie: *mut c_void,
187 pub dev_ptr_base: *mut c_void,
188 pub file_offset: i64,
189 pub dev_ptr_offset: i64,
190 pub size: usize,
191}
192
193impl Default for CUfileIOParams_t {
194 fn default() -> Self {
195 Self {
196 mode: 0,
197 fh: core::ptr::null_mut(),
198 opcode: 0,
199 cookie: core::ptr::null_mut(),
200 dev_ptr_base: core::ptr::null_mut(),
201 file_offset: 0,
202 dev_ptr_offset: 0,
203 size: 0,
204 }
205 }
206}
207
208#[repr(C)]
210#[derive(Copy, Clone, Debug, Default)]
211pub struct CUfileIOEvents_t {
212 pub cookie: *mut c_void,
213 pub status: c_int,
214 pub ret: usize,
215}
216
217unsafe impl Send for CUfileIOEvents_t {}
218
219pub type CUfileBatchHandle_t = *mut c_void;
221
222pub type PFN_cuFileBatchIOSetUp = unsafe extern "C" fn(
223 batch_handle_out: *mut CUfileBatchHandle_t,
224 num_batches: c_uint,
225) -> CUfileError_t;
226
227pub type PFN_cuFileBatchIOSubmit = unsafe extern "C" fn(
228 batch_handle: CUfileBatchHandle_t,
229 num_entries: c_uint,
230 io_batch_params: *mut CUfileIOParams_t,
231 flags: c_uint,
232) -> CUfileError_t;
233
234pub type PFN_cuFileBatchIOGetStatus = unsafe extern "C" fn(
235 batch_handle: CUfileBatchHandle_t,
236 min_nr: c_uint,
237 nr: *mut c_uint,
238 io_batch_events: *mut CUfileIOEvents_t,
239 timeout: *mut c_void, ) -> CUfileError_t;
241
242pub type PFN_cuFileBatchIOCancel =
243 unsafe extern "C" fn(batch_handle: CUfileBatchHandle_t) -> CUfileError_t;
244
245pub type PFN_cuFileBatchIODestroy =
246 unsafe extern "C" fn(batch_handle: CUfileBatchHandle_t) -> CUfileError_t;
247
248pub type PFN_cuFileUseCount = unsafe extern "C" fn(fh: CUfileHandle_t) -> c_int;
251
252pub type PFN_cuFileDriverSetMaxDirectIOSize =
255 unsafe extern "C" fn(max_direct_io_size_kb: usize) -> CUfileError_t;
256
257pub type PFN_cuFileDriverSetMaxCacheSize =
258 unsafe extern "C" fn(max_cache_size_kb: usize) -> CUfileError_t;
259
260pub type PFN_cuFileDriverSetMaxPinnedMemSize =
261 unsafe extern "C" fn(max_pinned_size_kb: usize) -> CUfileError_t;
262
263macro_rules! cufile_fns {
266 ($($(#[$attr:meta])* fn $name:ident as $sym:literal : $pfn:ty;)*) => {
267 pub struct Cufile {
268 pub lib: Library,
269 $(
270 $name: OnceLock<$pfn>,
271 )*
272 }
273
274 impl core::fmt::Debug for Cufile {
275 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
276 f.debug_struct("Cufile").field("lib", &self.lib).finish_non_exhaustive()
277 }
278 }
279
280 impl Cufile {
281 #[allow(dead_code)]
282 fn empty(lib: Library) -> Self {
283 Self { lib, $($name: OnceLock::new(),)* }
284 }
285 $(
286 $(#[$attr])*
287 #[doc = concat!("Resolve `", $sym, "`.")]
288 pub fn $name(&self) -> Result<$pfn, LoaderError> {
289 if let Some(&p) = self.$name.get() { return Ok(p); }
290 let raw: *mut () = unsafe { self.lib.raw_symbol($sym)? };
291 let p: $pfn = unsafe { core::mem::transmute_copy::<*mut (), $pfn>(&raw) };
292 let _ = self.$name.set(p);
293 Ok(p)
294 }
295 )*
296 }
297 };
298}
299
300cufile_fns! {
301 fn cu_file_driver_open as "cuFileDriverOpen": PFN_cuFileDriverOpen;
302 fn cu_file_driver_close as "cuFileDriverClose": PFN_cuFileDriverClose;
303 fn cu_file_driver_get_properties as "cuFileDriverGetProperties":
304 PFN_cuFileDriverGetProperties;
305 fn cu_file_driver_set_poll_mode as "cuFileDriverSetPollMode":
306 PFN_cuFileDriverSetPollMode;
307 fn cu_file_handle_register as "cuFileHandleRegister": PFN_cuFileHandleRegister;
308 fn cu_file_handle_deregister as "cuFileHandleDeregister": PFN_cuFileHandleDeregister;
309 fn cu_file_buf_register as "cuFileBufRegister": PFN_cuFileBufRegister;
310 fn cu_file_buf_deregister as "cuFileBufDeregister": PFN_cuFileBufDeregister;
311 fn cu_file_read as "cuFileRead": PFN_cuFileRead;
312 fn cu_file_write as "cuFileWrite": PFN_cuFileWrite;
313 fn cu_file_get_version as "cuFileGetVersion": PFN_cuFileGetVersion;
314 fn cu_file_op_status_error as "cuFileGetOpStatusErrorString":
315 PFN_cuFileOpStatusError;
316
317 fn cu_file_read_async as "cuFileReadAsync": PFN_cuFileReadAsync;
319 fn cu_file_write_async as "cuFileWriteAsync": PFN_cuFileWriteAsync;
320 fn cu_file_stream_register as "cuFileStreamRegister": PFN_cuFileStreamRegister;
321 fn cu_file_stream_deregister as "cuFileStreamDeregister": PFN_cuFileStreamDeregister;
322
323 fn cu_file_batch_io_set_up as "cuFileBatchIOSetUp": PFN_cuFileBatchIOSetUp;
325 fn cu_file_batch_io_submit as "cuFileBatchIOSubmit": PFN_cuFileBatchIOSubmit;
326 fn cu_file_batch_io_get_status as "cuFileBatchIOGetStatus": PFN_cuFileBatchIOGetStatus;
327 fn cu_file_batch_io_cancel as "cuFileBatchIOCancel": PFN_cuFileBatchIOCancel;
328 fn cu_file_batch_io_destroy as "cuFileBatchIODestroy": PFN_cuFileBatchIODestroy;
329
330 fn cu_file_use_count as "cuFileUseCount": PFN_cuFileUseCount;
332
333 fn cu_file_driver_set_max_direct_io_size as "cuFileDriverSetMaxDirectIOSize":
335 PFN_cuFileDriverSetMaxDirectIOSize;
336 fn cu_file_driver_set_max_cache_size as "cuFileDriverSetMaxCacheSize":
337 PFN_cuFileDriverSetMaxCacheSize;
338 fn cu_file_driver_set_max_pinned_mem_size as "cuFileDriverSetMaxPinnedMemSize":
339 PFN_cuFileDriverSetMaxPinnedMemSize;
340}
341
342#[cfg(target_os = "linux")]
343fn cufile_candidates() -> &'static [&'static str] {
344 &["libcufile.so.0", "libcufile.so"]
345}
346
347pub fn cufile() -> Result<&'static Cufile, LoaderError> {
348 static CUFILE: OnceLock<Cufile> = OnceLock::new();
349 if let Some(c) = CUFILE.get() {
350 return Ok(c);
351 }
352 #[cfg(not(target_os = "linux"))]
353 {
354 Err(LoaderError::UnsupportedPlatform {
355 platform: std::env::consts::OS,
356 })
357 }
358 #[cfg(target_os = "linux")]
359 {
360 let lib = Library::open("cufile", cufile_candidates())?;
361 let _ = CUFILE.set(Cufile::empty(lib));
362 Ok(CUFILE.get().expect("OnceLock set or lost race"))
363 }
364}