Merge branch 'userspace_proc' into 'master'
Use process manager See merge request redox-os/relibc!649
This commit is contained in:
Generated
+5
-5
@@ -227,9 +227,9 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.171"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
@@ -377,9 +377,9 @@ version = "0.1.2"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.94"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -458,7 +458,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.11"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#080f2003cd065bcc9a290230ede06da0a1ea0502"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/syscall.git?branch=master#8f646a63ac9c3aa532a37ddfdc136ec19878f0d6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
+1
-1
@@ -81,4 +81,4 @@ panic = "abort"
|
||||
|
||||
[patch.crates-io]
|
||||
cc-11 = { git = "https://github.com/tea/cc-rs", branch = "riscv-abi-arch-fix", package = "cc" }
|
||||
redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" }
|
||||
redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git", branch = "master" }
|
||||
|
||||
@@ -175,3 +175,10 @@ Before starting to contribute, read [this](CONTRIBUTING.md) document.
|
||||
- i686 (Intel/AMD)
|
||||
- x86_64 (Intel/AMD)
|
||||
- Aarch64 (ARM64)
|
||||
|
||||
## Funding - _Unix-style Signals and Process Management_
|
||||
|
||||
This project is funded through [NGI Zero Core](https://nlnet.nl/core), a fund established by [NLnet](https://nlnet.nl) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) program. Learn more at the [NLnet project page](https://nlnet.nl/project/RedoxOS-Signals).
|
||||
|
||||
[<img src="https://nlnet.nl/logo/banner.png" alt="NLnet foundation logo" width="20%" />](https://nlnet.nl)
|
||||
[<img src="https://nlnet.nl/image/logos/NGI0_tag.svg" alt="NGI Zero Logo" width="20%" />](https://nlnet.nl/core)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define _BITS_SYS_WAIT_H
|
||||
|
||||
#define WEXITSTATUS(s) (((s) >> 8) & 0xff)
|
||||
#define WTERMSIG(s) (((s) & 0x7f) != 0)
|
||||
#define WTERMSIG(s) ((s) & 0x7f)
|
||||
#define WSTOPSIG(s) WEXITSTATUS(s)
|
||||
#define WCOREDUMP(s) (((s) & 0x80) != 0)
|
||||
#define WIFEXITED(s) (((s) & 0x7f) == 0)
|
||||
|
||||
@@ -15,3 +15,7 @@ plain = "0.2"
|
||||
redox_syscall = "0.5.8"
|
||||
|
||||
generic-rt = { path = "../generic-rt" }
|
||||
|
||||
[features]
|
||||
proc = []
|
||||
default = ["proc"]
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use core::{mem::offset_of, ptr::NonNull};
|
||||
use core::{cell::SyncUnsafeCell, mem::offset_of, ptr::NonNull};
|
||||
|
||||
use syscall::{data::*, error::*};
|
||||
|
||||
use crate::{
|
||||
proc::{fork_inner, FdGuard},
|
||||
proc::{fork_inner, FdGuard, ForkArgs},
|
||||
protocol::{ProcCall, RtSigInfo},
|
||||
signal::{inner_c, PosixStackt, RtSigarea, SigStack, PROC_CONTROL_STRUCT},
|
||||
RtTcb, Tcb,
|
||||
};
|
||||
@@ -20,6 +21,7 @@ pub struct SigArea {
|
||||
pub tmp_x1_x2: [usize; 2],
|
||||
pub tmp_x3_x4: [usize; 2],
|
||||
pub tmp_x5_x6: [usize; 2],
|
||||
pub tmp_x7_x8: [usize; 2],
|
||||
pub tmp_sp: usize,
|
||||
pub onstack: u64,
|
||||
pub disable_signals_depth: u64,
|
||||
@@ -97,20 +99,24 @@ pub fn copy_env_regs(cur_pid_fd: usize, new_pid_fd: usize) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe extern "C" fn fork_impl(initial_rsp: *mut usize) -> usize {
|
||||
Error::mux(fork_inner(initial_rsp))
|
||||
unsafe extern "C" fn fork_impl(args: &ForkArgs, initial_rsp: *mut usize) -> usize {
|
||||
Error::mux(fork_inner(initial_rsp, args))
|
||||
}
|
||||
|
||||
unsafe extern "C" fn child_hook(cur_filetable_fd: usize, new_pid_fd: usize) {
|
||||
unsafe extern "C" fn child_hook(cur_filetable_fd: usize, new_proc_fd: usize, new_thr_fd: usize) {
|
||||
//let _ = syscall::write(1, alloc::format!("CUR{cur_filetable_fd}PROC{new_proc_fd}THR{new_thr_fd}\n").as_bytes());
|
||||
let _ = syscall::close(cur_filetable_fd);
|
||||
// TODO: Currently pidfd == threadfd, but this will not be the case later.
|
||||
RtTcb::current()
|
||||
.thr_fd
|
||||
.get()
|
||||
.write(Some(FdGuard::new(new_pid_fd)));
|
||||
crate::child_hook_common(crate::ChildHookCommonArgs {
|
||||
new_thr_fd: FdGuard::new(new_thr_fd),
|
||||
new_proc_fd: if new_proc_fd == usize::MAX {
|
||||
None
|
||||
} else {
|
||||
Some(FdGuard::new(new_proc_fd))
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
asmfunction!(__relibc_internal_fork_wrapper -> usize: ["
|
||||
asmfunction!(__relibc_internal_fork_wrapper (usize) -> usize: ["
|
||||
stp x29, x30, [sp, #-16]!
|
||||
stp x27, x28, [sp, #-16]!
|
||||
stp x25, x26, [sp, #-16]!
|
||||
@@ -122,7 +128,8 @@ asmfunction!(__relibc_internal_fork_wrapper -> usize: ["
|
||||
|
||||
//TODO: store floating point regs
|
||||
|
||||
mov x0, sp
|
||||
// x0: &ForkArgs
|
||||
mov x1, sp
|
||||
bl {fork_impl}
|
||||
|
||||
add sp, sp, #32
|
||||
@@ -136,14 +143,14 @@ asmfunction!(__relibc_internal_fork_wrapper -> usize: ["
|
||||
"] <= [fork_impl = sym fork_impl]);
|
||||
|
||||
asmfunction!(__relibc_internal_fork_ret: ["
|
||||
ldp x0, x1, [sp]
|
||||
ldp x0, x1, [sp], #16
|
||||
ldp x2, x3, [sp], #16
|
||||
bl {child_hook}
|
||||
|
||||
//TODO: load floating point regs
|
||||
|
||||
mov x0, xzr
|
||||
|
||||
add sp, sp, #32
|
||||
ldp x19, x20, [sp], #16
|
||||
ldp x21, x22, [sp], #16
|
||||
ldp x23, x24, [sp], #16
|
||||
@@ -167,6 +174,7 @@ asmfunction!(__relibc_internal_sigentry: ["
|
||||
stp x1, x2, [x0, #{tcb_sa_off} + {sa_tmp_x1_x2}]
|
||||
stp x3, x4, [x0, #{tcb_sa_off} + {sa_tmp_x3_x4}]
|
||||
stp x5, x6, [x0, #{tcb_sa_off} + {sa_tmp_x5_x6}]
|
||||
stp x7, x8, [x0, #{tcb_sa_off} + {sa_tmp_x7_x8}]
|
||||
mov x1, sp
|
||||
str x1, [x0, #{tcb_sa_off} + {sa_tmp_sp}]
|
||||
|
||||
@@ -219,37 +227,47 @@ asmfunction!(__relibc_internal_sigentry: ["
|
||||
clrex
|
||||
|
||||
// Load the pending set again. TODO: optimize this?
|
||||
// Process pending - realtime
|
||||
add x1, x6, #{pctl_pending}
|
||||
ldaxr x2, [x1]
|
||||
lsr x2, x2, #32
|
||||
|
||||
// Thread pending - realtime and allowset
|
||||
add x5, x0, #{tcb_sc_off} + {sc_word} + 8
|
||||
ldar x1, [x5]
|
||||
|
||||
orr x2, x1, x2
|
||||
and x2, x2, x2, lsr #32
|
||||
cbz x2, 7f
|
||||
orr x2, x1, x2 // combine proc and thread pending
|
||||
and x2, x2, x2, lsr #32 // AND pending with allowset
|
||||
cbz x2, 7f // spurious signal if realtime is clear
|
||||
|
||||
rbit x3, x2
|
||||
clz x3, x3
|
||||
mov x4, #31
|
||||
sub x2, x4, x3
|
||||
rbit x2, x2
|
||||
clz x2, x2
|
||||
// x2 now contains sig_idx - 32
|
||||
|
||||
// If realtime signal was directed at thread, handle it as an idempotent signal.
|
||||
lsr x3, x1, x2
|
||||
tbnz x3, #0, 5f
|
||||
lsr x3, x1, x2 // x3 := x1 >> x2; x1 is thread pending
|
||||
tbnz x3, #0, 5f // jump if bit is nonzero
|
||||
|
||||
mov x5, x0
|
||||
mov x4, x8
|
||||
mov x8, #{SYS_SIGDEQUEUE}
|
||||
mov x0, x1
|
||||
add x1, x0, #{tcb_sa_off} + {sa_tmp_rt_inf}
|
||||
// SYS_CALL(fd, payload_base, payload_len, metadata_len, metadata_base | (flags << 8))
|
||||
// x8 x0 x1 x2 x3 x4
|
||||
|
||||
mov x5, x0 // save TCB pointer
|
||||
mov x6, x2
|
||||
ldr x8, ={SYS_CALL}
|
||||
adrp x0, {proc_fd}
|
||||
ldr x0, [x0, #:lo12:{proc_fd}]
|
||||
add x1, x5, #{tcb_sa_off} + {sa_tmp_rt_inf}
|
||||
str x6, [x1]
|
||||
mov x2, #{RTINF_SIZE}
|
||||
adrp x4, {proc_call}
|
||||
add x4, x4, :lo12:{proc_call}
|
||||
mov x3, #1
|
||||
svc 0
|
||||
mov x0, x5
|
||||
mov x8, x4
|
||||
cbnz x0, 1b
|
||||
|
||||
mov x3, x0
|
||||
mov x0, x5 // restore TCB pointer
|
||||
mov x2, x6 // restore signal number - 32
|
||||
add x1, x2, #32 // signal number
|
||||
cbnz x3, 1b
|
||||
b 2f
|
||||
5:
|
||||
// A realtime signal was sent to this thread, try clearing its bit.
|
||||
@@ -278,7 +296,7 @@ asmfunction!(__relibc_internal_sigentry: ["
|
||||
b 2f
|
||||
3:
|
||||
// A standard signal was sent to this thread, try clearing its bit.
|
||||
clz x1, x1
|
||||
clz w1, w1
|
||||
mov x2, #31
|
||||
sub x1, x2, x1
|
||||
|
||||
@@ -299,7 +317,7 @@ asmfunction!(__relibc_internal_sigentry: ["
|
||||
str x2, [x0, #{tcb_sa_off} + {sa_tmp_id_inf}]
|
||||
2:
|
||||
ldr x3, [x0, #{tcb_sa_off} + {sa_pctl}]
|
||||
add x2, x2, {pctl_actions}
|
||||
add x3, x3, {pctl_actions}
|
||||
add x2, x3, w1, uxtb #4 // actions_base + sig_idx * sizeof Action
|
||||
// TODO: NOT ATOMIC (tearing allowed between regs)!
|
||||
ldxp x2, x3, [x2]
|
||||
@@ -328,8 +346,9 @@ asmfunction!(__relibc_internal_sigentry: ["
|
||||
stp x4, x3, [sp, #-16]!
|
||||
ldp x5, x6, [x0, #{tcb_sa_off} + {sa_tmp_x5_x6}]
|
||||
stp x6, x5, [sp, #-16]!
|
||||
|
||||
ldp x7, x8, [x0, #{tcb_sa_off} + {sa_tmp_x7_x8}]
|
||||
stp x8, x7, [sp, #-16]!
|
||||
|
||||
stp x10, x9, [sp, #-16]!
|
||||
stp x12, x11, [sp, #-16]!
|
||||
stp x14, x13, [sp, #-16]!
|
||||
@@ -400,6 +419,7 @@ asmfunction!(__relibc_internal_sigentry: ["
|
||||
sa_tmp_x1_x2 = const offset_of!(SigArea, tmp_x1_x2),
|
||||
sa_tmp_x3_x4 = const offset_of!(SigArea, tmp_x3_x4),
|
||||
sa_tmp_x5_x6 = const offset_of!(SigArea, tmp_x5_x6),
|
||||
sa_tmp_x7_x8 = const offset_of!(SigArea, tmp_x7_x8),
|
||||
sa_tmp_sp = const offset_of!(SigArea, tmp_sp),
|
||||
sa_tmp_rt_inf = const offset_of!(SigArea, tmp_rt_inf),
|
||||
sa_tmp_id_inf = const offset_of!(SigArea, tmp_id_inf),
|
||||
@@ -409,12 +429,17 @@ asmfunction!(__relibc_internal_sigentry: ["
|
||||
sc_sender_infos = const offset_of!(Sigcontrol, sender_infos),
|
||||
sc_word = const offset_of!(Sigcontrol, word),
|
||||
sc_flags = const offset_of!(Sigcontrol, control_flags),
|
||||
proc_fd = sym PROC_FD,
|
||||
inner = sym inner_c,
|
||||
proc_call = sym PROC_CALL,
|
||||
|
||||
SA_ONSTACK_BIT = const 58, // (1 << 58) >> 32 = 0x0400_0000
|
||||
SYS_SIGDEQUEUE = const syscall::SYS_SIGDEQUEUE,
|
||||
|
||||
SYS_CALL = const syscall::SYS_CALL,
|
||||
|
||||
STACK_ALIGN = const 16,
|
||||
REDZONE_SIZE = const 128,
|
||||
RTINF_SIZE = const size_of::<RtSigInfo>(),
|
||||
]);
|
||||
|
||||
asmfunction!(__relibc_internal_rlct_clone_ret: ["
|
||||
@@ -460,3 +485,5 @@ pub unsafe fn arch_pre(stack: &mut SigStack, os: &mut SigArea) -> PosixStackt {
|
||||
flags: 0, // TODO
|
||||
}
|
||||
}
|
||||
pub(crate) static PROC_FD: SyncUnsafeCell<usize> = SyncUnsafeCell::new(usize::MAX);
|
||||
static PROC_CALL: [usize; 1] = [ProcCall::Sigdeq as usize];
|
||||
|
||||
+66
-27
@@ -1,9 +1,10 @@
|
||||
use core::{mem::offset_of, ptr::NonNull, sync::atomic::Ordering};
|
||||
use core::{cell::SyncUnsafeCell, mem::offset_of, ptr::NonNull, sync::atomic::Ordering};
|
||||
|
||||
use syscall::*;
|
||||
|
||||
use crate::{
|
||||
proc::{fork_inner, FdGuard},
|
||||
proc::{fork_inner, FdGuard, ForkArgs},
|
||||
protocol::{ProcCall, RtSigInfo},
|
||||
signal::{inner_fastcall, PosixStackt, RtSigarea, SigStack, PROC_CONTROL_STRUCT},
|
||||
RtTcb,
|
||||
};
|
||||
@@ -20,12 +21,15 @@ pub struct SigArea {
|
||||
pub tmp_eip: usize,
|
||||
pub tmp_esp: usize,
|
||||
pub tmp_eax: usize,
|
||||
pub tmp_ebx: usize,
|
||||
pub tmp_ecx: usize,
|
||||
pub tmp_edx: usize,
|
||||
pub tmp_edi: usize,
|
||||
pub tmp_esi: usize,
|
||||
pub tmp_rt_inf: RtSigInfo,
|
||||
pub tmp_signo: usize,
|
||||
pub tmp_id_inf: u64,
|
||||
pub tmp_mm0: u64,
|
||||
pub pctl: usize, // TODO: reference pctl directly
|
||||
pub disable_signals_depth: u64,
|
||||
pub last_sig_was_restart: bool,
|
||||
pub last_sigstack: Option<NonNull<SigStack>>,
|
||||
@@ -79,16 +83,30 @@ pub fn copy_env_regs(cur_pid_fd: usize, new_pid_fd: usize) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe extern "cdecl" fn fork_impl(initial_rsp: *mut usize) -> usize {
|
||||
Error::mux(fork_inner(initial_rsp))
|
||||
unsafe extern "fastcall" fn fork_impl(args: &ForkArgs, initial_rsp: *mut usize) -> usize {
|
||||
Error::mux(fork_inner(initial_rsp, args))
|
||||
}
|
||||
|
||||
unsafe extern "cdecl" fn child_hook(cur_filetable_fd: usize, new_pid_fd: usize) {
|
||||
// TODO: duplicate code with x86_64
|
||||
unsafe extern "cdecl" fn child_hook(
|
||||
cur_filetable_fd: usize,
|
||||
new_proc_fd: usize,
|
||||
new_thr_fd: usize,
|
||||
) {
|
||||
let _ = syscall::close(cur_filetable_fd);
|
||||
crate::child_hook_common(FdGuard::new(new_pid_fd));
|
||||
crate::child_hook_common(crate::ChildHookCommonArgs {
|
||||
new_thr_fd: FdGuard::new(new_thr_fd),
|
||||
new_proc_fd: if new_proc_fd == usize::MAX {
|
||||
None
|
||||
} else {
|
||||
Some(FdGuard::new(new_proc_fd))
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
asmfunction!(__relibc_internal_fork_wrapper -> usize: ["
|
||||
asmfunction!(__relibc_internal_fork_wrapper (usize) -> usize: ["
|
||||
mov ecx, [esp+4]
|
||||
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
@@ -103,9 +121,9 @@ asmfunction!(__relibc_internal_fork_wrapper -> usize: ["
|
||||
//TODO stmxcsr [esp+16]
|
||||
fnstcw [esp+24]
|
||||
|
||||
push esp
|
||||
mov edx, esp
|
||||
call {fork_impl}
|
||||
pop esp
|
||||
|
||||
jmp 2f
|
||||
"] <= [fork_impl = sym fork_impl]);
|
||||
|
||||
@@ -137,6 +155,9 @@ asmfunction!(__relibc_internal_sigentry: ["
|
||||
mov gs:[{tcb_sa_off} + {sa_tmp_eax}], eax
|
||||
mov gs:[{tcb_sa_off} + {sa_tmp_edx}], edx
|
||||
mov gs:[{tcb_sa_off} + {sa_tmp_ecx}], ecx
|
||||
mov gs:[{tcb_sa_off} + {sa_tmp_ebx}], ebx
|
||||
mov gs:[{tcb_sa_off} + {sa_tmp_edi}], edi
|
||||
mov gs:[{tcb_sa_off} + {sa_tmp_esi}], esi
|
||||
1:
|
||||
// Read standard signal word - first for this thread
|
||||
mov edx, gs:[{tcb_sc_off} + {sc_word} + 4]
|
||||
@@ -145,9 +166,8 @@ asmfunction!(__relibc_internal_sigentry: ["
|
||||
bsf eax, eax
|
||||
jnz 9f
|
||||
|
||||
mov ecx, gs:[{tcb_sa_off} + {sa_pctl}]
|
||||
|
||||
// Read standard signal word - for the process
|
||||
lea ecx, [{pctl}]
|
||||
mov eax, [ecx + {pctl_pending}]
|
||||
and eax, edx
|
||||
bsf eax, eax
|
||||
@@ -169,24 +189,31 @@ asmfunction!(__relibc_internal_sigentry: ["
|
||||
mov eax, gs:[{tcb_sc_off} + {sc_word} + 8]
|
||||
or eax, edx
|
||||
and eax, gs:[{tcb_sc_off} + {sc_word} + 12]
|
||||
jz 7f // spurious signal
|
||||
bsf eax, eax
|
||||
jz 7f // spurious signal
|
||||
|
||||
// If thread was specifically targeted, send the signal to it first.
|
||||
// If thread rather than process was specifically targeted, send the signal to it first.
|
||||
bt edx, eax
|
||||
jc 8f
|
||||
jnc 8f
|
||||
|
||||
mov edx, ebx
|
||||
lea ecx, [eax+32]
|
||||
mov eax, {SYS_SIGDEQUEUE}
|
||||
mov edx, gs:[0]
|
||||
add edx, {tcb_sa_off} + {sa_tmp_rt_inf}
|
||||
// SYS_CALL(fd, payload_base, payload_len, metadata_len, metadata_base)
|
||||
// eax ebx ecx edx esi edi
|
||||
|
||||
mov ebx, [{proc_fd}]
|
||||
mov ecx, gs:[0]
|
||||
add ecx, {tcb_sa_off} + {sa_tmp_rt_inf}
|
||||
mov [ecx], eax
|
||||
mov gs:[{tcb_sa_off} + {sa_tmp_signo}], eax
|
||||
mov edx, {RTINF_SIZE}
|
||||
mov esi, 1
|
||||
lea edi, [{proc_call}]
|
||||
mov eax, {SYS_CALL}
|
||||
int 0x80
|
||||
mov ebx, edx
|
||||
test eax, eax
|
||||
jnz 1b
|
||||
|
||||
mov eax, ecx
|
||||
mov eax, gs:[{tcb_sa_off} + {sa_tmp_signo}]
|
||||
add eax, 32
|
||||
jmp 2f
|
||||
8:
|
||||
add eax, 32
|
||||
@@ -228,9 +255,9 @@ asmfunction!(__relibc_internal_sigentry: ["
|
||||
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_edx}]
|
||||
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_ecx}]
|
||||
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_eax}]
|
||||
push ebx
|
||||
push edi
|
||||
push esi
|
||||
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_ebx}]
|
||||
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_edi}]
|
||||
push dword ptr gs:[{tcb_sa_off} + {sa_tmp_esi}]
|
||||
push ebp
|
||||
|
||||
sub esp, 2 * 4 + 29 * 16
|
||||
@@ -274,8 +301,11 @@ __relibc_internal_sigentry_crit_second:
|
||||
mov gs:[{tcb_sa_off} + {sa_tmp_eip}], eax
|
||||
|
||||
mov eax, gs:[{tcb_sa_off} + {sa_tmp_eax}]
|
||||
mov ebx, gs:[{tcb_sa_off} + {sa_tmp_ebx}]
|
||||
mov ecx, gs:[{tcb_sa_off} + {sa_tmp_ecx}]
|
||||
mov edx, gs:[{tcb_sa_off} + {sa_tmp_edx}]
|
||||
mov edi, gs:[{tcb_sa_off} + {sa_tmp_edi}]
|
||||
mov esi, gs:[{tcb_sa_off} + {sa_tmp_esi}]
|
||||
|
||||
and dword ptr gs:[{tcb_sc_off} + {sc_control}], ~1
|
||||
.globl __relibc_internal_sigentry_crit_third
|
||||
@@ -286,14 +316,17 @@ __relibc_internal_sigentry_crit_third:
|
||||
sa_tmp_eip = const offset_of!(SigArea, tmp_eip),
|
||||
sa_tmp_esp = const offset_of!(SigArea, tmp_esp),
|
||||
sa_tmp_eax = const offset_of!(SigArea, tmp_eax),
|
||||
sa_tmp_ebx = const offset_of!(SigArea, tmp_ebx),
|
||||
sa_tmp_ecx = const offset_of!(SigArea, tmp_ecx),
|
||||
sa_tmp_edx = const offset_of!(SigArea, tmp_edx),
|
||||
sa_tmp_edi = const offset_of!(SigArea, tmp_edi),
|
||||
sa_tmp_esi = const offset_of!(SigArea, tmp_esi),
|
||||
sa_tmp_mm0 = const offset_of!(SigArea, tmp_mm0),
|
||||
sa_tmp_rt_inf = const offset_of!(SigArea, tmp_rt_inf),
|
||||
sa_tmp_id_inf = const offset_of!(SigArea, tmp_id_inf),
|
||||
sa_tmp_signo = const offset_of!(SigArea, tmp_signo),
|
||||
sa_altstack_top = const offset_of!(SigArea, altstack_top),
|
||||
sa_altstack_bottom = const offset_of!(SigArea, altstack_bottom),
|
||||
sa_pctl = const offset_of!(SigArea, pctl),
|
||||
sc_control = const offset_of!(Sigcontrol, control_flags),
|
||||
sc_saved_eflags = const offset_of!(Sigcontrol, saved_archdep_reg),
|
||||
sc_saved_eip = const offset_of!(Sigcontrol, saved_ip),
|
||||
@@ -305,8 +338,11 @@ __relibc_internal_sigentry_crit_third:
|
||||
pctl_sender_infos = const offset_of!(SigProcControl, sender_infos),
|
||||
pctl_pending = const offset_of!(SigProcControl, pending),
|
||||
pctl = sym PROC_CONTROL_STRUCT,
|
||||
proc_fd = sym PROC_FD,
|
||||
proc_call = sym PROC_CALL,
|
||||
STACK_ALIGN = const 16,
|
||||
SYS_SIGDEQUEUE = const syscall::SYS_SIGDEQUEUE,
|
||||
SYS_CALL = const syscall::SYS_CALL,
|
||||
RTINF_SIZE = const size_of::<RtSigInfo>(),
|
||||
]);
|
||||
|
||||
asmfunction!(__relibc_internal_rlct_clone_ret -> usize: ["
|
||||
@@ -377,3 +413,6 @@ pub fn current_sp() -> usize {
|
||||
}
|
||||
sp
|
||||
}
|
||||
|
||||
pub static PROC_FD: SyncUnsafeCell<usize> = SyncUnsafeCell::new(usize::MAX);
|
||||
static PROC_CALL: u64 = ProcCall::Sigdeq as u64;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use core::cell::SyncUnsafeCell;
|
||||
|
||||
use crate::{
|
||||
proc::{fork_inner, FdGuard},
|
||||
proc::{fork_inner, FdGuard, ForkArgs},
|
||||
protocol::{ProcCall, RtSigInfo},
|
||||
signal::{get_sigaltstack, inner_c, PosixStackt, RtSigarea, SigStack},
|
||||
RtTcb, Tcb,
|
||||
};
|
||||
@@ -21,6 +24,8 @@ pub struct SigArea {
|
||||
pub tmp_a0: u64,
|
||||
pub tmp_a1: u64,
|
||||
pub tmp_a2: u64,
|
||||
pub tmp_a3: u64,
|
||||
pub tmp_a4: u64,
|
||||
pub tmp_a7: u64,
|
||||
|
||||
pub pctl: usize, // TODO: remove
|
||||
@@ -70,16 +75,23 @@ pub fn copy_env_regs(cur_pid_fd: usize, new_pid_fd: usize) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe extern "C" fn fork_impl(initial_rsp: *mut usize) -> usize {
|
||||
Error::mux(fork_inner(initial_rsp))
|
||||
unsafe extern "C" fn fork_impl(args: &ForkArgs, initial_rsp: *mut usize) -> usize {
|
||||
Error::mux(fork_inner(initial_rsp, args))
|
||||
}
|
||||
|
||||
unsafe extern "C" fn child_hook(cur_filetable_fd: usize, new_pid_fd: usize) {
|
||||
unsafe extern "C" fn child_hook(cur_filetable_fd: usize, new_proc_fd: usize, new_thr_fd: usize) {
|
||||
let _ = syscall::close(cur_filetable_fd);
|
||||
crate::child_hook_common(FdGuard::new(new_pid_fd));
|
||||
crate::child_hook_common(crate::ChildHookCommonArgs {
|
||||
new_thr_fd: FdGuard::new(new_thr_fd),
|
||||
new_proc_fd: if new_proc_fd == usize::MAX {
|
||||
None
|
||||
} else {
|
||||
Some(FdGuard::new(new_proc_fd))
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
asmfunction!(__relibc_internal_fork_wrapper -> usize: ["
|
||||
asmfunction!(__relibc_internal_fork_wrapper (usize) -> usize: ["
|
||||
.attribute arch, \"rv64gc\" # rust bug 80608
|
||||
addi sp, sp, -200
|
||||
sd s0, 0(sp)
|
||||
@@ -110,7 +122,8 @@ asmfunction!(__relibc_internal_fork_wrapper -> usize: ["
|
||||
fsd fs11, 192(sp)
|
||||
|
||||
addi sp, sp, -32
|
||||
mv a0, sp
|
||||
// a0 is forwarded from this function
|
||||
mv a1, sp
|
||||
jal {fork_impl}
|
||||
|
||||
addi sp, sp, 32
|
||||
@@ -148,8 +161,9 @@ asmfunction!(__relibc_internal_fork_wrapper -> usize: ["
|
||||
|
||||
asmfunction!(__relibc_internal_fork_ret: ["
|
||||
.attribute arch, \"rv64gc\" # rust bug 80608
|
||||
ld a0, 0(sp)
|
||||
ld a1, 8(sp)
|
||||
ld a0, 0(sp) // cur_filetable_fd
|
||||
ld a1, 8(sp) // new_proc_fd
|
||||
ld a2, 16(sp) // new_thr_fd
|
||||
jal {child_hook}
|
||||
|
||||
mv a0, x0
|
||||
@@ -259,14 +273,30 @@ asmfunction!(__relibc_internal_sigentry: ["
|
||||
bnez t1, 10f // thread signal
|
||||
|
||||
// otherwise, try (competitively) dequeueing realtime signal
|
||||
|
||||
// SYS_CALL(fd, payload_base, payload_len, metadata_len, metadata_base)
|
||||
// a7 a0 a1 a2 a3 a4
|
||||
|
||||
// TODO: This SYS_CALL invocation has not yet been tested due to toolchain issues.
|
||||
|
||||
sd a0, ({tcb_sa_off} + {sa_tmp_a0})(t0)
|
||||
sd a1, ({tcb_sa_off} + {sa_tmp_a1})(t0)
|
||||
sd a2, ({tcb_sa_off} + {sa_tmp_a2})(t0)
|
||||
sd a3, ({tcb_sa_off} + {sa_tmp_a3})(t0)
|
||||
sd a4, ({tcb_sa_off} + {sa_tmp_a4})(t0)
|
||||
sd a7, ({tcb_sa_off} + {sa_tmp_a7})(t0)
|
||||
li a0, {SYS_SIGDEQUEUE}
|
||||
addi a1, t3, -32
|
||||
add a2, t0, {tcb_sa_off} + {sa_tmp_rt_inf} // out pointer of dequeued realtime sig
|
||||
li a7, {SYS_CALL}
|
||||
addi a2, t3, -32
|
||||
add a1, t0, {tcb_sa_off} + {sa_tmp_rt_inf} // out pointer of dequeued realtime sig
|
||||
sd a2, (a1)
|
||||
li a2, {RTINF_SIZE}
|
||||
li a3, 1
|
||||
1337:
|
||||
auipc a4, %pcrel_hi({proc_fd})
|
||||
addi a4, a4, %pcrel_lo(1337b)
|
||||
ecall
|
||||
ld a3, ({tcb_sa_off} + {sa_tmp_a3})(t0)
|
||||
ld a4, ({tcb_sa_off} + {sa_tmp_a4})(t0)
|
||||
bnez a0, 99b // assumes error can only be EAGAIN
|
||||
j 9f
|
||||
|
||||
@@ -520,6 +550,8 @@ __relibc_internal_sigentry_crit_fifth:
|
||||
sa_tmp_a0 = const offset_of!(SigArea, tmp_a0),
|
||||
sa_tmp_a1 = const offset_of!(SigArea, tmp_a1),
|
||||
sa_tmp_a2 = const offset_of!(SigArea, tmp_a2),
|
||||
sa_tmp_a3 = const offset_of!(SigArea, tmp_a3),
|
||||
sa_tmp_a4 = const offset_of!(SigArea, tmp_a4),
|
||||
sa_tmp_a7 = const offset_of!(SigArea, tmp_a7),
|
||||
sa_tmp_ip = const offset_of!(SigArea, tmp_ip),
|
||||
sa_tmp_id_inf = const offset_of!(SigArea, tmp_id_inf),
|
||||
@@ -531,7 +563,9 @@ __relibc_internal_sigentry_crit_fifth:
|
||||
inner = sym inner_c,
|
||||
pctl_off_pending = const offset_of!(SigProcControl, pending),
|
||||
pctl_off_sender_infos = const offset_of!(SigProcControl, sender_infos),
|
||||
SYS_SIGDEQUEUE = const syscall::SYS_SIGDEQUEUE,
|
||||
SYS_CALL = const syscall::SYS_CALL,
|
||||
RTINF_SIZE = const size_of::<RtSigInfo>(),
|
||||
proc_fd = sym PROC_FD,
|
||||
]);
|
||||
|
||||
asmfunction!(__relibc_internal_rlct_clone_ret: ["
|
||||
@@ -620,3 +654,5 @@ pub unsafe fn arch_pre(stack: &mut SigStack, area: &mut SigArea) -> PosixStackt
|
||||
|
||||
get_sigaltstack(area, stack.regs.int_regs[1] as usize).into()
|
||||
}
|
||||
pub(crate) static PROC_FD: SyncUnsafeCell<usize> = SyncUnsafeCell::new(usize::MAX);
|
||||
static PROC_CALL: [usize; 1] = [ProcCall::Sigdeq as usize];
|
||||
|
||||
+62
-24
@@ -1,4 +1,5 @@
|
||||
use core::{
|
||||
cell::SyncUnsafeCell,
|
||||
mem::offset_of,
|
||||
ptr::NonNull,
|
||||
sync::atomic::{AtomicU8, Ordering},
|
||||
@@ -7,11 +8,11 @@ use core::{
|
||||
use syscall::{
|
||||
data::{SigProcControl, Sigcontrol},
|
||||
error::*,
|
||||
RtSigInfo,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
proc::{fork_inner, FdGuard},
|
||||
proc::{fork_inner, FdGuard, ForkArgs},
|
||||
protocol::{ProcCall, RtSigInfo},
|
||||
signal::{get_sigaltstack, inner_c, PosixStackt, RtSigarea, SigStack, PROC_CONTROL_STRUCT},
|
||||
Tcb,
|
||||
};
|
||||
@@ -29,6 +30,9 @@ pub struct SigArea {
|
||||
pub tmp_rdx: usize,
|
||||
pub tmp_rdi: usize,
|
||||
pub tmp_rsi: usize,
|
||||
pub tmp_r8: usize,
|
||||
pub tmp_r10: usize,
|
||||
pub tmp_r12: usize,
|
||||
pub tmp_rt_inf: RtSigInfo,
|
||||
pub tmp_id_inf: u64,
|
||||
|
||||
@@ -92,16 +96,27 @@ pub fn copy_env_regs(cur_pid_fd: usize, new_pid_fd: usize) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe extern "sysv64" fn fork_impl(initial_rsp: *mut usize) -> usize {
|
||||
Error::mux(fork_inner(initial_rsp))
|
||||
unsafe extern "sysv64" fn fork_impl(args: &ForkArgs, initial_rsp: *mut usize) -> usize {
|
||||
Error::mux(fork_inner(initial_rsp, args))
|
||||
}
|
||||
|
||||
unsafe extern "sysv64" fn child_hook(cur_filetable_fd: usize, new_pid_fd: usize) {
|
||||
unsafe extern "sysv64" fn child_hook(
|
||||
cur_filetable_fd: usize,
|
||||
new_proc_fd: usize,
|
||||
new_thr_fd: usize,
|
||||
) {
|
||||
let _ = syscall::close(cur_filetable_fd);
|
||||
crate::child_hook_common(FdGuard::new(new_pid_fd));
|
||||
crate::child_hook_common(crate::ChildHookCommonArgs {
|
||||
new_thr_fd: FdGuard::new(new_thr_fd),
|
||||
new_proc_fd: if new_proc_fd == usize::MAX {
|
||||
None
|
||||
} else {
|
||||
Some(FdGuard::new(new_proc_fd))
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
asmfunction!(__relibc_internal_fork_wrapper -> usize: ["
|
||||
asmfunction!(__relibc_internal_fork_wrapper (usize) -> usize: ["
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
|
||||
@@ -112,15 +127,16 @@ asmfunction!(__relibc_internal_fork_wrapper -> usize: ["
|
||||
push r14
|
||||
push r15
|
||||
|
||||
sub rsp, 32
|
||||
sub rsp, 48
|
||||
|
||||
stmxcsr [rsp+16]
|
||||
fnstcw [rsp+24]
|
||||
stmxcsr [rsp+32]
|
||||
fnstcw [rsp+40]
|
||||
|
||||
mov rdi, rsp
|
||||
// rdi: &ForkArgs
|
||||
mov rsi, rsp
|
||||
call {fork_impl}
|
||||
|
||||
add rsp, 80
|
||||
add rsp, 96
|
||||
|
||||
pop rbp
|
||||
ret
|
||||
@@ -129,14 +145,15 @@ asmfunction!(__relibc_internal_fork_wrapper -> usize: ["
|
||||
asmfunction!(__relibc_internal_fork_ret: ["
|
||||
mov rdi, [rsp]
|
||||
mov rsi, [rsp + 8]
|
||||
mov rdx, [rsp + 16]
|
||||
call {child_hook}
|
||||
|
||||
ldmxcsr [rsp + 16]
|
||||
fldcw [rsp + 24]
|
||||
ldmxcsr [rsp + 32]
|
||||
fldcw [rsp + 40]
|
||||
|
||||
xor rax, rax
|
||||
|
||||
add rsp, 32
|
||||
add rsp, 48
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
@@ -175,6 +192,9 @@ asmfunction!(__relibc_internal_sigentry: ["
|
||||
mov fs:[{tcb_sa_off} + {sa_tmp_rdx}], rdx
|
||||
mov fs:[{tcb_sa_off} + {sa_tmp_rdi}], rdi
|
||||
mov fs:[{tcb_sa_off} + {sa_tmp_rsi}], rsi
|
||||
mov fs:[{tcb_sa_off} + {sa_tmp_r12}], r8
|
||||
mov fs:[{tcb_sa_off} + {sa_tmp_r12}], r10
|
||||
mov fs:[{tcb_sa_off} + {sa_tmp_r12}], r12
|
||||
|
||||
// First, select signal, always pick first available bit
|
||||
1:
|
||||
@@ -212,14 +232,23 @@ asmfunction!(__relibc_internal_sigentry: ["
|
||||
jc 2f // if so, continue as usual
|
||||
|
||||
// otherwise, try (competitively) dequeueing realtime signal
|
||||
mov esi, eax
|
||||
mov eax, {SYS_SIGDEQUEUE}
|
||||
mov rdi, fs:[0]
|
||||
add rdi, {tcb_sa_off} + {sa_tmp_rt_inf} // out pointer of dequeued realtime sig
|
||||
|
||||
// SYS_CALL(fd, payload_base, payload_len, metadata_len | (flags << 8), metadata_base)
|
||||
// rax rdi rsi rdx r10 r8
|
||||
|
||||
mov r12d, eax
|
||||
mov rsi, fs:[0]
|
||||
mov rdi, [rip+{proc_fd}]
|
||||
add rsi, {tcb_sa_off} + {sa_tmp_rt_inf} // out pointer of dequeued realtime sig
|
||||
mov rdx, {RTINF_SIZE}
|
||||
mov [rsi], eax
|
||||
lea r8, [rip + {proc_call_sigdeq}]
|
||||
mov r10, 1
|
||||
mov eax, {SYS_CALL}
|
||||
syscall
|
||||
test eax, eax
|
||||
jnz 1b // assumes error can only be EAGAIN
|
||||
lea eax, [esi + 32]
|
||||
lea eax, [r12d + 32]
|
||||
jmp 9f
|
||||
2:
|
||||
mov edx, eax
|
||||
@@ -272,13 +301,13 @@ asmfunction!(__relibc_internal_sigentry: ["
|
||||
push fs:[{tcb_sa_off} + {sa_tmp_rdx}]
|
||||
push rcx
|
||||
push fs:[{tcb_sa_off} + {sa_tmp_rax}]
|
||||
push r8
|
||||
push fs:[{tcb_sa_off} + {sa_tmp_r8}]
|
||||
push r9
|
||||
push r10
|
||||
push fs:[{tcb_sa_off} + {sa_tmp_r10}]
|
||||
push r11
|
||||
push rbx
|
||||
push rbp
|
||||
push r12
|
||||
push fs:[{tcb_sa_off} + {sa_tmp_r12}]
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
@@ -405,6 +434,9 @@ __relibc_internal_sigentry_crit_third:
|
||||
sa_tmp_rdx = const offset_of!(SigArea, tmp_rdx),
|
||||
sa_tmp_rdi = const offset_of!(SigArea, tmp_rdi),
|
||||
sa_tmp_rsi = const offset_of!(SigArea, tmp_rsi),
|
||||
sa_tmp_r8 = const offset_of!(SigArea, tmp_r8),
|
||||
sa_tmp_r10 = const offset_of!(SigArea, tmp_r10),
|
||||
sa_tmp_r12 = const offset_of!(SigArea, tmp_r12),
|
||||
sa_tmp_rt_inf = const offset_of!(SigArea, tmp_rt_inf),
|
||||
sa_tmp_id_inf = const offset_of!(SigArea, tmp_id_inf),
|
||||
sa_altstack_top = const offset_of!(SigArea, altstack_top),
|
||||
@@ -424,7 +456,10 @@ __relibc_internal_sigentry_crit_third:
|
||||
REDZONE_SIZE = const 128,
|
||||
STACK_ALIGN = const 16,
|
||||
SA_ONSTACK_BIT = const 58, // (1 << 58) >> 32 = 0x0400_0000
|
||||
SYS_SIGDEQUEUE = const syscall::SYS_SIGDEQUEUE,
|
||||
SYS_CALL = const syscall::SYS_CALL,
|
||||
proc_call_sigdeq = sym PROC_CALL_SIGDEQ,
|
||||
RTINF_SIZE = const size_of::<RtSigInfo>(),
|
||||
proc_fd = sym PROC_FD,
|
||||
]);
|
||||
|
||||
extern "C" {
|
||||
@@ -490,3 +525,6 @@ pub fn current_sp() -> usize {
|
||||
}
|
||||
sp
|
||||
}
|
||||
|
||||
static PROC_CALL_SIGDEQ: u64 = ProcCall::Sigdeq as u64;
|
||||
pub(crate) static PROC_FD: SyncUnsafeCell<usize> = SyncUnsafeCell::new(usize::MAX);
|
||||
|
||||
+136
-27
@@ -2,6 +2,7 @@
|
||||
#![feature(
|
||||
asm_const,
|
||||
array_chunks,
|
||||
core_intrinsics,
|
||||
int_roundings,
|
||||
let_chains,
|
||||
slice_ptr_get,
|
||||
@@ -9,18 +10,25 @@
|
||||
)]
|
||||
#![forbid(unreachable_patterns)]
|
||||
|
||||
use core::cell::{SyncUnsafeCell, UnsafeCell};
|
||||
use core::{
|
||||
cell::{SyncUnsafeCell, UnsafeCell},
|
||||
mem::{size_of, MaybeUninit},
|
||||
};
|
||||
|
||||
use generic_rt::{ExpectTlsFree, GenericTcb};
|
||||
use syscall::{Sigcontrol, O_CLOEXEC};
|
||||
use syscall::Sigcontrol;
|
||||
|
||||
use self::proc::FdGuard;
|
||||
use self::{
|
||||
proc::{FdGuard, STATIC_PROC_INFO},
|
||||
protocol::ProcMeta,
|
||||
sync::Mutex,
|
||||
};
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! asmfunction(
|
||||
($name:ident $(-> $ret:ty)? : [$($asmstmt:expr),*$(,)?] <= [$($decl:ident = $(sym $symname:ident)?$(const $constval:expr)?),*$(,)?]$(,)? ) => {
|
||||
($name:ident $(($($arg:ty),*))? $(-> $ret:ty)? : [$($asmstmt:expr),*$(,)?] <= [$($decl:ident = $(sym $symname:ident)?$(const $constval:expr)?),*$(,)?]$(,)? ) => {
|
||||
::core::arch::global_asm!(concat!("
|
||||
.p2align 4
|
||||
.section .text.", stringify!($name), ", \"ax\", @progbits
|
||||
@@ -32,7 +40,7 @@ macro_rules! asmfunction(
|
||||
"), $($decl = $(sym $symname)?$(const $constval)?),*);
|
||||
|
||||
extern "C" {
|
||||
pub fn $name() $(-> $ret)?;
|
||||
pub fn $name($($(_: $arg),*)?) $(-> $ret)?;
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -44,6 +52,7 @@ pub mod proc;
|
||||
#[path = "../../src/platform/auxv_defs.rs"]
|
||||
pub mod auxv_defs;
|
||||
|
||||
pub mod protocol;
|
||||
pub mod signal;
|
||||
pub mod sync;
|
||||
pub mod sys;
|
||||
@@ -60,14 +69,7 @@ impl RtTcb {
|
||||
unsafe { &Tcb::current().unwrap().os_specific }
|
||||
}
|
||||
pub fn thread_fd(&self) -> &FdGuard {
|
||||
unsafe {
|
||||
if (&*self.thr_fd.get()).is_none() {
|
||||
self.thr_fd.get().write(Some(FdGuard::new(
|
||||
syscall::open("/scheme/thisproc/current/open_via_dup", O_CLOEXEC).unwrap(),
|
||||
)));
|
||||
}
|
||||
(&*self.thr_fd.get()).as_ref().unwrap()
|
||||
}
|
||||
unsafe { (&*self.thr_fd.get()).as_ref().unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +136,8 @@ pub unsafe fn tcb_activate(_tcb: &RtTcb, tls_end: usize, tls_len: usize) {
|
||||
}
|
||||
|
||||
/// Initialize redox-rt in situations where relibc is not used
|
||||
pub unsafe fn initialize_freestanding() {
|
||||
#[cfg(not(feature = "proc"))]
|
||||
pub unsafe fn initialize_freestanding(this_thr_fd: FdGuard) -> &'static FdGuard {
|
||||
// TODO: This code is a hack! Integrate the ld_so TCB code into generic-rt, and then use that
|
||||
// (this function will need pointers to the ELF structs normally passed in auxvs), so the TCB
|
||||
// is initialized properly.
|
||||
@@ -157,8 +160,9 @@ pub unsafe fn initialize_freestanding() {
|
||||
page.tcb_ptr = page;
|
||||
page.tcb_len = syscall::PAGE_SIZE;
|
||||
page.tls_end = (page as *mut Tcb).cast();
|
||||
|
||||
// Make sure to use ptr::write to prevent dropping the existing FdGuard
|
||||
core::ptr::write(page.os_specific.thr_fd.get(), None);
|
||||
page.os_specific.thr_fd.get().write(Some(this_thr_fd));
|
||||
|
||||
#[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
|
||||
unsafe {
|
||||
@@ -176,19 +180,124 @@ pub unsafe fn initialize_freestanding() {
|
||||
core::arch::asm!("mv tp, {}", in(reg) (abi_ptr + 8));
|
||||
}
|
||||
initialize();
|
||||
|
||||
(*page.os_specific.thr_fd.get()).as_ref().unwrap()
|
||||
}
|
||||
pub unsafe fn initialize() {
|
||||
THIS_PID
|
||||
.get()
|
||||
.write(Some(syscall::getpid().unwrap().try_into().unwrap()).unwrap());
|
||||
pub(crate) fn read_proc_meta(proc: &FdGuard) -> syscall::Result<ProcMeta> {
|
||||
let mut bytes = [0_u8; size_of::<ProcMeta>()];
|
||||
let _ = syscall::read(**proc, &mut bytes)?;
|
||||
Ok(*plain::from_bytes::<ProcMeta>(&bytes).unwrap())
|
||||
}
|
||||
pub unsafe fn initialize(#[cfg(feature = "proc")] proc_fd: FdGuard) {
|
||||
#[cfg(feature = "proc")]
|
||||
let metadata = read_proc_meta(&proc_fd).unwrap();
|
||||
|
||||
#[cfg(not(feature = "proc"))]
|
||||
// Bootstrap mode, don't associate proc fds with PIDs
|
||||
let metadata = ProcMeta::default();
|
||||
|
||||
#[cfg(feature = "proc")]
|
||||
{
|
||||
crate::arch::PROC_FD.get().write(*proc_fd);
|
||||
}
|
||||
|
||||
STATIC_PROC_INFO.get().write(StaticProcInfo {
|
||||
pid: metadata.pid,
|
||||
|
||||
#[cfg(feature = "proc")]
|
||||
proc_fd: MaybeUninit::new(proc_fd),
|
||||
|
||||
#[cfg(not(feature = "proc"))]
|
||||
proc_fd: MaybeUninit::uninit(),
|
||||
|
||||
has_proc_fd: cfg!(feature = "proc"),
|
||||
});
|
||||
|
||||
#[cfg(feature = "proc")]
|
||||
{
|
||||
*DYNAMIC_PROC_INFO.lock() = DynamicProcInfo {
|
||||
pgid: metadata.pgid,
|
||||
ruid: metadata.ruid,
|
||||
euid: metadata.euid,
|
||||
suid: metadata.suid,
|
||||
egid: metadata.egid,
|
||||
rgid: metadata.rgid,
|
||||
sgid: metadata.sgid,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static THIS_PID: SyncUnsafeCell<u32> = SyncUnsafeCell::new(0);
|
||||
|
||||
unsafe fn child_hook_common(new_pid_fd: FdGuard) {
|
||||
// TODO: Currently pidfd == threadfd, but this will not be the case later.
|
||||
RtTcb::current().thr_fd.get().write(Some(new_pid_fd));
|
||||
THIS_PID
|
||||
.get()
|
||||
.write(Some(syscall::getpid().unwrap().try_into().unwrap()).unwrap());
|
||||
#[repr(C)] // TODO: is repr(C) required?
|
||||
pub(crate) struct StaticProcInfo {
|
||||
pid: u32,
|
||||
proc_fd: MaybeUninit<FdGuard>,
|
||||
has_proc_fd: bool,
|
||||
}
|
||||
struct DynamicProcInfo {
|
||||
pgid: u32,
|
||||
euid: u32,
|
||||
suid: u32,
|
||||
ruid: u32,
|
||||
egid: u32,
|
||||
rgid: u32,
|
||||
sgid: u32,
|
||||
}
|
||||
|
||||
static DYNAMIC_PROC_INFO: Mutex<DynamicProcInfo> = Mutex::new(DynamicProcInfo {
|
||||
pgid: u32::MAX,
|
||||
ruid: u32::MAX,
|
||||
euid: u32::MAX,
|
||||
suid: u32::MAX,
|
||||
rgid: u32::MAX,
|
||||
egid: u32::MAX,
|
||||
sgid: u32::MAX,
|
||||
});
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn static_proc_info() -> &'static StaticProcInfo {
|
||||
unsafe { &*STATIC_PROC_INFO.get() }
|
||||
}
|
||||
#[inline]
|
||||
pub fn current_proc_fd() -> &'static FdGuard {
|
||||
let info = static_proc_info();
|
||||
assert!(info.has_proc_fd);
|
||||
unsafe { info.proc_fd.assume_init_ref() }
|
||||
}
|
||||
|
||||
struct ChildHookCommonArgs {
|
||||
new_thr_fd: FdGuard,
|
||||
new_proc_fd: Option<FdGuard>,
|
||||
}
|
||||
|
||||
unsafe fn child_hook_common(args: ChildHookCommonArgs) {
|
||||
// TODO: just pass PID to child rather than obtaining it via IPC?
|
||||
#[cfg(feature = "proc")]
|
||||
let metadata = read_proc_meta(
|
||||
args.new_proc_fd
|
||||
.as_ref()
|
||||
.expect("must be present with proc feature"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
#[cfg(not(feature = "proc"))]
|
||||
let metadata = ProcMeta::default();
|
||||
|
||||
if let Some(proc_fd) = &args.new_proc_fd {
|
||||
crate::arch::PROC_FD.get().write(**proc_fd);
|
||||
}
|
||||
|
||||
let old_proc_fd = STATIC_PROC_INFO
|
||||
.get()
|
||||
.replace(StaticProcInfo {
|
||||
pid: metadata.pid,
|
||||
has_proc_fd: args.new_proc_fd.is_some(),
|
||||
proc_fd: args
|
||||
.new_proc_fd
|
||||
.map_or_else(MaybeUninit::uninit, MaybeUninit::new),
|
||||
})
|
||||
.proc_fd;
|
||||
drop(old_proc_fd);
|
||||
|
||||
let old_thr_fd = RtTcb::current().thr_fd.get().replace(Some(args.new_thr_fd));
|
||||
drop(old_thr_fd);
|
||||
}
|
||||
|
||||
+213
-86
@@ -1,6 +1,17 @@
|
||||
use core::{fmt::Debug, mem::size_of};
|
||||
use core::{
|
||||
cell::SyncUnsafeCell,
|
||||
fmt::Debug,
|
||||
mem::{size_of, MaybeUninit},
|
||||
};
|
||||
|
||||
use crate::{arch::*, auxv_defs::*};
|
||||
use crate::{
|
||||
arch::*,
|
||||
auxv_defs::*,
|
||||
protocol::{ProcCall, ThreadCall},
|
||||
read_proc_meta, static_proc_info,
|
||||
sys::{proc_call, thread_call},
|
||||
RtTcb, StaticProcInfo, DYNAMIC_PROC_INFO,
|
||||
};
|
||||
|
||||
use alloc::{boxed::Box, collections::BTreeMap, vec};
|
||||
|
||||
@@ -19,8 +30,8 @@ use goblin::elf64::{
|
||||
use syscall::{
|
||||
error::*,
|
||||
flag::{MapFlags, SEEK_SET},
|
||||
GrantDesc, GrantFlags, Map, SetSighandlerData, MAP_FIXED_NOREPLACE, MAP_SHARED, O_CLOEXEC,
|
||||
PAGE_SIZE, PROT_EXEC, PROT_READ, PROT_WRITE,
|
||||
CallFlags, GrantDesc, GrantFlags, Map, ProcSchemeAttrs, SetSighandlerData, MAP_FIXED_NOREPLACE,
|
||||
MAP_SHARED, O_CLOEXEC, PAGE_SIZE, PROT_EXEC, PROT_READ, PROT_WRITE,
|
||||
};
|
||||
|
||||
pub enum FexecResult {
|
||||
@@ -30,7 +41,6 @@ pub enum FexecResult {
|
||||
Interp {
|
||||
path: Box<[u8]>,
|
||||
image_file: FdGuard,
|
||||
open_via_dup: FdGuard,
|
||||
interp_override: InterpOverride,
|
||||
},
|
||||
}
|
||||
@@ -53,11 +63,16 @@ pub struct ExtraInfo<'a> {
|
||||
pub sigprocmask: u64,
|
||||
/// File mode creation mask (POSIX)
|
||||
pub umask: u32,
|
||||
/// Thread handle
|
||||
pub thr_fd: usize,
|
||||
/// Process handle
|
||||
pub proc_fd: usize,
|
||||
}
|
||||
|
||||
pub fn fexec_impl<A, E>(
|
||||
image_file: FdGuard,
|
||||
open_via_dup: FdGuard,
|
||||
thread_fd: &FdGuard,
|
||||
proc_fd: &FdGuard,
|
||||
memory_scheme_fd: &FdGuard,
|
||||
path: &[u8],
|
||||
args: A,
|
||||
@@ -74,15 +89,14 @@ where
|
||||
{
|
||||
// Here, we do the minimum part of loading an application, which is what the kernel used to do.
|
||||
// We load the executable into memory (albeit at different offsets in this executable), fix
|
||||
// some misalignments, and then execute the SYS_EXEC syscall to replace the program memory
|
||||
// entirely.
|
||||
// some misalignments, and then switch address space.
|
||||
|
||||
let mut header_bytes = [0_u8; size_of::<Header>()];
|
||||
pread_all(*image_file, 0, &mut header_bytes)?;
|
||||
let header = Header::from_bytes(&header_bytes);
|
||||
|
||||
let grants_fd = {
|
||||
let current_addrspace_fd = FdGuard::new(syscall::dup(*open_via_dup, b"addrspace")?);
|
||||
let current_addrspace_fd = FdGuard::new(syscall::dup(**thread_fd, b"addrspace")?);
|
||||
FdGuard::new(syscall::dup(*current_addrspace_fd, b"empty")?)
|
||||
};
|
||||
|
||||
@@ -107,7 +121,7 @@ where
|
||||
|o| core::mem::take(&mut o.tree),
|
||||
);
|
||||
|
||||
pread_all(*image_file as usize, header.e_phoff.into(), phs).map_err(|_| Error::new(EIO))?;
|
||||
pread_all(*image_file as usize, u64::from(header.e_phoff), phs).map_err(|_| Error::new(EIO))?;
|
||||
|
||||
for ph_idx in 0..phnum {
|
||||
let ph_bytes = &phs[ph_idx * phentsize..(ph_idx + 1) * phentsize];
|
||||
@@ -130,12 +144,15 @@ where
|
||||
// PT_INTERP must come before any PT_LOAD, so we don't have to iterate twice.
|
||||
PT_INTERP => {
|
||||
let mut interp = vec![0_u8; segment.p_filesz as usize];
|
||||
pread_all(*image_file as usize, segment.p_offset.into(), &mut interp)?;
|
||||
pread_all(
|
||||
*image_file as usize,
|
||||
u64::from(segment.p_offset),
|
||||
&mut interp,
|
||||
)?;
|
||||
|
||||
return Ok(FexecResult::Interp {
|
||||
path: interp.into_boxed_slice(),
|
||||
image_file,
|
||||
open_via_dup,
|
||||
interp_override: InterpOverride {
|
||||
at_entry: header.e_entry as usize,
|
||||
at_phnum: phnum,
|
||||
@@ -180,7 +197,7 @@ where
|
||||
};
|
||||
pread_all(
|
||||
*image_file,
|
||||
segment.p_offset.into(),
|
||||
u64::from(segment.p_offset),
|
||||
&mut dst_memory[voff..voff + filesz],
|
||||
)?;
|
||||
}
|
||||
@@ -372,7 +389,12 @@ where
|
||||
push(AT_REDOX_INHERITED_SIGPROCMASK)?;
|
||||
|
||||
push(extrainfo.umask as usize)?;
|
||||
push(AT_REDOX_UMASK);
|
||||
push(AT_REDOX_UMASK)?;
|
||||
|
||||
push(extrainfo.thr_fd as usize)?;
|
||||
push(AT_REDOX_THR_FD)?;
|
||||
push(extrainfo.proc_fd as usize)?;
|
||||
push(AT_REDOX_PROC_FD)?;
|
||||
|
||||
push(0)?;
|
||||
|
||||
@@ -390,7 +412,7 @@ where
|
||||
|
||||
push(argc)?;
|
||||
|
||||
if let Ok(sighandler_fd) = syscall::dup(*open_via_dup, b"sighandler").map(FdGuard::new) {
|
||||
if let Ok(sighandler_fd) = syscall::dup(**thread_fd, b"sighandler").map(FdGuard::new) {
|
||||
let _ = syscall::write(
|
||||
*sighandler_fd,
|
||||
&SetSighandlerData {
|
||||
@@ -400,15 +422,27 @@ where
|
||||
proc_control_addr: 0,
|
||||
},
|
||||
);
|
||||
// TODO: sync with procmgr
|
||||
}
|
||||
|
||||
unsafe {
|
||||
deactivate_tcb(*open_via_dup)?;
|
||||
deactivate_tcb(**thread_fd)?;
|
||||
}
|
||||
|
||||
// TODO: Restore old name if exec failed?
|
||||
if let Ok(name_fd) = syscall::dup(*open_via_dup, b"name").map(FdGuard::new) {
|
||||
let _ = syscall::write(*name_fd, interp_override.as_ref().map_or(path, |o| &o.name));
|
||||
{
|
||||
let mut buf = [0; 32];
|
||||
let new_name = interp_override.as_ref().map_or(path, |o| &o.name);
|
||||
let len = new_name.len().min(32);
|
||||
buf[..len].copy_from_slice(&new_name[..len]);
|
||||
// XXX: takes &mut [] since it can mutate, but we could unsafe{}ly pass it directly
|
||||
// otherwise
|
||||
let _ = proc_call(
|
||||
**proc_fd,
|
||||
&mut buf,
|
||||
CallFlags::empty(),
|
||||
&[ProcCall::Rename as u64],
|
||||
);
|
||||
}
|
||||
if interp_override.is_some() {
|
||||
let mmap_min_fd = FdGuard::new(syscall::dup(*grants_fd, b"mmap-min-addr")?);
|
||||
@@ -417,7 +451,7 @@ where
|
||||
let _ = syscall::write(*mmap_min_fd, &usize::to_ne_bytes(aligned_last_addr));
|
||||
}
|
||||
|
||||
let addrspace_selection_fd = FdGuard::new(syscall::dup(*open_via_dup, b"current-addrspace")?);
|
||||
let addrspace_selection_fd = FdGuard::new(syscall::dup(**thread_fd, b"current-addrspace")?);
|
||||
|
||||
let _ = syscall::write(
|
||||
*addrspace_selection_fd,
|
||||
@@ -631,32 +665,35 @@ impl Drop for MmapGuard {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct FdGuard {
|
||||
fd: usize,
|
||||
taken: bool,
|
||||
}
|
||||
impl FdGuard {
|
||||
pub fn new(fd: usize) -> Self {
|
||||
Self { fd, taken: false }
|
||||
#[inline]
|
||||
pub const fn new(fd: usize) -> Self {
|
||||
Self { fd }
|
||||
}
|
||||
pub fn take(&mut self) -> usize {
|
||||
self.taken = true;
|
||||
self.fd
|
||||
#[inline]
|
||||
pub fn take(self) -> usize {
|
||||
let fd = self.fd;
|
||||
core::mem::forget(self);
|
||||
fd
|
||||
}
|
||||
}
|
||||
impl core::ops::Deref for FdGuard {
|
||||
type Target = usize;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FdGuard {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
if !self.taken {
|
||||
let _ = syscall::close(self.fd);
|
||||
}
|
||||
let _ = syscall::close(self.fd);
|
||||
}
|
||||
}
|
||||
impl Debug for FdGuard {
|
||||
@@ -680,9 +717,13 @@ pub fn create_set_addr_space_buf(
|
||||
/// Spawns a new context which will not share the same address space as the current one. File
|
||||
/// descriptors from other schemes are reobtained with `dup`, and grants referencing such file
|
||||
/// descriptors are reobtained through `fmap`. Other mappings are kept but duplicated using CoW.
|
||||
pub fn fork_impl() -> Result<usize> {
|
||||
pub fn fork_impl(args: &ForkArgs<'_>) -> Result<usize> {
|
||||
let old_mask = crate::signal::get_sigmask()?;
|
||||
let pid = unsafe { Error::demux(__relibc_internal_fork_wrapper())? };
|
||||
let pid = unsafe {
|
||||
Error::demux(__relibc_internal_fork_wrapper(
|
||||
args as *const ForkArgs as usize,
|
||||
))?
|
||||
};
|
||||
|
||||
if pid == 0 {
|
||||
crate::signal::set_sigmask(Some(old_mask), None)?;
|
||||
@@ -690,36 +731,52 @@ pub fn fork_impl() -> Result<usize> {
|
||||
Ok(pid)
|
||||
}
|
||||
|
||||
pub fn fork_inner(initial_rsp: *mut usize) -> Result<usize> {
|
||||
let (cur_filetable_fd, new_pid_fd, new_pid);
|
||||
pub enum ForkArgs<'a> {
|
||||
Init {
|
||||
this_thr_fd: &'a FdGuard,
|
||||
auth: &'a FdGuard,
|
||||
},
|
||||
Managed,
|
||||
}
|
||||
|
||||
pub fn fork_inner(initial_rsp: *mut usize, args: &ForkArgs) -> Result<usize> {
|
||||
let (cur_filetable_fd, new_proc_fd, new_thr_fd, new_pid);
|
||||
|
||||
{
|
||||
let cur_pid_fd = FdGuard::new(syscall::open(
|
||||
"/scheme/thisproc/current/open_via_dup",
|
||||
O_CLOEXEC,
|
||||
)?);
|
||||
(new_pid_fd, new_pid) = new_child_process()?;
|
||||
|
||||
copy_str(*cur_pid_fd, *new_pid_fd, "name")?;
|
||||
let cur_thr_fd = match args {
|
||||
ForkArgs::Init { this_thr_fd, .. } => this_thr_fd,
|
||||
ForkArgs::Managed => RtTcb::current().thread_fd(),
|
||||
};
|
||||
let NewChildProc {
|
||||
proc_fd,
|
||||
thr_fd,
|
||||
pid,
|
||||
} = new_child_process(args)?;
|
||||
new_proc_fd = proc_fd;
|
||||
new_thr_fd = thr_fd;
|
||||
new_pid = pid;
|
||||
|
||||
// Copy existing files into new file table, but do not reuse the same file table (i.e. new
|
||||
// parent FDs will not show up for the child).
|
||||
{
|
||||
cur_filetable_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"filetable")?);
|
||||
cur_filetable_fd = FdGuard::new(syscall::dup(**cur_thr_fd, b"filetable")?);
|
||||
|
||||
// This must be done before the address space is copied.
|
||||
unsafe {
|
||||
let proc_fd = new_proc_fd.as_ref().map_or(usize::MAX, |p| **p);
|
||||
//let _ = syscall::write(1, alloc::format!("FDTBL{}PROC{}THR{}\n", *cur_filetable_fd, proc_fd, *new_thr_fd).as_bytes());
|
||||
initial_rsp.write(*cur_filetable_fd);
|
||||
initial_rsp.add(1).write(*new_pid_fd);
|
||||
initial_rsp.add(1).write(proc_fd);
|
||||
initial_rsp.add(2).write(*new_thr_fd);
|
||||
}
|
||||
}
|
||||
|
||||
// CoW-duplicate address space.
|
||||
{
|
||||
let new_addr_space_sel_fd =
|
||||
FdGuard::new(syscall::dup(*new_pid_fd, b"current-addrspace")?);
|
||||
FdGuard::new(syscall::dup(*new_thr_fd, b"current-addrspace")?);
|
||||
|
||||
let cur_addr_space_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"addrspace")?);
|
||||
let cur_addr_space_fd = FdGuard::new(syscall::dup(**cur_thr_fd, b"addrspace")?);
|
||||
let new_addr_space_fd = FdGuard::new(syscall::dup(*cur_addr_space_fd, b"exclusive")?);
|
||||
|
||||
let mut grant_desc_buf = [GrantDesc::default(); 16];
|
||||
@@ -795,14 +852,28 @@ pub fn fork_inner(initial_rsp: *mut usize) -> Result<usize> {
|
||||
// Do this after the address space is cloned, since the kernel will get a shared
|
||||
// reference to the TCB and whatever pages stores the signal proc control struct.
|
||||
{
|
||||
let new_sighandler_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"sighandler")?);
|
||||
let new_sighandler_fd = FdGuard::new(syscall::dup(*new_thr_fd, b"sighandler")?);
|
||||
let _ = syscall::write(
|
||||
*new_sighandler_fd,
|
||||
&crate::signal::current_setsighandler_struct(),
|
||||
)?;
|
||||
}
|
||||
if let Some(ref proc_fd) = new_proc_fd {
|
||||
proc_call(
|
||||
**proc_fd,
|
||||
&mut [],
|
||||
CallFlags::empty(),
|
||||
&[ProcCall::SyncSigPctl as u64],
|
||||
)?;
|
||||
thread_call(
|
||||
*new_thr_fd,
|
||||
&mut [],
|
||||
CallFlags::empty(),
|
||||
&[ThreadCall::SyncSigTctl as u64],
|
||||
)?;
|
||||
}
|
||||
}
|
||||
copy_env_regs(*cur_pid_fd, *new_pid_fd)?;
|
||||
copy_env_regs(**cur_thr_fd, *new_thr_fd)?;
|
||||
}
|
||||
// Copy the file table. We do this last to ensure that all previously used file descriptors are
|
||||
// closed. The only exception -- the filetable selection fd and the current filetable fd --
|
||||
@@ -811,59 +882,115 @@ pub fn fork_inner(initial_rsp: *mut usize) -> Result<usize> {
|
||||
// TODO: Use file descriptor forwarding or something similar to avoid copying the file
|
||||
// table in the kernel.
|
||||
let new_filetable_fd = FdGuard::new(syscall::dup(*cur_filetable_fd, b"copy")?);
|
||||
let new_filetable_sel_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"current-filetable")?);
|
||||
let new_filetable_sel_fd = FdGuard::new(syscall::dup(*new_thr_fd, b"current-filetable")?);
|
||||
let _ = syscall::write(
|
||||
*new_filetable_sel_fd,
|
||||
&usize::to_ne_bytes(*new_filetable_fd),
|
||||
)?;
|
||||
}
|
||||
let start_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"start")?);
|
||||
let start_fd = FdGuard::new(syscall::dup(*new_thr_fd, b"start")?);
|
||||
let _ = syscall::write(*start_fd, &[0])?;
|
||||
|
||||
Ok(new_pid)
|
||||
}
|
||||
|
||||
pub fn new_child_process() -> Result<(FdGuard, usize)> {
|
||||
// Create a new context (fields such as uid/gid will be inherited from the current context).
|
||||
let fd = FdGuard::new(syscall::open(
|
||||
"/scheme/thisproc/new/open_via_dup",
|
||||
O_CLOEXEC,
|
||||
)?);
|
||||
struct NewChildProc {
|
||||
proc_fd: Option<FdGuard>,
|
||||
|
||||
// Extract pid.
|
||||
let mut buffer = [0_u8; 64];
|
||||
let len = syscall::fpath(*fd, &mut buffer)?;
|
||||
let buffer = buffer.get(..len).ok_or(Error::new(ENAMETOOLONG))?;
|
||||
|
||||
let colon_idx = buffer
|
||||
.iter()
|
||||
.position(|c| *c == b':')
|
||||
.ok_or(Error::new(EINVAL))?;
|
||||
let slash_idx = buffer
|
||||
.iter()
|
||||
.skip(colon_idx)
|
||||
.position(|c| *c == b'/')
|
||||
.ok_or(Error::new(EINVAL))?
|
||||
+ colon_idx;
|
||||
let pid_bytes = buffer
|
||||
.get(colon_idx + 1..slash_idx)
|
||||
.ok_or(Error::new(EINVAL))?;
|
||||
let pid_str = core::str::from_utf8(pid_bytes).map_err(|_| Error::new(EINVAL))?;
|
||||
let pid = pid_str.parse::<usize>().map_err(|_| Error::new(EINVAL))?;
|
||||
|
||||
Ok((fd, pid))
|
||||
thr_fd: FdGuard,
|
||||
pid: usize,
|
||||
}
|
||||
|
||||
pub fn copy_str(cur_pid_fd: usize, new_pid_fd: usize, key: &str) -> Result<()> {
|
||||
let cur_name_fd = FdGuard::new(syscall::dup(cur_pid_fd, key.as_bytes())?);
|
||||
let new_name_fd = FdGuard::new(syscall::dup(new_pid_fd, key.as_bytes())?);
|
||||
pub fn new_child_process(args: &ForkArgs<'_>) -> Result<NewChildProc> {
|
||||
match *args {
|
||||
ForkArgs::Managed => {
|
||||
let proc_info = crate::static_proc_info();
|
||||
assert!(
|
||||
proc_info.has_proc_fd,
|
||||
"cannot use ForkArgs::Managed without an existing proc info"
|
||||
);
|
||||
let this_proc_fd = unsafe { proc_info.proc_fd.assume_init_ref() };
|
||||
let child_proc_fd = FdGuard::new(syscall::dup(**this_proc_fd, b"fork")?);
|
||||
let only_thread_fd = FdGuard::new(syscall::dup(*child_proc_fd, b"thread-0")?);
|
||||
let meta = read_proc_meta(&child_proc_fd)?;
|
||||
Ok(NewChildProc {
|
||||
proc_fd: Some(child_proc_fd),
|
||||
thr_fd: only_thread_fd,
|
||||
pid: meta.pid as usize,
|
||||
})
|
||||
}
|
||||
#[cfg(feature = "proc")]
|
||||
ForkArgs::Init { .. } => unreachable!(),
|
||||
|
||||
// TODO: Max path size?
|
||||
let mut buf = [0_u8; 256];
|
||||
let len = syscall::read(*cur_name_fd, &mut buf)?;
|
||||
let buf = buf.get(..len).ok_or(Error::new(ENAMETOOLONG))?;
|
||||
|
||||
syscall::write(*new_name_fd, &buf)?;
|
||||
|
||||
Ok(())
|
||||
#[cfg(not(feature = "proc"))]
|
||||
ForkArgs::Init { this_thr_fd, auth } => {
|
||||
let thr_fd = FdGuard::new(syscall::dup(**auth, b"new-context")?);
|
||||
let buf = ProcSchemeAttrs {
|
||||
pid: 0,
|
||||
euid: 0,
|
||||
egid: 0,
|
||||
ens: 1,
|
||||
debug_name: {
|
||||
let mut buf = [0; 32];
|
||||
let src = b"[init]";
|
||||
buf[..src.len()].copy_from_slice(src);
|
||||
buf
|
||||
},
|
||||
};
|
||||
let attr_fd = FdGuard::new(syscall::dup(
|
||||
*thr_fd,
|
||||
alloc::format!("auth-{}-attrs", **auth).as_bytes(),
|
||||
)?);
|
||||
let _ = syscall::write(*attr_fd, &buf)?;
|
||||
Ok(NewChildProc {
|
||||
thr_fd,
|
||||
pid: 1, // dummy fd to distinguish child from parent
|
||||
proc_fd: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn make_init() -> [&'static FdGuard; 2] {
|
||||
let proc_fd = FdGuard::new(
|
||||
syscall::open("/scheme/proc/init", syscall::O_CLOEXEC).expect("failed to create init"),
|
||||
);
|
||||
syscall::sendfd(
|
||||
*proc_fd,
|
||||
syscall::dup(**RtTcb::current().thread_fd(), &[]).unwrap(),
|
||||
0,
|
||||
0,
|
||||
)
|
||||
.expect("failed to assign current thread to init process");
|
||||
|
||||
let managed_thr_fd = FdGuard::new(
|
||||
syscall::dup(*proc_fd, b"thread-0").expect("failed to get managed thread for init"),
|
||||
);
|
||||
|
||||
let managed_thr_fd = (*RtTcb::current().thr_fd.get()).insert(managed_thr_fd);
|
||||
|
||||
STATIC_PROC_INFO.get().write(crate::StaticProcInfo {
|
||||
pid: 1,
|
||||
proc_fd: MaybeUninit::new(proc_fd),
|
||||
has_proc_fd: true,
|
||||
});
|
||||
*DYNAMIC_PROC_INFO.lock() = crate::DynamicProcInfo {
|
||||
pgid: 1,
|
||||
ruid: 0,
|
||||
euid: 0,
|
||||
suid: 0,
|
||||
rgid: 0,
|
||||
egid: 0,
|
||||
sgid: 0,
|
||||
};
|
||||
[
|
||||
(*STATIC_PROC_INFO.get()).proc_fd.assume_init_ref(),
|
||||
managed_thr_fd,
|
||||
]
|
||||
}
|
||||
pub(crate) static STATIC_PROC_INFO: SyncUnsafeCell<StaticProcInfo> =
|
||||
SyncUnsafeCell::new(StaticProcInfo {
|
||||
pid: 0,
|
||||
proc_fd: MaybeUninit::zeroed(),
|
||||
has_proc_fd: false,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
use bitflags::bitflags;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[repr(C)]
|
||||
pub struct ProcMeta {
|
||||
pub pid: u32,
|
||||
pub pgid: u32,
|
||||
pub ppid: u32,
|
||||
pub ruid: u32,
|
||||
pub euid: u32,
|
||||
pub suid: u32,
|
||||
pub rgid: u32,
|
||||
pub egid: u32,
|
||||
pub sgid: u32,
|
||||
pub ens: u32,
|
||||
pub rns: u32,
|
||||
}
|
||||
unsafe impl plain::Plain for ProcMeta {}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[repr(usize)]
|
||||
pub enum ProcCall {
|
||||
Waitpid = 0,
|
||||
Setrens = 1,
|
||||
Exit = 2,
|
||||
Waitpgid = 3,
|
||||
SetResugid = 4,
|
||||
Setpgid = 5,
|
||||
Getsid = 6,
|
||||
Setsid = 7,
|
||||
Kill = 8,
|
||||
Sigq = 9,
|
||||
|
||||
// TODO: replace with sendfd equivalent syscall for sending memory
|
||||
SyncSigPctl = 10,
|
||||
Sigdeq = 11,
|
||||
Getppid = 12,
|
||||
Rename = 13,
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[repr(usize)]
|
||||
pub enum ThreadCall {
|
||||
// TODO: replace with sendfd equivalent syscall for sending memory, or force userspace to
|
||||
// obtain its TCB memory from this server
|
||||
SyncSigTctl = 0,
|
||||
SignalThread = 1,
|
||||
}
|
||||
|
||||
impl ProcCall {
|
||||
pub fn try_from_raw(raw: usize) -> Option<Self> {
|
||||
Some(match raw {
|
||||
0 => Self::Waitpid,
|
||||
1 => Self::Setrens,
|
||||
2 => Self::Exit,
|
||||
3 => Self::Waitpgid,
|
||||
4 => Self::SetResugid,
|
||||
5 => Self::Setpgid,
|
||||
6 => Self::Getsid,
|
||||
7 => Self::Setsid,
|
||||
8 => Self::Kill,
|
||||
9 => Self::Sigq,
|
||||
10 => Self::SyncSigPctl,
|
||||
11 => Self::Sigdeq,
|
||||
12 => Self::Getppid,
|
||||
13 => Self::Rename,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
impl ThreadCall {
|
||||
pub fn try_from_raw(raw: usize) -> Option<Self> {
|
||||
Some(match raw {
|
||||
0 => Self::SyncSigTctl,
|
||||
1 => Self::SignalThread,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
||||
pub struct WaitFlags: usize {
|
||||
const WNOHANG = 0x01;
|
||||
const WUNTRACED = 0x02;
|
||||
const WCONTINUED = 0x08;
|
||||
}
|
||||
}
|
||||
/// True if status indicates the child is stopped.
|
||||
pub fn wifstopped(status: usize) -> bool {
|
||||
(status & 0xff) == 0x7f
|
||||
}
|
||||
|
||||
/// If wifstopped(status), the signal that stopped the child.
|
||||
pub fn wstopsig(status: usize) -> usize {
|
||||
(status >> 8) & 0xff
|
||||
}
|
||||
|
||||
/// True if status indicates the child continued after a stop.
|
||||
pub fn wifcontinued(status: usize) -> bool {
|
||||
status == 0xffff
|
||||
}
|
||||
|
||||
/// True if STATUS indicates termination by a signal.
|
||||
pub fn wifsignaled(status: usize) -> bool {
|
||||
((status & 0x7f) + 1) as i8 >= 2
|
||||
}
|
||||
|
||||
/// If wifsignaled(status), the terminating signal.
|
||||
pub fn wtermsig(status: usize) -> usize {
|
||||
status & 0x7f
|
||||
}
|
||||
|
||||
/// True if status indicates normal termination.
|
||||
pub fn wifexited(status: usize) -> bool {
|
||||
wtermsig(status) == 0
|
||||
}
|
||||
|
||||
/// If wifexited(status), the exit status.
|
||||
pub fn wexitstatus(status: usize) -> usize {
|
||||
(status >> 8) & 0xff
|
||||
}
|
||||
|
||||
/// True if status indicates a core dump was created.
|
||||
pub fn wcoredump(status: usize) -> bool {
|
||||
(status & 0x80) != 0
|
||||
}
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum ProcKillTarget {
|
||||
ThisGroup,
|
||||
SingleProc(usize),
|
||||
ProcGroup(usize),
|
||||
All,
|
||||
}
|
||||
impl ProcKillTarget {
|
||||
pub fn raw(self) -> usize {
|
||||
match self {
|
||||
Self::ThisGroup => 0,
|
||||
Self::SingleProc(p) => p,
|
||||
Self::ProcGroup(g) => usize::wrapping_neg(g),
|
||||
Self::All => usize::wrapping_neg(1),
|
||||
}
|
||||
}
|
||||
pub fn from_raw(raw: usize) -> Self {
|
||||
let raw = raw as isize;
|
||||
if raw == 0 {
|
||||
Self::ThisGroup
|
||||
} else if raw == -1 {
|
||||
Self::All
|
||||
} else if raw < 0 {
|
||||
Self::ProcGroup(raw as usize)
|
||||
} else {
|
||||
Self::SingleProc(raw as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub struct RtSigInfo {
|
||||
pub arg: usize,
|
||||
pub code: i32,
|
||||
pub uid: u32,
|
||||
pub pid: u32, // TODO: usize?
|
||||
}
|
||||
unsafe impl plain::Plain for RtSigInfo {}
|
||||
|
||||
pub const SIGHUP: usize = 1;
|
||||
pub const SIGINT: usize = 2;
|
||||
pub const SIGQUIT: usize = 3;
|
||||
pub const SIGILL: usize = 4;
|
||||
pub const SIGTRAP: usize = 5;
|
||||
pub const SIGABRT: usize = 6;
|
||||
pub const SIGBUS: usize = 7;
|
||||
pub const SIGFPE: usize = 8;
|
||||
pub const SIGKILL: usize = 9;
|
||||
pub const SIGUSR1: usize = 10;
|
||||
pub const SIGSEGV: usize = 11;
|
||||
pub const SIGUSR2: usize = 12;
|
||||
pub const SIGPIPE: usize = 13;
|
||||
pub const SIGALRM: usize = 14;
|
||||
pub const SIGTERM: usize = 15;
|
||||
pub const SIGSTKFLT: usize = 16;
|
||||
pub const SIGCHLD: usize = syscall::SIGCHLD;
|
||||
pub const SIGCONT: usize = 18;
|
||||
pub const SIGSTOP: usize = 19;
|
||||
pub const SIGTSTP: usize = syscall::SIGTSTP;
|
||||
pub const SIGTTIN: usize = syscall::SIGTTIN;
|
||||
pub const SIGTTOU: usize = syscall::SIGTTOU;
|
||||
pub const SIGURG: usize = 23;
|
||||
pub const SIGXCPU: usize = 24;
|
||||
pub const SIGXFSZ: usize = 25;
|
||||
pub const SIGVTALRM: usize = 26;
|
||||
pub const SIGPROF: usize = 27;
|
||||
pub const SIGWINCH: usize = 28;
|
||||
pub const SIGIO: usize = 29;
|
||||
pub const SIGPWR: usize = 30;
|
||||
pub const SIGSYS: usize = 31;
|
||||
+89
-24
@@ -1,12 +1,23 @@
|
||||
use core::{ffi::c_int, mem::MaybeUninit, ptr::NonNull, sync::atomic::Ordering};
|
||||
use core::{ffi::c_int, ptr::NonNull, sync::atomic::Ordering};
|
||||
|
||||
use syscall::{
|
||||
data::AtomicU64, Error, RawAction, Result, RtSigInfo, SenderInfo, SetSighandlerData,
|
||||
data::AtomicU64, CallFlags, Error, RawAction, Result, SenderInfo, SetSighandlerData,
|
||||
SigProcControl, Sigcontrol, SigcontrolFlags, TimeSpec, EAGAIN, EINTR, EINVAL, ENOMEM, EPERM,
|
||||
SIGCHLD, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGWINCH,
|
||||
};
|
||||
|
||||
use crate::{arch::*, proc::FdGuard, sync::Mutex, RtTcb, Tcb};
|
||||
use crate::{
|
||||
arch::*,
|
||||
current_proc_fd,
|
||||
proc::FdGuard,
|
||||
protocol::{
|
||||
ProcCall, RtSigInfo, ThreadCall, SIGCHLD, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU,
|
||||
SIGURG, SIGWINCH,
|
||||
},
|
||||
static_proc_info,
|
||||
sync::Mutex,
|
||||
sys::{proc_call, this_thread_call},
|
||||
RtTcb, Tcb,
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
static CPUID_EAX1_ECX: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
|
||||
@@ -149,11 +160,18 @@ unsafe fn inner(stack: &mut SigStack) {
|
||||
|
||||
let handler = match sigaction.kind {
|
||||
SigactionKind::Ignore => {
|
||||
panic!("ctl {:x?} signal {}", os.control, stack.sig_num)
|
||||
panic!("ctl {:#x?} signal {}", os.control, stack.sig_num)
|
||||
}
|
||||
SigactionKind::Default => {
|
||||
syscall::exit(stack.sig_num as usize);
|
||||
unreachable!();
|
||||
let sig = (stack.sig_num & 0x3f) as u8;
|
||||
|
||||
let _ = proc_call(
|
||||
**current_proc_fd(),
|
||||
&mut [],
|
||||
CallFlags::empty(),
|
||||
&[ProcCall::Exit as u64, u64::from(sig) << 8],
|
||||
);
|
||||
core::intrinsics::abort()
|
||||
}
|
||||
SigactionKind::Handled { handler } => handler,
|
||||
};
|
||||
@@ -270,7 +288,10 @@ fn get_allowset_raw(words: &[AtomicU64; 2]) -> u64 {
|
||||
(words[0].load(Ordering::Relaxed) >> 32) | ((words[1].load(Ordering::Relaxed) >> 32) << 32)
|
||||
}
|
||||
/// Sets mask from old to new, returning what was pending at the time.
|
||||
fn set_allowset_raw(words: &[AtomicU64; 2], old: u64, new: u64) -> u64 {
|
||||
fn set_allowset_raw(words: &[AtomicU64; 2], old: u64, new_raw: u64) -> u64 {
|
||||
// TODO: should these bits always be set, or never be set?
|
||||
let new = new_raw | ALLOWSET_ALWAYS;
|
||||
|
||||
// This assumes *only this thread* can change the allowset. If this rule is broken, the use of
|
||||
// fetch_add will corrupt the words entirely. fetch_add is very efficient on x86, being
|
||||
// generated as LOCK XADD which is the fastest RMW instruction AFAIK.
|
||||
@@ -285,6 +306,7 @@ fn set_allowset_raw(words: &[AtomicU64; 2], old: u64, new: u64) -> u64 {
|
||||
|
||||
prev_w0 | (prev_w1 << 32)
|
||||
}
|
||||
const ALLOWSET_ALWAYS: u64 = sig_bit(SIGSTOP as u32) | sig_bit(SIGKILL as u32);
|
||||
fn modify_sigmask(old: Option<&mut u64>, op: Option<impl FnOnce(u64) -> u64>) -> Result<()> {
|
||||
let _guard = tmp_disable_signals();
|
||||
let ctl = current_sigctl();
|
||||
@@ -375,9 +397,29 @@ fn convert_old(action: &RawAction) -> Sigaction {
|
||||
}
|
||||
|
||||
pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction>) -> Result<()> {
|
||||
if matches!(usize::from(signal), 0 | 32 | SIGKILL | SIGSTOP | 65..) {
|
||||
// TODO: Now that the goal of keeping logic out of the IPC backend, no longer holds when
|
||||
// procmgr has taken over signal handling from the kernel, it would probably make sense to make
|
||||
// parts of this function an IPC call, for synchronization purposes. Apart from SA_RESETHAND
|
||||
// logic which may need to be fast, regular sigaction is typically in the 'configuration'
|
||||
// category, allowed to be slower.
|
||||
|
||||
if matches!(usize::from(signal), 0 | 32 | 65..) {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
if matches!(usize::from(signal), SIGKILL | SIGSTOP) {
|
||||
if new.is_some() {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
if let Some(old) = old {
|
||||
// TODO: Is this the correct value to set it to?
|
||||
*old = Sigaction {
|
||||
kind: SigactionKind::Default,
|
||||
mask: 0,
|
||||
flags: SigactionFlags::empty(),
|
||||
};
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let _sigguard = tmp_disable_signals();
|
||||
let ctl = current_sigctl();
|
||||
@@ -398,8 +440,16 @@ pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction
|
||||
|
||||
let (mask, flags, handler) = match (usize::from(signal), new.kind) {
|
||||
(_, SigactionKind::Ignore) | (SIGURG | SIGWINCH, SigactionKind::Default) => {
|
||||
// TODO: POSIX specifies that pending signals shall be discarded if set to SIG_IGN by
|
||||
// sigaction.
|
||||
let sig_group = (signal - 1) / 32;
|
||||
let sig_idx = (signal - 1) % 32;
|
||||
|
||||
// TODO: relibc and the procmgr has access to all threads, redox_rt doesn't currently.
|
||||
// Do this for all threads!
|
||||
ctl.word[usize::from(sig_group)].fetch_and(!(1 << sig_idx), Ordering::Relaxed);
|
||||
PROC_CONTROL_STRUCT
|
||||
.pending
|
||||
.fetch_and(!sig_bit(signal.into()), Ordering::Relaxed);
|
||||
|
||||
// TODO: handle tmp_disable_signals
|
||||
(
|
||||
MASK_DONTCARE,
|
||||
@@ -497,7 +547,7 @@ bitflags::bitflags! {
|
||||
const STORED_FLAGS: u32 = 0xfe00_0000;
|
||||
|
||||
fn default_handler(sig: c_int) {
|
||||
syscall::exit(sig as usize);
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -529,8 +579,8 @@ const fn sig_bit(sig: u32) -> u64 {
|
||||
1 << (sig - 1)
|
||||
}
|
||||
|
||||
pub fn setup_sighandler(tcb: &RtTcb) {
|
||||
{
|
||||
pub fn setup_sighandler(tcb: &RtTcb, first_thread: bool) {
|
||||
if first_thread {
|
||||
let _guard = SIGACTIONS_LOCK.lock();
|
||||
for (sig_idx, action) in PROC_CONTROL_STRUCT.actions.iter().enumerate() {
|
||||
let sig = sig_idx + 1;
|
||||
@@ -554,8 +604,7 @@ pub fn setup_sighandler(tcb: &RtTcb) {
|
||||
// equivalent to not using any altstack at all (the default).
|
||||
arch.altstack_top = usize::MAX;
|
||||
arch.altstack_bottom = 0;
|
||||
// TODO
|
||||
#[cfg(any(target_arch = "x86", target_arch = "aarch64", target_arch = "riscv64"))]
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
||||
{
|
||||
arch.pctl = core::ptr::addr_of!(PROC_CONTROL_STRUCT) as usize;
|
||||
}
|
||||
@@ -574,6 +623,12 @@ pub fn setup_sighandler(tcb: &RtTcb) {
|
||||
syscall::dup(**tcb.thread_fd(), b"sighandler").expect("failed to open sighandler fd"),
|
||||
);
|
||||
let _ = syscall::write(*fd, &data).expect("failed to write to sighandler fd");
|
||||
this_thread_call(
|
||||
&mut [],
|
||||
CallFlags::empty(),
|
||||
&[ThreadCall::SyncSigTctl as u64],
|
||||
)
|
||||
.expect("failed to sync signal tctl");
|
||||
|
||||
// TODO: Inherited set of ignored signals
|
||||
set_sigmask(Some(0), None);
|
||||
@@ -684,17 +739,25 @@ pub fn await_signal_async(inner_allowset: u64) -> Result<Unreachable> {
|
||||
},
|
||||
&mut TimeSpec::default(),
|
||||
);
|
||||
set_allowset_raw(&control.word, inner_allowset, old_allowset);
|
||||
|
||||
if res == Err(Error::new(EINTR)) {
|
||||
unsafe {
|
||||
manually_enter_trampoline();
|
||||
}
|
||||
}
|
||||
// POSIX says it shall restore the mask to what it was prior to the call, which is interpreted
|
||||
// as allowing any changes to sigprocmask inside the signal handler, to be discarded.
|
||||
set_allowset_raw(&control.word, inner_allowset, old_allowset);
|
||||
|
||||
res?;
|
||||
unreachable!()
|
||||
}
|
||||
/*#[no_mangle]
|
||||
pub extern "C" fn __redox_rt_debug_sigctl() {
|
||||
let tcb = &RtTcb::current().control;
|
||||
let _ = syscall::write(1, alloc::format!("SIGCTL: {tcb:#x?}\n").as_bytes());
|
||||
}*/
|
||||
|
||||
// TODO: deadline-based API
|
||||
pub fn await_signal_sync(inner_allowset: u64, timeout: Option<&TimeSpec>) -> Result<SiginfoAbi> {
|
||||
let _guard = tmp_disable_signals();
|
||||
@@ -764,15 +827,17 @@ fn try_claim_single(sig_idx: u32, thread_control: Option<&Sigcontrol>) -> Option
|
||||
|
||||
if sig_group == 1 && thread_control.is_none() {
|
||||
// Queued (realtime) signal
|
||||
let mut ret = MaybeUninit::<RtSigInfo>::uninit();
|
||||
let rt_inf = unsafe {
|
||||
syscall::syscall2(
|
||||
syscall::SYS_SIGDEQUEUE,
|
||||
ret.as_mut_ptr() as usize,
|
||||
sig_idx as usize - 32,
|
||||
let rt_inf: RtSigInfo = unsafe {
|
||||
let mut buf = [0_u8; size_of::<RtSigInfo>()];
|
||||
buf[..4].copy_from_slice(&(sig_idx - 32).to_ne_bytes());
|
||||
proc_call(
|
||||
**static_proc_info().proc_fd.assume_init_ref(),
|
||||
&mut buf,
|
||||
CallFlags::empty(),
|
||||
&[ProcCall::Sigdeq as u64],
|
||||
)
|
||||
.ok()?;
|
||||
ret.assume_init()
|
||||
core::mem::transmute(buf)
|
||||
};
|
||||
Some(SiginfoAbi {
|
||||
si_signo: sig_idx as i32 + 1,
|
||||
|
||||
+243
-30
@@ -1,24 +1,31 @@
|
||||
use core::{
|
||||
mem::size_of,
|
||||
ptr::addr_of,
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
};
|
||||
|
||||
use syscall::{
|
||||
error::{Error, Result, EINTR},
|
||||
RtSigInfo, TimeSpec,
|
||||
error::{self, Error, Result, EINTR},
|
||||
CallFlags, TimeSpec, EINVAL, ERESTART,
|
||||
};
|
||||
|
||||
use crate::{arch::manually_enter_trampoline, proc::FdGuard, signal::tmp_disable_signals, Tcb};
|
||||
use crate::{
|
||||
arch::manually_enter_trampoline,
|
||||
protocol::{ProcCall, ProcKillTarget, RtSigInfo, ThreadCall, WaitFlags},
|
||||
signal::tmp_disable_signals,
|
||||
DynamicProcInfo, RtTcb, Tcb, DYNAMIC_PROC_INFO,
|
||||
};
|
||||
|
||||
#[inline]
|
||||
fn wrapper<T>(restart: bool, mut f: impl FnMut() -> Result<T>) -> Result<T> {
|
||||
fn wrapper<T>(restart: bool, erestart: bool, mut f: impl FnMut() -> Result<T>) -> Result<T> {
|
||||
loop {
|
||||
let _guard = tmp_disable_signals();
|
||||
let rt_sigarea = unsafe { &Tcb::current().unwrap().os_specific };
|
||||
let res = f();
|
||||
let code = if erestart { ERESTART } else { EINTR };
|
||||
|
||||
if let Err(err) = res
|
||||
&& err == Error::new(EINTR)
|
||||
&& err == Error::new(code)
|
||||
{
|
||||
unsafe {
|
||||
manually_enter_trampoline();
|
||||
@@ -35,49 +42,60 @@ fn wrapper<T>(restart: bool, mut f: impl FnMut() -> Result<T>) -> Result<T> {
|
||||
// TODO: uninitialized memory?
|
||||
#[inline]
|
||||
pub fn posix_read(fd: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
wrapper(true, || syscall::read(fd, buf))
|
||||
wrapper(true, false, || syscall::read(fd, buf))
|
||||
}
|
||||
#[inline]
|
||||
pub fn posix_write(fd: usize, buf: &[u8]) -> Result<usize> {
|
||||
wrapper(true, || syscall::write(fd, buf))
|
||||
wrapper(true, false, || syscall::write(fd, buf))
|
||||
}
|
||||
#[inline]
|
||||
pub fn posix_kill(pid: usize, sig: usize) -> Result<()> {
|
||||
match wrapper(false, || syscall::kill(pid, sig)) {
|
||||
Ok(_) | Err(Error { errno: EINTR }) => Ok(()),
|
||||
pub fn posix_kill(target: ProcKillTarget, sig: usize) -> Result<()> {
|
||||
match wrapper(false, true, || {
|
||||
this_proc_call(
|
||||
&mut [],
|
||||
CallFlags::empty(),
|
||||
&[ProcCall::Kill as u64, target.raw() as u64, sig as u64],
|
||||
)
|
||||
}) {
|
||||
Ok(_) | Err(Error { errno: ERESTART }) => Ok(()),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn posix_sigqueue(pid: usize, sig: usize, arg: usize) -> Result<()> {
|
||||
let siginf = RtSigInfo {
|
||||
let mut siginf = RtSigInfo {
|
||||
arg,
|
||||
code: -1, // TODO: SI_QUEUE constant
|
||||
uid: 0, // TODO
|
||||
pid: posix_getpid(),
|
||||
};
|
||||
match wrapper(false, || unsafe {
|
||||
syscall::syscall3(syscall::SYS_SIGENQUEUE, pid, sig, addr_of!(siginf) as usize)
|
||||
match wrapper(false, true, || {
|
||||
this_proc_call(
|
||||
unsafe { plain::as_mut_bytes(&mut siginf) },
|
||||
CallFlags::empty(),
|
||||
&[ProcCall::Sigq as u64, pid as u64, sig as u64],
|
||||
)
|
||||
}) {
|
||||
Ok(_) | Err(Error { errno: EINTR }) => Ok(()),
|
||||
Ok(_)
|
||||
| Err(Error {
|
||||
errno: error::EINTR,
|
||||
}) => Ok(()),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn posix_getpid() -> u32 {
|
||||
// SAFETY: read-only except during program/fork child initialization
|
||||
unsafe { crate::THIS_PID.get().read() }
|
||||
unsafe { addr_of!((*crate::STATIC_PROC_INFO.get()).pid).read() }
|
||||
}
|
||||
#[inline]
|
||||
pub fn posix_killpg(pgrp: usize, sig: usize) -> Result<()> {
|
||||
match wrapper(false, || syscall::kill(usize::wrapping_neg(pgrp), sig)) {
|
||||
Ok(_) | Err(Error { errno: EINTR }) => Ok(()),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
pub fn posix_getppid() -> u32 {
|
||||
this_proc_call(&mut [], CallFlags::empty(), &[ProcCall::Getppid as u64]).expect("cannot fail")
|
||||
as u32
|
||||
}
|
||||
#[inline]
|
||||
pub unsafe fn sys_futex_wait(addr: *mut u32, val: u32, deadline: Option<&TimeSpec>) -> Result<()> {
|
||||
wrapper(true, || {
|
||||
wrapper(true, false, || {
|
||||
syscall::syscall5(
|
||||
syscall::SYS_FUTEX,
|
||||
addr as usize,
|
||||
@@ -101,19 +119,91 @@ pub unsafe fn sys_futex_wake(addr: *mut u32, num: u32) -> Result<u32> {
|
||||
)
|
||||
.map(|awoken| awoken as u32)
|
||||
}
|
||||
pub fn sys_waitpid(pid: usize, status: &mut usize, flags: usize) -> Result<usize> {
|
||||
wrapper(true, || {
|
||||
syscall::waitpid(
|
||||
pid,
|
||||
status,
|
||||
syscall::WaitFlags::from_bits(flags).expect("waitpid: invalid bit pattern"),
|
||||
pub fn sys_call(
|
||||
fd: usize,
|
||||
payload: &mut [u8],
|
||||
flags: CallFlags,
|
||||
metadata: &[u64],
|
||||
) -> Result<usize> {
|
||||
unsafe {
|
||||
syscall::syscall5(
|
||||
syscall::SYS_CALL,
|
||||
fd,
|
||||
payload.as_mut_ptr() as usize,
|
||||
payload.len(),
|
||||
metadata.len() | flags.bits(),
|
||||
metadata.as_ptr() as usize,
|
||||
)
|
||||
}
|
||||
}
|
||||
pub fn this_proc_call(payload: &mut [u8], flags: CallFlags, metadata: &[u64]) -> Result<usize> {
|
||||
proc_call(**crate::current_proc_fd(), payload, flags, metadata)
|
||||
}
|
||||
pub fn proc_call(
|
||||
proc_fd: usize,
|
||||
payload: &mut [u8],
|
||||
flags: CallFlags,
|
||||
metadata: &[u64],
|
||||
) -> Result<usize> {
|
||||
sys_call(proc_fd, payload, flags, metadata)
|
||||
}
|
||||
pub fn thread_call(
|
||||
thread_fd: usize,
|
||||
payload: &mut [u8],
|
||||
flags: CallFlags,
|
||||
metadata: &[u64],
|
||||
) -> Result<usize> {
|
||||
sys_call(thread_fd, payload, flags, metadata)
|
||||
}
|
||||
pub fn this_thread_call(payload: &mut [u8], flags: CallFlags, metadata: &[u64]) -> Result<usize> {
|
||||
thread_call(**RtTcb::current().thread_fd(), payload, flags, metadata)
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum WaitpidTarget {
|
||||
AnyChild,
|
||||
AnyGroupMember,
|
||||
SingleProc { pid: usize },
|
||||
ProcGroup { pgid: usize },
|
||||
}
|
||||
impl WaitpidTarget {
|
||||
pub fn from_posix_arg(raw: isize) -> Self {
|
||||
match raw {
|
||||
0 => Self::AnyGroupMember,
|
||||
-1 => Self::AnyChild,
|
||||
1.. => Self::SingleProc { pid: raw as usize },
|
||||
..-1 => Self::ProcGroup {
|
||||
pgid: -raw as usize,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sys_waitpid(target: WaitpidTarget, status: &mut usize, flags: WaitFlags) -> Result<usize> {
|
||||
let (call, pid) = match target {
|
||||
WaitpidTarget::AnyChild => (ProcCall::Waitpid, 0),
|
||||
WaitpidTarget::SingleProc { pid } => (ProcCall::Waitpid, pid),
|
||||
WaitpidTarget::AnyGroupMember => (ProcCall::Waitpgid, 0),
|
||||
WaitpidTarget::ProcGroup { pgid } => (ProcCall::Waitpgid, pgid),
|
||||
};
|
||||
wrapper(true, false, || {
|
||||
this_proc_call(
|
||||
unsafe { plain::as_mut_bytes(status) },
|
||||
CallFlags::empty(),
|
||||
&[call as u64, pid as u64, flags.bits() as u64],
|
||||
)
|
||||
})
|
||||
}
|
||||
pub fn posix_kill_thread(thread_fd: usize, signal: u32) -> Result<()> {
|
||||
let killfd = FdGuard::new(syscall::dup(thread_fd, b"signal")?);
|
||||
match wrapper(false, || syscall::write(*killfd, &signal.to_ne_bytes())) {
|
||||
Ok(_) | Err(Error { errno: EINTR }) => Ok(()),
|
||||
match wrapper(false, true, || {
|
||||
thread_call(
|
||||
thread_fd,
|
||||
&mut [],
|
||||
CallFlags::empty(),
|
||||
&[ThreadCall::SignalThread as u64, signal.into()],
|
||||
)
|
||||
}) {
|
||||
Ok(_) | Err(Error { errno: ERESTART }) => Ok(()),
|
||||
Err(error) => Err(error),
|
||||
}
|
||||
}
|
||||
@@ -134,3 +224,126 @@ pub fn swap_umask(mask: u32) -> u32 {
|
||||
pub fn get_umask() -> u32 {
|
||||
UMASK.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
/// Real/Effective/Set-User/Group ID
|
||||
pub struct Resugid<T> {
|
||||
pub ruid: T,
|
||||
pub euid: T,
|
||||
pub suid: T,
|
||||
pub rgid: T,
|
||||
pub egid: T,
|
||||
pub sgid: T,
|
||||
}
|
||||
|
||||
/// Sets [res][ug]id, fields that are None will be unchanged.
|
||||
pub fn posix_setresugid(ids: &Resugid<Option<u32>>) -> Result<()> {
|
||||
// TODO: not sure how "tmp" an IPC call is?
|
||||
let _sig_guard = tmp_disable_signals();
|
||||
let mut guard = DYNAMIC_PROC_INFO.lock();
|
||||
|
||||
let mut buf = [0_u8; size_of::<u32>() * 6];
|
||||
plain::slice_from_mut_bytes(&mut buf)
|
||||
.unwrap()
|
||||
.copy_from_slice(&[
|
||||
ids.ruid.unwrap_or(u32::MAX),
|
||||
ids.euid.unwrap_or(u32::MAX),
|
||||
ids.suid.unwrap_or(u32::MAX),
|
||||
ids.rgid.unwrap_or(u32::MAX),
|
||||
ids.egid.unwrap_or(u32::MAX),
|
||||
ids.sgid.unwrap_or(u32::MAX),
|
||||
]);
|
||||
|
||||
this_proc_call(&mut buf, CallFlags::empty(), &[ProcCall::SetResugid as u64])?;
|
||||
|
||||
if let Some(ruid) = ids.ruid {
|
||||
guard.ruid = ruid;
|
||||
}
|
||||
if let Some(euid) = ids.euid {
|
||||
guard.euid = euid;
|
||||
}
|
||||
if let Some(suid) = ids.suid {
|
||||
guard.suid = suid;
|
||||
}
|
||||
if let Some(rgid) = ids.rgid {
|
||||
guard.rgid = rgid;
|
||||
}
|
||||
if let Some(egid) = ids.egid {
|
||||
guard.egid = egid;
|
||||
}
|
||||
if let Some(sgid) = ids.sgid {
|
||||
guard.sgid = sgid;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub fn posix_getresugid() -> Resugid<u32> {
|
||||
let _sig_guard = tmp_disable_signals();
|
||||
let DynamicProcInfo {
|
||||
ruid,
|
||||
euid,
|
||||
suid,
|
||||
rgid,
|
||||
egid,
|
||||
sgid,
|
||||
..
|
||||
} = *DYNAMIC_PROC_INFO.lock();
|
||||
Resugid {
|
||||
ruid,
|
||||
euid,
|
||||
suid,
|
||||
rgid,
|
||||
egid,
|
||||
sgid,
|
||||
}
|
||||
}
|
||||
pub fn posix_exit(status: i32) -> ! {
|
||||
this_proc_call(
|
||||
&mut [],
|
||||
CallFlags::empty(),
|
||||
&[ProcCall::Exit as u64, status as u64],
|
||||
)
|
||||
.expect("failed to call proc mgr with Exit");
|
||||
let _ = syscall::write(1, b"redox-rt: ProcCall::Exit FAILED, abort()ing!\n");
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
pub fn setrens(rns: usize, ens: usize) -> Result<()> {
|
||||
this_proc_call(
|
||||
&mut [],
|
||||
CallFlags::empty(),
|
||||
&[ProcCall::Setrens as u64, rns as u64, ens as u64],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn posix_getpgid(pid: usize) -> Result<usize> {
|
||||
this_proc_call(
|
||||
&mut [],
|
||||
CallFlags::empty(),
|
||||
&[ProcCall::Setpgid as u64, pid as u64, u64::wrapping_neg(1)],
|
||||
)
|
||||
}
|
||||
pub fn posix_setpgid(pid: usize, pgid: usize) -> Result<()> {
|
||||
if pgid == usize::wrapping_neg(1) {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
this_proc_call(
|
||||
&mut [],
|
||||
CallFlags::empty(),
|
||||
&[ProcCall::Setpgid as u64, pid as u64, pgid as u64],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn posix_getsid(pid: usize) -> Result<usize> {
|
||||
this_proc_call(
|
||||
&mut [],
|
||||
CallFlags::empty(),
|
||||
&[ProcCall::Getsid as u64, pid as u64],
|
||||
)
|
||||
}
|
||||
pub fn posix_setsid() -> Result<()> {
|
||||
this_proc_call(&mut [], CallFlags::empty(), &[ProcCall::Setsid as u64])?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn posix_nanosleep(rqtp: &TimeSpec, rmtp: &mut TimeSpec) -> Result<()> {
|
||||
wrapper(false, false, || syscall::nanosleep(rqtp, rmtp))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+10
-11
@@ -1,18 +1,17 @@
|
||||
use core::mem::size_of;
|
||||
|
||||
use syscall::{Result, O_CLOEXEC};
|
||||
use syscall::Result;
|
||||
|
||||
use crate::{arch::*, proc::*, signal::tmp_disable_signals, RtTcb};
|
||||
use crate::{arch::*, proc::*, signal::tmp_disable_signals, static_proc_info, RtTcb};
|
||||
|
||||
/// Spawns a new context sharing the same address space as the current one (i.e. a new thread).
|
||||
pub unsafe fn rlct_clone_impl(stack: *mut usize) -> Result<FdGuard> {
|
||||
let cur_thr_fd = RtTcb::current().thread_fd();
|
||||
let new_thr_fd = FdGuard::new(syscall::open(
|
||||
"/scheme/thisproc/new-thread/open_via_dup",
|
||||
O_CLOEXEC,
|
||||
)?);
|
||||
let proc_info = static_proc_info();
|
||||
assert!(proc_info.has_proc_fd);
|
||||
let cur_proc_fd = proc_info.proc_fd.assume_init_ref();
|
||||
|
||||
copy_str(**cur_thr_fd, *new_thr_fd, "name")?;
|
||||
let cur_thr_fd = RtTcb::current().thread_fd();
|
||||
let new_thr_fd = FdGuard::new(syscall::dup(**cur_proc_fd, b"new-thread")?);
|
||||
|
||||
// Inherit existing address space
|
||||
{
|
||||
@@ -54,16 +53,16 @@ pub unsafe fn exit_this_thread(stack_base: *mut (), stack_size: usize) -> ! {
|
||||
let _guard = tmp_disable_signals();
|
||||
|
||||
let tcb = RtTcb::current();
|
||||
let thread_fd = tcb.thread_fd();
|
||||
// TODO: modify interface so it writes directly to the thread fd?
|
||||
let status_fd = syscall::dup(**tcb.thread_fd(), b"status").unwrap();
|
||||
|
||||
let _ = syscall::funmap(tcb as *const RtTcb as usize, syscall::PAGE_SIZE);
|
||||
|
||||
// TODO: modify interface so it writes directly to the thread fd?
|
||||
let status_fd = syscall::dup(**thread_fd, b"status").unwrap();
|
||||
let mut buf = [0; size_of::<usize>() * 3];
|
||||
plain::slice_from_mut_bytes(&mut buf)
|
||||
.unwrap()
|
||||
.copy_from_slice(&[usize::MAX, stack_base as usize, stack_size]);
|
||||
// TODO: SYS_CALL w/CONSUME
|
||||
syscall::write(status_fd, &buf).unwrap();
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ pub mod sys;
|
||||
#[path = "redox.rs"]
|
||||
pub mod sys;
|
||||
|
||||
type SigSet = BitSet<[c_ulong; 1]>;
|
||||
type SigSet = BitSet<[u64; 1]>;
|
||||
|
||||
pub(crate) const SIG_DFL: usize = 0;
|
||||
pub(crate) const SIG_IGN: usize = 1;
|
||||
@@ -309,7 +309,9 @@ pub unsafe extern "C" fn sigpause(sig: c_int) -> c_int {
|
||||
let mut pset = mem::MaybeUninit::<sigset_t>::uninit();
|
||||
sigprocmask(0, ptr::null_mut(), pset.as_mut_ptr());
|
||||
let mut set = pset.assume_init();
|
||||
sigdelset(&mut set, sig);
|
||||
if sigdelset(&mut set, sig) == -1 {
|
||||
return -1;
|
||||
}
|
||||
sigsuspend(&set)
|
||||
}
|
||||
|
||||
|
||||
@@ -569,15 +569,21 @@ pub extern "C" fn getppid() -> pid_t {
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getresgid.html>.
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn getresgid(rgid: *mut gid_t, egid: *mut gid_t, sgid: *mut gid_t) -> c_int {
|
||||
unimplemented!();
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getresgid(rgid: *mut gid_t, egid: *mut gid_t, sgid: *mut gid_t) -> c_int {
|
||||
// TODO: Out<T> write-only wrapper?
|
||||
Sys::getresgid(rgid.as_mut(), egid.as_mut(), sgid.as_mut())
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getresuid.html>.
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn getresuid(ruid: *mut uid_t, euid: *mut uid_t, suid: *mut uid_t) -> c_int {
|
||||
unimplemented!();
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getresuid(ruid: *mut uid_t, euid: *mut uid_t, suid: *mut uid_t) -> c_int {
|
||||
// TODO: Out<T> write-only wrapper?
|
||||
Sys::getresuid(ruid.as_mut(), euid.as_mut(), suid.as_mut())
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getsid.html>.
|
||||
@@ -812,13 +818,13 @@ pub unsafe extern "C" fn set_default_scheme(scheme: *const c_char) -> c_int {
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/setegid.html>.
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn setegid(gid: gid_t) -> c_int {
|
||||
unimplemented!();
|
||||
Sys::setresgid(-1, gid, -1).map(|()| 0).or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/seteuid.html>.
|
||||
// #[no_mangle]
|
||||
pub extern "C" fn seteuid(uid: uid_t) -> c_int {
|
||||
unimplemented!();
|
||||
Sys::setresuid(-1, uid, -1).map(|()| 0).or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/setgid.html>.
|
||||
|
||||
+9
-3
@@ -612,10 +612,13 @@ impl Linker {
|
||||
unsafe {
|
||||
if !dlopened {
|
||||
#[cfg(target_os = "redox")]
|
||||
let (tcb, old_tcb) = {
|
||||
let (tcb, old_tcb, thr_fd) = {
|
||||
use redox_rt::signal::tmp_disable_signals;
|
||||
|
||||
let old_tcb = Tcb::current().expect("failed to get bootstrap TCB");
|
||||
let thr_fd = (&mut *old_tcb.os_specific.thr_fd.get())
|
||||
.take()
|
||||
.expect("no thread FD present");
|
||||
let new_tcb = Tcb::new(self.tls_size)?; // This actually allocates TCB, TLS and ABI page.
|
||||
|
||||
// Stash
|
||||
@@ -653,7 +656,7 @@ impl Linker {
|
||||
new_tcb.generic.tcb_len = new_tcb_len;
|
||||
|
||||
drop(_guard);
|
||||
(new_tcb, old_tcb as *mut Tcb as *mut c_void)
|
||||
(new_tcb, old_tcb as *mut Tcb as *mut c_void, thr_fd)
|
||||
};
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
@@ -692,7 +695,10 @@ impl Linker {
|
||||
tcb.append_masters(tcb_masters);
|
||||
// Copy the master data into the static TLS block.
|
||||
tcb.copy_masters().map_err(|_| DlError::Malformed)?;
|
||||
tcb.activate();
|
||||
tcb.activate(
|
||||
#[cfg(target_os = "redox")]
|
||||
thr_fd,
|
||||
);
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
{
|
||||
|
||||
+25
-14
@@ -41,7 +41,10 @@ static mut STATIC_TCB_MASTER: Master = Master {
|
||||
};
|
||||
|
||||
#[inline(never)]
|
||||
pub fn static_init(sp: &'static Stack) {
|
||||
pub fn static_init(
|
||||
sp: &'static Stack,
|
||||
#[cfg(target_os = "redox")] thr_fd: redox_rt::proc::FdGuard,
|
||||
) {
|
||||
const SIZEOF_PHDR64: usize = mem::size_of::<ProgramHeader64<Endianness>>();
|
||||
const SIZEOF_PHDR32: usize = mem::size_of::<ProgramHeader32<Endianness>>();
|
||||
|
||||
@@ -120,7 +123,10 @@ pub fn static_init(sp: &'static Stack) {
|
||||
tcb.masters_len = mem::size_of::<Master>();
|
||||
tcb.copy_masters()
|
||||
.expect_notls("failed to copy TLS master data");
|
||||
tcb.activate();
|
||||
tcb.activate(
|
||||
#[cfg(target_os = "redox")]
|
||||
thr_fd,
|
||||
);
|
||||
}
|
||||
|
||||
//TODO: Warning on multiple TLS sections?
|
||||
@@ -130,7 +136,10 @@ pub fn static_init(sp: &'static Stack) {
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "redox"))]
|
||||
pub unsafe fn init(sp: &'static Stack) {
|
||||
pub unsafe fn init(
|
||||
sp: &'static Stack,
|
||||
#[cfg(target_os = "redox")] thr_fd: redox_rt::proc::FdGuard,
|
||||
) {
|
||||
let tp: usize;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
@@ -151,11 +160,8 @@ pub unsafe fn init(sp: &'static Stack) {
|
||||
{
|
||||
let mut env = syscall::EnvRegisters::default();
|
||||
|
||||
let file = syscall::open(
|
||||
"/scheme/thisproc/current/regs/env",
|
||||
syscall::O_CLOEXEC | syscall::O_RDONLY,
|
||||
)
|
||||
.expect_notls("failed to open handle for process registers");
|
||||
let file = syscall::dup(*thr_fd, b"regs/env")
|
||||
.expect_notls("failed to open handle for process registers");
|
||||
|
||||
let _ = syscall::read(file, &mut env).expect_notls("failed to read gsbase");
|
||||
|
||||
@@ -167,11 +173,8 @@ pub unsafe fn init(sp: &'static Stack) {
|
||||
{
|
||||
let mut env = syscall::EnvRegisters::default();
|
||||
|
||||
let file = syscall::open(
|
||||
"/scheme/thisproc/current/regs/env",
|
||||
syscall::O_CLOEXEC | syscall::O_RDONLY,
|
||||
)
|
||||
.expect_notls("failed to open handle for process registers");
|
||||
let file = syscall::dup(*thr_fd, b"regs/env")
|
||||
.expect_notls("failed to open handle for process registers");
|
||||
|
||||
let _ = syscall::read(file, &mut env).expect_notls("failed to read fsbase");
|
||||
|
||||
@@ -188,7 +191,15 @@ pub unsafe fn init(sp: &'static Stack) {
|
||||
}
|
||||
|
||||
if tp == 0 {
|
||||
static_init(sp);
|
||||
static_init(
|
||||
sp,
|
||||
#[cfg(target_os = "redox")]
|
||||
thr_fd,
|
||||
);
|
||||
} else {
|
||||
// The thread fd must already be present in the already existing TCB. Don't close it.
|
||||
#[cfg(target_os = "redox")]
|
||||
core::mem::forget(thr_fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+21
-6
@@ -145,16 +145,31 @@ fn resolve_path_name(
|
||||
None
|
||||
}
|
||||
|
||||
// TODO: Make unsafe
|
||||
#[no_mangle]
|
||||
pub extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> usize {
|
||||
pub unsafe extern "C" fn relibc_ld_so_start(sp: &'static mut Stack, ld_entry: usize) -> usize {
|
||||
// Setup TCB for ourselves.
|
||||
unsafe {
|
||||
let tcb = Tcb::new(0).expect_notls("ld.so: failed to allocate bootstrap TCB");
|
||||
tcb.activate();
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
redox_rt::signal::setup_sighandler(&tcb.os_specific);
|
||||
let thr_fd =
|
||||
crate::platform::get_auxv_raw(sp.auxv().cast(), redox_rt::auxv_defs::AT_REDOX_THR_FD)
|
||||
.expect_notls("no thread fd present");
|
||||
|
||||
let tcb = Tcb::new(0).expect_notls("ld.so: failed to allocate bootstrap TCB");
|
||||
tcb.activate(
|
||||
#[cfg(target_os = "redox")]
|
||||
redox_rt::proc::FdGuard::new(thr_fd),
|
||||
);
|
||||
#[cfg(target_os = "redox")]
|
||||
{
|
||||
let proc_fd = crate::platform::get_auxv_raw(
|
||||
sp.auxv().cast(),
|
||||
redox_rt::auxv_defs::AT_REDOX_PROC_FD,
|
||||
)
|
||||
.expect_notls("no proc fd present");
|
||||
|
||||
redox_rt::initialize(redox_rt::proc::FdGuard::new(proc_fd));
|
||||
redox_rt::signal::setup_sighandler(&tcb.os_specific, true);
|
||||
}
|
||||
}
|
||||
|
||||
// We get the arguments, the environment, and the auxilary vector
|
||||
|
||||
+15
-3
@@ -202,8 +202,14 @@ impl Tcb {
|
||||
}
|
||||
|
||||
/// Activate TLS
|
||||
pub unsafe fn activate(&mut self) {
|
||||
Self::os_arch_activate(&self.os_specific, self.tls_end as usize, self.tls_len);
|
||||
pub unsafe fn activate(&mut self, #[cfg(target_os = "redox")] thr_fd: redox_rt::proc::FdGuard) {
|
||||
Self::os_arch_activate(
|
||||
&self.os_specific,
|
||||
self.tls_end as usize,
|
||||
self.tls_len,
|
||||
#[cfg(target_os = "redox")]
|
||||
thr_fd,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn setup_dtv(&mut self, n: usize) {
|
||||
@@ -327,7 +333,13 @@ impl Tcb {
|
||||
}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
unsafe fn os_arch_activate(os: &OsSpecific, tls_end: usize, tls_len: usize) {
|
||||
unsafe fn os_arch_activate(
|
||||
os: &OsSpecific,
|
||||
tls_end: usize,
|
||||
tls_len: usize,
|
||||
thr_fd: redox_rt::proc::FdGuard,
|
||||
) {
|
||||
os.thr_fd.get().write(Some(thr_fd));
|
||||
redox_rt::tcb_activate(os, tls_end, tls_len)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,9 @@ pub const AT_RANDOM: usize = 25; /* Address of 16 random bytes. */
|
||||
pub const AT_HWCAP2: usize = 26; /* More machine-dependent hints about*/
|
||||
pub const AT_EXECFN: usize = 31; /* Filename of executable. */
|
||||
|
||||
// TODO: Downgrade aux vectors to getauxval constants on Redox, and use a regular struct for
|
||||
// passing important runtime info between exec (or posix_spawn in the future) calls.
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
// XXX: The name AT_CWD is already used in openat... for a completely different purpose.
|
||||
pub const AT_REDOX_INITIAL_CWD_PTR: usize = 32;
|
||||
@@ -48,3 +51,9 @@ pub const AT_REDOX_INITIAL_DEFAULT_SCHEME_LEN: usize = 39;
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
pub const AT_REDOX_UMASK: usize = 40;
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
pub const AT_REDOX_PROC_FD: usize = 41;
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
pub const AT_REDOX_THR_FD: usize = 42;
|
||||
|
||||
@@ -328,6 +328,37 @@ impl Pal for Sys {
|
||||
e_raw(syscall!(GETRLIMIT, resource, rlim)).map(|_| ())
|
||||
}
|
||||
|
||||
fn getresgid(
|
||||
rgid: Option<&mut gid_t>,
|
||||
egid: Option<&mut gid_t>,
|
||||
sgid: Option<&mut gid_t>,
|
||||
) -> Result<()> {
|
||||
unsafe {
|
||||
e_raw(syscall!(
|
||||
GETRESGID,
|
||||
rgid.map_or(0, |r| r as *const _ as usize),
|
||||
egid.map_or(0, |r| r as *const _ as usize),
|
||||
sgid.map_or(0, |r| r as *const _ as usize)
|
||||
))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
fn getresuid(
|
||||
ruid: Option<&mut uid_t>,
|
||||
euid: Option<&mut uid_t>,
|
||||
suid: Option<&mut uid_t>,
|
||||
) -> Result<()> {
|
||||
unsafe {
|
||||
e_raw(syscall!(
|
||||
GETRESUID,
|
||||
ruid.map_or(0, |r| r as *const _ as usize),
|
||||
euid.map_or(0, |r| r as *const _ as usize),
|
||||
suid.map_or(0, |r| r as *const _ as usize)
|
||||
))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn setrlimit(resource: c_int, rlimit: *const rlimit) -> Result<()> {
|
||||
e_raw(syscall!(SETRLIMIT, resource, rlimit)).map(|_| ())
|
||||
}
|
||||
|
||||
+42
-13
@@ -280,21 +280,40 @@ impl<T: Write> Write for CountingWriter<T> {
|
||||
// get_auxv.
|
||||
|
||||
#[cold]
|
||||
pub unsafe fn get_auxvs(mut ptr: *const usize) -> Box<[[usize; 2]]> {
|
||||
//traverse the stack and collect argument environment variables
|
||||
let mut auxvs = Vec::new();
|
||||
unsafe fn auxv_iter<'a>(ptr: *const usize) -> impl Iterator<Item = [usize; 2]> + 'a {
|
||||
struct St(*const usize);
|
||||
impl Iterator for St {
|
||||
type Item = [usize; 2];
|
||||
|
||||
while *ptr != self::auxv_defs::AT_NULL {
|
||||
let kind = ptr.read();
|
||||
ptr = ptr.add(1);
|
||||
let value = ptr.read();
|
||||
ptr = ptr.add(1);
|
||||
auxvs.push([kind, value]);
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
unsafe {
|
||||
if self.0.read() == self::auxv_defs::AT_NULL {
|
||||
return None;
|
||||
}
|
||||
let kind = self.0.read();
|
||||
let value = self.0.add(1).read();
|
||||
self.0 = self.0.add(2);
|
||||
|
||||
Some([kind, value])
|
||||
}
|
||||
}
|
||||
}
|
||||
St(ptr)
|
||||
}
|
||||
|
||||
#[cold]
|
||||
pub unsafe fn get_auxvs(ptr: *const usize) -> Box<[[usize; 2]]> {
|
||||
//traverse the stack and collect argument environment variables
|
||||
let mut auxvs = auxv_iter(ptr).collect::<Vec<_>>();
|
||||
|
||||
auxvs.sort_unstable_by_key(|[kind, _]| *kind);
|
||||
auxvs.into_boxed_slice()
|
||||
}
|
||||
// TODO: Find an auxv replacement for Redox's execv protocol
|
||||
#[cold]
|
||||
pub unsafe fn get_auxv_raw(ptr: *const usize, requested_kind: usize) -> Option<usize> {
|
||||
auxv_iter(ptr).find_map(|[kind, value]| Some(value).filter(|_| kind == requested_kind))
|
||||
}
|
||||
pub fn get_auxv(auxvs: &[[usize; 2]], key: usize) -> Option<usize> {
|
||||
auxvs
|
||||
.binary_search_by_key(&key, |[entry_key, _]| *entry_key)
|
||||
@@ -306,13 +325,23 @@ pub fn get_auxv(auxvs: &[[usize; 2]], key: usize) -> Option<usize> {
|
||||
#[cfg(target_os = "redox")]
|
||||
// SAFETY: Must only be called when only one thread exists.
|
||||
pub unsafe fn init(auxvs: Box<[[usize; 2]]>) {
|
||||
redox_rt::initialize();
|
||||
|
||||
use self::auxv_defs::*;
|
||||
use crate::header::sys_stat::S_ISVTX;
|
||||
use redox_rt::proc::FdGuard;
|
||||
use syscall::MODE_PERM;
|
||||
|
||||
use crate::header::sys_stat::S_ISVTX;
|
||||
let Some(proc_fd) = get_auxv(&auxvs, AT_REDOX_PROC_FD) else {
|
||||
panic!("Missing proc and thread fd!");
|
||||
};
|
||||
redox_rt::initialize(FdGuard::new(proc_fd));
|
||||
|
||||
use self::auxv_defs::*;
|
||||
// TODO: Is it safe to assume setup_sighandler has been called at this point?
|
||||
redox_rt::sys::this_proc_call(
|
||||
&mut [],
|
||||
syscall::CallFlags::empty(),
|
||||
&[redox_rt::protocol::ProcCall::SyncSigPctl as u64],
|
||||
)
|
||||
.expect("failed to sync signal pctl");
|
||||
|
||||
if let (Some(cwd_ptr), Some(cwd_len)) = (
|
||||
get_auxv(&auxvs, AT_REDOX_INITIAL_CWD_PTR),
|
||||
|
||||
@@ -131,6 +131,18 @@ pub trait Pal {
|
||||
|
||||
fn getrandom(buf: &mut [u8], flags: c_uint) -> Result<usize>;
|
||||
|
||||
fn getresgid(
|
||||
rgid: Option<&mut gid_t>,
|
||||
egid: Option<&mut gid_t>,
|
||||
sgid: Option<&mut gid_t>,
|
||||
) -> Result<()>;
|
||||
|
||||
fn getresuid(
|
||||
ruid: Option<&mut uid_t>,
|
||||
euid: Option<&mut uid_t>,
|
||||
suid: Option<&mut uid_t>,
|
||||
) -> Result<()>;
|
||||
|
||||
unsafe fn getrlimit(resource: c_int, rlim: *mut rlimit) -> Result<()>;
|
||||
|
||||
unsafe fn setrlimit(resource: c_int, rlim: *const rlimit) -> Result<()>;
|
||||
|
||||
@@ -4,7 +4,7 @@ use syscall::{
|
||||
data::Map,
|
||||
error::Result,
|
||||
flag::{MapFlags, O_CLOEXEC},
|
||||
SetSighandlerData, SIGCONT,
|
||||
SetSighandlerData,
|
||||
};
|
||||
|
||||
use redox_rt::{proc::FdGuard, signal::sighandler_function};
|
||||
|
||||
+19
-13
@@ -14,12 +14,15 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use redox_rt::proc::{ExtraInfo, FdGuard, FexecResult, InterpOverride};
|
||||
use redox_rt::{
|
||||
proc::{ExtraInfo, FdGuard, FexecResult, InterpOverride},
|
||||
sys::Resugid,
|
||||
RtTcb,
|
||||
};
|
||||
use syscall::{data::Stat, error::*, flag::*};
|
||||
|
||||
fn fexec_impl(
|
||||
exec_file: FdGuard,
|
||||
open_via_dup: FdGuard,
|
||||
path: &[u8],
|
||||
args: &[&[u8]],
|
||||
envs: &[&[u8]],
|
||||
@@ -31,7 +34,8 @@ fn fexec_impl(
|
||||
|
||||
let addrspace_selection_fd = match redox_rt::proc::fexec_impl(
|
||||
exec_file,
|
||||
open_via_dup,
|
||||
&RtTcb::current().thread_fd(),
|
||||
redox_rt::current_proc_fd(),
|
||||
&memory,
|
||||
path,
|
||||
args.iter().rev(),
|
||||
@@ -43,12 +47,10 @@ fn fexec_impl(
|
||||
FexecResult::Normal { addrspace_handle } => addrspace_handle,
|
||||
FexecResult::Interp {
|
||||
image_file,
|
||||
open_via_dup,
|
||||
path,
|
||||
interp_override: new_interp_override,
|
||||
} => {
|
||||
drop(image_file);
|
||||
drop(open_via_dup);
|
||||
drop(memory);
|
||||
|
||||
// According to elf(5), PT_INTERP requires that the interpreter path be
|
||||
@@ -119,12 +121,11 @@ pub fn execve(
|
||||
|
||||
let mut stat = Stat::default();
|
||||
syscall::fstat(*image_file as usize, &mut stat)?;
|
||||
let uid = syscall::getuid()?;
|
||||
let gid = syscall::getuid()?;
|
||||
let Resugid { ruid, rgid, .. } = redox_rt::sys::posix_getresugid();
|
||||
|
||||
let mode = if uid == stat.st_uid as usize {
|
||||
let mode = if ruid == stat.st_uid {
|
||||
(stat.st_mode >> 3 * 2) & 0o7
|
||||
} else if gid == stat.st_gid as usize {
|
||||
} else if rgid == stat.st_gid {
|
||||
(stat.st_mode >> 3 * 1) & 0o7
|
||||
} else {
|
||||
stat.st_mode & 0o7
|
||||
@@ -243,7 +244,7 @@ pub fn execve(
|
||||
// threads, it could still be allowed by keeping certain file descriptors and instead
|
||||
// set the active file table.
|
||||
let files_fd =
|
||||
File::new(syscall::open("/scheme/thisproc/current/filetable", O_RDONLY)? as c_int);
|
||||
File::new(syscall::dup(**RtTcb::current().thread_fd(), b"filetable")? as c_int);
|
||||
for line in BufReader::new(files_fd).lines() {
|
||||
let line = match line {
|
||||
Ok(l) => l,
|
||||
@@ -262,7 +263,8 @@ pub fn execve(
|
||||
}
|
||||
}
|
||||
|
||||
let this_context_fd = FdGuard::new(syscall::open("/scheme/thisproc/current/open_via_dup", 0)?);
|
||||
let this_thr_fd = RtTcb::current().thread_fd();
|
||||
|
||||
// TODO: Convert image_file to FdGuard earlier?
|
||||
let exec_fd_guard = FdGuard::new(image_file.fd as usize);
|
||||
core::mem::forget(image_file);
|
||||
@@ -272,7 +274,10 @@ pub fn execve(
|
||||
let escalate_fd = FdGuard::new(syscall::open("/scheme/escalate", O_WRONLY)?);
|
||||
|
||||
// First, send the context handle of this process to escalated.
|
||||
send_fd_guard(*escalate_fd, this_context_fd)?;
|
||||
send_fd_guard(
|
||||
*escalate_fd,
|
||||
FdGuard::new(syscall::dup(**this_thr_fd, &[])?),
|
||||
)?;
|
||||
|
||||
// Then, send the file descriptor containing the file descriptor to be executed.
|
||||
send_fd_guard(*escalate_fd, exec_fd_guard)?;
|
||||
@@ -314,10 +319,11 @@ pub fn execve(
|
||||
sigignmask: 0,
|
||||
sigprocmask,
|
||||
umask: redox_rt::sys::get_umask(),
|
||||
thr_fd: **RtTcb::current().thread_fd(),
|
||||
proc_fd: **redox_rt::current_proc_fd(),
|
||||
};
|
||||
fexec_impl(
|
||||
exec_fd_guard,
|
||||
this_context_fd,
|
||||
arg0,
|
||||
&args,
|
||||
&envs,
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use core::{slice, str};
|
||||
|
||||
use redox_rt::sys::{posix_read, posix_write};
|
||||
use syscall::{Error, Result, WaitFlags, EMFILE};
|
||||
use redox_rt::{
|
||||
protocol::{ProcKillTarget, WaitFlags},
|
||||
sys::{posix_read, posix_write, WaitpidTarget},
|
||||
};
|
||||
use syscall::{Error, Result, EMFILE};
|
||||
|
||||
use crate::{
|
||||
header::{
|
||||
@@ -219,34 +222,34 @@ pub unsafe extern "C" fn redox_close_v1(fd: usize) -> RawResult {
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_get_pid_v1() -> RawResult {
|
||||
Error::mux(syscall::getpid())
|
||||
redox_rt::sys::posix_getpid() as _
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_get_euid_v1() -> RawResult {
|
||||
Error::mux(syscall::geteuid())
|
||||
redox_rt::sys::posix_getresugid().euid as _
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_get_ruid_v1() -> RawResult {
|
||||
Error::mux(syscall::getuid())
|
||||
redox_rt::sys::posix_getresugid().ruid as _
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_get_egid_v1() -> RawResult {
|
||||
Error::mux(syscall::getegid())
|
||||
redox_rt::sys::posix_getresugid().egid as _
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_get_rgid_v1() -> RawResult {
|
||||
Error::mux(syscall::getgid())
|
||||
redox_rt::sys::posix_getresugid().rgid as _
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_setrens_v1(rns: usize, ens: usize) -> RawResult {
|
||||
Error::mux(syscall::setrens(rns, ens))
|
||||
Error::mux(redox_rt::sys::setrens(rns, ens).map(|()| 0))
|
||||
}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_waitpid_v1(pid: usize, status: *mut i32, options: u32) -> RawResult {
|
||||
let mut sts = 0_usize;
|
||||
let res = Error::mux(syscall::waitpid(
|
||||
pid,
|
||||
let res = Error::mux(redox_rt::sys::sys_waitpid(
|
||||
WaitpidTarget::from_posix_arg(pid as isize),
|
||||
&mut sts,
|
||||
WaitFlags::from_bits_truncate(options as usize),
|
||||
));
|
||||
@@ -256,7 +259,9 @@ pub unsafe extern "C" fn redox_waitpid_v1(pid: usize, status: *mut i32, options:
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_kill_v1(pid: usize, signal: u32) -> RawResult {
|
||||
Error::mux(syscall::kill(pid, signal as usize))
|
||||
Error::mux(
|
||||
redox_rt::sys::posix_kill(ProcKillTarget::from_raw(pid), signal as usize).map(|()| 0),
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -360,3 +365,9 @@ pub unsafe extern "C" fn redox_mkns_v1(
|
||||
syscall::mkns(core::slice::from_raw_parts(names.cast(), num_names))
|
||||
})())
|
||||
}
|
||||
|
||||
// ABI-UNSTABLE
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_cur_thrfd_v0() -> usize {
|
||||
**redox_rt::RtTcb::current().thread_fd()
|
||||
}
|
||||
|
||||
+98
-56
@@ -3,7 +3,11 @@ use core::{
|
||||
mem::{self, size_of},
|
||||
ptr, slice, str,
|
||||
};
|
||||
use redox_rt::RtTcb;
|
||||
use redox_rt::{
|
||||
protocol::{wifstopped, wstopsig, WaitFlags},
|
||||
sys::{Resugid, WaitpidTarget},
|
||||
RtTcb,
|
||||
};
|
||||
use syscall::{
|
||||
self,
|
||||
data::{Map, Stat as redox_stat, StatVfs as redox_statvfs, TimeSpec as redox_timespec},
|
||||
@@ -50,6 +54,13 @@ fn round_up_to_page_size(val: usize) -> Option<usize> {
|
||||
.map(|val| (val - 1) / PAGE_SIZE * PAGE_SIZE)
|
||||
}
|
||||
|
||||
fn cvt_uid(id: c_int) -> Result<Option<u32>> {
|
||||
if id == -1 {
|
||||
return Ok(None);
|
||||
}
|
||||
Ok(Some(id.try_into().map_err(|_| Errno(EINVAL))?))
|
||||
}
|
||||
|
||||
mod clone;
|
||||
mod epoll;
|
||||
mod event;
|
||||
@@ -93,12 +104,11 @@ impl Pal for Sys {
|
||||
|
||||
syscall::fstat(*fd as usize, &mut stat)?;
|
||||
|
||||
let uid = syscall::getuid()?;
|
||||
let gid = syscall::getgid()?;
|
||||
let Resugid { ruid, rgid, .. } = redox_rt::sys::posix_getresugid();
|
||||
|
||||
let perms = if stat.st_uid as usize == uid {
|
||||
let perms = if stat.st_uid == ruid {
|
||||
stat.st_mode >> (3 * 2 & 0o7)
|
||||
} else if stat.st_gid as usize == gid {
|
||||
} else if stat.st_gid == rgid {
|
||||
stat.st_mode >> (3 * 1 & 0o7)
|
||||
} else {
|
||||
stat.st_mode & 0o7
|
||||
@@ -199,7 +209,7 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn exit(status: c_int) -> ! {
|
||||
let _ = syscall::exit((status as usize) << 8);
|
||||
let _ = redox_rt::sys::posix_exit(status);
|
||||
loop {}
|
||||
}
|
||||
|
||||
@@ -265,7 +275,7 @@ impl Pal for Sys {
|
||||
// TODO: Find way to avoid lock.
|
||||
let _guard = CLONE_LOCK.write();
|
||||
|
||||
Ok(clone::fork_impl()? as pid_t)
|
||||
Ok(clone::fork_impl(&redox_rt::proc::ForkArgs::Managed)? as pid_t)
|
||||
}
|
||||
|
||||
unsafe fn fstat(fildes: c_int, buf: *mut stat) -> Result<()> {
|
||||
@@ -401,15 +411,15 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn getegid() -> gid_t {
|
||||
syscall::getegid().unwrap() as gid_t
|
||||
redox_rt::sys::posix_getresugid().egid as gid_t
|
||||
}
|
||||
|
||||
fn geteuid() -> uid_t {
|
||||
syscall::geteuid().unwrap() as uid_t
|
||||
redox_rt::sys::posix_getresugid().euid as uid_t
|
||||
}
|
||||
|
||||
fn getgid() -> gid_t {
|
||||
syscall::getgid().unwrap() as gid_t
|
||||
redox_rt::sys::posix_getresugid().rgid as gid_t
|
||||
}
|
||||
|
||||
unsafe fn getgroups(size: c_int, list: *mut gid_t) -> Result<c_int> {
|
||||
@@ -423,7 +433,7 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn getpgid(pid: pid_t) -> Result<pid_t> {
|
||||
Ok(syscall::getpgid(pid as usize)? as pid_t)
|
||||
Ok(redox_rt::sys::posix_getpgid(pid as usize)? as pid_t)
|
||||
}
|
||||
|
||||
fn getpid() -> pid_t {
|
||||
@@ -431,7 +441,7 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn getppid() -> pid_t {
|
||||
syscall::getppid().unwrap() as pid_t
|
||||
redox_rt::sys::posix_getppid() as pid_t
|
||||
}
|
||||
|
||||
fn getpriority(which: c_int, who: id_t) -> Result<c_int> {
|
||||
@@ -458,6 +468,45 @@ impl Pal for Sys {
|
||||
Ok(syscall::read(*fd, buf)?)
|
||||
}
|
||||
|
||||
fn getresgid(
|
||||
rgid_out: Option<&mut gid_t>,
|
||||
egid_out: Option<&mut gid_t>,
|
||||
sgid_out: Option<&mut gid_t>,
|
||||
) -> Result<()> {
|
||||
let Resugid {
|
||||
rgid, egid, sgid, ..
|
||||
} = redox_rt::sys::posix_getresugid();
|
||||
if let Some(rgid_out) = rgid_out {
|
||||
*rgid_out = rgid as _;
|
||||
}
|
||||
if let Some(egid_out) = egid_out {
|
||||
*egid_out = egid as _;
|
||||
}
|
||||
if let Some(sgid_out) = sgid_out {
|
||||
*sgid_out = sgid as _;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn getresuid(
|
||||
ruid_out: Option<&mut uid_t>,
|
||||
euid_out: Option<&mut uid_t>,
|
||||
suid_out: Option<&mut uid_t>,
|
||||
) -> Result<()> {
|
||||
let Resugid {
|
||||
ruid, euid, suid, ..
|
||||
} = redox_rt::sys::posix_getresugid();
|
||||
if let Some(ruid_out) = ruid_out {
|
||||
*ruid_out = ruid as _;
|
||||
}
|
||||
if let Some(euid_out) = euid_out {
|
||||
*euid_out = euid as _;
|
||||
}
|
||||
if let Some(suid_out) = suid_out {
|
||||
*suid_out = suid as _;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn getrlimit(resource: c_int, rlim: *mut rlimit) -> Result<()> {
|
||||
//TODO
|
||||
eprintln!(
|
||||
@@ -487,17 +536,7 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn getsid(pid: pid_t) -> Result<pid_t> {
|
||||
let mut buf = [0; mem::size_of::<usize>()];
|
||||
let path = if pid == 0 {
|
||||
format!("/scheme/thisproc/current/session_id")
|
||||
} else {
|
||||
format!("/scheme/proc/{}/session_id", pid)
|
||||
};
|
||||
let path_c = CString::new(path).unwrap();
|
||||
let mut file = File::open(CStr::borrow(&path_c), fcntl::O_RDONLY | fcntl::O_CLOEXEC)?;
|
||||
file.read(&mut buf)
|
||||
.map_err(|err| Errno(err.raw_os_error().unwrap_or(EIO)))?;
|
||||
Ok(usize::from_ne_bytes(buf).try_into().unwrap())
|
||||
Ok(redox_rt::sys::posix_getsid(pid as usize)? as _)
|
||||
}
|
||||
|
||||
fn gettid() -> pid_t {
|
||||
@@ -527,7 +566,7 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn getuid() -> uid_t {
|
||||
syscall::getuid().unwrap() as pid_t
|
||||
redox_rt::sys::posix_getresugid().ruid as uid_t
|
||||
}
|
||||
|
||||
fn lchown(path: CStr, owner: uid_t, group: gid_t) -> Result<()> {
|
||||
@@ -703,7 +742,7 @@ impl Pal for Sys {
|
||||
} else {
|
||||
redox_rmtp = unsafe { redox_timespec::from(&*rmtp) };
|
||||
}
|
||||
match syscall::nanosleep(&redox_rqtp, &mut redox_rmtp) {
|
||||
match redox_rt::sys::posix_nanosleep(&redox_rqtp, &mut redox_rmtp) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(Error { errno: EINTR }) => {
|
||||
unsafe {
|
||||
@@ -838,7 +877,7 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn setpgid(pid: pid_t, pgid: pid_t) -> Result<()> {
|
||||
syscall::setpgid(pid as usize, pgid as usize)?;
|
||||
redox_rt::sys::posix_setpgid(pid as usize, pgid as usize)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -852,30 +891,31 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn setsid() -> Result<()> {
|
||||
let session_id = Self::getpid();
|
||||
assert!(session_id >= 0);
|
||||
let mut file = File::open(
|
||||
c"/scheme/thisproc/current/session_id".into(),
|
||||
fcntl::O_WRONLY | fcntl::O_CLOEXEC,
|
||||
)?;
|
||||
file.write(&usize::to_ne_bytes(session_id.try_into().unwrap()))
|
||||
.map_err(|err| Errno(err.raw_os_error().unwrap_or(EIO)))?;
|
||||
redox_rt::sys::posix_setsid()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setresgid(rgid: gid_t, egid: gid_t, sgid: gid_t) -> Result<()> {
|
||||
if sgid != -1 {
|
||||
println!("TODO: suid");
|
||||
}
|
||||
syscall::setregid(rgid as usize, egid as usize)?;
|
||||
redox_rt::sys::posix_setresugid(&Resugid {
|
||||
ruid: None,
|
||||
euid: None,
|
||||
suid: None,
|
||||
rgid: cvt_uid(rgid)?,
|
||||
egid: cvt_uid(egid)?,
|
||||
sgid: cvt_uid(sgid)?,
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setresuid(ruid: uid_t, euid: uid_t, suid: uid_t) -> Result<()> {
|
||||
if suid != -1 {
|
||||
println!("TODO: suid");
|
||||
}
|
||||
syscall::setreuid(ruid as usize, euid as usize)?;
|
||||
redox_rt::sys::posix_setresugid(&Resugid {
|
||||
ruid: cvt_uid(ruid)?,
|
||||
euid: cvt_uid(euid)?,
|
||||
suid: cvt_uid(suid)?,
|
||||
rgid: None,
|
||||
egid: None,
|
||||
sgid: None,
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -981,14 +1021,16 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
unsafe fn waitpid(mut pid: pid_t, stat_loc: *mut c_int, options: c_int) -> Result<pid_t> {
|
||||
if pid == !0 {
|
||||
pid = 0;
|
||||
}
|
||||
let mut res = None;
|
||||
let mut status = 0;
|
||||
|
||||
let options = usize::try_from(options)
|
||||
.ok()
|
||||
.and_then(WaitFlags::from_bits)
|
||||
.ok_or(Errno(EINVAL))?;
|
||||
|
||||
let inner = |status: &mut usize, flags| {
|
||||
redox_rt::sys::sys_waitpid(pid as usize, status, flags as usize)
|
||||
redox_rt::sys::sys_waitpid(WaitpidTarget::from_posix_arg(pid as isize), status, flags)
|
||||
};
|
||||
|
||||
// First, allow ptrace to handle waitpid
|
||||
@@ -996,19 +1038,19 @@ impl Pal for Sys {
|
||||
let state = ptrace::init_state();
|
||||
let mut sessions = state.sessions.lock();
|
||||
if let Ok(session) = ptrace::get_session(&mut sessions, pid) {
|
||||
if options & sys_wait::WNOHANG != sys_wait::WNOHANG {
|
||||
if !options.contains(WaitFlags::WNOHANG) {
|
||||
let mut _event = PtraceEvent::default();
|
||||
let _ = (&mut &session.tracer).read(&mut _event);
|
||||
|
||||
res = Some(inner(
|
||||
&mut status,
|
||||
options | sys_wait::WNOHANG | sys_wait::WUNTRACED,
|
||||
options | WaitFlags::WNOHANG | WaitFlags::WUNTRACED,
|
||||
));
|
||||
if res == Some(Ok(0)) {
|
||||
// WNOHANG, just pretend ptrace SIGSTOP:ped this
|
||||
status = (syscall::SIGSTOP << 8) | 0x7f;
|
||||
assert!(syscall::wifstopped(status));
|
||||
assert_eq!(syscall::wstopsig(status), syscall::SIGSTOP);
|
||||
status = (redox_rt::protocol::SIGSTOP << 8) | 0x7f;
|
||||
assert!(wifstopped(status));
|
||||
assert_eq!(wstopsig(status), redox_rt::protocol::SIGSTOP);
|
||||
res = Some(Ok(pid as usize));
|
||||
}
|
||||
}
|
||||
@@ -1019,11 +1061,11 @@ impl Pal for Sys {
|
||||
// it if (and only if) a ptrace traceme was activated during
|
||||
// the wait.
|
||||
let res = res.unwrap_or_else(|| loop {
|
||||
let res = inner(&mut status, options | sys_wait::WUNTRACED);
|
||||
let res = inner(&mut status, options | WaitFlags::WUNTRACED);
|
||||
|
||||
// TODO: Also handle special PIDs here
|
||||
if !syscall::wifstopped(status)
|
||||
|| options & sys_wait::WUNTRACED != 0
|
||||
if !wifstopped(status)
|
||||
|| options.contains(WaitFlags::WUNTRACED)
|
||||
|| ptrace::is_traceme(pid)
|
||||
{
|
||||
break res;
|
||||
@@ -1057,8 +1099,8 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn verify() -> bool {
|
||||
// GETPID on Redox is 20, which is WRITEV on Linux
|
||||
(unsafe { syscall::syscall5(syscall::number::SYS_GETPID, !0, !0, !0, !0, !0) }).is_ok()
|
||||
// YIELD on Redox is 20, which is SYS_ARCH_PRCTL on Linux
|
||||
(unsafe { syscall::syscall5(syscall::number::SYS_YIELD, !0, !0, !0, !0, !0) }).is_ok()
|
||||
}
|
||||
|
||||
unsafe fn exit_thread(stack_base: *mut (), stack_size: usize) -> ! {
|
||||
|
||||
@@ -18,6 +18,7 @@ use crate::{
|
||||
use core::mem::{self, offset_of};
|
||||
use redox_rt::{
|
||||
proc::FdGuard,
|
||||
protocol::ProcKillTarget,
|
||||
signal::{
|
||||
PosixStackt, SigStack, Sigaction, SigactionFlags, SigactionKind, Sigaltstack, SignalHandler,
|
||||
},
|
||||
@@ -65,7 +66,7 @@ impl PalSignal for Sys {
|
||||
}
|
||||
|
||||
fn kill(pid: pid_t, sig: c_int) -> Result<()> {
|
||||
redox_rt::sys::posix_kill(pid as usize, sig as usize)?;
|
||||
redox_rt::sys::posix_kill(ProcKillTarget::from_raw(pid as usize), sig as usize)?;
|
||||
Ok(())
|
||||
}
|
||||
fn sigqueue(pid: pid_t, sig: c_int, val: sigval) -> Result<()> {
|
||||
@@ -77,8 +78,10 @@ impl PalSignal for Sys {
|
||||
}
|
||||
|
||||
fn killpg(pgrp: pid_t, sig: c_int) -> Result<()> {
|
||||
redox_rt::sys::posix_killpg(pgrp as usize, sig as usize)?;
|
||||
Ok(())
|
||||
if pgrp == 1 {
|
||||
return Err(Errno(EINVAL));
|
||||
}
|
||||
Self::kill(-pgrp, sig)
|
||||
}
|
||||
|
||||
fn raise(sig: c_int) -> Result<()> {
|
||||
|
||||
+11
-9
@@ -210,19 +210,21 @@ unsafe extern "C" fn new_thread_shim(
|
||||
mutex1: *const Mutex<MaybeUninit<OsTid>>,
|
||||
mutex2: *const Mutex<u64>,
|
||||
) -> ! {
|
||||
let tid = (*(&*mutex1).lock()).assume_init();
|
||||
|
||||
if let Some(tcb) = tcb.as_mut() {
|
||||
tcb.activate();
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
{
|
||||
tcb.activate();
|
||||
}
|
||||
#[cfg(target_os = "redox")]
|
||||
{
|
||||
tcb.activate(redox_rt::proc::FdGuard::new(tid.thread_fd));
|
||||
redox_rt::signal::setup_sighandler(&tcb.os_specific, false);
|
||||
}
|
||||
}
|
||||
|
||||
let procmask = (&*mutex2).as_ptr().read();
|
||||
let tid = (*(&*mutex1).lock()).assume_init();
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
(*tcb)
|
||||
.os_specific
|
||||
.thr_fd
|
||||
.get()
|
||||
.write(Some(redox_rt::proc::FdGuard::new(tid.thread_fd)));
|
||||
|
||||
if let Some(tcb) = tcb.as_mut() {
|
||||
tcb.copy_masters().unwrap();
|
||||
|
||||
+13
-2
@@ -2,6 +2,7 @@
|
||||
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use core::{intrinsics, ptr};
|
||||
use generic_rt::ExpectTlsFree;
|
||||
|
||||
use crate::{
|
||||
header::{libgen, stdio, stdlib},
|
||||
@@ -141,8 +142,18 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! {
|
||||
// Ensure correct host system before executing more system calls
|
||||
relibc_verify_host();
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
let thr_fd = redox_rt::proc::FdGuard::new(
|
||||
crate::platform::get_auxv_raw(sp.auxv().cast(), redox_rt::auxv_defs::AT_REDOX_THR_FD)
|
||||
.expect_notls("no thread fd present"),
|
||||
);
|
||||
|
||||
// Initialize TLS, if necessary
|
||||
ld_so::init(sp);
|
||||
ld_so::init(
|
||||
sp,
|
||||
#[cfg(target_os = "redox")]
|
||||
thr_fd,
|
||||
);
|
||||
|
||||
// Set up the right allocator...
|
||||
// if any memory rust based memory allocation happen before this step .. we are doomed.
|
||||
@@ -160,7 +171,7 @@ pub unsafe extern "C" fn relibc_start(sp: &'static Stack) -> ! {
|
||||
tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker)));
|
||||
}
|
||||
#[cfg(target_os = "redox")]
|
||||
redox_rt::signal::setup_sighandler(&tcb.os_specific);
|
||||
redox_rt::signal::setup_sighandler(&tcb.os_specific, true);
|
||||
}
|
||||
|
||||
// Set up argc and argv
|
||||
|
||||
+5
-2
@@ -125,10 +125,12 @@ EXPECT_NAMES=\
|
||||
unistd/getopt_long \
|
||||
unistd/pipe \
|
||||
unistd/rmdir \
|
||||
waitpid \
|
||||
waitpid_multiple \
|
||||
kill-waitpid \
|
||||
# unistd/sleep \
|
||||
unistd/swab \
|
||||
unistd/write \
|
||||
waitpid \
|
||||
wchar/fgetwc \
|
||||
wchar/fwide \
|
||||
wchar/mbrtowc \
|
||||
@@ -204,6 +206,7 @@ NAMES=\
|
||||
unistd/sysconf \
|
||||
pthread/main \
|
||||
pthread/cleanup \
|
||||
pthread/exit \
|
||||
pthread/extjoin \
|
||||
pthread/once \
|
||||
pthread/customstack \
|
||||
@@ -216,9 +219,9 @@ NAMES=\
|
||||
grp/getgrgid_r \
|
||||
grp/getgrnam_r \
|
||||
grp/gr_iter \
|
||||
sigqueue
|
||||
# resource/getrusage
|
||||
# time/times
|
||||
# sigqueue
|
||||
|
||||
# Tests run with `expect` (require a .c file and an .exp file
|
||||
# that takes the produced binary as the first argument)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "test_helpers.h"
|
||||
|
||||
int main(void) {
|
||||
int err;
|
||||
|
||||
int fds[2];
|
||||
err = pipe(fds);
|
||||
ERROR_IF(pipe, err, == -1);
|
||||
|
||||
int child = fork();
|
||||
ERROR_IF(fork, child, == -1);
|
||||
|
||||
if (child == 0) {
|
||||
// block forever
|
||||
char buf[1];
|
||||
read(fds[0], buf, 1);
|
||||
}
|
||||
|
||||
err = kill(child, SIGTERM);
|
||||
ERROR_IF(kill, err, == -1);
|
||||
|
||||
int status;
|
||||
err = waitpid(child, &status, 0);
|
||||
ERROR_IF(waitpid, err, == -1);
|
||||
printf("STATUS %d\n", status);
|
||||
assert(WIFSIGNALED(status));
|
||||
assert(WTERMSIG(status) == SIGTERM);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
void *routine(void *arg) {
|
||||
assert(arg == NULL);
|
||||
|
||||
sleep(1);
|
||||
|
||||
puts("Thread succeeded");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int status;
|
||||
pthread_t thread;
|
||||
|
||||
if ((status = pthread_create(&thread, NULL, routine, NULL)) != 0) {
|
||||
return fail(status, "failed to create thread");
|
||||
}
|
||||
if ((status = pthread_detach(thread)) != 0) {
|
||||
return fail(status, "failed to detach thread");
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
+22
-7
@@ -1,21 +1,36 @@
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "test_helpers.h"
|
||||
|
||||
int main(void) {
|
||||
void for_code(int code) {
|
||||
pid_t pid = fork();
|
||||
ERROR_IF(fork, pid, == -1);
|
||||
|
||||
// Testing successful exit
|
||||
if (pid == 0) {
|
||||
// child
|
||||
sleep(1);
|
||||
exit(EXIT_SUCCESS);
|
||||
} else {
|
||||
// parent
|
||||
int stat_loc;
|
||||
pid_t wid = waitpid(pid, &stat_loc, 0);
|
||||
ERROR_IF(waitpid, wid, == -1);
|
||||
_Exit(code);
|
||||
}
|
||||
printf("Testing waitpid of child %d for code %d\n", pid, code);
|
||||
// parent
|
||||
int status;
|
||||
pid_t wid = waitpid(pid, &status, 0);
|
||||
ERROR_IF(waitpid, wid, == -1);
|
||||
|
||||
assert(WIFEXITED(status));
|
||||
assert(WEXITSTATUS(status) == code);
|
||||
|
||||
puts("Success");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
for_code(EXIT_SUCCESS);
|
||||
for_code(EXIT_FAILURE);
|
||||
for_code(42);
|
||||
for_code(255);
|
||||
// TODO: Also add coverage for e.g. WIFSTOPPED, WSTOPSIG, WTERMSIG, etc
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "test_helpers.h"
|
||||
|
||||
int main(void) {
|
||||
// Spawn two children, one with same pgid and one with pgid set to its own
|
||||
// pid, so that the one with different pgid completes first. Then test
|
||||
// waitpid both for 'any child' and for 'any child with same pgid'.
|
||||
|
||||
pid_t pid_samepgid = fork();
|
||||
ERROR_IF(fork, pid_samepgid, == -1);
|
||||
|
||||
if (pid_samepgid == 0) {
|
||||
// child
|
||||
sleep(2);
|
||||
_Exit(2);
|
||||
}
|
||||
pid_t pid_diffpgids[2];
|
||||
for (int i = 0; i < 2; i++) {
|
||||
pid_diffpgids[i] = fork();
|
||||
ERROR_IF(fork, pid_diffpgids[i], == -1);
|
||||
|
||||
if (pid_diffpgids[i] == 0) {
|
||||
int ret = setpgid(0, 0);
|
||||
ERROR_IF(setpgid, ret, == -1);
|
||||
|
||||
// child
|
||||
sleep(1);
|
||||
_Exit(i);
|
||||
}
|
||||
}
|
||||
int status;
|
||||
pid_t wid;
|
||||
|
||||
// First, check that the first different-pgid proc is recognized.
|
||||
wid = waitpid(-1, &status, 0);
|
||||
ERROR_IF(waitpid, wid, == -1);
|
||||
assert(wid == pid_diffpgids[0]);
|
||||
assert(WIFEXITED(status));
|
||||
assert(WEXITSTATUS(status) == 0);
|
||||
|
||||
// Then, check that the longest-waiting proc with the same pgid is properly matched.
|
||||
wid = waitpid(0, &status, 0);
|
||||
ERROR_IF(waitpid, wid, == -1);
|
||||
assert(wid == pid_samepgid);
|
||||
assert(WIFEXITED(status));
|
||||
assert(WEXITSTATUS(status) == 2);
|
||||
|
||||
// Finally, the last same-pgid must have completed.
|
||||
wid = waitpid(-1, &status, WNOHANG);
|
||||
ERROR_IF(waitpid, wid, == -1);
|
||||
assert(wid == pid_diffpgids[1]);
|
||||
assert(WIFEXITED(status));
|
||||
assert(WEXITSTATUS(status) == 1);
|
||||
}
|
||||
Reference in New Issue
Block a user