diff --git a/docs/src/kernel/linux-compatibility.md b/docs/src/kernel/linux-compatibility.md index 3ee773370..d751a1c20 100644 --- a/docs/src/kernel/linux-compatibility.md +++ b/docs/src/kernel/linux-compatibility.md @@ -224,7 +224,7 @@ provided by Linux on x86-64 architecture. | 201 | time | ✅ | | 202 | futex | ✅ | | 203 | sched_setaffinity | ❌ | -| 204 | sched_getaffinity | ❌ | +| 204 | sched_getaffinity | ✅ | | 205 | set_thread_area | ❌ | | 206 | io_setup | ❌ | | 207 | io_destroy | ❌ | diff --git a/kernel/aster-nix/src/syscall/arch/x86.rs b/kernel/aster-nix/src/syscall/arch/x86.rs index 46ccd03fb..d04eee9db 100644 --- a/kernel/aster-nix/src/syscall/arch/x86.rs +++ b/kernel/aster-nix/src/syscall/arch/x86.rs @@ -72,6 +72,7 @@ use crate::syscall::{ rt_sigprocmask::sys_rt_sigprocmask, rt_sigreturn::sys_rt_sigreturn, rt_sigsuspend::sys_rt_sigsuspend, + sched_getaffinity::sys_sched_getaffinity, sched_yield::sys_sched_yield, select::sys_select, sendfile::sys_sendfile, @@ -220,6 +221,7 @@ impl_syscall_nums_and_dispatch_fn! { SYS_GETTID = 186 => sys_gettid(args[..0]); SYS_TIME = 201 => sys_time(args[..1]); SYS_FUTEX = 202 => sys_futex(args[..6]); + SYS_SCHED_GETAFFINITY = 204 => sys_sched_getaffinity(args[..3]); SYS_EPOLL_CREATE = 213 => sys_epoll_create(args[..1]); SYS_GETDENTS64 = 217 => sys_getdents64(args[..3]); SYS_SET_TID_ADDRESS = 218 => sys_set_tid_address(args[..1]); diff --git a/kernel/aster-nix/src/syscall/mod.rs b/kernel/aster-nix/src/syscall/mod.rs index 625d52c36..d81da552c 100644 --- a/kernel/aster-nix/src/syscall/mod.rs +++ b/kernel/aster-nix/src/syscall/mod.rs @@ -79,6 +79,7 @@ mod rt_sigaction; mod rt_sigprocmask; mod rt_sigreturn; mod rt_sigsuspend; +mod sched_getaffinity; mod sched_yield; mod select; mod sendfile; diff --git a/kernel/aster-nix/src/syscall/sched_getaffinity.rs b/kernel/aster-nix/src/syscall/sched_getaffinity.rs new file mode 100644 index 000000000..163fbd694 --- /dev/null +++ b/kernel/aster-nix/src/syscall/sched_getaffinity.rs @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MPL-2.0 + +use core::{cmp, mem}; + +use super::SyscallReturn; +use crate::{ + prelude::*, + process::{process_table, Pid}, + util::write_val_to_user, +}; + +fn get_num_cpus() -> usize { + // TODO: Properly determine the number of available CPUs + // This could be through a system configuration query. + 1 +} + +pub fn sys_sched_getaffinity( + pid: Pid, + cpuset_size: usize, + cpu_set_ptr: Vaddr, +) -> Result { + let num_cpus = get_num_cpus(); + + if cpuset_size < core::mem::size_of::() { + return Err(Error::with_message(Errno::EINVAL, "invalid cpuset size")); + } + + match pid { + 0 => { + // TODO: Get the current thread's CPU affinity + // Placeholder for future implementation. + } + _ => { + match process_table::get_process(&pid) { + Some(_process) => { /* Placeholder if process-specific logic needed */ } + None => return Err(Error::with_message(Errno::ESRCH, "process does not exist")), + } + } + } + + let dummy_cpu_set = cpu_set_t::new(num_cpus); + + write_val_to_user(cpu_set_ptr, &dummy_cpu_set)?; + + Ok(SyscallReturn::Return(0)) +} + +const CPU_SETSIZE: usize = 1024; // Max number of CPU bits. +const __NCPUBITS: usize = 8 * mem::size_of::(); + +#[derive(Debug, Clone, Copy, Pod)] +#[repr(C, packed)] +struct cpu_set_t { + __bits: [usize; CPU_SETSIZE / __NCPUBITS], +} + +impl cpu_set_t { + /// Creates a new cpu_set_t representing available CPUs. + fn new(num_cpus: usize) -> Self { + let mut bits = [0usize; CPU_SETSIZE / __NCPUBITS]; + + for cpu in 0..cmp::min(num_cpus, CPU_SETSIZE) { + bits[cpu / __NCPUBITS] |= 1 << (cpu % __NCPUBITS); + } + + Self { __bits: bits } + } +} diff --git a/regression/apps/Makefile b/regression/apps/Makefile index b32c2d2b8..5a91525ad 100644 --- a/regression/apps/Makefile +++ b/regression/apps/Makefile @@ -12,6 +12,7 @@ REGRESSION_BUILD_DIR ?= $(INITRAMFS)/regression TEST_APPS := \ alarm \ clone3 \ + cpu_affinity \ eventfd2 \ execve \ file_io \ diff --git a/regression/apps/cpu_affinity/Makefile b/regression/apps/cpu_affinity/Makefile new file mode 100644 index 000000000..ce42e33b0 --- /dev/null +++ b/regression/apps/cpu_affinity/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MPL-2.0 + +include ../test_common.mk + +EXTRA_C_FLAGS := \ No newline at end of file diff --git a/regression/apps/cpu_affinity/sched_getaffinity.c b/regression/apps/cpu_affinity/sched_getaffinity.c new file mode 100644 index 000000000..31e6187c0 --- /dev/null +++ b/regression/apps/cpu_affinity/sched_getaffinity.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MPL-2.0 + +#define _GNU_SOURCE +#include +#include +#include +#include +#include // Include sched.h for CPU_SETSIZE + +int main() +{ + // Create a mask for CPU_SETSIZE number of CPUs + unsigned long mask[CPU_SETSIZE / sizeof(unsigned long)]; + int mask_size = sizeof(mask); + + // Call the raw syscall to retrieve the CPU affinity mask of the current process + long res = syscall(__NR_sched_getaffinity, 0, mask_size, &mask); + + if (res < 0) { + perror("Error calling sched_getaffinity"); + return errno; + } + + // Print the CPUs that are part of the current process's affinity mask + printf("Process can run on: "); + for (int i = 0; i < CPU_SETSIZE; ++i) { + if (mask[i / (8 * sizeof(long))] & + (1UL << (i % (8 * sizeof(long))))) { + printf("%d ", i); + } + } + printf("\n"); + + return 0; +}