diff options
Diffstat (limited to 'usr/src/lib/libc')
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. |