1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
/*
* 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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
.file "vforkx.s"
#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 $MASKSET3 /* block all signals */
pushl $MASKSET2
pushl $MASKSET1
pushl $MASKSET0
pushl $SIG_SETMASK
pushl %ecx
__SYSCALLINT(lwp_sigmask)
addl $24, %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+12 /* reinstate signals */
pushl %gs:UL_SIGMASK+8
pushl %gs:UL_SIGMASK+4
pushl %gs:UL_SIGMASK
pushl $SIG_SETMASK
pushl %ecx
__SYSCALLINT(lwp_sigmask)
addl $24, %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+12 /* reinstate signals */
pushl %gs:UL_SIGMASK+8
pushl %gs:UL_SIGMASK+4
pushl %gs:UL_SIGMASK
pushl $SIG_SETMASK
pushl %ecx
__SYSCALLINT(lwp_sigmask)
addl $24, %esp
popl %eax /* restore the vfork() return value */
jmp *%ecx /* jump back to the caller */
SET_SIZE(vfork)
SET_SIZE(vforkx)
|