Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions os/StarryOS/kernel/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- support `FUTEX_WAKE_OP` in Starry futex syscall handling.
- *(prctl)* implement `PR_SET_CHILD_SUBREAPER` and `PR_GET_CHILD_SUBREAPER` with orphan reparenting tests.

## [0.5.12](https://github.com/rcore-os/tgoskits/compare/starry-kernel-v0.5.11...starry-kernel-v0.5.12) - 2026-05-22
Expand Down
6 changes: 3 additions & 3 deletions os/StarryOS/kernel/src/syscall/fs/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -672,12 +672,12 @@ fn do_send(mut src: SendFile, mut dst: SendFile, len: usize) -> AxResult<usize>
*pos += bytes_written as u64;
user.vm_write(*pos)?;
}
total_written += bytes_written;
remaining -= bytes_written;

if bytes_written < bytes_read {
break;
}

total_written += bytes_written;
remaining -= bytes_written;
}

Ok(total_written)
Expand Down
88 changes: 86 additions & 2 deletions os/StarryOS/kernel/src/syscall/sync/futex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ use ax_errno::{AxError, AxResult};
use ax_runtime::hal::time::{TimeValue, monotonic_time, wall_time};
use ax_task::current;
use linux_raw_sys::general::{
FUTEX_CLOCK_REALTIME, FUTEX_CMP_REQUEUE, FUTEX_REQUEUE, FUTEX_WAIT, FUTEX_WAIT_BITSET,
FUTEX_WAKE, FUTEX_WAKE_BITSET, robust_list_head, timespec,
FUTEX_CLOCK_REALTIME, FUTEX_CMP_REQUEUE, FUTEX_OP_ADD, FUTEX_OP_ANDN, FUTEX_OP_CMP_EQ,
FUTEX_OP_CMP_GE, FUTEX_OP_CMP_GT, FUTEX_OP_CMP_LE, FUTEX_OP_CMP_LT, FUTEX_OP_CMP_NE,
FUTEX_OP_OPARG_SHIFT, FUTEX_OP_OR, FUTEX_OP_SET, FUTEX_OP_XOR, FUTEX_REQUEUE, FUTEX_WAIT,
FUTEX_WAIT_BITSET, FUTEX_WAKE, FUTEX_WAKE_BITSET, FUTEX_WAKE_OP, robust_list_head, timespec,
};
use starry_vm::{VmMutPtr, VmPtr};

Expand All @@ -26,6 +28,7 @@ enum FutexCommand {
WakeBitset,
Requeue,
CmpRequeue,
WakeOp,
}

