summaryrefslogtreecommitdiff
path: root/usr/src/lib/libc
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libc')
-rw-r--r--usr/src/lib/libc/amd64/Makefile8
-rw-r--r--usr/src/lib/libc/amd64/sys/forkallx.s (renamed from usr/src/lib/libc/amd64/sys/fork1.s)24
-rw-r--r--usr/src/lib/libc/amd64/sys/forkx.s (renamed from usr/src/lib/libc/amd64/sys/forkall.s)20
-rw-r--r--usr/src/lib/libc/amd64/sys/vforkx.s (renamed from usr/src/lib/libc/amd64/sys/vfork.s)82
-rw-r--r--usr/src/lib/libc/i386/Makefile.com8
-rw-r--r--usr/src/lib/libc/i386/sys/fork1.s46
-rw-r--r--usr/src/lib/libc/i386/sys/forkall.s50
-rw-r--r--usr/src/lib/libc/i386/sys/forkallx.s59
-rw-r--r--usr/src/lib/libc/i386/sys/forkx.s59
-rw-r--r--usr/src/lib/libc/i386/sys/vfork.s121
-rw-r--r--usr/src/lib/libc/i386/sys/vforkx.s141
-rw-r--r--usr/src/lib/libc/inc/mtlib.h1
-rw-r--r--usr/src/lib/libc/inc/synonyms.h4
-rw-r--r--usr/src/lib/libc/inc/thr_uberdata.h7
-rw-r--r--usr/src/lib/libc/port/gen/getutx.c25
-rw-r--r--usr/src/lib/libc/port/gen/syslog.c38
-rw-r--r--usr/src/lib/libc/port/mapfile-vers6
-rw-r--r--usr/src/lib/libc/port/regex/wordexp.c159
-rw-r--r--usr/src/lib/libc/port/stdio/popen.c147
-rw-r--r--usr/src/lib/libc/port/stdio/system.c153
-rw-r--r--usr/src/lib/libc/port/threads/scalls.c60
-rw-r--r--usr/src/lib/libc/port/threads/spawn.c36
-rw-r--r--usr/src/lib/libc/port/threads/thr.c8
-rw-r--r--usr/src/lib/libc/sparc/Makefile8
-rw-r--r--usr/src/lib/libc/sparc/sys/forkallx.s (renamed from usr/src/lib/libc/sparc/sys/forkall.s)28
-rw-r--r--usr/src/lib/libc/sparc/sys/forkx.s (renamed from usr/src/lib/libc/sparc/sys/fork1.s)28
-rw-r--r--usr/src/lib/libc/sparc/sys/vforkx.s (renamed from usr/src/lib/libc/sparc/sys/vfork.s)91
-rw-r--r--usr/src/lib/libc/sparcv9/Makefile8
28 files changed, 849 insertions, 576 deletions
diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile
index 8af48c4361..41d5c3004a 100644
--- a/usr/src/lib/libc/amd64/Makefile
+++ b/usr/src/lib/libc/amd64/Makefile
@@ -293,8 +293,8 @@ SYSOBJS= \
_lwp_mutex_unlock.o \
_stack_grow.o \
door.o \
- fork1.o \
- forkall.o \
+ forkx.o \
+ forkallx.o \
fxstat.o \
getcontext.o \
gettimeofday.o \
@@ -308,7 +308,7 @@ SYSOBJS= \
uadmin.o \
umount.o \
uname.o \
- vfork.o \
+ vforkx.o \
xmknod.o \
xstat.o
@@ -1094,7 +1094,7 @@ ASSYMDEP_OBJS= \
asm_subr.o \
getcontext.o \
tls_get_addr.o \
- vfork.o
+ vforkx.o
$(ASSYMDEP_OBJS:%=pics/%): assym.h
diff --git a/usr/src/lib/libc/amd64/sys/fork1.s b/usr/src/lib/libc/amd64/sys/forkallx.s
index 6251fb32ae..dc367d005c 100644
--- a/usr/src/lib/libc/amd64/sys/fork1.s
+++ b/usr/src/lib/libc/amd64/sys/forkallx.s
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -31,18 +31,26 @@
#include "SYS.h"
/*
- * pid = fork1();
+ * pid = __forkallx(flags);
+ *
+ * syscall trap: forksys(1, flags)
*
+ * From the syscall:
* %edx == 0 in parent process, %edx = 1 in child process.
* %eax == pid of child in parent, %eax == pid of parent in child.
+ *
+ * The child gets a zero return value.
+ * The parent gets the pid of the child.
*/
- ENTRY(__fork1)
- SYSTRAP_2RVALS(fork1)
+ ENTRY(__forkallx)
+ movl %edi, %esi
+ movl $1, %edi
+ SYSTRAP_2RVALS(forksys)
SYSCERROR
testl %edx, %edx
jz 1f /* jump if parent */
xorl %eax, %eax /* child, return (0) */
1:
RET
- SET_SIZE(__fork1)
+ SET_SIZE(__forkallx)
diff --git a/usr/src/lib/libc/amd64/sys/forkall.s b/usr/src/lib/libc/amd64/sys/forkx.s
index d9a8258566..afdb99297f 100644
--- a/usr/src/lib/libc/amd64/sys/forkall.s
+++ b/usr/src/lib/libc/amd64/sys/forkx.s
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -31,7 +31,9 @@
#include "SYS.h"
/*
- * pid = forkall();
+ * pid = __forkx(flags);
+ *
+ * syscall trap: forksys(0, flags)
*
* From the syscall:
* %edx == 0 in parent process, %edx = 1 in child process.
@@ -41,12 +43,14 @@
* The parent gets the pid of the child.
*/
- ENTRY(__forkall)
- SYSTRAP_2RVALS(forkall)
+ ENTRY(__forkx)
+ movl %edi, %esi
+ xorl %edi, %edi
+ SYSTRAP_2RVALS(forksys)
SYSCERROR
testl %edx, %edx
jz 1f /* jump if parent */
xorl %eax, %eax /* child, return (0) */
1:
RET
- SET_SIZE(__forkall)
+ SET_SIZE(__forkx)
diff --git a/usr/src/lib/libc/amd64/sys/vfork.s b/usr/src/lib/libc/amd64/sys/vforkx.s
index 3d9f81728c..507518572b 100644
--- a/usr/src/lib/libc/amd64/sys/vfork.s
+++ b/usr/src/lib/libc/amd64/sys/vforkx.s
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,10 +30,26 @@
#include <sys/asm_linkage.h>
+ ANSI_PRAGMA_WEAK(vforkx,function)
ANSI_PRAGMA_WEAK(vfork,function)
#include "SYS.h"
-#include <../assym.h>
+#include <assym.h>
+
+/*
+ * pid = vforkx(flags);
+ * syscall trap: forksys(2, flags)
+ *
+ * pid = vfork();
+ * syscall trap: forksys(2, 0)
+ *
+ * From the syscall:
+ * %edx == 0 in parent process, %edx = 1 in child process.
+ * %eax == pid of child in parent, %eax == pid of parent in child.
+ *
+ * The child gets a zero return value.
+ * The parent gets the pid of the child.
+ */
/*
* The child of vfork() will execute in the parent's address space,
@@ -46,56 +62,55 @@
* don't end up in a signal handler with curthread->ul_vfork set wrong.
*/
- ENTRY(vfork)
- movq 0(%rsp),%r9 /* save %rip in %r9 */
- leaq _sref_(0f),%rax /* arrange for RET to return here */
- movq %rax,0(%rsp)
- ret
-
+ ENTRY_NP(vforkx)
+ movq %rdi, %r8 /* flags */
+ jmp 0f
+ ENTRY_NP(vfork)
+ xorq %r8, %r8 /* flags = 0 */
0:
- movl $MASKSET1, %edx
+ popq %r9 /* save return %rip in %r9 */
+ movl $MASKSET1, %edx /* block all signals */
movl $MASKSET0, %esi
movl $SIG_SETMASK, %edi
__SYSCALL(lwp_sigmask)
- __SYSCALL(vfork)
- jae 2f
+ movq %r8, %rsi /* flags */
+ movl $2, %edi
+ __SYSCALL(forksys) /* vforkx(flags) */
+ jae 1f
/* reconstruct stack before jumping to __cerror */
- call 1f
-1: movq %r9, 0(%rsp)
- pushq %rax /* save the vfork() return value */
+ pushq %r9
+ movq %rax, %r8 /* save the vfork() error number */
movl %fs:UL_SIGMASK+4, %edx /* reinstate signals */
movl %fs:UL_SIGMASK, %esi
movl $SIG_SETMASK, %edi
__SYSCALL(lwp_sigmask)
- popq %rax /* restore the vfork() return value */
+ movq %r8, %rax /* restore the vfork() error number */
jmp __cerror
-2:
+1:
/*
* To determine if we are (still) a child of vfork(), the child
* increments curthread->ul_vfork by one and the parent decrements
* it by one. If the result is zero, then we are not a child of
* vfork(), else we are. We do this to deal with the case of
* a vfork() child calling vfork().
- *
- * %edx is zero if we are the parent, non-zero if we are the child.
*/
cmpl $0, %edx
- jne 3f
+ jne 2f
movl %fs:UL_VFORK, %edx
- cmpl $0, %edx /* don't let it go negative */
- je 4f
- subl $1, %edx /* curthread->ul_vfork--; */
- jmp 4f
-3:
- movl $0, %eax /* zero the return value in the child */
+ cmpl $0, %edx /* don't let it go negative */
+ je 3f
+ subl $1, %edx /* curthread->ul_vfork--; */
+ jmp 3f
+2:
+ xorl %eax, %eax /* zero the return value in the child */
movl %fs:UL_VFORK, %edx
- addl $1, %edx /* curthread->ul_vfork++; */
-4:
+ addl $1, %edx /* curthread->ul_vfork++; */
+3:
movl %edx, %fs:UL_VFORK
/*
* Clear the schedctl interface in both parent and child.
@@ -104,13 +119,14 @@
xorq %rdx, %rdx
movq %rdx, %fs:UL_SCHEDCTL
movq %rdx, %fs:UL_SCHEDCTL_CALLED
- pushq %rax /* save the vfork() return value */
+ movq %rax, %r8 /* save the vfork() return value */
movl %fs:UL_SIGMASK+4, %edx /* reinstate signals */
movl %fs:UL_SIGMASK, %esi
movl $SIG_SETMASK, %edi
__SYSCALL(lwp_sigmask)
- popq %rax /* restore the vfork() return value */
- jmp *%r9 /* jump back to the caller */
+ movq %r8, %rax /* restore the vfork() return value */
+ jmp *%r9 /* jump back to the caller */
SET_SIZE(vfork)
+ SET_SIZE(vforkx)
diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com
index 153937921b..17b3be0244 100644
--- a/usr/src/lib/libc/i386/Makefile.com
+++ b/usr/src/lib/libc/i386/Makefile.com
@@ -315,8 +315,8 @@ SYSOBJS= \
_lwp_mutex_unlock.o \
_stack_grow.o \
door.o \
- fork1.o \
- forkall.o \
+ forkx.o \
+ forkallx.o \
fxstat.o \
getcontext.o \
gettimeofday.o \
@@ -331,7 +331,7 @@ SYSOBJS= \
uadmin.o \
umount.o \
uname.o \
- vfork.o \
+ vforkx.o \
xmknod.o \
xstat.o
@@ -1155,7 +1155,7 @@ ASSYMDEP_OBJS= \
_stack_grow.o \
getcontext.o \
tls_get_addr.o \
- vfork.o
+ vforkx.o
$(ASSYMDEP_OBJS:%=pics/%) := CPPFLAGS += -I.
diff --git a/usr/src/lib/libc/i386/sys/fork1.s b/usr/src/lib/libc/i386/sys/fork1.s
deleted file mode 100644
index ed154666f5..0000000000
--- a/usr/src/lib/libc/i386/sys/fork1.s
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
- .file "%M%"
-
-#include "SYS.h"
-
-/ pid = fork1();
-
-/ %edx == 0 in parent process, %edx = 1 in child process.
-/ %eax == pid of child in parent, %eax == pid of parent in child.
-
- ENTRY(__fork1)
- SYSTRAP_2RVALS(fork1)
- SYSCERROR
- testl %edx, %edx
- jz 1f / jump if parent
- xorl %eax, %eax / child, return (0)
-1:
- RET
- SET_SIZE(__fork1)
diff --git a/usr/src/lib/libc/i386/sys/forkall.s b/usr/src/lib/libc/i386/sys/forkall.s
deleted file mode 100644
index 6a64e45d34..0000000000
--- a/usr/src/lib/libc/i386/sys/forkall.s
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
- .file "%M%"
-
-#include "SYS.h"
-
-/ pid = forkall();
-
-/ From the syscall:
-/ %edx == 0 in parent process, %edx = 1 in child process.
-/ %eax == pid of child in parent, %eax == pid of parent in child.
-/
-/ The child gets a zero return value.
-/ The parent gets the pid of the child.
-
- ENTRY(__forkall)
- SYSTRAP_2RVALS(forkall)
- SYSCERROR
- testl %edx, %edx
- jz 1f / jump if parent
- xorl %eax, %eax / child, return (0)
-1:
- RET
- SET_SIZE(__forkall)
diff --git a/usr/src/lib/libc/i386/sys/forkallx.s b/usr/src/lib/libc/i386/sys/forkallx.s
new file mode 100644
index 0000000000..7cf6b58e1d
--- /dev/null
+++ b/usr/src/lib/libc/i386/sys/forkallx.s
@@ -0,0 +1,59 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+ .file "%M%"
+
+#include "SYS.h"
+
+/*
+ * pid = __forkallx(flags);
+ *
+ * syscall trap: forksys(1, flags)
+ *
+ * From the syscall:
+ * %edx == 0 in parent process, %edx = 1 in child process.
+ * %eax == pid of child in parent, %eax == pid of parent in child.
+ *
+ * The child gets a zero return value.
+ * The parent gets the pid of the child.
+ */
+
+ ENTRY(__forkallx)
+ popl %ecx
+ pushl $1
+ pushl %ecx
+ SYSTRAP_2RVALS(forksys)
+ popl %ecx
+ movl %ecx, 0(%esp)
+ SYSCERROR
+ testl %edx, %edx
+ jz 1f /* jump if parent */
+ xorl %eax, %eax /* child, return (0) */
+1:
+ RET
+ SET_SIZE(__forkallx)
diff --git a/usr/src/lib/libc/i386/sys/forkx.s b/usr/src/lib/libc/i386/sys/forkx.s
new file mode 100644
index 0000000000..9a24c05d32
--- /dev/null
+++ b/usr/src/lib/libc/i386/sys/forkx.s
@@ -0,0 +1,59 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+ .file "%M%"
+
+#include "SYS.h"
+
+/*
+ * pid = __forkx(flags);
+ *
+ * syscall trap: forksys(0, flags)
+ *
+ * From the syscall:
+ * %edx == 0 in parent process, %edx = 1 in child process.
+ * %eax == pid of child in parent, %eax == pid of parent in child.
+ *
+ * The child gets a zero return value.
+ * The parent gets the pid of the child.
+ */
+
+ ENTRY(__forkx)
+ popl %ecx
+ pushl $0
+ pushl %ecx
+ SYSTRAP_2RVALS(forksys)
+ popl %ecx
+ movl %ecx, 0(%esp)
+ SYSCERROR
+ testl %edx, %edx
+ jz 1f /* jump if parent */
+ xorl %eax, %eax /* child, return (0) */
+1:
+ RET
+ SET_SIZE(__forkx)
diff --git a/usr/src/lib/libc/i386/sys/vfork.s b/usr/src/lib/libc/i386/sys/vfork.s
deleted file mode 100644
index cf8d013767..0000000000
--- a/usr/src/lib/libc/i386/sys/vfork.s
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
- .file "%M%"
-
-#include <sys/asm_linkage.h>
-
- ANSI_PRAGMA_WEAK(vfork,function)
-
-#include "SYS.h"
-#include <assym.h>
-
-/ The child of vfork() will execute in the parent's address space,
-/ thereby changing the stack before the parent runs again.
-/ Therefore we have to be careful how we return from vfork().
-/ Pity the poor debugger developer who has to deal with this kludge.
-/
-/ We block all blockable signals while performing the vfork() system call
-/ trap. This enables us to set curthread->ul_vfork safely, so that we
-/ don't end up in a signal handler with curthread->ul_vfork set wrong.
-
- ENTRY(vfork)
- movl 0(%esp),%ecx / save %eip in %ecx
- _prologue_
- leal _sref_(0f),%eax / arrange for RET to return here
- _epilogue_
- movl %eax,0(%esp)
- ret
-
-0:
- pushl $MASKSET1 / block signals
- pushl $MASKSET0
- pushl $SIG_SETMASK
- pushl %ecx
- __SYSCALLINT(lwp_sigmask)
- addl $16, %esp
-
- __SYSCALLINT(vfork)
- jae 2f
-
- / reconstruct stack before jumping to __cerror
- call 1f
-1: movl %ecx,0(%esp)
- pushl %eax / save the vfork() error number
-
- pushl %gs:UL_SIGMASK+4 / reinstate signals
- pushl %gs:UL_SIGMASK
- pushl $SIG_SETMASK
- pushl %ecx
- __SYSCALLINT(lwp_sigmask)
- addl $16, %esp
-
- popl %eax / restore the vfork() error number
- jmp __cerror
-
-2:
- / To determine if we are (still) a child of vfork(), the child
- / increments curthread->ul_vfork by one and the parent decrements
- / it by one. If the result is zero, then we are not a child of
- / vfork(), else we are. We do this to deal with the case of
- / a vfork() child calling vfork().
- /
- / %edx is zero if we are the parent, non-zero if we are the child.
- /
- cmpl $0,%edx
- jne 3f
- movl %gs:UL_VFORK, %edx
- cmpl $0, %edx / don't let it go negative
- je 4f
- subl $1, %edx / curthread->ul_vfork--;
- jmp 4f
-3:
- movl $0,%eax / zero the return value in the child
- movl %gs:UL_VFORK, %edx
- addl $1, %edx / curthread->ul_vfork++;
-4:
- movl %edx, %gs:UL_VFORK
- /
- / Clear the schedctl interface in both parent and child.
- / (The child might have modified the parent.)
- /
- xorl %edx, %edx
- movl %edx, %gs:UL_SCHEDCTL
- movl %edx, %gs:UL_SCHEDCTL_CALLED
- pushl %eax / save the vfork() return value
-
- pushl %gs:UL_SIGMASK+4 / reinstate signals
- pushl %gs:UL_SIGMASK
- pushl $SIG_SETMASK
- pushl %ecx
- __SYSCALLINT(lwp_sigmask)
- addl $16, %esp
-
- popl %eax / restore the vfork() return value
- jmp *%ecx / jump back to the caller
- SET_SIZE(vfork)
diff --git a/usr/src/lib/libc/i386/sys/vforkx.s b/usr/src/lib/libc/i386/sys/vforkx.s
new file mode 100644
index 0000000000..4659498dc5
--- /dev/null
+++ b/usr/src/lib/libc/i386/sys/vforkx.s
@@ -0,0 +1,141 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+ .file "%M%"
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(vforkx,function)
+ ANSI_PRAGMA_WEAK(vfork,function)
+
+#include "SYS.h"
+#include <assym.h>
+
+/*
+ * pid = vforkx(flags);
+ * syscall trap: forksys(2, flags)
+ *
+ * pid = vfork();
+ * syscall trap: forksys(2, 0)
+ *
+ * From the syscall:
+ * %edx == 0 in parent process, %edx = 1 in child process.
+ * %eax == pid of child in parent, %eax == pid of parent in child.
+ *
+ * The child gets a zero return value.
+ * The parent gets the pid of the child.
+ */
+
+/*
+ * The child of vfork() will execute in the parent's address space,
+ * thereby changing the stack before the parent runs again.
+ * Therefore we have to be careful how we return from vfork().
+ * Pity the poor debugger developer who has to deal with this kludge.
+ *
+ * We block all blockable signals while performing the vfork() system call
+ * trap. This enables us to set curthread->ul_vfork safely, so that we
+ * don't end up in a signal handler with curthread->ul_vfork set wrong.
+ */
+
+ ENTRY_NP(vforkx)
+ movl 4(%esp), %eax /* flags */
+ jmp 0f
+ ENTRY_NP(vfork)
+ xorl %eax, %eax /* flags = 0 */
+0:
+ popl %ecx /* save return %eip in %ecx */
+ pushl %eax /* flags */
+ pushl $MASKSET1 /* block all signals */
+ pushl $MASKSET0
+ pushl $SIG_SETMASK
+ pushl %ecx
+ __SYSCALLINT(lwp_sigmask)
+ addl $16, %esp
+
+ pushl $2
+ pushl %ecx
+ __SYSCALLINT(forksys) /* vforkx(flags) */
+ jae 1f
+
+ /* reconstruct stack before jumping to __cerror */
+ addl $12, %esp
+ pushl %ecx
+ pushl %eax /* save the vfork() error number */
+
+ pushl %gs:UL_SIGMASK+4 /* reinstate signals */
+ pushl %gs:UL_SIGMASK
+ pushl $SIG_SETMASK
+ pushl %ecx
+ __SYSCALLINT(lwp_sigmask)
+ addl $16, %esp
+
+ popl %eax /* restore the vfork() error number */
+ jmp __cerror
+
+1:
+ addl $12, %esp
+ /*
+ * To determine if we are (still) a child of vfork(), the child
+ * increments curthread->ul_vfork by one and the parent decrements
+ * it by one. If the result is zero, then we are not a child of
+ * vfork(), else we are. We do this to deal with the case of
+ * a vfork() child calling vfork().
+ */
+ cmpl $0, %edx
+ jne 2f
+ movl %gs:UL_VFORK, %edx
+ cmpl $0, %edx /* don't let it go negative */
+ je 3f
+ subl $1, %edx /* curthread->ul_vfork--; */
+ jmp 3f
+2:
+ xorl %eax, %eax /* zero the return value in the child */
+ movl %gs:UL_VFORK, %edx
+ addl $1, %edx /* curthread->ul_vfork++; */
+3:
+ movl %edx, %gs:UL_VFORK
+ /*
+ * Clear the schedctl interface in both parent and child.
+ * (The child might have modified the parent.)
+ */
+ xorl %edx, %edx
+ movl %edx, %gs:UL_SCHEDCTL
+ movl %edx, %gs:UL_SCHEDCTL_CALLED
+ pushl %eax /* save the vfork() return value */
+
+ pushl %gs:UL_SIGMASK+4 /* reinstate signals */
+ pushl %gs:UL_SIGMASK
+ pushl $SIG_SETMASK
+ pushl %ecx
+ __SYSCALLINT(lwp_sigmask)
+ addl $16, %esp
+
+ popl %eax /* restore the vfork() return value */
+ jmp *%ecx /* jump back to the caller */
+ SET_SIZE(vfork)
+ SET_SIZE(vforkx)
diff --git a/usr/src/lib/libc/inc/mtlib.h b/usr/src/lib/libc/inc/mtlib.h
index d864e8e75a..629b61ee9b 100644
--- a/usr/src/lib/libc/inc/mtlib.h
+++ b/usr/src/lib/libc/inc/mtlib.h
@@ -97,6 +97,7 @@ extern int _rw_unlock(rwlock_t *);
extern int _thr_main(void);
extern thread_t _thr_self(void);
+extern int _thrp_cancelled(void);
extern void _thr_exit(void *);
extern size_t _thr_min_stack(void);
extern int _thr_kill(thread_t, int);
diff --git a/usr/src/lib/libc/inc/synonyms.h b/usr/src/lib/libc/inc/synonyms.h
index 30f17eb6cb..faa9d33034 100644
--- a/usr/src/lib/libc/inc/synonyms.h
+++ b/usr/src/lib/libc/inc/synonyms.h
@@ -27,7 +27,6 @@
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
-
#ifndef _LIBC_SYNONYMS_H
#define _LIBC_SYNONYMS_H
@@ -351,7 +350,9 @@ extern "C" {
#define fnmatch _fnmatch
#define fork1 _fork1
#define forkall _forkall
+#define forkallx _forkallx
#define fork _fork
+#define forkx _forkx
#define fpathconf _fpathconf
#define fpclass _fpclass
#define fpgetmask _fpgetmask
@@ -1121,6 +1122,7 @@ extern "C" {
#define uucopy _uucopy
#define uucopystr _uucopystr
#define vfork _vfork
+#define vforkx _vforkx
#define vfscanf _vfscanf
#define vhangup _vhangup
#define vlfmt _vlfmt
diff --git a/usr/src/lib/libc/inc/thr_uberdata.h b/usr/src/lib/libc/inc/thr_uberdata.h
index 2671ac0a69..b5ecc7a1be 100644
--- a/usr/src/lib/libc/inc/thr_uberdata.h
+++ b/usr/src/lib/libc/inc/thr_uberdata.h
@@ -1188,11 +1188,8 @@ extern void _thrp_unwind(void *);
/*
* Prototypes for the strong versions of the interface functions
*/
-extern pid_t _fork(void);
-extern pid_t _fork1(void);
-extern pid_t __fork1(void);
-extern pid_t _forkall(void);
-extern pid_t __forkall(void);
+extern pid_t __forkx(int);
+extern pid_t __forkallx(int);
extern pid_t _private_getpid(void);
extern uid_t _private_geteuid(void);
extern int _kill(pid_t, int);
diff --git a/usr/src/lib/libc/port/gen/getutx.c b/usr/src/lib/libc/port/gen/getutx.c
index c091a27013..255282d406 100644
--- a/usr/src/lib/libc/port/gen/getutx.c
+++ b/usr/src/lib/libc/port/gen/getutx.c
@@ -506,6 +506,7 @@ invoke_utmp_update(const struct utmpx *entryx)
{
extern char **environ;
+ posix_spawnattr_t attr;
int status;
pid_t child;
pid_t w;
@@ -517,7 +518,6 @@ invoke_utmp_update(const struct utmpx *entryx)
char host[sizeof (entryx->ut_host) + 1];
struct utmpx *curx = NULL;
char bin2hex[] = "0123456789ABCDEF";
- sigset_t mask, omask;
unsigned char *cp;
char *argvec[15];
int error;
@@ -566,14 +566,22 @@ invoke_utmp_update(const struct utmpx *entryx)
argvec[14] = NULL;
/*
- * Block SIGCLD while we do this.
- * This avoids having an unexpected SIGCLD sent to the process.
+ * No SIGCHLD, please, and let no one else reap our child.
*/
- (void) sigemptyset(&mask);
- (void) sigaddset(&mask, SIGCLD);
- (void) sigprocmask(SIG_BLOCK, &mask, &omask);
-
- error = posix_spawn(&child, UTMP_UPDATE, NULL, NULL, argvec, environ);
+ error = posix_spawnattr_init(&attr);
+ if (error) {
+ errno = error;
+ goto out;
+ }
+ error = posix_spawnattr_setflags(&attr,
+ POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP);
+ if (error) {
+ (void) posix_spawnattr_destroy(&attr);
+ errno = error;
+ goto out;
+ }
+ error = posix_spawn(&child, UTMP_UPDATE, NULL, &attr, argvec, environ);
+ (void) posix_spawnattr_destroy(&attr);
if (error) {
errno = error;
goto out;
@@ -610,7 +618,6 @@ invoke_utmp_update(const struct utmpx *entryx)
}
out:
- (void) sigprocmask(SIG_SETMASK, &omask, NULL);
return (curx);
}
diff --git a/usr/src/lib/libc/port/gen/syslog.c b/usr/src/lib/libc/port/gen/syslog.c
index 38d28d772e..487da876e0 100644
--- a/usr/src/lib/libc/port/gen/syslog.c
+++ b/usr/src/lib/libc/port/gen/syslog.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -83,6 +83,7 @@
#include <sys/door.h>
#include <sys/stat.h>
#include <stropts.h>
+#include <sys/fork.h>
#include <sys/wait.h>
#include "libc.h"
@@ -183,8 +184,6 @@ vsyslog(int pri, const char *fmt, va_list ap)
struct log_ctl hdr;
struct strbuf dat;
struct strbuf ctl;
- sigset_t sigs;
- sigset_t osigs;
char timestr[26]; /* hardwired value 26 due to Posix */
size_t taglen;
int olderrno = errno;
@@ -195,6 +194,7 @@ vsyslog(int pri, const char *fmt, va_list ap)
int showpid;
uint32_t msgid;
char *msgid_start, *msgid_end;
+ int nowait;
/*
* Maximum tag length is 256 (the pad in outline) minus the size of the
@@ -358,21 +358,19 @@ vsyslog(int pri, const char *fmt, va_list ap)
clen = strlen(outline) + 1;
- (void) sigemptyset(&sigs);
- (void) sigaddset(&sigs, SIGCHLD);
- (void) sigprocmask(SIG_BLOCK, &sigs, &osigs);
- pid = fork1();
- if (pid == -1) {
- (void) sigprocmask(SIG_SETMASK, &osigs, NULL);
+ nowait = (LogStat & LOG_NOWAIT);
+ pid = forkx(nowait? 0 : (FORK_NOSIGCHLD | FORK_WAITPID));
+ if (pid == -1)
return;
- }
+
if (pid == 0) {
+ sigset_t sigs;
int fd;
- (void) signal(SIGALRM, SIG_DFL);
- (void) sigprocmask(SIG_BLOCK, NULL, &sigs);
- (void) sigdelset(&sigs, SIGALRM);
- (void) sigprocmask(SIG_SETMASK, &sigs, NULL);
+ (void) sigset(SIGALRM, SIG_DFL);
+ (void) sigemptyset(&sigs);
+ (void) sigaddset(&sigs, SIGALRM);
+ (void) sigprocmask(SIG_UNBLOCK, &sigs, NULL);
(void) alarm(5);
if (((fd = open(sysmsg, O_WRONLY)) >= 0) ||
(fd = open(ctty, O_WRONLY)) >= 0) {
@@ -383,9 +381,9 @@ vsyslog(int pri, const char *fmt, va_list ap)
}
_exit(0);
}
- if (!(LogStat & LOG_NOWAIT))
- (void) waitpid(pid, NULL, 0);
- (void) sigprocmask(SIG_SETMASK, &osigs, NULL);
+ if (!nowait)
+ while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
+ continue;
}
/*
diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers
index bafd47ab0e..22227a6413 100644
--- a/usr/src/lib/libc/port/mapfile-vers
+++ b/usr/src/lib/libc/port/mapfile-vers
@@ -57,6 +57,8 @@ SUNW_1.23 { # SunOS 5.11 (Solaris 11)
door_ucred;
door_unbind;
fdatasync;
+ forkallx;
+ forkx;
lio_listio;
mkdtemp;
_mkdtemp;
@@ -109,6 +111,7 @@ SUNW_1.23 { # SunOS 5.11 (Solaris 11)
timer_settime;
uucopy;
uucopystr;
+ vforkx;
} SUNW_1.22.2;
SUNW_1.22.2 {
@@ -1510,6 +1513,8 @@ SUNWprivate_1.1 {
__fnmatch_std;
_fork1;
_forkall;
+ _forkallx;
+ _forkx;
_fpclass;
_fpgetmask;
_fpgetround;
@@ -2162,6 +2167,7 @@ SUNWprivate_1.1 {
utssys;
_utssys;
_vfork;
+ _vforkx;
_vhangup;
_vsyslog;
_wait3;
diff --git a/usr/src/lib/libc/port/regex/wordexp.c b/usr/src/lib/libc/port/regex/wordexp.c
index fb65534656..117976e9c5 100644
--- a/usr/src/lib/libc/port/regex/wordexp.c
+++ b/usr/src/lib/libc/port/regex/wordexp.c
@@ -18,6 +18,7 @@
*
* CDDL HEADER END
*/
+
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
@@ -58,6 +59,7 @@
#include <unistd.h>
#include <wordexp.h>
#include <stdio.h>
+#include <spawn.h>
#include <errno.h>
#define INITIAL 8 /* initial pathv allocation */
@@ -68,6 +70,12 @@ static int append(wordexp_t *, char *);
extern int __xpg4; /* defined in _xpg4.c; 0 if not xpg4-compiled program */
/*
+ * Needs no locking if fetched only once.
+ * See getenv()/putenv()/setenv().
+ */
+extern const char **environ;
+
+/*
* Do word expansion.
* We just pass our arguments to shell with -E option. Note that the
* underlying shell must recognize the -E option, and do the right thing
@@ -76,8 +84,9 @@ extern int __xpg4; /* defined in _xpg4.c; 0 if not xpg4-compiled program */
int
wordexp(const char *word, wordexp_t *wp, int flags)
{
- static char options[9] = "-";
- static char *args[4];
+ char options[9];
+ char *optendp = options;
+ char *argv[4];
const char *path;
wordexp_t wptmp;
size_t si;
@@ -88,9 +97,15 @@ wordexp(const char *word, wordexp_t *wp, int flags)
int status;
int pv[2]; /* pipe from shell stdout */
FILE *fp; /* pipe read stream */
- char *optendp = options+1;
- int serrno, tmpalloc;
+ int tmpalloc;
char *wd = NULL;
+ const char **env = NULL;
+ const char **envp;
+ const char *ev;
+ int n;
+ posix_spawnattr_t attr;
+ posix_spawn_file_actions_t fact;
+ int error;
static const char *sun_path = "/bin/ksh";
static const char *xpg4_path = "/usr/xpg4/bin/sh";
@@ -114,7 +129,7 @@ wordexp(const char *word, wordexp_t *wp, int flags)
/*
* Man page says:
- * 2. All of the calls must set WRDE_DOOFFS, or all must not
+ * 2. All of the calls must set WRDE_DOOFFS, or all must not
* set it.
* Therefore, if it's not set, we_offs will always be reset.
*/
@@ -129,8 +144,7 @@ wordexp(const char *word, wordexp_t *wp, int flags)
if ((flags & WRDE_APPEND) == 0 || (flags & WRDE_REUSE)) {
wptmp.we_wordc = 0;
wptmp.we_wordn = wptmp.we_offs + INITIAL;
- wptmp.we_wordv = (char **)malloc(
- sizeof (char *) * wptmp.we_wordn);
+ wptmp.we_wordv = malloc(sizeof (char *) * wptmp.we_wordn);
if (wptmp.we_wordv == NULL)
return (WRDE_NOSPACE);
wptmp.we_wordp = wptmp.we_wordv + wptmp.we_offs;
@@ -142,6 +156,7 @@ wordexp(const char *word, wordexp_t *wp, int flags)
/*
* Turn flags into shell options
*/
+ *optendp++ = '-';
*optendp++ = (char)0x05; /* ksh -^E */
if (flags & WRDE_UNDEF)
*optendp++ = 'u';
@@ -149,69 +164,89 @@ wordexp(const char *word, wordexp_t *wp, int flags)
*optendp++ = 'N';
*optendp = '\0';
- if (getenv("PWD") == NULL) {
- if ((wd = malloc(PATH_MAX + 4)) == NULL)
+ /*
+ * Make sure PWD is in the environment.
+ */
+ if ((envp = environ) == NULL) { /* can't happen? */
+ ev = NULL;
+ n = 0;
+ } else {
+ for (n = 0; (ev = envp[n]) != NULL; n++) {
+ if (*ev == 'P' && strncmp(ev, "PWD=", 4) == 0)
+ break;
+ }
+ }
+ if (ev == NULL) { /* PWD missing from the environment */
+ /* allocate a new environment */
+ if ((env = malloc((n + 2) * sizeof (char *))) == NULL ||
+ (wd = malloc(PATH_MAX + 4)) == NULL)
goto cleanup;
+ for (i = 0; i < n; i++)
+ env[i] = envp[i];
(void) strcpy(wd, "PWD=");
if (getcwd(&wd[4], PATH_MAX) == NULL)
(void) strcpy(&wd[4], "/");
+ env[i] = wd;
+ env[i + 1] = NULL;
+ envp = env;
+ }
+
+ if ((error = posix_spawnattr_init(&attr)) != 0) {
+ errno = error;
+ goto cleanup;
+ }
+ if ((error = posix_spawn_file_actions_init(&fact)) != 0) {
+ (void) posix_spawnattr_destroy(&attr);
+ errno = error;
+ goto cleanup;
}
/*
* Set up pipe from shell stdout to "fp" for us
*/
- if (pipe(pv) < 0)
+ if (pipe(pv) < 0) {
+ error = errno;
+ (void) posix_spawnattr_destroy(&attr);
+ (void) posix_spawn_file_actions_destroy(&fact);
+ errno = error;
goto cleanup;
+ }
/*
- * Fork/exec shell with -E word
+ * Spawn shell with -E word
*/
-
- if ((pid = fork1()) == -1) {
- serrno = errno;
+ error = posix_spawnattr_setflags(&attr,
+ POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP);
+ if (error == 0)
+ error = posix_spawn_file_actions_adddup2(&fact, pv[1], 1);
+ if (error == 0 && pv[0] != 1)
+ error = posix_spawn_file_actions_addclose(&fact, pv[0]);
+ if (error == 0 && pv[1] != 1)
+ error = posix_spawn_file_actions_addclose(&fact, pv[1]);
+ if (error == 0 && !(flags & WRDE_SHOWERR))
+ error = posix_spawn_file_actions_addopen(&fact, 2,
+ "/dev/null", O_WRONLY, 0);
+ path = __xpg4 ? xpg4_path : sun_path;
+ argv[0] = strrchr(path, '/') + 1;
+ argv[1] = options;
+ argv[2] = (char *)word;
+ argv[3] = NULL;
+ if (error == 0)
+ error = posix_spawn(&pid, path, &fact, &attr,
+ (char *const *)argv, (char *const *)envp);
+ (void) posix_spawnattr_destroy(&attr);
+ (void) posix_spawn_file_actions_destroy(&fact);
+ (void) close(pv[1]);
+ if (error) {
(void) close(pv[0]);
- (void) close(pv[1]);
- errno = serrno;
+ errno = error;
goto cleanup;
}
- if (pid == 0) { /* child */
- if (wd != NULL) {
- /*
- * fork1 handler takes care of __environ_lock.
- * Thus we can safely call putenv().
- */
- (void) putenv(wd);
- }
-
- (void) dup2(pv[1], 1);
- (void) close(pv[0]);
- (void) close(pv[1]);
-
- if ((flags & WRDE_SHOWERR) == 0) {
- int devnull;
- devnull = open("/dev/null", O_WRONLY);
- (void) dup2(devnull, 2);
- if (devnull != 2)
- (void) close(devnull);
- }
-
- path = __xpg4 ? xpg4_path : sun_path;
- args[0] = strrchr(path, '/') + 1;
- args[1] = options;
- args[2] = (char *)word;
- args[3] = NULL;
-
- (void) execv(path, args);
- _exit(127);
- }
-
- (void) close(pv[1]);
-
if ((fp = fdopen(pv[0], "rF")) == NULL) {
- serrno = errno;
+ error = errno;
(void) close(pv[0]);
- errno = serrno;
+ errno = error;
goto wait_cleanup;
}
@@ -222,8 +257,9 @@ wordexp(const char *word, wordexp_t *wp, int flags)
*/
cp = line = malloc(BUFSZ);
if (line == NULL) {
+ error = errno;
(void) fclose(fp);
- rv = WRDE_NOSPACE;
+ errno = error;
goto wait_cleanup;
}
eob = line + BUFSZ;
@@ -257,19 +293,24 @@ wordexp(const char *word, wordexp_t *wp, int flags)
(void) fclose(fp); /* kill shell if still writing */
wait_cleanup:
- if (waitpid(pid, &status, 0) == -1)
- rv = WRDE_ERRNO;
- else if (rv == 0)
+ while (waitpid(pid, &status, 0) == -1) {
+ if (errno != EINTR) {
+ if (rv == 0)
+ rv = WRDE_ERRNO;
+ break;
+ }
+ }
+ if (rv == 0)
rv = WEXITSTATUS(status); /* shell WRDE_* status */
cleanup:
if (rv == 0)
*wp = wptmp;
- else {
- if (tmpalloc)
- wordfree(&wptmp);
- }
+ else if (tmpalloc)
+ wordfree(&wptmp);
+ if (env)
+ free(env);
if (wd)
free(wd);
/*
diff --git a/usr/src/lib/libc/port/stdio/popen.c b/usr/src/lib/libc/port/stdio/popen.c
index 6168a8c13b..11071de5bc 100644
--- a/usr/src/lib/libc/port/stdio/popen.c
+++ b/usr/src/lib/libc/port/stdio/popen.c
@@ -29,7 +29,6 @@
#pragma ident "%Z%%M% %I% %E% SMI"
-
#pragma weak pclose = _pclose
#pragma weak popen = _popen
@@ -45,6 +44,7 @@
#include <unistd.h>
#include <errno.h>
#include <thread.h>
+#include <pthread.h>
#include <synch.h>
#include <spawn.h>
#include "stdiom.h"
@@ -55,8 +55,6 @@
#define RDR 0
#define WTR 1
-static int _insert_nolock(pid_t, int);
-
extern int __xpg4; /* defined in _xpg4.c; 0 if not xpg4-compiled program */
extern const char **environ;
@@ -69,19 +67,38 @@ typedef struct node {
} node_t;
static node_t *head = NULL;
+static void _insert_nolock(pid_t, int, node_t *);
+/*
+ * Cancellation cleanup handler.
+ * If we were cancelled in waitpid(), create a daemon thread to
+ * reap our abandoned child. No other thread can do this for us.
+ */
+static void
+cleanup(void *arg)
+{
+ extern const sigset_t maskset;
+ extern void *reapchild(void *); /* see port/stdio/system.c */
+
+ (void) thr_sigsetmask(SIG_SETMASK, &maskset, NULL);
+ (void) thr_create(NULL, 0, reapchild, arg, THR_DAEMON, NULL);
+}
FILE *
popen(const char *cmd, const char *mode)
{
int p[2];
pid_t pid;
- int myside, yourside;
+ int myside;
+ int yourside;
+ int fd;
const char *shpath;
FILE *iop;
int stdio;
node_t *curr;
char *argvec[4];
+ node_t *node;
+ posix_spawnattr_t attr;
posix_spawn_file_actions_t fact;
int error;
static const char *sun_path = "/bin/sh";
@@ -89,8 +106,27 @@ popen(const char *cmd, const char *mode)
static const char *shell = "sh";
static const char *sh_flg = "-c";
- if (pipe(p) < 0)
+ if ((node = lmalloc(sizeof (node_t))) == NULL)
+ return (NULL);
+ if ((error = posix_spawnattr_init(&attr)) != 0) {
+ lfree(node, sizeof (node_t));
+ errno = error;
return (NULL);
+ }
+ if ((error = posix_spawn_file_actions_init(&fact)) != 0) {
+ lfree(node, sizeof (node_t));
+ (void) posix_spawnattr_destroy(&attr);
+ errno = error;
+ return (NULL);
+ }
+ if (pipe(p) < 0) {
+ error = errno;
+ lfree(node, sizeof (node_t));
+ (void) posix_spawnattr_destroy(&attr);
+ (void) posix_spawn_file_actions_destroy(&fact);
+ errno = error;
+ return (NULL);
+ }
shpath = __xpg4? xpg4_path : sun_path;
if (access(shpath, X_OK)) /* XPG4 Requirement: */
@@ -103,23 +139,30 @@ popen(const char *cmd, const char *mode)
/* This will fail more quickly if we run out of fds */
if ((iop = fdopen(myside, mode)) == NULL) {
+ error = errno;
+ lfree(node, sizeof (node_t));
+ (void) posix_spawnattr_destroy(&attr);
+ (void) posix_spawn_file_actions_destroy(&fact);
(void) close(yourside);
(void) close(myside);
+ errno = error;
return (NULL);
}
lmutex_lock(&popen_lock);
/* in the child, close all pipes from other popen's */
- if ((error = posix_spawn_file_actions_init(&fact)) != 0) {
- lmutex_unlock(&popen_lock);
- (void) fclose(iop);
- (void) close(yourside);
- errno = error;
- return (NULL);
+ for (curr = head; curr != NULL && error == 0; curr = curr->next) {
+ /*
+ * These conditions may apply if a previous iob returned
+ * by popen() was closed with fclose() rather than pclose(),
+ * or if close(fileno(iob)) was called.
+ * Accommodate these programming error.
+ */
+ if ((fd = curr->fd) != myside && fd != yourside &&
+ fcntl(fd, F_GETFD) >= 0)
+ error = posix_spawn_file_actions_addclose(&fact, fd);
}
- for (curr = head; curr != NULL && error == 0; curr = curr->next)
- error = posix_spawn_file_actions_addclose(&fact, curr->fd);
if (error == 0)
error = posix_spawn_file_actions_addclose(&fact, myside);
if (yourside != stdio) {
@@ -130,8 +173,13 @@ popen(const char *cmd, const char *mode)
error = posix_spawn_file_actions_addclose(&fact,
yourside);
}
+ if (error == 0)
+ error = posix_spawnattr_setflags(&attr,
+ POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP);
if (error) {
lmutex_unlock(&popen_lock);
+ lfree(node, sizeof (node_t));
+ (void) posix_spawnattr_destroy(&attr);
(void) posix_spawn_file_actions_destroy(&fact);
(void) fclose(iop);
(void) close(yourside);
@@ -142,16 +190,19 @@ popen(const char *cmd, const char *mode)
argvec[1] = (char *)sh_flg;
argvec[2] = (char *)cmd;
argvec[3] = NULL;
- error = posix_spawn(&pid, shpath, &fact, NULL,
+ error = posix_spawn(&pid, shpath, &fact, &attr,
(char *const *)argvec, (char *const *)environ);
+ (void) posix_spawnattr_destroy(&attr);
(void) posix_spawn_file_actions_destroy(&fact);
-
(void) close(yourside);
- if ((errno = error) != 0 || _insert_nolock(pid, myside) == -1) {
+ if (error) {
lmutex_unlock(&popen_lock);
+ lfree(node, sizeof (node_t));
(void) fclose(iop);
+ errno = error;
return (NULL);
}
+ _insert_nolock(pid, myside, node);
lmutex_unlock(&popen_lock);
@@ -171,33 +222,63 @@ pclose(FILE *ptr)
/* mark this pipe closed */
(void) fclose(ptr);
- if (pid == -1)
+ if (pid <= 0) {
+ errno = ECHILD;
return (-1);
+ }
+
+ /*
+ * pclose() is a cancellation point.
+ * Call waitpid_cancel() rather than _waitpid() to make
+ * sure that we actually perform the cancellation logic.
+ *
+ * If we have already been cancelled (pclose() was called from
+ * a cancellation cleanup handler), attempt to reap the process
+ * w/o waiting, and if that fails just call cleanup(pid).
+ */
+
+ if (_thrp_cancelled()) {
+ if (waitpid(pid, &status, WNOHANG) == pid)
+ return (status);
+ cleanup((void *)(uintptr_t)pid);
+ errno = ECHILD;
+ return (-1);
+ }
- while (waitpid(pid, &status, 0) < 0) {
- /* If waitpid fails with EINTR, restart the waitpid call */
+ pthread_cleanup_push(cleanup, (void *)(uintptr_t)pid);
+ while (waitpid_cancel(pid, &status, 0) < 0) {
if (errno != EINTR) {
status = -1;
break;
}
}
+ pthread_cleanup_pop(0);
return (status);
}
-static int
-_insert_nolock(pid_t pid, int fd)
+static void
+_insert_nolock(pid_t pid, int fd, node_t *new)
{
node_t *prev;
node_t *curr;
- node_t *new;
- for (prev = curr = head; curr != NULL; curr = curr->next)
+ for (prev = curr = head; curr != NULL; curr = curr->next) {
+ /*
+ * curr->fd can equal fd if a previous iob returned by
+ * popen() was closed with fclose() rather than pclose(),
+ * or if close(fileno(iob)) was called.
+ * Accommodate this programming error.
+ */
+ if (curr->fd == fd) {
+ (void) waitpid(curr->pid, NULL, WNOHANG);
+ curr->pid = pid;
+ lfree(new, sizeof (node_t));
+ return;
+ }
prev = curr;
-
- if ((new = lmalloc(sizeof (node_t))) == NULL)
- return (-1);
+ }
new->pid = pid;
new->fd = fd;
@@ -207,8 +288,6 @@ _insert_nolock(pid_t pid, int fd)
head = new;
else
prev->next = new;
-
- return (0);
}
/*
@@ -217,13 +296,16 @@ _insert_nolock(pid_t pid, int fd)
int
_insert(pid_t pid, int fd)
{
- int rc;
+ node_t *node;
+
+ if ((node = lmalloc(sizeof (node_t))) == NULL)
+ return (-1);
lmutex_lock(&popen_lock);
- rc = _insert_nolock(pid, fd);
+ _insert_nolock(pid, fd, node);
lmutex_unlock(&popen_lock);
- return (rc);
+ return (0);
}
@@ -242,10 +324,9 @@ _delete(int fd)
head = curr->next;
else
prev->next = curr->next;
-
+ lmutex_unlock(&popen_lock);
pid = curr->pid;
lfree(curr, sizeof (node_t));
- lmutex_unlock(&popen_lock);
return (pid);
}
prev = curr;
diff --git a/usr/src/lib/libc/port/stdio/system.c b/usr/src/lib/libc/port/stdio/system.c
index b641e6592e..707134751d 100644
--- a/usr/src/lib/libc/port/stdio/system.c
+++ b/usr/src/lib/libc/port/stdio/system.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -30,7 +29,6 @@
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
-
#include "synonyms.h"
#include "mtlib.h"
#include <sys/types.h>
@@ -41,6 +39,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include <memory.h>
+#include <thread.h>
#include <pthread.h>
#include <errno.h>
#include <synch.h>
@@ -50,50 +49,82 @@
extern const char **environ;
extern int __xpg4; /* defined in _xpg4.c; 0 if not xpg4-compiled program */
+extern const sigset_t maskset; /* all maskable signals */
static mutex_t sys_lock = DEFAULTMUTEX; /* protects the following */
static uint_t sys_count = 0; /* number of threads in system() */
-static struct sigaction sys_ibuf; /* SIGINT */
-static struct sigaction sys_qbuf; /* SIGQUIT */
-static struct sigaction sys_cbuf; /* SIGCHLD */
+static struct sigaction sys_ibuf; /* saved SIGINT sigaction */
+static struct sigaction sys_qbuf; /* saved SIGQUIT sigaction */
+static struct sigaction ignore = {0, {SIG_IGN}, {0}};
+
+/*
+ * Things needed by the cancellation cleanup handler.
+ */
+typedef struct {
+ sigset_t savemask; /* saved signal mask */
+ pid_t pid; /* if nonzero, the child's pid */
+} cleanup_t;
+
+/*
+ * Daemon thread whose sole function is to reap an abandoned child.
+ * Also invoked from pclose() (see port/stdio/popen.c).
+ */
+void *
+reapchild(void *arg)
+{
+ pid_t pid = (pid_t)(uintptr_t)arg;
+
+ while (waitpid(pid, NULL, 0) == -1) {
+ if (errno != EINTR)
+ break;
+ }
+ return (NULL);
+}
/*
* Cancellation cleanup handler.
+ * If we were cancelled in waitpid(), create a daemon thread to
+ * reap our abandoned child. No other thread can do this for us.
+ * It would be better if there were a system call to disinherit
+ * a child process (give it to init, just as though we exited).
*/
static void
cleanup(void *arg)
{
- sigset_t *savemaskp = arg;
+ cleanup_t *cup = arg;
+
+ if (cup->pid != 0) { /* we were cancelled; abandoning our pid */
+ (void) thr_sigsetmask(SIG_SETMASK, &maskset, NULL);
+ (void) thr_create(NULL, 0,
+ reapchild, (void *)(uintptr_t)cup->pid,
+ THR_DAEMON, NULL);
+ }
lmutex_lock(&sys_lock);
if (--sys_count == 0) { /* leaving system() */
/*
- * There are no remaining threads in system(),
- * so restore the several signal actions.
+ * There are no remaining threads in system(), so
+ * restore the SIGINT and SIGQUIT signal actions.
*/
(void) sigaction(SIGINT, &sys_ibuf, NULL);
(void) sigaction(SIGQUIT, &sys_qbuf, NULL);
- if (sys_cbuf.sa_handler == SIG_IGN ||
- (sys_cbuf.sa_flags & SA_NOCLDWAIT))
- (void) sigaction(SIGCHLD, &sys_cbuf, NULL);
}
lmutex_unlock(&sys_lock);
- (void) sigprocmask(SIG_SETMASK, savemaskp, NULL);
+
+ (void) thr_sigsetmask(SIG_SETMASK, &cup->savemask, NULL);
}
int
system(const char *cmd)
{
- pid_t pid;
+ cleanup_t cu;
pid_t w;
int status;
int error;
- struct sigaction action;
sigset_t mask;
- sigset_t savemask;
struct stat64 buf;
const char *shpath;
- char *argvec[4];
+ char *argv[4];
posix_spawnattr_t attr;
static const char *sun_path = "/bin/sh";
static const char *xpg4_path = "/usr/xpg4/bin/sh";
@@ -120,28 +151,40 @@ system(const char *cmd)
/*
* Initialize the posix_spawn() attributes structure.
+ * The setting of POSIX_SPAWN_WAITPID_NP ensures that no
+ * wait-for-multiple wait() operation will reap our child
+ * and that the child will not be automatically reaped due
+ * to the disposition of SIGCHLD being set to be ignored.
+ * Only a specific wait for the specific pid will be able
+ * to reap the child. Since no other thread knows the pid
+ * of our child, this should be safe enough.
*/
- if ((error = posix_spawnattr_init(&attr)) != 0) {
- errno = error;
- return (-1);
- }
- error = posix_spawnattr_setflags(&attr,
- POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF);
+ error = posix_spawnattr_init(&attr);
+ if (error == 0)
+ error = posix_spawnattr_setflags(&attr,
+ POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF |
+ POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP);
/*
- * We are required to block SIGCHLD so that we don't cause
- * the process's signal handler, if any, to be called.
- * This doesn't really work for a multithreaded process
- * because some other thread may receive the SIGCHLD.
+ * The POSIX spec for system() requires us to block SIGCHLD,
+ * the rationale being that the process's signal handler for
+ * SIGCHLD, if any, should not be called when our child exits.
+ * This doesn't work for a multithreaded process because some
+ * other thread could receive the SIGCHLD.
+ *
+ * The above setting of POSIX_SPAWN_NOSIGCHLD_NP ensures that no
+ * SIGCHLD signal will be posted for our child when it exits, so
+ * we don't have to block SIGCHLD to meet the intent of the spec.
+ * We block SIGCHLD anyway, just because the spec requires it.
*/
(void) sigemptyset(&mask);
(void) sigaddset(&mask, SIGCHLD);
- (void) sigprocmask(SIG_BLOCK, &mask, &savemask);
+ (void) thr_sigsetmask(SIG_BLOCK, &mask, &cu.savemask);
/*
* Tell posix_spawn() to restore the signal mask in the child.
*/
if (error == 0)
- error = posix_spawnattr_setsigmask(&attr, &savemask);
+ error = posix_spawnattr_setsigmask(&attr, &cu.savemask);
/*
* We are required to set the disposition of SIGINT and SIGQUIT
@@ -158,33 +201,8 @@ system(const char *cmd)
*/
lmutex_lock(&sys_lock);
if (sys_count++ == 0) {
- (void) memset(&action, 0, sizeof (action));
- action.sa_handler = SIG_IGN;
- (void) sigaction(SIGINT, &action, &sys_ibuf);
- (void) sigaction(SIGQUIT, &action, &sys_qbuf);
- /*
- * If the action for SIGCHLD is SIG_IGN, then set it to SIG_DFL
- * so we can retrieve the status of the spawned-off shell.
- * The execve() performed in posix_spawn() will set the action
- * for SIGCHLD in the child process to SIG_DFL regardless,
- * so this has no negative consequencies for the child.
- *
- * Note that this is not required by the SUSv3 standard.
- * The standard permits this error:
- * ECHILD The status of the child process created
- * by system() is no longer available.
- * So we could leave the action for SIGCHLD alone and
- * still be standards-conforming, but this is the way
- * the SunOS system() has always behaved (in fact it
- * used to set the action to SIG_DFL unconditinally),
- * so we retain this behavior here.
- */
- (void) sigaction(SIGCHLD, NULL, &sys_cbuf);
- if (sys_cbuf.sa_handler == SIG_IGN ||
- (sys_cbuf.sa_flags & SA_NOCLDWAIT)) {
- action.sa_handler = SIG_DFL;
- (void) sigaction(SIGCHLD, &action, NULL);
- }
+ (void) sigaction(SIGINT, &ignore, &sys_ibuf);
+ (void) sigaction(SIGQUIT, &ignore, &sys_qbuf);
}
lmutex_unlock(&sys_lock);
@@ -201,13 +219,13 @@ system(const char *cmd)
if (error == 0)
error = posix_spawnattr_setsigdefault(&attr, &mask);
- argvec[0] = (char *)shell;
- argvec[1] = "-c";
- argvec[2] = (char *)cmd;
- argvec[3] = NULL;
+ argv[0] = (char *)shell;
+ argv[1] = "-c";
+ argv[2] = (char *)cmd;
+ argv[3] = NULL;
if (error == 0)
- error = posix_spawn(&pid, shpath, NULL, &attr,
- (char *const *)argvec, (char *const *)environ);
+ error = posix_spawn(&cu.pid, shpath, NULL, &attr,
+ (char *const *)argv, (char *const *)environ);
(void) posix_spawnattr_destroy(&attr);
@@ -220,15 +238,18 @@ system(const char *cmd)
* Call waitpid_cancel() rather than _waitpid() to make
* sure that we actually perform the cancellation logic.
*/
- pthread_cleanup_push(cleanup, &savemask);
+ pthread_cleanup_push(cleanup, &cu);
do {
- w = waitpid_cancel(pid, &status, 0);
+ w = waitpid_cancel(cu.pid, &status, 0);
} while (w == -1 && errno == EINTR);
pthread_cleanup_pop(0);
if (w == -1)
status = -1;
}
- cleanup(&savemask);
+ error = errno;
+ cu.pid = 0;
+ cleanup(&cu);
+ errno = error;
return (status);
}
diff --git a/usr/src/lib/libc/port/threads/scalls.c b/usr/src/lib/libc/port/threads/scalls.c
index 67a2a6341f..e950bb38d1 100644
--- a/usr/src/lib/libc/port/threads/scalls.c
+++ b/usr/src/lib/libc/port/threads/scalls.c
@@ -113,16 +113,10 @@ fork_lock_exit(void)
sigon(self);
}
-/*
- * fork() is fork1() for both Posix threads and Solaris threads.
- * The forkall() interface exists for applications that require
- * the semantics of replicating all threads.
- */
-#pragma weak fork = _fork1
-#pragma weak _fork = _fork1
-#pragma weak fork1 = _fork1
-pid_t
-_fork1(void)
+#pragma weak forkx = _private_forkx
+#pragma weak _forkx = _private_forkx
+static pid_t
+_private_forkx(int flags)
{
ulwp_t *self = curthread;
uberdata_t *udp = self->ul_uberdata;
@@ -140,7 +134,7 @@ _fork1(void)
errno = ENOTSUP;
return (-1);
}
- pid = __fork1();
+ pid = __forkx(flags);
if (pid == 0) { /* child */
udp->pid = _private_getpid();
self->ul_vfork = 0;
@@ -177,7 +171,7 @@ _fork1(void)
* Block all signals.
* Just deferring them via sigon() is not enough.
* We have to avoid taking a deferred signal in the child
- * that was actually sent to the parent before __fork1().
+ * that was actually sent to the parent before __forkx().
*/
block_all_signals(self);
@@ -185,19 +179,19 @@ _fork1(void)
* This suspends all threads but this one, leaving them
* suspended outside of any critical regions in the library.
* Thus, we are assured that no library locks are held
- * while we invoke fork1() from the current thread.
+ * while we invoke fork() from the current thread.
*/
(void) _private_mutex_lock(&udp->fork_lock);
suspend_fork();
(void) _private_mutex_unlock(&udp->fork_lock);
- pid = __fork1();
+ pid = __forkx(flags);
if (pid == 0) { /* child */
/*
* Clear our schedctl pointer.
* Discard any deferred signal that was sent to the parent.
- * Because we blocked all signals before __fork1(), a
+ * Because we blocked all signals before __forkx(), a
* deferred signal cannot have been taken by the child.
*/
self->ul_schedctl_called = NULL;
@@ -210,7 +204,7 @@ _fork1(void)
restore_signals(self);
_postfork_child_handler();
} else {
- /* restart all threads that were suspended for fork1() */
+ /* restart all threads that were suspended for fork() */
continue_fork(0);
restore_signals(self);
_postfork_parent_handler();
@@ -223,12 +217,27 @@ _fork1(void)
}
/*
- * Much of the logic here is the same as in fork1().
- * See the comments in fork1(), above.
+ * fork() is fork1() for both Posix threads and Solaris threads.
+ * The forkall() interface exists for applications that require
+ * the semantics of replicating all threads.
*/
-#pragma weak forkall = _forkall
+#pragma weak fork1 = _fork
+#pragma weak _fork1 = _fork
+#pragma weak fork = _fork
pid_t
-_forkall(void)
+_fork(void)
+{
+ return (_private_forkx(0));
+}
+
+/*
+ * Much of the logic here is the same as in forkx().
+ * See the comments in forkx(), above.
+ */
+#pragma weak forkallx = _private_forkallx
+#pragma weak _forkallx = _private_forkallx
+static pid_t
+_private_forkallx(int flags)
{
ulwp_t *self = curthread;
uberdata_t *udp = self->ul_uberdata;
@@ -240,7 +249,7 @@ _forkall(void)
errno = ENOTSUP;
return (-1);
}
- pid = __forkall();
+ pid = __forkallx(flags);
if (pid == 0) { /* child */
udp->pid = _private_getpid();
self->ul_vfork = 0;
@@ -257,7 +266,7 @@ _forkall(void)
block_all_signals(self);
suspend_fork();
- pid = __forkall();
+ pid = __forkallx(flags);
if (pid == 0) {
self->ul_schedctl_called = NULL;
@@ -276,6 +285,13 @@ _forkall(void)
return (pid);
}
+#pragma weak forkall = _forkall
+pid_t
+_forkall(void)
+{
+ return (_private_forkallx(0));
+}
+
/*
* Hacks for system calls to provide cancellation
* and improve java garbage collection.
diff --git a/usr/src/lib/libc/port/threads/spawn.c b/usr/src/lib/libc/port/threads/spawn.c
index ca3bd3d3d7..ddf74327b5 100644
--- a/usr/src/lib/libc/port/threads/spawn.c
+++ b/usr/src/lib/libc/port/threads/spawn.c
@@ -32,6 +32,7 @@
#include <sys/procset.h>
#include <sys/rtpriocntl.h>
#include <sys/tspriocntl.h>
+#include <sys/fork.h>
#include <sys/rt.h>
#include <sys/ts.h>
#include <alloca.h>
@@ -44,7 +45,9 @@
POSIX_SPAWN_SETSIGDEF | \
POSIX_SPAWN_SETSIGMASK | \
POSIX_SPAWN_SETSCHEDPARAM | \
- POSIX_SPAWN_SETSCHEDULER)
+ POSIX_SPAWN_SETSCHEDULER | \
+ POSIX_SPAWN_NOSIGCHLD_NP | \
+ POSIX_SPAWN_WAITPID_NP)
typedef struct {
short sa_psflags; /* POSIX_SPAWN_* flags */
@@ -69,8 +72,8 @@ typedef struct file_attr {
extern struct pcclass ts_class, rt_class;
-extern pid_t _vfork(void);
-#pragma unknown_control_flow(_vfork)
+extern pid_t _vforkx(int);
+#pragma unknown_control_flow(_vforkx)
extern void *_private_memset(void *, int, size_t);
extern int __lwp_sigmask(int, const sigset_t *, sigset_t *);
extern int __open(const char *, int, mode_t);
@@ -262,6 +265,21 @@ perform_file_actions(file_attr_t *fap)
return (0);
}
+static int
+forkflags(spawn_attr_t *sap)
+{
+ int flags = 0;
+
+ if (sap != NULL) {
+ if (sap->sa_psflags & POSIX_SPAWN_NOSIGCHLD_NP)
+ flags |= FORK_NOSIGCHLD;
+ if (sap->sa_psflags & POSIX_SPAWN_WAITPID_NP)
+ flags |= FORK_WAITPID;
+ }
+
+ return (flags);
+}
+
/*
* set_error() / get_error() are used to guarantee that the local variable
* 'error' is set correctly in memory on return from vfork() in the parent.
@@ -286,7 +304,7 @@ get_error(int *errp)
* (with a defunct owner) and we would deadlock ourself if we invoked it.
*
* Therefore, all of the functions we call here after returning from
- * _vfork() in the child are not and must never be exported from libc
+ * _vforkx() in the child are not and must never be exported from libc
* as global symbols. To do so would risk invoking the dynamic linker.
*/
@@ -308,7 +326,7 @@ _posix_spawn(
if (attrp != NULL && sap == NULL)
return (EINVAL);
- switch (pid = _vfork()) {
+ switch (pid = _vforkx(forkflags(sap))) {
case 0: /* child */
break;
case -1: /* parent, failure */
@@ -410,7 +428,7 @@ _posix_spawnp(
continue;
newargs = alloca((argc + 2) * sizeof (char *));
- switch (pid = _vfork()) {
+ switch (pid = _vforkx(forkflags(sap))) {
case 0: /* child */
break;
case -1: /* parent, failure */
@@ -624,15 +642,11 @@ int
_posix_spawnattr_init(
posix_spawnattr_t *attr)
{
- spawn_attr_t *sap;
-
- if ((sap = lmalloc(sizeof (*sap))) == NULL)
+ if ((attr->__spawn_attrp = lmalloc(sizeof (posix_spawnattr_t))) == NULL)
return (ENOMEM);
-
/*
* Add default stuff here?
*/
- attr->__spawn_attrp = sap;
return (0);
}
diff --git a/usr/src/lib/libc/port/threads/thr.c b/usr/src/lib/libc/port/threads/thr.c
index 483ade8dd7..ac023cf5aa 100644
--- a/usr/src/lib/libc/port/threads/thr.c
+++ b/usr/src/lib/libc/port/threads/thr.c
@@ -1588,7 +1588,7 @@ finish_init()
}
/*
- * Used only by _postfork1_child(), below.
+ * Used only by postfork1_child(), below.
*/
static void
mark_dead_and_buried(ulwp_t *ulwp)
@@ -1745,6 +1745,12 @@ _thr_main()
}
int
+_thrp_cancelled(void)
+{
+ return (curthread->ul_rval == PTHREAD_CANCELED);
+}
+
+int
_thrp_stksegment(ulwp_t *ulwp, stack_t *stk)
{
stk->ss_sp = (void *)ulwp->ul_stktop;
diff --git a/usr/src/lib/libc/sparc/Makefile b/usr/src/lib/libc/sparc/Makefile
index 452b116802..eced13c518 100644
--- a/usr/src/lib/libc/sparc/Makefile
+++ b/usr/src/lib/libc/sparc/Makefile
@@ -330,8 +330,8 @@ SYSOBJS= \
_lwp_mutex_unlock.o \
_stack_grow.o \
door.o \
- fork1.o \
- forkall.o \
+ forkx.o \
+ forkallx.o \
gettimeofday.o \
pipe.o \
ptrace.o \
@@ -341,7 +341,7 @@ SYSOBJS= \
uadmin.o \
umount.o \
uname.o \
- vfork.o
+ vforkx.o
# objects under ../port which contain transitional large file interfaces
PORTGEN64= \
@@ -1214,7 +1214,7 @@ ASSYMDEP_OBJS= \
asm_subr.o \
tls_get_addr.o \
unwind_frame.o \
- vfork.o
+ vforkx.o
$(ASSYMDEP_OBJS:%=pics/%) := CPPFLAGS += -I.
diff --git a/usr/src/lib/libc/sparc/sys/forkall.s b/usr/src/lib/libc/sparc/sys/forkallx.s
index 43ef74e8bb..32dbdadd6e 100644
--- a/usr/src/lib/libc/sparc/sys/forkall.s
+++ b/usr/src/lib/libc/sparc/sys/forkallx.s
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -19,12 +18,12 @@
*
* CDDL HEADER END
*/
+
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
-
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -32,12 +31,13 @@
.file "%M%"
-/*
- * C library -- forkall
- * pid_t forkall(void)
- */
+#include "SYS.h"
/*
+ * pid = __forkallx(flags);
+ *
+ * syscall trap: forksys(1, flags)
+ *
* From the syscall:
* %o1 == 0 in parent process, %o1 == 1 in child process.
* %o0 == pid of child in parent, %o0 == pid of parent in child.
@@ -46,11 +46,11 @@
* The parent gets the pid of the child.
*/
-#include "SYS.h"
-
- ENTRY(__forkall)
- SYSTRAP_2RVALS(forkall)
+ ENTRY(__forkallx)
+ mov %o0, %o1
+ mov 1, %o0
+ SYSTRAP_2RVALS(forksys)
SYSCERROR
movrnz %o1, 0, %o0
RET
- SET_SIZE(__forkall)
+ SET_SIZE(__forkallx)
diff --git a/usr/src/lib/libc/sparc/sys/fork1.s b/usr/src/lib/libc/sparc/sys/forkx.s
index 1d011cbb37..b86bcbbfcc 100644
--- a/usr/src/lib/libc/sparc/sys/fork1.s
+++ b/usr/src/lib/libc/sparc/sys/forkx.s
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -19,12 +18,12 @@
*
* CDDL HEADER END
*/
+
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
-
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -32,12 +31,13 @@
.file "%M%"
-/*
- * C library -- fork1
- * pid_t fork1(void)
- */
+#include "SYS.h"
/*
+ * pid = __forkx(flags);
+ *
+ * syscall trap: forksys(0, flags)
+ *
* From the syscall:
* %o1 == 0 in parent process, %o1 == 1 in child process.
* %o0 == pid of child in parent, %o0 == pid of parent in child.
@@ -46,11 +46,11 @@
* The parent gets the pid of the child.
*/
-#include "SYS.h"
-
- ENTRY(__fork1);
- SYSTRAP_2RVALS(fork1);
+ ENTRY(__forkx)
+ mov %o0, %o1
+ clr %o0
+ SYSTRAP_2RVALS(forksys)
SYSCERROR
movrnz %o1, 0, %o0
RET
- SET_SIZE(__fork1)
+ SET_SIZE(__forkx)
diff --git a/usr/src/lib/libc/sparc/sys/vfork.s b/usr/src/lib/libc/sparc/sys/vforkx.s
index 45153a1374..d5e41b571a 100644
--- a/usr/src/lib/libc/sparc/sys/vfork.s
+++ b/usr/src/lib/libc/sparc/sys/vforkx.s
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -19,66 +18,79 @@
*
* CDDL HEADER END
*/
+
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
-
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-.ident "%Z%%M% %I% %E% SMI"
+#pragma ident "%Z%%M% %I% %E% SMI"
-/*
- * C library -- vfork
- * pid_t vfork(void);
- */
+ .file "%M%"
+
+#include <sys/asm_linkage.h>
+
+ ANSI_PRAGMA_WEAK(vforkx,function)
+ ANSI_PRAGMA_WEAK(vfork,function)
+
+#include "SYS.h"
+#include <assym.h>
/*
+ * pid = vforkx(flags);
+ * syscall trap: forksys(2, flags)
+ *
+ * pid = vfork();
+ * syscall trap: forksys(2, 0)
+ *
* From the syscall:
* %o1 == 0 in parent process, %o1 == 1 in child process.
* %o0 == pid of child in parent, %o0 == pid of parent in child.
*
- * The child process gets a zero return value from vfork; the parent
- * gets the pid of the child.
+ * The child gets a zero return value.
+ * The parent gets the pid of the child.
+ */
+
+/*
+ * Note that since the SPARC architecture maintains stack maintence
+ * information (return pc, sp, fp) in the register windows, both parent
+ * and child can execute in a common address space without conflict.
*
* We block all blockable signals while performing the vfork() system call
* trap. This enables us to set curthread->ul_vfork safely, so that we
* don't end up in a signal handler with curthread->ul_vfork set wrong.
- *
- * Note that since the SPARC architecture maintains stack maintence
- * information (return pc, sp, fp) in the register windows, both parent
- * and child can execute in a common address space without conflict.
*/
- .file "%M%"
-
-#include <sys/asm_linkage.h>
-
- ANSI_PRAGMA_WEAK(vfork,function)
-
-#include "SYS.h"
-#include <../assym.h>
-
- ENTRY(vfork)
- mov SIG_SETMASK, %o0 ! block signals
+ ENTRY_NP(vforkx)
+ ba 0f
+ mov %o0, %o3 /* flags */
+ ENTRY_NP(vfork)
+ clr %o3 /* flags = 0 */
+0:
+ mov SIG_SETMASK, %o0 /* block all signals */
set MASKSET0, %o1
set MASKSET1, %o2
SYSTRAP_2RVALS(lwp_sigmask)
- SYSTRAP_2RVALS(vfork)
+ mov %o3, %o1 /* flags */
+ mov 2, %o0
+ SYSTRAP_2RVALS(forksys) /* vforkx(flags) */
bcc,a,pt %icc, 1f
tst %o1
- mov %o0, %o3 ! save the vfork() error number
- mov SIG_SETMASK, %o0 ! reinstate signals
+ mov %o0, %o3 /* save the vfork() error number */
+
+ mov SIG_SETMASK, %o0 /* reinstate signals */
ld [%g7 + UL_SIGMASK], %o1
ld [%g7 + UL_SIGMASK + 4], %o2
SYSTRAP_2RVALS(lwp_sigmask)
- mov %o3, %o0 ! restore the vfork() error number
- ba,a __cerror
+ ba __cerror
+ mov %o3, %o0 /* restore the vfork() error number */
+
1:
/*
* To determine if we are (still) a child of vfork(), the child
@@ -89,12 +101,12 @@
*/
bnz,pt %icc, 2f
ld [%g7 + UL_VFORK], %g1
- brnz,a,pt %g1, 3f ! don't let it go negative
- sub %g1, 1, %g1 ! curthread->ul_vfork--;
+ brnz,a,pt %g1, 3f /* don't let it go negative */
+ sub %g1, 1, %g1 /* curthread->ul_vfork--; */
ba,a 3f
2:
- clr %o0 ! child, return (0)
- add %g1, 1, %g1 ! curthread->ul_vfork++;
+ clr %o0 /* zero the return value in the child */
+ add %g1, 1, %g1 /* curthread->ul_vfork++; */
3:
st %g1, [%g7 + UL_VFORK]
/*
@@ -103,13 +115,14 @@
*/
stn %g0, [%g7 + UL_SCHEDCTL]
stn %g0, [%g7 + UL_SCHEDCTL_CALLED]
- mov %o0, %o3 ! save the vfork() return value
+ mov %o0, %o3 /* save the vfork() return value */
- mov SIG_SETMASK, %o0 ! reinstate signals
+ mov SIG_SETMASK, %o0 /* reinstate signals */
ld [%g7 + UL_SIGMASK], %o1
ld [%g7 + UL_SIGMASK + 4], %o2
SYSTRAP_2RVALS(lwp_sigmask)
retl
- mov %o3, %o0 ! restore the vfork() return value
+ mov %o3, %o0 /* restore the vfork() return value */
SET_SIZE(vfork)
+ SET_SIZE(vforkx)
diff --git a/usr/src/lib/libc/sparcv9/Makefile b/usr/src/lib/libc/sparcv9/Makefile
index bfbb37f2d8..04054aaa81 100644
--- a/usr/src/lib/libc/sparcv9/Makefile
+++ b/usr/src/lib/libc/sparcv9/Makefile
@@ -316,8 +316,8 @@ SYSOBJS= \
_lwp_mutex_unlock.o \
_stack_grow.o \
door.o \
- fork1.o \
- forkall.o \
+ forkx.o \
+ forkallx.o \
gettimeofday.o \
pipe.o \
sparc_utrap_install.o \
@@ -327,7 +327,7 @@ SYSOBJS= \
uadmin.o \
umount.o \
uname.o \
- vfork.o
+ vforkx.o
# Preserved solely to ease maintenance of 32-bit and 64-bit library builds
# This macro should ALWAYS be empty; native APIs are already 'large file'.
@@ -1150,7 +1150,7 @@ ASSYMDEP_OBJS= \
asm_subr.o \
tls_get_addr.o \
unwind_frame.o \
- vfork.o
+ vforkx.o
$(ASSYMDEP_OBJS:%=pics/%) := CPPFLAGS += -I.