strat9_kernel/syscall/
robust_list.rs1use crate::{
14 memory::userslice::{UserSliceRead, UserSliceWrite},
15 process::current_task_clone,
16 syscall::error::SyscallError,
17};
18
19const ROBUST_LIST_LIMIT: u32 = 4096;
21
22const FUTEX_OWNER_DIED: u32 = 0x4000_0000;
24
25const TID_MASK: u32 = 0x3FFF_FFFF;
27
28pub fn sys_set_robust_list(head: u64, len: usize) -> Result<u64, SyscallError> {
38 if head != 0 && len < 24 {
40 return Err(SyscallError::InvalidArgument);
41 }
42
43 let task = current_task_clone().ok_or(SyscallError::PermissionDenied)?;
44 task.robust_list_head
45 .store(head, core::sync::atomic::Ordering::Relaxed);
46 task.robust_list_len
47 .store(len, core::sync::atomic::Ordering::Relaxed);
48 Ok(0)
49}
50
51pub fn sys_get_robust_list(pid: i64, head_ptr: u64, len_ptr: u64) -> Result<u64, SyscallError> {
64 let task = if pid == 0 {
65 current_task_clone().ok_or(SyscallError::PermissionDenied)?
66 } else {
67 let pid_u = pid as u32;
68 crate::process::get_task_by_pid(pid_u.into()).ok_or(SyscallError::NotFound)?
69 };
70
71 let head = task
72 .robust_list_head
73 .load(core::sync::atomic::Ordering::Relaxed);
74 let len = task
75 .robust_list_len
76 .load(core::sync::atomic::Ordering::Relaxed);
77
78 if head_ptr != 0 {
79 let user = UserSliceWrite::new(head_ptr, core::mem::size_of::<u64>())?;
80 user.copy_from(&head.to_ne_bytes());
81 }
82 if len_ptr != 0 {
83 let user = UserSliceWrite::new(len_ptr, core::mem::size_of::<usize>())?;
84 user.copy_from(&len.to_ne_bytes());
85 }
86
87 Ok(0)
88}
89
90pub fn cleanup_robust_list(task: &crate::process::Task) {
98 let head_ptr = task
99 .robust_list_head
100 .load(core::sync::atomic::Ordering::Relaxed);
101 if head_ptr == 0 {
102 return;
103 }
104
105 let tid = task.tid;
106
107 let head_slice = match UserSliceRead::new(head_ptr, 24) {
112 Ok(s) => s,
113 Err(_) => return,
114 };
115
116 let first_entry = match head_slice.read_u64(0) {
117 Ok(v) => v,
118 Err(_) => return,
119 };
120 let futex_offset = match head_slice.read_u64(8) {
121 Ok(v) => v as i64,
122 Err(_) => return,
123 };
124 let pending = match head_slice.read_u64(16) {
125 Ok(v) => v,
126 Err(_) => return,
127 };
128
129 if pending != 0 && pending != head_ptr {
131 mark_futex_owner_died(pending, futex_offset, tid);
132 }
133
134 let mut entry = first_entry;
136 let mut count = 0u32;
137
138 while entry != head_ptr && count < ROBUST_LIST_LIMIT {
139 let next_ptr = match UserSliceRead::new(entry, 8) {
141 Ok(s) => match s.read_u64(0) {
142 Ok(v) => v,
143 Err(_) => break,
144 },
145 Err(_) => break,
146 };
147
148 mark_futex_owner_died(entry, futex_offset, tid);
150
151 entry = next_ptr;
152 count += 1;
153 }
154}
155
156fn mark_futex_owner_died(entry: u64, futex_offset: i64, tid: u32) {
161 let futex_addr = (entry as i64 + futex_offset) as u64;
162
163 let futex_val = match read_u32_from_user(futex_addr) {
165 Some(v) => v,
166 None => return,
167 };
168
169 if (futex_val & TID_MASK) != tid {
171 return; }
173
174 let new_val = futex_val | FUTEX_OWNER_DIED;
176
177 if let Ok(user) = UserSliceWrite::new(futex_addr, 4) {
179 user.copy_from(&new_val.to_ne_bytes());
180 }
181
182 let _ = crate::syscall::futex::sys_futex_wake(futex_addr, u32::MAX);
184}
185
186fn read_u32_from_user(addr: u64) -> Option<u32> {
188 let slice = UserSliceRead::new(addr, 4).ok()?;
189 let b0 = slice.read_u8(0).ok()? as u32;
190 let b1 = slice.read_u8(1).ok()? as u32;
191 let b2 = slice.read_u8(2).ok()? as u32;
192 let b3 = slice.read_u8(3).ok()? as u32;
193 Some(b0 | (b1 << 8) | (b2 << 16) | (b3 << 24))
194}