struct ParsedFutexOp {
Expand All @@ -50,6 +53,61 @@ fn validate_futex_word(uaddr: *const u32) -> AxResult<()> {
Ok(())
}

fn sign_extend_12(value: u32) -> i32 {
((value << 20) as i32) >> 20
}

fn futex_wake_op_arg(raw_op: u32, encoded_op: u32) -> i32 {
let mut oparg = sign_extend_12((encoded_op >> 12) & 0xfff);
if raw_op & FUTEX_OP_OPARG_SHIFT != 0 {
oparg = (1u32 << ((oparg & 31) as u32)) as i32;
}
oparg
}

fn apply_futex_wake_op(old_value: u32, raw_op: u32, oparg: i32) -> AxResult<u32> {
let op = raw_op & !FUTEX_OP_OPARG_SHIFT;
let new_value = match op {
FUTEX_OP_SET => oparg as u32,
FUTEX_OP_ADD => (old_value as i32).wrapping_add(oparg) as u32,
FUTEX_OP_OR => old_value | oparg as u32,
FUTEX_OP_ANDN => old_value & !(oparg as u32),
FUTEX_OP_XOR => old_value ^ oparg as u32,
_ => return Err(AxError::Unsupported),
};
Ok(new_value)
}

fn compare_futex_wake_op(old_value: u32, raw_cmp: u32, cmparg: i32) -> AxResult<bool> {
let old_value = old_value as i32;
let matched = match raw_cmp {
FUTEX_OP_CMP_EQ => old_value == cmparg,
FUTEX_OP_CMP_NE => old_value != cmparg,
FUTEX_OP_CMP_LT => old_value < cmparg,
FUTEX_OP_CMP_LE => old_value <= cmparg,
FUTEX_OP_CMP_GT => old_value > cmparg,
FUTEX_OP_CMP_GE => old_value >= cmparg,
_ => return Err(AxError::Unsupported),
};
Ok(matched)
}

fn futex_atomic_op_in_user(uaddr: *mut u32, encoded_op: u32) -> AxResult<bool> {
if !uaddr.addr().is_multiple_of(align_of::<u32>()) {
return Err(AxError::InvalidInput);
}

let raw_op = (encoded_op >> 28) & 0xf;
let raw_cmp = (encoded_op >> 24) & 0xf;
let oparg = futex_wake_op_arg(raw_op, encoded_op);
let cmparg = sign_extend_12(encoded_op & 0xfff);

let old_value = uaddr.vm_read()?;
let new_value = apply_futex_wake_op(old_value, raw_op, oparg)?;
uaddr.vm_write(new_value)?;
Comment thread
cqwhfhh marked this conversation as resolved.
Outdated
compare_futex_wake_op(old_value, raw_cmp, cmparg)
}

fn parse_futex_op(futex_op: u32) -> AxResult<ParsedFutexOp> {
let flags = futex_op & !FUTEX_COMMAND_MASK;
if flags & !SUPPORTED_FLAGS != 0 {
Expand All @@ -63,10 +121,14 @@ fn parse_futex_op(futex_op: u32) -> AxResult<ParsedFutexOp> {
FUTEX_WAKE_BITSET => FutexCommand::WakeBitset,
FUTEX_REQUEUE => FutexCommand::Requeue,
FUTEX_CMP_REQUEUE => FutexCommand::CmpRequeue,
FUTEX_WAKE_OP => FutexCommand::WakeOp,
_ => return Err(AxError::Unsupported),
};

let clock_realtime = flags & FUTEX_CLOCK_REALTIME != 0;
if clock_realtime && command == FutexCommand::WakeOp {
return Err(AxError::Unsupported);
}
if clock_realtime && !matches!(command, FutexCommand::Wait | FutexCommand::WaitBitset) {
return Err(AxError::InvalidInput);
}
Expand Down Expand Up @@ -219,6 +281,28 @@ pub fn sys_futex(
return Err(AxError::WouldBlock);
};

if count > 0 {
ax_task::yield_now();
}
Ok(count as _)
}
FutexCommand::WakeOp => {
let wake_count = value as usize;
let wake2_count = timeout.addr();
validate_futex_word(uaddr)?;

let key2 = FutexKey::new_current(uaddr2.addr(), op.key_mode);
let table2 = futex_table_for(&key2);
let wake_second = futex_atomic_op_in_user(uaddr2, value3)?;

let mut count = 0;
if let Some(futex) = futex_table.get(&key) {
count += futex.wq.wake(wake_count, u32::MAX);
}
if wake_second && let Some(futex) = table2.get(&key2) {
count += futex.wq.wake(wake2_count, u32::MAX);
}

if count > 0 {
ax_task::yield_now();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.20)
project(test-futex-wake-op C)

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)

add_executable(test-futex-wake-op src/main.c)
target_include_directories(
test-futex-wake-op
PRIVATE
src
${CMAKE_CURRENT_SOURCE_DIR}/../../common
)
target_compile_options(test-futex-wake-op PRIVATE -Wall -Wextra -Werror)
target_link_libraries(test-futex-wake-op PRIVATE pthread)

install(TARGETS test-futex-wake-op RUNTIME DESTINATION usr/bin/starry-test-suit)
Loading