2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A .file "vforkx.s"
2N/A
2N/A#include "SYS.h"
2N/A#include <assym.h>
2N/A
2N/A/*
2N/A * pid = vforkx(flags);
2N/A * syscall trap: forksys(2, flags)
2N/A *
2N/A * pid = vfork();
2N/A * syscall trap: forksys(2, 0)
2N/A *
2N/A * From the syscall:
2N/A * %edx == 0 in parent process, %edx = 1 in child process.
2N/A * %eax == pid of child in parent, %eax == pid of parent in child.
2N/A *
2N/A * The child gets a zero return value.
2N/A * The parent gets the pid of the child.
2N/A */
2N/A
2N/A/*
2N/A * The child of vfork() will execute in the parent's address space,
2N/A * thereby changing the stack before the parent runs again.
2N/A * Therefore we have to be careful how we return from vfork().
2N/A * Pity the poor debugger developer who has to deal with this kludge.
2N/A *
2N/A * We block all blockable signals while performing the vfork() system call
2N/A * trap. This enables us to set curthread->ul_vfork safely, so that we
2N/A * don't end up in a signal handler with curthread->ul_vfork set wrong.
2N/A */
2N/A
2N/A ENTRY_NP(vforkx)
2N/A movl 4(%esp), %eax /* flags */
2N/A jmp 0f
2N/A ENTRY_NP(vfork)
2N/A xorl %eax, %eax /* flags = 0 */
2N/A0:
2N/A popl %ecx /* save return %eip in %ecx */
2N/A pushl %eax /* flags */
2N/A pushl $MASKSET3 /* block all signals */
2N/A pushl $MASKSET2
2N/A pushl $MASKSET1
2N/A pushl $MASKSET0
2N/A pushl $SIG_SETMASK
2N/A pushl %ecx
2N/A __SYSCALLINT(lwp_sigmask)
2N/A addl $24, %esp
2N/A
2N/A pushl $2
2N/A pushl %ecx
2N/A __SYSCALLINT(forksys) /* vforkx(flags) */
2N/A jae 1f
2N/A
2N/A /* reconstruct stack before jumping to __cerror */
2N/A addl $12, %esp
2N/A pushl %ecx
2N/A pushl %eax /* save the vfork() error number */
2N/A
2N/A pushl %gs:UL_SIGMASK+12 /* reinstate signals */
2N/A pushl %gs:UL_SIGMASK+8
2N/A pushl %gs:UL_SIGMASK+4
2N/A pushl %gs:UL_SIGMASK
2N/A pushl $SIG_SETMASK
2N/A pushl %ecx
2N/A __SYSCALLINT(lwp_sigmask)
2N/A addl $24, %esp
2N/A
2N/A popl %eax /* restore the vfork() error number */
2N/A jmp __cerror
2N/A
2N/A1:
2N/A addl $12, %esp
2N/A /*
2N/A * To determine if we are (still) a child of vfork(), the child
2N/A * increments curthread->ul_vfork by one and the parent decrements
2N/A * it by one. If the result is zero, then we are not a child of
2N/A * vfork(), else we are. We do this to deal with the case of
2N/A * a vfork() child calling vfork().
2N/A */
2N/A cmpl $0, %edx
2N/A jne 2f
2N/A movl %gs:UL_VFORK, %edx
2N/A cmpl $0, %edx /* don't let it go negative */
2N/A je 3f
2N/A subl $1, %edx /* curthread->ul_vfork--; */
2N/A jmp 3f
2N/A2:
2N/A xorl %eax, %eax /* zero the return value in the child */
2N/A movl %gs:UL_VFORK, %edx
2N/A addl $1, %edx /* curthread->ul_vfork++; */
2N/A3:
2N/A movl %edx, %gs:UL_VFORK
2N/A /*
2N/A * Clear the schedctl interface in both parent and child.
2N/A * (The child might have modified the parent.)
2N/A */
2N/A xorl %edx, %edx
2N/A movl %edx, %gs:UL_SCHEDCTL
2N/A movl %edx, %gs:UL_SCHEDCTL_CALLED
2N/A pushl %eax /* save the vfork() return value */
2N/A
2N/A pushl %gs:UL_SIGMASK+12 /* reinstate signals */
2N/A pushl %gs:UL_SIGMASK+8
2N/A pushl %gs:UL_SIGMASK+4
2N/A pushl %gs:UL_SIGMASK
2N/A pushl $SIG_SETMASK
2N/A pushl %ecx
2N/A __SYSCALLINT(lwp_sigmask)
2N/A addl $24, %esp
2N/A
2N/A popl %eax /* restore the vfork() return value */
2N/A jmp *%ecx /* jump back to the caller */
2N/A SET_SIZE(vfork)
2N/A SET_SIZE(vforkx)