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