Include string.h in common-defs.h
[external/binutils.git] / gdb / nat / linux-waitpid.c
1 /* Wrapper implementation for waitpid for GNU/Linux (LWP layer).
2
3    Copyright (C) 2001-2014 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 #ifdef GDBSERVER
21 #include "server.h"
22 #else
23 #include "defs.h"
24 #include "signal.h"
25 #endif
26
27 #include "linux-nat.h"
28 #include "linux-waitpid.h"
29 #include "gdb_wait.h"
30
31 /* Print debugging output based on the format string FORMAT and
32    its parameters.  */
33
34 static inline void
35 linux_debug (const char *format, ...)
36 {
37 #ifdef GDBSERVER
38   if (debug_threads)
39     {
40       va_list args;
41       va_start (args, format);
42       vfprintf (stderr, format, args);
43       va_end (args);
44     }
45 #else
46   /* GDB-specific debugging output.  */
47 #endif
48 }
49
50 /* Convert wait status STATUS to a string.  Used for printing debug
51    messages only.  */
52
53 char *
54 status_to_str (int status)
55 {
56   static char buf[64];
57
58   if (WIFSTOPPED (status))
59     {
60       if (WSTOPSIG (status) == SYSCALL_SIGTRAP)
61         snprintf (buf, sizeof (buf), "%s (stopped at syscall)",
62                   strsignal (SIGTRAP));
63       else
64         snprintf (buf, sizeof (buf), "%s (stopped)",
65                   strsignal (WSTOPSIG (status)));
66     }
67   else if (WIFSIGNALED (status))
68     snprintf (buf, sizeof (buf), "%s (terminated)",
69               strsignal (WTERMSIG (status)));
70   else
71     snprintf (buf, sizeof (buf), "%d (exited)", WEXITSTATUS (status));
72
73   return buf;
74 }
75
76 /* Wrapper function for waitpid which handles EINTR, and emulates
77    __WALL for systems where that is not available.  */
78
79 int
80 my_waitpid (int pid, int *status, int flags)
81 {
82   int ret, out_errno;
83
84   linux_debug ("my_waitpid (%d, 0x%x)\n", pid, flags);
85
86   if (flags & __WALL)
87     {
88       sigset_t block_mask, org_mask, wake_mask;
89       int wnohang;
90
91       wnohang = (flags & WNOHANG) != 0;
92       flags &= ~(__WALL | __WCLONE);
93
94       if (!wnohang)
95         {
96           flags |= WNOHANG;
97
98           /* Block all signals while here.  This avoids knowing about
99              LinuxThread's signals.  */
100           sigfillset (&block_mask);
101           sigprocmask (SIG_BLOCK, &block_mask, &org_mask);
102
103           /* ... except during the sigsuspend below.  */
104           sigemptyset (&wake_mask);
105         }
106
107       while (1)
108         {
109           /* Since all signals are blocked, there's no need to check
110              for EINTR here.  */
111           ret = waitpid (pid, status, flags);
112           out_errno = errno;
113
114           if (ret == -1 && out_errno != ECHILD)
115             break;
116           else if (ret > 0)
117             break;
118
119           if (flags & __WCLONE)
120             {
121               /* We've tried both flavors now.  If WNOHANG is set,
122                  there's nothing else to do, just bail out.  */
123               if (wnohang)
124                 break;
125
126               linux_debug ("blocking\n");
127
128               /* Block waiting for signals.  */
129               sigsuspend (&wake_mask);
130             }
131           flags ^= __WCLONE;
132         }
133
134       if (!wnohang)
135         sigprocmask (SIG_SETMASK, &org_mask, NULL);
136     }
137   else
138     {
139       do
140         ret = waitpid (pid, status, flags);
141       while (ret == -1 && errno == EINTR);
142       out_errno = errno;
143     }
144
145   linux_debug ("my_waitpid (%d, 0x%x): status(%x), %d\n",
146                pid, flags, status ? *status : -1, ret);
147
148   errno = out_errno;
149   return ret;
150 }