metrale_gpu_runtime/
pinned_hosts.rs1use std::sync::RwLock;
22
23static PINNED: RwLock<Vec<(usize, usize)>> = RwLock::new(Vec::new());
25
26pub fn register(ptr: *const u8, bytes: usize) {
29 if ptr.is_null() || bytes == 0 {
30 return;
31 }
32 let base = ptr as usize;
33 let mut g = match PINNED.write() {
34 Ok(g) => g,
35 Err(e) => e.into_inner(),
38 };
39 match g.binary_search_by_key(&base, |&(b, _)| b) {
40 Ok(i) => g[i].1 = bytes,
41 Err(i) => g.insert(i, (base, bytes)),
42 }
43}
44
45pub fn unregister(ptr: *const u8) {
48 if ptr.is_null() {
49 return;
50 }
51 let base = ptr as usize;
52 let mut g = match PINNED.write() {
53 Ok(g) => g,
54 Err(e) => e.into_inner(),
55 };
56 if let Ok(i) = g.binary_search_by_key(&base, |&(b, _)| b) {
57 g.remove(i);
58 }
59}
60
61pub fn is_pinned(src: &[u8]) -> bool {
64 if src.is_empty() {
65 return false;
66 }
67 let start = src.as_ptr() as usize;
68 let g = match PINNED.read() {
69 Ok(g) => g,
70 Err(e) => e.into_inner(),
71 };
72 match g.binary_search_by_key(&start, |&(b, _)| b) {
75 Ok(i) => start + src.len() <= g[i].0 + g[i].1,
76 Err(0) => false,
77 Err(i) => {
78 let (b, len) = g[i - 1];
79 start < b + len && start + src.len() <= b + len
80 }
81 }
82}
83
84pub fn live_count() -> usize {
86 match PINNED.read() {
87 Ok(g) => g.len(),
88 Err(e) => e.into_inner().len(),
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 static SERIAL: std::sync::Mutex<()> = std::sync::Mutex::new(());
98
99 #[test]
100 fn a_pageable_buffer_is_not_pinned() {
101 let _s = SERIAL.lock().unwrap_or_else(|e| e.into_inner());
102 let v = vec![0u8; 128];
103 assert!(!is_pinned(&v));
104 }
105
106 #[test]
107 fn a_registered_region_and_its_subslices_are_pinned() {
108 let _s = SERIAL.lock().unwrap_or_else(|e| e.into_inner());
109 let mut v = vec![0u8; 256];
110 register(v.as_ptr(), v.len());
111
112 assert!(is_pinned(&v), "the whole region");
113 assert!(is_pinned(&v[..64]), "prefix");
115 assert!(is_pinned(&v[64..128]), "interior");
116 assert!(is_pinned(&v[255..]), "last byte");
117
118 unregister(v.as_ptr());
119 assert!(!is_pinned(&v), "unregistered again");
120 v[0] = 1;
121 assert_eq!(v[0], 1);
122 }
123
124 #[test]
125 fn a_neighbouring_pageable_buffer_is_not_caught() {
126 let _s = SERIAL.lock().unwrap_or_else(|e| e.into_inner());
127 let pinned = vec![0u8; 128];
128 let other = vec![0u8; 128];
129 register(pinned.as_ptr(), pinned.len());
130 assert!(is_pinned(&pinned));
131 assert!(!is_pinned(&other), "a different allocation must not match");
132 unregister(pinned.as_ptr());
133 }
134
135 #[test]
136 fn empty_and_null_are_handled() {
137 let _s = SERIAL.lock().unwrap_or_else(|e| e.into_inner());
138 let before = live_count();
139 register(std::ptr::null(), 16);
140 register(0x1000 as *const u8, 0);
141 assert_eq!(live_count(), before, "neither is a real region");
142 unregister(std::ptr::null());
143 assert!(!is_pinned(&[]));
144 }
145
146 #[test]
147 fn re_registering_the_same_base_updates_the_length() {
148 let _s = SERIAL.lock().unwrap_or_else(|e| e.into_inner());
149 let v = vec![0u8; 256];
150 let before = live_count();
151 register(v.as_ptr(), 64);
152 register(v.as_ptr(), 256);
153 assert_eq!(live_count(), before + 1, "one entry, not two");
154 assert!(is_pinned(&v[..256]), "the updated length is in effect");
155 unregister(v.as_ptr());
156 }
157}