Implement semctl syscall

This commit is contained in:
Yuke Peng 2024-08-10 18:52:03 +08:00 committed by Tate, Hongliang Tian
parent 9d83e76931
commit 60ef523aaf
4 changed files with 125 additions and 1 deletions

View File

@ -86,7 +86,7 @@ provided by Linux on x86-64 architecture.
| 63 | uname | ✅ | | 63 | uname | ✅ |
| 64 | semget | ✅ | | 64 | semget | ✅ |
| 65 | semop | ✅ | | 65 | semop | ✅ |
| 66 | semctl | | | 66 | semctl | |
| 67 | shmdt | ❌ | | 67 | shmdt | ❌ |
| 68 | msgget | ❌ | | 68 | msgget | ❌ |
| 69 | msgsnd | ❌ | | 69 | msgsnd | ❌ |

View File

@ -89,6 +89,7 @@ use crate::syscall::{
sched_getaffinity::sys_sched_getaffinity, sched_getaffinity::sys_sched_getaffinity,
sched_yield::sys_sched_yield, sched_yield::sys_sched_yield,
select::sys_select, select::sys_select,
semctl::sys_semctl,
semget::sys_semget, semget::sys_semget,
semop::{sys_semop, sys_semtimedop}, semop::{sys_semop, sys_semtimedop},
sendfile::sys_sendfile, sendfile::sys_sendfile,
@ -194,6 +195,7 @@ impl_syscall_nums_and_dispatch_fn! {
SYS_UNAME = 63 => sys_uname(args[..1]); SYS_UNAME = 63 => sys_uname(args[..1]);
SYS_SEMGET = 64 => sys_semget(args[..3]); SYS_SEMGET = 64 => sys_semget(args[..3]);
SYS_SEMOP = 65 => sys_semop(args[..3]); SYS_SEMOP = 65 => sys_semop(args[..3]);
SYS_SEMCTL = 66 => sys_semctl(args[..4]);
SYS_FCNTL = 72 => sys_fcntl(args[..3]); SYS_FCNTL = 72 => sys_fcntl(args[..3]);
SYS_FLOCK = 73 => sys_flock(args[..2]); SYS_FLOCK = 73 => sys_flock(args[..2]);
SYS_FSYNC = 74 => sys_fsync(args[..1]); SYS_FSYNC = 74 => sys_fsync(args[..1]);

View File

@ -96,6 +96,7 @@ mod rt_sigsuspend;
mod sched_getaffinity; mod sched_getaffinity;
mod sched_yield; mod sched_yield;
mod select; mod select;
mod semctl;
mod semget; mod semget;
mod semop; mod semop;
mod sendfile; mod sendfile;

View File

@ -0,0 +1,121 @@
// SPDX-License-Identifier: MPL-2.0
use super::SyscallReturn;
use crate::{
ipc::{
semaphore::system_v::{
sem_set::{check_sem, sem_sets, sem_sets_mut, SemaphoreSet},
PermissionMode,
},
IpcControlCmd,
},
prelude::*,
process::Pid,
};
pub fn sys_semctl(
semid: i32,
semnum: i32,
cmd: i32,
arg: Vaddr,
ctx: &Context,
) -> Result<SyscallReturn> {
if semid <= 0 || semnum < 0 {
return_errno!(Errno::EINVAL)
}
let cmd = IpcControlCmd::try_from(cmd)?;
debug!(
"[sys_semctl] semid = {}, semnum = {}, cmd = {:?}, arg = {:x}",
semid, semnum, cmd, arg
);
match cmd {
IpcControlCmd::IPC_RMID => {
let mut sem_sets_mut = sem_sets_mut();
let sem_set = sem_sets_mut.get(&semid).ok_or(Error::new(Errno::EINVAL))?;
let euid = ctx.posix_thread.credentials().euid();
let permission = sem_set.permission();
let can_removed = (euid == permission.uid()) || (euid == permission.cuid());
if !can_removed {
return_errno!(Errno::EPERM);
}
sem_sets_mut
.remove(&semid)
.ok_or(Error::new(Errno::EINVAL))?;
}
IpcControlCmd::SEM_SETVAL => {
// In setval, arg is parse as i32
let val = arg as i32;
if val < 0 {
return_errno!(Errno::ERANGE);
}
check_and_ctl(semid, PermissionMode::ALTER, |sem_set| {
let sem = sem_set
.get(semnum as usize)
.ok_or(Error::new(Errno::EINVAL))?;
sem.set_val(val)?;
sem_set.update_ctime();
Ok(())
})?;
}
IpcControlCmd::SEM_GETVAL => {
let val: i32 = check_and_ctl(semid, PermissionMode::READ, |sem_set| {
Ok(sem_set
.get(semnum as usize)
.ok_or(Error::new(Errno::EINVAL))?
.val())
})?;
return Ok(SyscallReturn::Return(val as isize));
}
IpcControlCmd::SEM_GETPID => {
let pid: Pid = check_and_ctl(semid, PermissionMode::READ, |sem_set| {
Ok(sem_set
.get(semnum as usize)
.ok_or(Error::new(Errno::EINVAL))?
.last_modified_pid())
})?;
return Ok(SyscallReturn::Return(pid as isize));
}
IpcControlCmd::SEM_GETZCNT => {
let cnt: usize = check_and_ctl(semid, PermissionMode::READ, |sem_set| {
Ok(sem_set
.get(semnum as usize)
.ok_or(Error::new(Errno::EINVAL))?
.pending_zero_count())
})?;
return Ok(SyscallReturn::Return(cnt as isize));
}
IpcControlCmd::SEM_GETNCNT => {
let cnt: usize = check_and_ctl(semid, PermissionMode::READ, |sem_set| {
Ok(sem_set
.get(semnum as usize)
.ok_or(Error::new(Errno::EINVAL))?
.pending_alter_count())
})?;
return Ok(SyscallReturn::Return(cnt as isize));
}
_ => todo!("Need to support {:?} in SYS_SEMCTL", cmd),
}
Ok(SyscallReturn::Return(0))
}
fn check_and_ctl<T, F>(semid: i32, permission: PermissionMode, ctl_func: F) -> Result<T>
where
F: FnOnce(&SemaphoreSet) -> Result<T>,
{
check_sem(semid, None, permission)?;
let sem_sets = sem_sets();
let sem_set = sem_sets.get(&semid).ok_or(Error::new(Errno::EINVAL))?;
ctl_func.call_once((sem_set,))
}