1 /* Wrapper implementation for waitpid for GNU/Linux (LWP layer). 2 3 Copyright (C) 2001-2015 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 #include "common-defs.h" 21 22 #ifdef GDBSERVER 23 /* FIXME: server.h is required for the definition of debug_threads 24 which is used in the gdbserver-specific debug printing in 25 linux_debug. This code should be made available to GDB also, 26 but the lack of a suitable flag to enable it prevents this. */ 27 #include "server.h" 28 #endif 29 30 #include "linux-nat.h" 31 #include "linux-waitpid.h" 32 #include "gdb_wait.h" 33 34 /* Print debugging output based on the format string FORMAT and 35 its parameters. */ 36 37 static inline void 38 linux_debug (const char *format, ...) 39 { 40 #ifdef GDBSERVER 41 if (debug_threads) 42 { 43 va_list args; 44 va_start (args, format); 45 vfprintf (stderr, format, args); 46 va_end (args); 47 } 48 #endif 49 } 50 51 /* Convert wait status STATUS to a string. Used for printing debug 52 messages only. */ 53 54 char * 55 status_to_str (int status) 56 { 57 static char buf[64]; 58 59 if (WIFSTOPPED (status)) 60 { 61 if (WSTOPSIG (status) == SYSCALL_SIGTRAP) 62 snprintf (buf, sizeof (buf), "%s (stopped at syscall)", 63 strsignal (SIGTRAP)); 64 else 65 snprintf (buf, sizeof (buf), "%s (stopped)", 66 strsignal (WSTOPSIG (status))); 67 } 68 else if (WIFSIGNALED (status)) 69 snprintf (buf, sizeof (buf), "%s (terminated)", 70 strsignal (WTERMSIG (status))); 71 else 72 snprintf (buf, sizeof (buf), "%d (exited)", WEXITSTATUS (status)); 73 74 return buf; 75 } 76 77 /* Wrapper function for waitpid which handles EINTR, and emulates 78 __WALL for systems where that is not available. */ 79 80 int 81 my_waitpid (int pid, int *status, int flags) 82 { 83 int ret, out_errno; 84 85 linux_debug ("my_waitpid (%d, 0x%x)\n", pid, flags); 86 87 if (flags & __WALL) 88 { 89 sigset_t block_mask, org_mask, wake_mask; 90 int wnohang; 91 92 wnohang = (flags & WNOHANG) != 0; 93 flags &= ~(__WALL | __WCLONE); 94 95 if (!wnohang) 96 { 97 flags |= WNOHANG; 98 99 /* Block all signals while here. This avoids knowing about 100 LinuxThread's signals. */ 101 sigfillset (&block_mask); 102 sigprocmask (SIG_BLOCK, &block_mask, &org_mask); 103 104 /* ... except during the sigsuspend below. */ 105 sigemptyset (&wake_mask); 106 } 107 108 while (1) 109 { 110 /* Since all signals are blocked, there's no need to check 111 for EINTR here. */ 112 ret = waitpid (pid, status, flags); 113 out_errno = errno; 114 115 if (ret == -1 && out_errno != ECHILD) 116 break; 117 else if (ret > 0) 118 break; 119 120 if (flags & __WCLONE) 121 { 122 /* We've tried both flavors now. If WNOHANG is set, 123 there's nothing else to do, just bail out. */ 124 if (wnohang) 125 break; 126 127 linux_debug ("blocking\n"); 128 129 /* Block waiting for signals. */ 130 sigsuspend (&wake_mask); 131 } 132 flags ^= __WCLONE; 133 } 134 135 if (!wnohang) 136 sigprocmask (SIG_SETMASK, &org_mask, NULL); 137 } 138 else 139 { 140 do 141 ret = waitpid (pid, status, flags); 142 while (ret == -1 && errno == EINTR); 143 out_errno = errno; 144 } 145 146 linux_debug ("my_waitpid (%d, 0x%x): status(%x), %d\n", 147 pid, flags, status ? *status : -1, ret); 148 149 errno = out_errno; 150 return ret; 151 } 152