xref: /titanic_44/usr/src/lib/libc/sparc/sys/vforkx.s (revision 39c23413b8df94a95f67b34cfd4a4dfc3fd0b48d)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*	Copyright (c) 1988 AT&T	*/
23/*	  All Rights Reserved	*/
24
25/*
26 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
27 * Use is subject to license terms.
28 */
29
30#pragma ident	"%Z%%M%	%I%	%E% SMI"
31
32	.file	"%M%"
33
34#include <sys/asm_linkage.h>
35
36	ANSI_PRAGMA_WEAK(vforkx,function)
37	ANSI_PRAGMA_WEAK(vfork,function)
38
39#include "SYS.h"
40#include <assym.h>
41
42/*
43 * pid = vforkx(flags);
44 * syscall trap: forksys(2, flags)
45 *
46 * pid = vfork();
47 * syscall trap: forksys(2, 0)
48 *
49 * From the syscall:
50 * %o1 == 0 in parent process, %o1 == 1 in child process.
51 * %o0 == pid of child in parent, %o0 == pid of parent in child.
52 *
53 * The child gets a zero return value.
54 * The parent gets the pid of the child.
55 */
56
57/*
58 * Note that since the SPARC architecture maintains stack maintence
59 * information (return pc, sp, fp) in the register windows, both parent
60 * and child can execute in a common address space without conflict.
61 *
62 * We block all blockable signals while performing the vfork() system call
63 * trap.  This enables us to set curthread->ul_vfork safely, so that we
64 * don't end up in a signal handler with curthread->ul_vfork set wrong.
65 */
66
67	ENTRY_NP(vforkx)
68	ba	0f
69	mov	%o0, %o3		/* flags */
70	ENTRY_NP(vfork)
71	clr	%o3			/* flags = 0 */
720:
73	mov	SIG_SETMASK, %o0	/* block all signals */
74	set	MASKSET0, %o1
75	set	MASKSET1, %o2
76	SYSTRAP_2RVALS(lwp_sigmask)
77
78	mov	%o3, %o1		/* flags */
79	mov	2, %o0
80	SYSTRAP_2RVALS(forksys)		/* vforkx(flags) */
81	bcc,a,pt %icc, 1f
82	tst	%o1
83
84	mov	%o0, %o3		/* save the vfork() error number */
85
86	mov	SIG_SETMASK, %o0	/* reinstate signals */
87	ld	[%g7 + UL_SIGMASK], %o1
88	ld	[%g7 + UL_SIGMASK + 4], %o2
89	SYSTRAP_2RVALS(lwp_sigmask)
90
91	ba	__cerror
92	mov	%o3, %o0		/* restore the vfork() error number */
93
941:
95	/*
96	 * To determine if we are (still) a child of vfork(), the child
97	 * increments curthread->ul_vfork by one and the parent decrements
98	 * it by one.  If the result is zero, then we are not a child of
99	 * vfork(), else we are.  We do this to deal with the case of
100	 * a vfork() child calling vfork().
101	 */
102	bnz,pt	%icc, 2f
103	ld	[%g7 + UL_VFORK], %g1
104	brnz,a,pt %g1, 3f		/* don't let it go negative */
105	sub	%g1, 1, %g1		/* curthread->ul_vfork--; */
106	ba,a	3f
1072:
108	clr	%o0			/* zero the return value in the child */
109	add	%g1, 1, %g1		/* curthread->ul_vfork++; */
1103:
111	st	%g1, [%g7 + UL_VFORK]
112	/*
113	 * Clear the schedctl interface in both parent and child.
114	 * (The child might have modified the parent.)
115	 */
116	stn	%g0, [%g7 + UL_SCHEDCTL]
117	stn	%g0, [%g7 + UL_SCHEDCTL_CALLED]
118	mov	%o0, %o3		/* save the vfork() return value */
119
120	mov	SIG_SETMASK, %o0	/* reinstate signals */
121	ld	[%g7 + UL_SIGMASK], %o1
122	ld	[%g7 + UL_SIGMASK + 4], %o2
123	SYSTRAP_2RVALS(lwp_sigmask)
124
125	retl
126	mov	%o3, %o0		/* restore the vfork() return value */
127	SET_SIZE(vfork)
128	SET_SIZE(vforkx)
129