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 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * wait() family of functions. 31 * 32 * The first minor difference between the Linux and Solaris family of wait() 33 * calls is that the values for WNOHANG and WUNTRACED are different. Solaris 34 * also has additional options (WCONTINUED, WNOWAIT) which should be flagged as 35 * invalid on Linux. Thankfully, the exit status values are identical between 36 * the two implementations. 37 * 38 * Things get very different and very complicated when we introduce the Linux 39 * threading model. Under linux, both threads and child processes are 40 * represented as processes. However, the behavior of wait() with respect to 41 * each child varies according to the flags given to clone() 42 * 43 * SIGCHLD The SIGCHLD signal should be sent on termination 44 * CLONE_THREAD The child shares the same thread group as the parent 45 * CLONE_DETACHED The parent receives no notification when the child exits 46 * 47 * The following flags control the Linux behavior w.r.t. the above attributes: 48 * 49 * __WALL Wait on all children, regardless of type 50 * __WCLONE Wait only on non-SIGCHLD children 51 * __WNOTHREAD Don't wait on children of other threads in this group 52 * 53 * The following chart shows whether wait() returns when the child exits: 54 * 55 * default __WCLONE __WALL 56 * no SIGCHLD - X X 57 * SIGCHLD X - X 58 * 59 * The following chart shows whether wait() returns when the grandchild exits: 60 * 61 * default __WNOTHREAD 62 * no CLONE_THREAD - - 63 * CLONE_THREAD X - 64 * 65 * The CLONE_DETACHED flag is universal - when the child exits, no state is 66 * stored and wait() has no effect. 67 * 68 * XXX Support the above combination of options, or some reasonable subset that 69 * covers at least fork() and pthread_create(). 70 */ 71 72 #include <errno.h> 73 #include <sys/wait.h> 74 #include <sys/lx_types.h> 75 #include <sys/lx_signal.h> 76 #include <sys/lx_misc.h> 77 #include <sys/lx_syscall.h> 78 #include <sys/times.h> 79 #include <strings.h> 80 #include <unistd.h> 81 #include <assert.h> 82 83 /* 84 * Convert between Linux options and Solaris options, returning -1 if any 85 * invalid flags are found. 86 */ 87 #define LX_WNOHANG 0x1 88 #define LX_WUNTRACED 0x2 89 90 #define LX_WNOTHREAD 0x20000000 91 #define LX_WALL 0x40000000 92 #define LX_WCLONE 0x80000000 93 94 #define LX_P_ALL 0x0 95 #define LX_P_PID 0x1 96 #define LX_P_GID 0x2 97 98 static int 99 ltos_options(uintptr_t options) 100 { 101 int newoptions = 0; 102 103 if (((options) & ~(LX_WNOHANG | LX_WUNTRACED | LX_WNOTHREAD | 104 LX_WALL | LX_WCLONE)) != 0) { 105 return (-1); 106 } 107 /* XXX implement LX_WNOTHREAD, LX_WALL, LX_WCLONE */ 108 109 if (options & LX_WNOHANG) 110 newoptions |= WNOHANG; 111 if (options & LX_WUNTRACED) 112 newoptions |= WUNTRACED; 113 114 return (newoptions); 115 } 116 117 static int 118 lx_wstat(int code, int status) 119 { 120 int stat = 0; 121 122 switch (code) { 123 case CLD_EXITED: 124 stat = status << 8; 125 break; 126 case CLD_DUMPED: 127 stat = stol_signo[status]; 128 assert(stat != -1); 129 stat |= WCOREFLG; 130 break; 131 case CLD_KILLED: 132 stat = stol_signo[status]; 133 assert(stat != -1); 134 break; 135 case CLD_TRAPPED: 136 case CLD_STOPPED: 137 stat = stol_signo[status]; 138 assert(stat != -1); 139 stat <<= 8; 140 stat |= WSTOPFLG; 141 break; 142 case CLD_CONTINUED: 143 stat = WCONTFLG; 144 break; 145 } 146 147 return (stat); 148 } 149 150 /* wrapper to make solaris waitid work properly with ptrace */ 151 static int 152 lx_waitid_helper(idtype_t idtype, id_t id, siginfo_t *info, int options) 153 { 154 do { 155 /* 156 * It's possible that we return EINVAL here if the idtype is 157 * P_PID or P_PGID and id is out of bounds for a valid pid or 158 * pgid, but Linux expects to see ECHILD. No good way occurs to 159 * handle this so we'll punt for now. 160 */ 161 if (waitid(idtype, id, info, options) < 0) 162 return (-errno); 163 164 /* 165 * If the WNOHANG flag was specified and no child was found 166 * return 0. 167 */ 168 if ((options & WNOHANG) && info->si_pid == 0) 169 return (0); 170 171 /* 172 * It's possible that we may have a spurious return for one of 173 * the child processes created by the ptrace subsystem. If 174 * that's the case, we simply try again. 175 */ 176 } while (lx_ptrace_wait(info) == -1); 177 return (0); 178 } 179 180 int 181 lx_wait4(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4) 182 { 183 siginfo_t info = { 0 }; 184 struct rusage ru = { 0 }; 185 idtype_t idtype; 186 id_t id; 187 int options, status = 0; 188 pid_t pid = (pid_t)p1; 189 int rval; 190 191 if ((options = ltos_options(p3)) == -1) 192 return (-EINVAL); 193 194 /* 195 * While not listed as a valid return code, Linux's wait4(2) does, 196 * in fact, get an EFAULT if either the status pointer or rusage 197 * pointer is invalid. Since a failed waitpid should leave child 198 * process in a state where a future wait4(2) will succeed, we 199 * check them by copying out the values their buffers originally 200 * contained. (We need to do this as a failed system call should 201 * never affect the contents of a passed buffer.) 202 * 203 * This will fail if the buffers in question are write-only. 204 */ 205 if ((void *)p2 != NULL && 206 ((uucopy((void *)p2, &status, sizeof (status)) != 0) || 207 (uucopy(&status, (void *)p2, sizeof (status)) != 0))) 208 return (-EFAULT); 209 210 if ((void *)p4 != NULL) { 211 if ((uucopy((void *)p4, &ru, sizeof (ru)) != 0) || 212 (uucopy(&ru, (void *)p4, sizeof (ru)) != 0)) 213 return (-EFAULT); 214 } 215 216 if (pid < -1) { 217 idtype = P_PGID; 218 id = -pid; 219 } else if (pid == -1) { 220 idtype = P_ALL; 221 id = 0; 222 } else if (pid == 0) { 223 idtype = P_PGID; 224 id = getpgrp(); 225 } else { 226 idtype = P_PID; 227 id = pid; 228 } 229 230 options |= WEXITED | WTRAPPED; 231 232 if ((rval = lx_waitid_helper(idtype, id, &info, options)) < 0) 233 return (rval); 234 /* 235 * If the WNOHANG flag was specified and no child was found return 0. 236 */ 237 if ((options & WNOHANG) && info.si_pid == 0) 238 return (0); 239 240 status = lx_wstat(info.si_code, info.si_status); 241 242 /* 243 * Unfortunately if this attempt to copy out either the status or the 244 * rusage fails, the process will be in an inconsistent state as 245 * subsequent calls to wait for the same child will fail where they 246 * should succeed on a Linux system. This, however, is rather 247 * unlikely since we tested the validity of both above. 248 */ 249 if (p2 != NULL && uucopy(&status, (void *)p2, sizeof (status)) != 0) 250 return (-EFAULT); 251 252 if (p4 != NULL && (rval = lx_getrusage(LX_RUSAGE_CHILDREN, p4)) != 0) 253 return (rval); 254 255 return (info.si_pid); 256 } 257 258 int 259 lx_waitpid(uintptr_t p1, uintptr_t p2, uintptr_t p3) 260 { 261 return (lx_wait4(p1, p2, p3, NULL)); 262 } 263 264 int 265 lx_waitid(uintptr_t idtype, uintptr_t id, uintptr_t infop, uintptr_t opt) 266 { 267 int rval, options; 268 siginfo_t s_infop = {0}; 269 if ((options = ltos_options(opt)) == -1) 270 return (-1); 271 switch (idtype) { 272 case LX_P_ALL: 273 idtype = P_ALL; 274 break; 275 case LX_P_PID: 276 idtype = P_PID; 277 break; 278 case LX_P_GID: 279 idtype = P_GID; 280 break; 281 default: 282 return (-EINVAL); 283 } 284 if ((rval = lx_waitid_helper(idtype, (id_t)id, &s_infop, options)) < 0) 285 return (rval); 286 287 return (stol_siginfo(&s_infop, (lx_siginfo_t *)infop)); 288 }