Unify ptrace options discovery code and make both GDB and
[external/binutils.git] / gdb / nat / linux-waitpid.c
1 /* Wrapper implementation for waitpid for GNU/Linux (LWP layer).
2
3    Copyright (C) 2001-2013 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 /* 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       fprintf (stderr, "\n");
44       va_end (args);
45     }
46 #else
47   /* GDB-specific debugging output.  */
48 #endif
49 }
50
51 /* Wrapper function for waitpid which handles EINTR, and emulates
52    __WALL for systems where that is not available.  */
53
54 int
55 my_waitpid (int pid, int *status, int flags)
56 {
57   int ret, out_errno;
58
59   linux_debug ("my_waitpid (%d, 0x%x)\n", pid, flags);
60
61   if (flags & __WALL)
62     {
63       sigset_t block_mask, org_mask, wake_mask;
64       int wnohang;
65
66       wnohang = (flags & WNOHANG) != 0;
67       flags &= ~(__WALL | __WCLONE);
68       flags |= WNOHANG;
69
70       /* Block all signals while here.  This avoids knowing about
71          LinuxThread's signals.  */
72       sigfillset (&block_mask);
73       sigprocmask (SIG_BLOCK, &block_mask, &org_mask);
74
75       /* ... except during the sigsuspend below.  */
76       sigemptyset (&wake_mask);
77
78       while (1)
79         {
80           /* Since all signals are blocked, there's no need to check
81              for EINTR here.  */
82           ret = waitpid (pid, status, flags);
83           out_errno = errno;
84
85           if (ret == -1 && out_errno != ECHILD)
86             break;
87           else if (ret > 0)
88             break;
89
90           if (flags & __WCLONE)
91             {
92               /* We've tried both flavors now.  If WNOHANG is set,
93                  there's nothing else to do, just bail out.  */
94               if (wnohang)
95                 break;
96
97               linux_debug ("blocking\n");
98
99               /* Block waiting for signals.  */
100               sigsuspend (&wake_mask);
101             }
102           flags ^= __WCLONE;
103         }
104
105       sigprocmask (SIG_SETMASK, &org_mask, NULL);
106     }
107   else
108     {
109       do
110         ret = waitpid (pid, status, flags);
111       while (ret == -1 && errno == EINTR);
112       out_errno = errno;
113     }
114
115   linux_debug ("my_waitpid (%d, 0x%x): status(%x), %d\n",
116                pid, flags, status ? *status : -1, ret);
117
118   errno = out_errno;
119   return ret;
120 }