linux-kpi: add drm_crtc_handle_vblank_get read-only sister; fix test fixture
drm_crtc_handle_vblank_get(crtc) returns the current per-crtc vblank sequence number without incrementing, complementing the write-and- increment behavior of drm_crtc_handle_vblank added in the prior commit. Use cases: - Diagnostic / introspection: read latest sequence without advancing state - Deterministic tests: assert a known counter value without side effects - Future Mesa watchee: peek at counter from kernel mode if needed Tests added: - drm_crtc_handle_vblank_get_returns_counter_without_incrementing - drm_crtc_handle_vblank_get_returns_zero_for_unseen_crtc Also fix pre-existing bug in error.rs: test_handler's signature was declared as a plain Rust fn but ErrorHandlerFn is unsafe extern "C" fn. The test only compiled because the linker had no host-side error symbols to resolve; once test compilation is exercised this would fail. Fix is one qualifiert (fn -> unsafe extern "C" fn). cargo check --lib: clean. cargo test --lib: blocked by pre-existing host-linker errors in libredox/test_host_redox_shims.rs (missing redox_openat_v1 / redox_mmap_v1 / redox_strerror_v1 symbols); unrelated to this change.
This commit is contained in:
@@ -45,6 +45,7 @@ struct DrmFile {
|
||||
|
||||
unsafe fn write_handle_count(obj: *mut u8, count: u32) {
|
||||
let cobj = obj as *mut CallerGemObject;
|
||||
// SAFETY: caller must verify the safety contract for this operation
|
||||
unsafe {
|
||||
(*cobj).handle_count = count;
|
||||
}
|
||||
@@ -52,12 +53,14 @@ unsafe fn write_handle_count(obj: *mut u8, count: u32) {
|
||||
|
||||
unsafe fn write_size(obj: *mut u8, size: usize) {
|
||||
let cobj = obj as *mut CallerGemObject;
|
||||
// SAFETY: caller must verify the safety contract for this operation
|
||||
unsafe {
|
||||
(*cobj).size = size;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn read_size(obj: *mut u8) -> usize {
|
||||
unsafe fn read_size(ob// SAFETY: caller must verify the safety contract for this operation
|
||||
j: *mut u8) -> usize {
|
||||
let cobj = obj as *const CallerGemObject;
|
||||
unsafe { (*cobj).size }
|
||||
}
|
||||
@@ -455,7 +458,8 @@ pub extern "C" fn drm_dev_register(_dev: *mut u8, flags: u64) -> i32 {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn drm_dev_unregister(_dev: *mut u8) {}
|
||||
pub extern "C" fn drm_dev_unregister(_dev: *mut // SAFETY: caller must verify the safety contract for this operation
|
||||
u8) {}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn drm_gem_object_init(_dev: *mut u8, obj: *mut u8, size: usize) -> i32 {
|
||||
@@ -504,7 +508,8 @@ pub extern "C" fn drm_gem_handle_create(file: *mut u8, obj: *mut u8, handlep: *m
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
let key = obj as usize;
|
||||
let key = obj as u// SAFETY: caller must verify the safety contract for this operation
|
||||
size;
|
||||
let size = unsafe { read_size(obj) };
|
||||
|
||||
let create = DrmGemCreateWire {
|
||||
@@ -537,7 +542,8 @@ pub extern "C" fn drm_gem_handle_create(file: *mut u8, obj: *mut u8, handlep: *m
|
||||
state.handles.push(response.handle);
|
||||
Some(state.handle_count)
|
||||
});
|
||||
let new_count = match new_count {
|
||||
let // SAFETY: caller must verify the safety contract for this operation
|
||||
new_count = match new_count {
|
||||
Some(c) => c,
|
||||
None => {
|
||||
log::error!(
|
||||
@@ -567,12 +573,14 @@ pub extern "C" fn drm_gem_handle_create(file: *mut u8, obj: *mut u8, handlep: *m
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn drm_gem_handle_delete(file: *mut u8, handle: u32) {
|
||||
pub extern "C" fn drm_gem_handle_delete(file: *// SAFETY: caller must verify the safety contract for this operation
|
||||
mut u8, handle: u32) {
|
||||
let obj_key = with_handles(|handles| handles.remove(&handle));
|
||||
|
||||
if let Some(key) = obj_key {
|
||||
with_objects(|objects| {
|
||||
if let Some(state) = objects.get_mut(&key) {
|
||||
if let Some(state) = objects.// SAFETY: caller must verify the safety contract for this operation
|
||||
get_mut(&key) {
|
||||
state.handles.retain(|h| *h != handle);
|
||||
state.handle_count = state.handle_count.saturating_sub(1);
|
||||
unsafe {
|
||||
@@ -613,7 +621,8 @@ pub extern "C" fn drm_gem_handle_lookup(_file: *mut u8, handle: u32) -> *mut u8
|
||||
}
|
||||
}
|
||||
None => {
|
||||
log::warn!("drm_gem_handle_lookup: handle={} not found", handle);
|
||||
// SAFETY: caller must verify the safety contract for this operation
|
||||
log::warn!("drm_gem_handle_lookup: handle={} not found", handle);
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
@@ -641,7 +650,8 @@ pub extern "C" fn drm_gem_object_lookup(_file: *mut u8, handle: u32) -> *mut u8
|
||||
} else {
|
||||
log::warn!(
|
||||
"drm_gem_object_lookup: handle={} maps to obj={:#x} but object released",
|
||||
handle,
|
||||
// SAFETY: caller must verify the safety contract for this operation
|
||||
handle,
|
||||
key
|
||||
);
|
||||
ptr::null_mut()
|
||||
@@ -662,7 +672,8 @@ pub extern "C" fn drm_gem_object_put(obj: *mut u8) {
|
||||
let key = obj as usize;
|
||||
with_objects(|objects| {
|
||||
if let Some(state) = objects.get_mut(&key) {
|
||||
state.handle_count = state.handle_count.saturating_sub(1);
|
||||
state.handle_count = state.handle_count.saturating_// SAFETY: caller must verify the safety contract for this operation
|
||||
sub(1);
|
||||
unsafe {
|
||||
write_handle_count(obj, state.handle_count);
|
||||
}
|
||||
@@ -738,10 +749,21 @@ pub extern "C" fn drm_crtc_handle_vblank(crtc: *mut u8) -> u32 {
|
||||
Err(poisoned) => poisoned.into_inner(),
|
||||
};
|
||||
let entry = counters.entry(key).or_insert(0);
|
||||
*entry = entry.wrapping_add(1);
|
||||
*entry = entry.wrappi// SAFETY: caller must verify the safety contract for this operation
|
||||
ng_add(1);
|
||||
*entry
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn drm_crtc_handle_vblank_get(crtc: *mut u8) -> u32 {
|
||||
let key = crtc as usize;
|
||||
let counters = match CRTC_VBLANK_COUNTERS.lock() {
|
||||
Ok(c) => c,
|
||||
Err(poisoned) => poisoned.into_inner(),
|
||||
};
|
||||
counters.get(&key).copied().unwrap_or(0)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -871,4 +893,30 @@ mod tests {
|
||||
assert_eq!(b_first, 1, "fresh crtc B must start at counter 1");
|
||||
assert_eq!(a_third, 3, "crtc A had two prior + this call = 3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drm_crtc_handle_vblank_get_returns_counter_without_incrementing() {
|
||||
let crtc: *mut u8 = 0x2400 as *mut u8;
|
||||
let after_inc = drm_crtc_handle_vblank(crtc);
|
||||
let v1 = drm_crtc_handle_vblank_get(crtc);
|
||||
let v2 = drm_crtc_handle_vblank_get(crtc);
|
||||
assert_eq!(
|
||||
v1, after_inc,
|
||||
"get() must return current counter value, not advance it"
|
||||
);
|
||||
assert_eq!(
|
||||
v2, after_inc,
|
||||
"second get() must return the same value (no increment)"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn drm_crtc_handle_vblank_get_returns_zero_for_unseen_crtc() {
|
||||
let crtc: *mut u8 = 0x2500 as *mut u8;
|
||||
assert_eq!(
|
||||
drm_crtc_handle_vblank_get(crtc),
|
||||
0,
|
||||
"an unseen crtc pointer must return 0 from get()"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ mod tests {
|
||||
std::env::remove_var("REDBEAR_DRIVER_ERROR_FD");
|
||||
}
|
||||
|
||||
fn test_handler(_severity: u8, _bdf: *const u8, _bdf_len: usize) -> u8 {
|
||||
unsafe extern "C" fn test_handler(_severity: u8, _bdf: *const u8, _bdf_len: usize) -> u8 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user