Page MenuHomeFreeBSD

D54879.id170418.diff
No OneTemporary

D54879.id170418.diff

diff --git a/include/spawn.h b/include/spawn.h
--- a/include/spawn.h
+++ b/include/spawn.h
@@ -126,8 +126,12 @@
#if __BSD_VISIBLE
int posix_spawnattr_setexecfd_np(posix_spawnattr_t * __restrict, int);
+int posix_spawnattr_setprocdescp_np(const posix_spawnattr_t * __restrict,
+ int * __restrict, int);
int posix_spawnattr_getexecfd_np(const posix_spawnattr_t * __restrict,
int * __restrict);
+int posix_spawnattr_getprocdescp_np(const posix_spawnattr_t * __restrict,
+ int ** __restrict, int * __restrict);
#endif
__END_DECLS
diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map
--- a/lib/libc/gen/Symbol.map
+++ b/lib/libc/gen/Symbol.map
@@ -476,7 +476,9 @@
FBSD_1.9 {
posix_spawnattr_getexecfd_np;
+ posix_spawnattr_getprocdescp_np;
posix_spawnattr_setexecfd_np;
+ posix_spawnattr_setprocdescp_np;
};
FBSDprivate_1.0 {
diff --git a/lib/libc/gen/posix_spawn.c b/lib/libc/gen/posix_spawn.c
--- a/lib/libc/gen/posix_spawn.c
+++ b/lib/libc/gen/posix_spawn.c
@@ -29,6 +29,7 @@
#include "namespace.h"
#include <sys/param.h>
#include <sys/procctl.h>
+#include <sys/procdesc.h>
#include <sys/queue.h>
#include <sys/wait.h>
@@ -37,6 +38,7 @@
#include <sched.h>
#include <spawn.h>
#include <signal.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -51,6 +53,8 @@
sigset_t sa_sigdefault;
sigset_t sa_sigmask;
int sa_execfd;
+ int *sa_pdrfork_fdp;
+ int sa_pdflags;
};
struct __posix_spawn_file_actions {
@@ -281,6 +285,8 @@
{
struct posix_spawn_args psa;
pid_t p;
+ int pfd;
+ bool do_pfd;
#ifdef _RFORK_THREAD_STACK_SIZE
char *stack;
size_t cnt, stacksz;
@@ -322,6 +328,8 @@
psa.use_env_path = use_env_path;
psa.error = 0;
+ do_pfd = sa != NULL && (*sa)->sa_pdrfork_fdp != NULL;
+
/*
* Passing RFSPAWN to rfork(2) gives us effectively a vfork that drops
* non-ignored signal handlers. We'll fall back to the slightly less
@@ -341,10 +349,20 @@
* parent. Because of this, we must use rfork_thread instead while
* almost every other arch stores the return address in a register.
*/
- p = rfork_thread(RFSPAWN, stack + stacksz, _posix_spawn_thr, &psa);
+ if (do_pfd) {
+ p = pdrfork_thread(&pfd, PD_CLOEXEC | (*sa)->sa_pdflags,
+ RFSPAWN, stack + stacksz, _posix_spawn_thr, &psa);
+ } else {
+ p = rfork_thread(RFSPAWN, stack + stacksz, _posix_spawn_thr,
+ &psa);
+ }
free(stack);
#else
- p = rfork(RFSPAWN);
+ if (do_pfd) {
+ p = pdrfork(&pfd, PD_CLOEXEC | (*sa)->sa_pdflags, RFSPAWN);
+ } else {
+ p = rfork(RFSPAWN);
+ }
if (p == 0)
/* _posix_spawn_thr does not return */
_posix_spawn_thr(&psa);
@@ -356,6 +374,8 @@
*/
if (p == -1 && errno == EINVAL) {
+ if (do_pfd)
+ return (EOPNOTSUPP);
p = vfork();
if (p == 0)
/* _posix_spawn_thr does not return */
@@ -363,12 +383,18 @@
}
if (p == -1)
return (errno);
- if (psa.error != 0)
+ if (psa.error != 0) {
/* Failed; ready to reap */
- _waitpid(p, NULL, WNOHANG);
- else if (pid != NULL)
+ if (do_pfd)
+ (void)_close(pfd);
+ else
+ _waitpid(p, NULL, WNOHANG);
+ } else if (pid != NULL) {
/* exec succeeded */
*pid = p;
+ if (do_pfd)
+ *((*sa)->sa_pdrfork_fdp) = pfd;
+ }
return (psa.error);
}
@@ -651,6 +677,15 @@
return (0);
}
+int
+posix_spawnattr_getprocdescp_np(const posix_spawnattr_t * __restrict sa,
+ int ** __restrict fdpp, int * __restrict pdrflagsp)
+{
+ *fdpp = (*sa)->sa_pdrfork_fdp;
+ *pdrflagsp = (*sa)->sa_pdflags;
+ return (0);
+}
+
int
posix_spawnattr_setflags(posix_spawnattr_t *sa, short flags)
{
@@ -708,3 +743,12 @@
(*sa)->sa_execfd = execfd;
return (0);
}
+
+int
+posix_spawnattr_setprocdescp_np(const posix_spawnattr_t * __restrict sa,
+ int * __restrict fdp, int pdrflags)
+{
+ (*sa)->sa_pdrfork_fdp = fdp;
+ (*sa)->sa_pdflags = pdrflags;
+ return (0);
+}
diff --git a/lib/libsys/amd64/Makefile.sys b/lib/libsys/amd64/Makefile.sys
--- a/lib/libsys/amd64/Makefile.sys
+++ b/lib/libsys/amd64/Makefile.sys
@@ -4,6 +4,7 @@
amd64_set_fsbase.c \
amd64_set_gsbase.c \
amd64_set_tlsbase.c \
- rfork_thread.S
+ rfork_thread.S \
+ pdrfork_thread.S
MDASM= vfork.S cerror.S getcontext.S
diff --git a/lib/libsys/amd64/Symbol.sys.map b/lib/libsys/amd64/Symbol.sys.map
--- a/lib/libsys/amd64/Symbol.sys.map
+++ b/lib/libsys/amd64/Symbol.sys.map
@@ -17,6 +17,10 @@
amd64_set_tlsbase;
};
+FBSD_1.9 {
+ pdrfork_thread;
+};
+
FBSDprivate_1.0 {
_vfork;
};
diff --git a/lib/libsys/amd64/pdrfork_thread.S b/lib/libsys/amd64/pdrfork_thread.S
new file mode 100644
--- /dev/null
+++ b/lib/libsys/amd64/pdrfork_thread.S
@@ -0,0 +1,83 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright 2000 Peter Wemm <peter@FreeBSD.org>
+ * Copyright 2003 Alan L. Cox <alc@cs.rice.edu>
+ * Copyright 2026 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by
+ * Konstantin Belousov <kib@FreeBSD.org> under sponsorship from
+ * the FreeBSD Foundation.
+ */
+
+#include <machine/asm.h>
+/*
+ * With thanks to John Dyson for the original version of this.
+ */
+
+#include <SYS.h>
+
+/*
+ * %rdi %esi %rdx %rcx %r8 %r9
+ * pdrfork_thread(fdp, pdflags, rfflags, stack_addr, start_fnc, start_arg);
+ *
+ * fdp Pointer for the resulting fd location
+ * pdflags Flags as to pdfork.
+ * rfflags: Flags as to rfork.
+ * stack_addr: Top of stack for thread.
+ * start_fnc: Address of thread function to call in child.
+ * start_arg: Argument to pass to the thread function in child.
+ */
+
+ENTRY(pdrfork_thread)
+ pushq %rbx
+ pushq %r12
+ pushq %r13
+ movq %r8, %rbx
+ movq %r9, %r12
+ movq %rcx, %r13
+
+ /*
+ * Prepare and execute the thread creation syscall
+ */
+ _SYSCALL(pdrfork)
+ jb 2f
+
+ /*
+ * Check to see if we are in the parent or child
+ */
+ cmpl $0, %edx
+ jnz 1f
+ popq %r13
+ popq %r12
+ popq %rbx
+ ret
+
+ /*
+ * If we are in the child (new thread), then
+ * set-up the call to the internal subroutine. If it
+ * returns, then call __exit.
+ */
+1:
+ movq %r13, %rsp
+ movq %r12, %rdi
+ call *%rbx
+ movl %eax, %edi
+
+ /*
+ * Exit system call
+ */
+ _SYSCALL(exit)
+
+ /*
+ * Branch here if the thread creation fails:
+ */
+2:
+ popq %r13
+ popq %r12
+ popq %rbx
+ jmp HIDENAME(cerror)
+END(pdrfork_thread)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libsys/i386/Makefile.sys b/lib/libsys/i386/Makefile.sys
--- a/lib/libsys/i386/Makefile.sys
+++ b/lib/libsys/i386/Makefile.sys
@@ -1,7 +1,7 @@
SRCS+= i386_get_fsbase.c i386_get_gsbase.c i386_get_ioperm.c i386_get_ldt.c \
i386_set_fsbase.c i386_set_gsbase.c i386_set_ioperm.c i386_set_ldt.c \
i386_clr_watch.c i386_set_watch.c i386_vm86.c \
- rfork_thread.S
+ rfork_thread.S pdrfork_thread.S
MDASM= vfork.S cerror.S getcontext.S syscall.S
diff --git a/lib/libsys/i386/Symbol.sys.map b/lib/libsys/i386/Symbol.sys.map
--- a/lib/libsys/i386/Symbol.sys.map
+++ b/lib/libsys/i386/Symbol.sys.map
@@ -20,6 +20,10 @@
x86_pkru_unprotect_range;
};
+FBSD_1.9 {
+ pdrfork_thread;
+};
+
FBSDprivate_1.0 {
_vfork;
};
diff --git a/lib/libsys/i386/pdrfork_thread.S b/lib/libsys/i386/pdrfork_thread.S
new file mode 100644
--- /dev/null
+++ b/lib/libsys/i386/pdrfork_thread.S
@@ -0,0 +1,101 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright 2000 Peter Wemm <peter@FreeBSD.org>
+ * Copyright 2026 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by
+ * Konstantin Belousov <kib@FreeBSD.org> under sponsorship from
+ * the FreeBSD Foundation.
+ */
+
+#include <machine/asm.h>
+/*
+ * With thanks to John Dyson for the original version of this.
+ */
+
+#include <SYS.h>
+
+/*
+ * 8 12 16 20 24 28
+ * rfork_thread(fdp, pdflags rfflags, stack_addr, start_fnc, start_arg);
+ *
+ * fdp Pointer for the resulting fd location
+ * pdflags Flags as to pdfork.
+ * rfflags: Flags as to rfork.
+ * stack_addr: Top of stack for thread.
+ * start_fnc: Address of thread function to call in child.
+ * start_arg: Argument to pass to the thread function in child.
+ */
+
+ENTRY(pdrfork_thread)
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %esi
+
+ /*
+ * Push thread info onto the new thread's stack
+ */
+ movl 20(%ebp), %esi # get stack addr
+
+ subl $4, %esi
+ movl 28(%ebp), %eax # get start argument
+ movl %eax, (%esi)
+
+ subl $4, %esi
+ movl 24(%ebp), %eax # get start thread address
+ movl %eax, (%esi)
+
+ /*
+ * Prepare and execute the thread creation syscall
+ */
+ pushl 16(%ebp)
+ pushl 12(%ebp)
+ pushl 8(%ebp)
+ pushl $0
+ _SYSCALL(pdrfork)
+ jb 2f
+
+ /*
+ * Check to see if we are in the parent or child
+ */
+ cmpl $0, %edx
+ jnz 1f
+ addl $16, %esp
+ popl %esi
+ movl %ebp, %esp
+ popl %ebp
+ ret
+ .p2align 2
+
+ /*
+ * If we are in the child (new thread), then
+ * set-up the call to the internal subroutine. If it
+ * returns, then call __exit.
+ */
+1:
+ movl %esi,%esp
+ popl %eax
+ call *%eax
+ addl $4, %esp
+
+ /*
+ * Exit system call
+ */
+ pushl %eax
+ pushl $0
+ _SYSCALL(exit)
+
+ /*
+ * Branch here if the thread creation fails:
+ */
+2:
+ addl $16, %esp
+ popl %esi
+ movl %ebp, %esp
+ popl %ebp
+ jmp HIDENAME(cerror)
+END(pdrfork_thread)
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/sys/sys/procdesc.h b/sys/sys/procdesc.h
--- a/sys/sys/procdesc.h
+++ b/sys/sys/procdesc.h
@@ -130,6 +130,7 @@
int pdkill(int, int);
int pdgetpid(int, pid_t *);
int pdwait(int, int *, int, struct __wrusage *, struct __siginfo *);
+pid_t pdrfork_thread(int *, int, int, void *, int (*)(void *), void *);
__END_DECLS
#endif /* _KERNEL */

File Metadata

Mime Type
text/plain
Expires
Wed, Mar 18, 7:33 PM (12 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29922679
Default Alt Text
D54879.id170418.diff (9 KB)

Event Timeline