1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
//! macOS kqueue async I/O implementation
//!
//! This module provides async I/O using macOS's kqueue interface.
//! kqueue is a scalable event notification interface available on
//! BSD-derived systems including macOS.
//!
//! While kqueue is primarily designed for socket and pipe I/O, this
//! implementation provides event-driven file operations using EVFILT_VNODE
//! for monitoring file changes and optimized batch operations.
use std::fs::{File, OpenOptions};
use std::io::{self, Read, Write};
use std::os::unix::io::{AsRawFd, RawFd};
use std::path::Path;
use super::AsyncFileIO;
#[cfg(target_os = "macos")]
use libc::{kevent, kqueue, timespec, EVFILT_VNODE, EV_ADD, EV_CLEAR, NOTE_WRITE};
/// kqueue-based async I/O implementation for macOS
///
/// Uses kqueue for event-driven file operations. This implementation
/// leverages EVFILT_VNODE for file monitoring and provides optimized
/// batch operations for serialization workloads.
pub struct KqueueIO {
#[cfg(target_os = "macos")]
kq: RawFd,
}
impl KqueueIO {
/// Create a new kqueue I/O instance
pub fn new() -> Self {
#[cfg(target_os = "macos")]
{
// SAFETY: kqueue() is a safe syscall that returns a file descriptor
let kq = unsafe { kqueue() };
Self { kq }
}
#[cfg(not(target_os = "macos"))]
{
Self {}
}
}
/// Check if kqueue is available (always true on macOS)
pub fn is_available() -> bool {
cfg!(target_os = "macos")
}
/// Perform event-driven write operation
///
/// This method uses kqueue to monitor file write completion,
/// enabling efficient batch operations.
#[cfg(target_os = "macos")]
fn write_with_event(&self, path: &Path, data: &[u8]) -> io::Result<()> {
// Ensure parent directory exists
if let Some(parent) = path.parent() {
if !parent.as_os_str().is_empty() && !parent.exists() {
std::fs::create_dir_all(parent)?;
}
}
// Open file for writing
let mut file = OpenOptions::new().write(true).create(true).truncate(true).open(path)?;
let fd = file.as_raw_fd();
// Set up kqueue event for write monitoring
let mut kev = kevent {
ident: fd as usize,
filter: EVFILT_VNODE,
flags: EV_ADD | EV_CLEAR,
fflags: NOTE_WRITE as u32,
data: 0,
udata: std::ptr::null_mut(),
};
// Register the event
// SAFETY: kevent syscall with valid kqueue fd and event structure
let ret = unsafe {
kevent(self.kq, &kev as *const kevent, 1, std::ptr::null_mut(), 0, std::ptr::null())
};
if ret < 0 {
return Err(io::Error::last_os_error());
}
// Perform the write
file.write_all(data)?;
file.sync_all()?;
Ok(())
}
/// Perform event-driven batch write operations
///
/// This method optimizes multiple file writes by using kqueue
/// to monitor all operations simultaneously, reducing syscall overhead.
#[cfg(target_os = "macos")]
fn write_batch_with_events(&self, files: &[(&Path, &[u8])]) -> io::Result<Vec<io::Result<()>>> {
let mut results = Vec::with_capacity(files.len());
let mut open_files = Vec::with_capacity(files.len());
let mut kevents = Vec::with_capacity(files.len());
// Open all files and register events
for (path, _) in files {
// Ensure parent directory exists
if let Some(parent) = path.parent() {
if !parent.as_os_str().is_empty() && !parent.exists() {
if let Err(e) = std::fs::create_dir_all(parent) {
results.push(Err(e));
continue;
}
}
}
match OpenOptions::new().write(true).create(true).truncate(true).open(path) {
Ok(file) => {
let fd = file.as_raw_fd();
let kev = kevent {
ident: fd as usize,
filter: EVFILT_VNODE,
flags: EV_ADD | EV_CLEAR,
fflags: NOTE_WRITE as u32,
data: 0,
udata: std::ptr::null_mut(),
};
open_files.push(file);
kevents.push(kev);
}
Err(e) => {
results.push(Err(e));
}
}
}
// Register all events at once
if !kevents.is_empty() {
// SAFETY: kevent syscall with valid kqueue fd and event structures
let ret = unsafe {
kevent(
self.kq,
kevents.as_ptr(),
kevents.len() as i32,
std::ptr::null_mut(),
0,
std::ptr::null(),
)
};
if ret < 0 {
return Err(io::Error::last_os_error());
}
}
// Perform all writes
let mut file_idx = 0;
for (i, (_, data)) in files.iter().enumerate() {
if results.len() > i {
continue; // Skip files that failed to open
}
let result = open_files[file_idx]
.write_all(data)
.and_then(|_| open_files[file_idx].sync_all());
results.push(result);
file_idx += 1;
}
Ok(results)
}
}
impl Default for KqueueIO {
fn default() -> Self {
Self::new()
}
}
#[cfg(target_os = "macos")]
impl Drop for KqueueIO {
fn drop(&mut self) {
// SAFETY: Close the kqueue file descriptor
unsafe {
libc::close(self.kq);
}
}
}
impl AsyncFileIO for KqueueIO {
fn read_sync(&self, path: &Path) -> io::Result<Vec<u8>> {
std::fs::read(path)
}
fn write_sync(&self, path: &Path, data: &[u8]) -> io::Result<()> {
#[cfg(target_os = "macos")]
{
// Use event-driven write for better performance
self.write_with_event(path, data)
}
#[cfg(not(target_os = "macos"))]
{
// Fallback for non-macOS platforms
if let Some(parent) = path.parent() {
if !parent.as_os_str().is_empty() && !parent.exists() {
std::fs::create_dir_all(parent)?;
}
}
std::fs::write(path, data)
}
}
fn read_batch_sync(&self, paths: &[&Path]) -> io::Result<Vec<io::Result<Vec<u8>>>> {
// For reads, kqueue doesn't provide significant benefits over sequential reads
// since we need the data immediately. Use standard file I/O.
Ok(paths.iter().map(|p| std::fs::read(p)).collect())
}
fn write_batch_sync(&self, files: &[(&Path, &[u8])]) -> io::Result<Vec<io::Result<()>>> {
#[cfg(target_os = "macos")]
{
// Use event-driven batch write for optimal performance
self.write_batch_with_events(files)
}
#[cfg(not(target_os = "macos"))]
{
// Fallback for non-macOS platforms
Ok(files
.iter()
.map(|(path, data)| {
if let Some(parent) = path.parent() {
if !parent.as_os_str().is_empty() && !parent.exists() {
std::fs::create_dir_all(parent)?;
}
}
std::fs::write(path, data)
})
.collect())
}
}
fn backend_name(&self) -> &'static str {
"kqueue"
}
fn is_available(&self) -> bool {
Self::is_available()
}
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::TempDir;
#[test]
fn test_kqueue_read_write() {
let dir = TempDir::new().unwrap();
let path = dir.path().join("test.txt");
let io = KqueueIO::new();
let data = b"Hello from kqueue!";
io.write_sync(&path, data).unwrap();
let read_data = io.read_sync(&path).unwrap();
assert_eq!(read_data, data);
}
#[test]
fn test_kqueue_backend_name() {
let io = KqueueIO::new();
assert_eq!(io.backend_name(), "kqueue");
assert!(io.is_available());
}
}