mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-21 16:33:24 +00:00
Respect user-defined exit signal in clone() and clone3()
When calling clone() and clone3(), the user is allowed to specify a signal to be sent to the parent process on exit. Respect this value by storing it in the Process struct and sending the signal on exit. Add a test as well to verify that the signal is properly delivered to the parent.
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
130a0f7030
commit
0a36760f7a
@ -345,6 +345,10 @@ fn clone_child_process(
|
|||||||
process_builder.build()?
|
process_builder.build()?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(sig) = clone_args.exit_signal {
|
||||||
|
child.set_exit_signal(sig);
|
||||||
|
};
|
||||||
|
|
||||||
// Deals with clone flags
|
// Deals with clone flags
|
||||||
let child_thread = thread_table::get_thread(child_tid).unwrap();
|
let child_thread = thread_table::get_thread(child_tid).unwrap();
|
||||||
let child_posix_thread = child_thread.as_posix_thread().unwrap();
|
let child_posix_thread = child_thread.as_posix_thread().unwrap();
|
||||||
|
@ -5,7 +5,7 @@ use crate::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
process::{
|
process::{
|
||||||
posix_thread::{do_exit, PosixThreadExt},
|
posix_thread::{do_exit, PosixThreadExt},
|
||||||
signal::{constants::SIGCHLD, signals::kernel::KernelSignal},
|
signal::signals::kernel::KernelSignal,
|
||||||
},
|
},
|
||||||
thread::Thread,
|
thread::Thread,
|
||||||
};
|
};
|
||||||
@ -60,10 +60,11 @@ pub fn do_exit_group(term_status: TermStatus) {
|
|||||||
let parent = current.parent().lock().process();
|
let parent = current.parent().lock().process();
|
||||||
if let Some(parent) = parent.upgrade() {
|
if let Some(parent) = parent.upgrade() {
|
||||||
// Notify parent
|
// Notify parent
|
||||||
let signal = KernelSignal::new(SIGCHLD);
|
if let Some(signal) = current.exit_signal().map(KernelSignal::new) {
|
||||||
parent.enqueue_signal(signal);
|
parent.enqueue_signal(signal);
|
||||||
|
};
|
||||||
parent.children_wait_queue().wake_all();
|
parent.children_wait_queue().wake_all();
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const INIT_PROCESS_PID: Pid = 1;
|
const INIT_PROCESS_PID: Pid = 1;
|
||||||
|
@ -101,6 +101,9 @@ pub struct Process {
|
|||||||
/// The signal that the process should receive when parent process exits.
|
/// The signal that the process should receive when parent process exits.
|
||||||
parent_death_signal: AtomicSigNum,
|
parent_death_signal: AtomicSigNum,
|
||||||
|
|
||||||
|
/// The signal that should be sent to the parent when this process exits.
|
||||||
|
exit_signal: AtomicSigNum,
|
||||||
|
|
||||||
/// A profiling clock measures the user CPU time and kernel CPU time of the current process.
|
/// A profiling clock measures the user CPU time and kernel CPU time of the current process.
|
||||||
prof_clock: Arc<ProfClock>,
|
prof_clock: Arc<ProfClock>,
|
||||||
|
|
||||||
@ -218,6 +221,7 @@ impl Process {
|
|||||||
umask,
|
umask,
|
||||||
sig_dispositions,
|
sig_dispositions,
|
||||||
parent_death_signal: AtomicSigNum::new_empty(),
|
parent_death_signal: AtomicSigNum::new_empty(),
|
||||||
|
exit_signal: AtomicSigNum::new_empty(),
|
||||||
resource_limits: Mutex::new(resource_limits),
|
resource_limits: Mutex::new(resource_limits),
|
||||||
nice: Atomic::new(nice),
|
nice: Atomic::new(nice),
|
||||||
timer_manager: PosixTimerManager::new(&prof_clock, process_ref),
|
timer_manager: PosixTimerManager::new(&prof_clock, process_ref),
|
||||||
@ -690,6 +694,14 @@ impl Process {
|
|||||||
self.parent_death_signal.as_sig_num()
|
self.parent_death_signal.as_sig_num()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_exit_signal(&self, sig_num: SigNum) {
|
||||||
|
self.exit_signal.set(sig_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exit_signal(&self) -> Option<SigNum> {
|
||||||
|
self.exit_signal.as_sig_num()
|
||||||
|
}
|
||||||
|
|
||||||
// ******************* Status ********************
|
// ******************* Status ********************
|
||||||
|
|
||||||
fn set_runnable(&self) {
|
fn set_runnable(&self) {
|
||||||
|
@ -7,11 +7,7 @@ use ostd::cpu::UserContext;
|
|||||||
use super::SyscallReturn;
|
use super::SyscallReturn;
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::{
|
process::{clone_child, signal::sig_num::SigNum, CloneArgs, CloneFlags},
|
||||||
clone_child,
|
|
||||||
signal::{constants::SIGCHLD, sig_num::SigNum},
|
|
||||||
CloneArgs, CloneFlags,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// The order of arguments for clone differs in different architecture.
|
// The order of arguments for clone differs in different architecture.
|
||||||
@ -87,11 +83,7 @@ struct Clone3Args {
|
|||||||
|
|
||||||
impl From<Clone3Args> for CloneArgs {
|
impl From<Clone3Args> for CloneArgs {
|
||||||
fn from(value: Clone3Args) -> Self {
|
fn from(value: Clone3Args) -> Self {
|
||||||
// TODO: deal with pidfd, exit_signal, set_tid, set_tid_size, cgroup
|
// TODO: deal with pidfd, set_tid, set_tid_size, cgroup
|
||||||
if value.exit_signal != 0 || value.exit_signal as u8 != SIGCHLD.as_u8() {
|
|
||||||
warn!("exit signal is not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
if value.pidfd != 0 {
|
if value.pidfd != 0 {
|
||||||
warn!("pidfd is not supported");
|
warn!("pidfd is not supported");
|
||||||
}
|
}
|
||||||
|
55
test/apps/clone3/clone_exit_signal.c
Normal file
55
test/apps/clone3/clone_exit_signal.c
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <err.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
static pid_t sys_clone3(struct clone_args *args)
|
||||||
|
{
|
||||||
|
return syscall(SYS_clone3, args, sizeof(struct clone_args));
|
||||||
|
}
|
||||||
|
|
||||||
|
int child_exit_recv = 0;
|
||||||
|
|
||||||
|
void sig_handler(int signal)
|
||||||
|
{
|
||||||
|
printf("Received child exit signal\n");
|
||||||
|
child_exit_recv++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
struct clone_args args = {
|
||||||
|
.exit_signal = SIGUSR2,
|
||||||
|
};
|
||||||
|
|
||||||
|
signal(SIGUSR2, sig_handler);
|
||||||
|
|
||||||
|
pid = sys_clone3(&args);
|
||||||
|
if (pid < 0)
|
||||||
|
err(EXIT_FAILURE, "Failed to create new process");
|
||||||
|
|
||||||
|
if (pid == 0) {
|
||||||
|
printf("Child process with pid %d\n", getpid());
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From the clone(2) manual:
|
||||||
|
* If [the exit signal] is specified as anything other than SIGCHLD,
|
||||||
|
* then the parent process must specify the __WALL or __WCLONE
|
||||||
|
* options when waiting for the child with wait(2).
|
||||||
|
*/
|
||||||
|
waitpid(pid, NULL, __WALL);
|
||||||
|
|
||||||
|
if (child_exit_recv != 1)
|
||||||
|
errx(EXIT_FAILURE, "did not receive exit signal from child");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
42
test/apps/clone3/clone_no_exit_signal.c
Normal file
42
test/apps/clone3/clone_no_exit_signal.c
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <err.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
static pid_t sys_clone3(struct clone_args *args)
|
||||||
|
{
|
||||||
|
return syscall(SYS_clone3, args, sizeof(struct clone_args));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
struct clone_args args = {
|
||||||
|
.exit_signal = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pid = sys_clone3(&args);
|
||||||
|
if (pid < 0)
|
||||||
|
err(EXIT_FAILURE, "Failed to create new process");
|
||||||
|
|
||||||
|
if (pid == 0) {
|
||||||
|
printf("Child process with pid %d\n", getpid());
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From the clone(2) manual:
|
||||||
|
* If [the exit signal] is specified as anything other than SIGCHLD,
|
||||||
|
* then the parent process must specify the __WALL or __WCLONE
|
||||||
|
* options when waiting for the child with wait(2).
|
||||||
|
*/
|
||||||
|
waitpid(pid, NULL, __WALL);
|
||||||
|
|
||||||
|
/* We should have gotten this far without receiving any signals */
|
||||||
|
return 0;
|
||||||
|
}
|
@ -10,6 +10,8 @@ cd ${SCRIPT_DIR}/..
|
|||||||
echo "Start process test......"
|
echo "Start process test......"
|
||||||
# These test programs are sorted by name.
|
# These test programs are sorted by name.
|
||||||
tests="
|
tests="
|
||||||
|
clone3/clone_exit_signal
|
||||||
|
clone3/clone_no_exit_signal
|
||||||
clone3/clone_process
|
clone3/clone_process
|
||||||
execve/execve
|
execve/execve
|
||||||
eventfd2/eventfd2
|
eventfd2/eventfd2
|
||||||
|
Reference in New Issue
Block a user