mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-25 00:37:38 +00:00
* lin-lwp.c (detach_callback): Don't call stop_wait_callback.
(stop_wait_callback): Handle !lp->signalled also. (lin_lwp_has_pending, flush_callback): New functions. (lin_lwp_wait): Call flush_callback. * linux-proc.c (linux_proc_add_line_to_sigset): New function. (linux_proc_pending_signals): New function. * linux-nat.h (linux_proc_pending_signals): Add prototype.
This commit is contained in:
@@ -1,3 +1,13 @@
|
|||||||
|
2003-09-07 Daniel Jacobowitz <drow@mvista.com>
|
||||||
|
|
||||||
|
* lin-lwp.c (detach_callback): Don't call stop_wait_callback.
|
||||||
|
(stop_wait_callback): Handle !lp->signalled also.
|
||||||
|
(lin_lwp_has_pending, flush_callback): New functions.
|
||||||
|
(lin_lwp_wait): Call flush_callback.
|
||||||
|
* linux-proc.c (linux_proc_add_line_to_sigset): New function.
|
||||||
|
(linux_proc_pending_signals): New function.
|
||||||
|
* linux-nat.h (linux_proc_pending_signals): Add prototype.
|
||||||
|
|
||||||
2003-09-07 Daniel Jacobowitz <drow@mvista.com>
|
2003-09-07 Daniel Jacobowitz <drow@mvista.com>
|
||||||
|
|
||||||
From Nick Kelsey <nickk@ubicom.com>:
|
From Nick Kelsey <nickk@ubicom.com>:
|
||||||
|
|||||||
@@ -417,7 +417,12 @@ detach_callback (struct lwp_info *lp, void *data)
|
|||||||
lp->stopped = 0;
|
lp->stopped = 0;
|
||||||
lp->signalled = 0;
|
lp->signalled = 0;
|
||||||
lp->status = 0;
|
lp->status = 0;
|
||||||
stop_wait_callback (lp, NULL);
|
/* FIXME drow/2003-08-26: There was a call to stop_wait_callback
|
||||||
|
here. But since lp->signalled was cleared above,
|
||||||
|
stop_wait_callback didn't do anything; the process was left
|
||||||
|
running. Shouldn't we be waiting for it to stop?
|
||||||
|
I've removed the call, since stop_wait_callback now does do
|
||||||
|
something when called with lp->signalled == 0. */
|
||||||
|
|
||||||
gdb_assert (lp->status == 0 || WIFSTOPPED (lp->status));
|
gdb_assert (lp->status == 0 || WIFSTOPPED (lp->status));
|
||||||
}
|
}
|
||||||
@@ -696,7 +701,7 @@ stop_wait_callback (struct lwp_info *lp, void *data)
|
|||||||
{
|
{
|
||||||
sigset_t *flush_mask = data;
|
sigset_t *flush_mask = data;
|
||||||
|
|
||||||
if (!lp->stopped && lp->signalled)
|
if (!lp->stopped)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
@@ -707,6 +712,12 @@ stop_wait_callback (struct lwp_info *lp, void *data)
|
|||||||
/* Ignore any signals in FLUSH_MASK. */
|
/* Ignore any signals in FLUSH_MASK. */
|
||||||
if (flush_mask && sigismember (flush_mask, WSTOPSIG (status)))
|
if (flush_mask && sigismember (flush_mask, WSTOPSIG (status)))
|
||||||
{
|
{
|
||||||
|
if (!lp->signalled)
|
||||||
|
{
|
||||||
|
lp->stopped = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
|
ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
|
||||||
if (debug_lin_lwp)
|
if (debug_lin_lwp)
|
||||||
@@ -822,6 +833,88 @@ stop_wait_callback (struct lwp_info *lp, void *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check whether PID has any pending signals in FLUSH_MASK. If so set
|
||||||
|
the appropriate bits in PENDING, and return 1 - otherwise return 0. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
lin_lwp_has_pending (int pid, sigset_t *pending, sigset_t *flush_mask)
|
||||||
|
{
|
||||||
|
sigset_t blocked, ignored;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
linux_proc_pending_signals (pid, pending, &blocked, &ignored);
|
||||||
|
|
||||||
|
if (!flush_mask)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 1; i < NSIG; i++)
|
||||||
|
if (sigismember (pending, i))
|
||||||
|
if (!sigismember (flush_mask, i)
|
||||||
|
|| sigismember (&blocked, i)
|
||||||
|
|| sigismember (&ignored, i))
|
||||||
|
sigdelset (pending, i);
|
||||||
|
|
||||||
|
if (sigisemptyset (pending))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DATA is interpreted as a mask of signals to flush. If LP has
|
||||||
|
signals pending, and they are all in the flush mask, then arrange
|
||||||
|
to flush them. LP should be stopped, as should all other threads
|
||||||
|
it might share a signal queue with. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
flush_callback (struct lwp_info *lp, void *data)
|
||||||
|
{
|
||||||
|
sigset_t *flush_mask = data;
|
||||||
|
sigset_t pending, intersection, blocked, ignored;
|
||||||
|
int pid, status;
|
||||||
|
|
||||||
|
/* Normally, when an LWP exits, it is removed from the LWP list. The
|
||||||
|
last LWP isn't removed till later, however. So if there is only
|
||||||
|
one LWP on the list, make sure it's alive. */
|
||||||
|
if (lwp_list == lp && lp->next == NULL)
|
||||||
|
if (!lin_lwp_thread_alive (lp->ptid))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Just because the LWP is stopped doesn't mean that new signals
|
||||||
|
can't arrive from outside, so this function must be careful of
|
||||||
|
race conditions. However, because all threads are stopped, we
|
||||||
|
can assume that the pending mask will not shrink unless we resume
|
||||||
|
the LWP, and that it will then get another signal. We can't
|
||||||
|
control which one, however. */
|
||||||
|
|
||||||
|
if (lp->status)
|
||||||
|
{
|
||||||
|
if (debug_lin_lwp)
|
||||||
|
printf_unfiltered ("FC: LP has pending status %06x\n", lp->status);
|
||||||
|
if (WIFSTOPPED (lp->status) && sigismember (flush_mask, WSTOPSIG (lp->status)))
|
||||||
|
lp->status = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (lin_lwp_has_pending (GET_LWP (lp->ptid), &pending, flush_mask))
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
ret = ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
|
||||||
|
if (debug_lin_lwp)
|
||||||
|
fprintf_unfiltered (gdb_stderr,
|
||||||
|
"FC: Sent PTRACE_CONT, ret %d %d\n", ret, errno);
|
||||||
|
|
||||||
|
lp->stopped = 0;
|
||||||
|
stop_wait_callback (lp, flush_mask);
|
||||||
|
if (debug_lin_lwp)
|
||||||
|
fprintf_unfiltered (gdb_stderr,
|
||||||
|
"FC: Wait finished; saved status is %d\n",
|
||||||
|
lp->status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return non-zero if LP has a wait status pending. */
|
/* Return non-zero if LP has a wait status pending. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -1465,6 +1558,7 @@ retry:
|
|||||||
/* ... and wait until all of them have reported back that they're no
|
/* ... and wait until all of them have reported back that they're no
|
||||||
longer running. */
|
longer running. */
|
||||||
iterate_over_lwps (stop_wait_callback, &flush_mask);
|
iterate_over_lwps (stop_wait_callback, &flush_mask);
|
||||||
|
iterate_over_lwps (flush_callback, &flush_mask);
|
||||||
|
|
||||||
/* If we're not waiting for a specific LWP, choose an event LWP from
|
/* If we're not waiting for a specific LWP, choose an event LWP from
|
||||||
among those that have had events. Giving equal priority to all
|
among those that have had events. Giving equal priority to all
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ extern int linux_proc_xfer_memory (CORE_ADDR addr, char *myaddr, int len,
|
|||||||
int write, struct mem_attrib *attrib,
|
int write, struct mem_attrib *attrib,
|
||||||
struct target_ops *target);
|
struct target_ops *target);
|
||||||
|
|
||||||
|
/* Find process PID's pending signal set from /proc/pid/status. */
|
||||||
|
void linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigset_t *ignored);
|
||||||
|
|
||||||
/* linux-nat functions for handling fork events. */
|
/* linux-nat functions for handling fork events. */
|
||||||
extern void linux_record_stopped_pid (int pid);
|
extern void linux_record_stopped_pid (int pid);
|
||||||
extern void linux_enable_event_reporting (ptid_t ptid);
|
extern void linux_enable_event_reporting (ptid_t ptid);
|
||||||
|
|||||||
@@ -35,6 +35,8 @@
|
|||||||
#include "cli/cli-decode.h" /* for add_info */
|
#include "cli/cli-decode.h" /* for add_info */
|
||||||
#include "gdb_string.h"
|
#include "gdb_string.h"
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#include "linux-nat.h"
|
#include "linux-nat.h"
|
||||||
|
|
||||||
#ifndef O_LARGEFILE
|
#ifndef O_LARGEFILE
|
||||||
@@ -622,3 +624,84 @@ linux_proc_xfer_memory (CORE_ADDR addr, char *myaddr, int len, int write,
|
|||||||
close (fd);
|
close (fd);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse LINE as a signal set and add its set bits to SIGS. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
linux_proc_add_line_to_sigset (const char *line, sigset_t *sigs)
|
||||||
|
{
|
||||||
|
int len = strlen (line) - 1;
|
||||||
|
const char *p;
|
||||||
|
int signum;
|
||||||
|
|
||||||
|
if (line[len] != '\n')
|
||||||
|
error ("Could not parse signal set: %s", line);
|
||||||
|
|
||||||
|
p = line;
|
||||||
|
signum = len * 4;
|
||||||
|
while (len-- > 0)
|
||||||
|
{
|
||||||
|
int digit;
|
||||||
|
|
||||||
|
if (*p >= '0' && *p <= '9')
|
||||||
|
digit = *p - '0';
|
||||||
|
else if (*p >= 'a' && *p <= 'f')
|
||||||
|
digit = *p - 'a' + 10;
|
||||||
|
else
|
||||||
|
error ("Could not parse signal set: %s", line);
|
||||||
|
|
||||||
|
signum -= 4;
|
||||||
|
|
||||||
|
if (digit & 1)
|
||||||
|
sigaddset (sigs, signum + 1);
|
||||||
|
if (digit & 2)
|
||||||
|
sigaddset (sigs, signum + 2);
|
||||||
|
if (digit & 4)
|
||||||
|
sigaddset (sigs, signum + 3);
|
||||||
|
if (digit & 8)
|
||||||
|
sigaddset (sigs, signum + 4);
|
||||||
|
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find process PID's pending signals from /proc/pid/status and set SIGS
|
||||||
|
to match. */
|
||||||
|
|
||||||
|
void
|
||||||
|
linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigset_t *ignored)
|
||||||
|
{
|
||||||
|
FILE *procfile;
|
||||||
|
char buffer[MAXPATHLEN], fname[MAXPATHLEN];
|
||||||
|
int signum;
|
||||||
|
|
||||||
|
sigemptyset (pending);
|
||||||
|
sigemptyset (blocked);
|
||||||
|
sigemptyset (ignored);
|
||||||
|
sprintf (fname, "/proc/%d/status", pid);
|
||||||
|
procfile = fopen (fname, "r");
|
||||||
|
if (procfile == NULL)
|
||||||
|
error ("Could not open %s", fname);
|
||||||
|
|
||||||
|
while (fgets (buffer, MAXPATHLEN, procfile) != NULL)
|
||||||
|
{
|
||||||
|
/* Normal queued signals are on the SigPnd line in the status
|
||||||
|
file. However, 2.6 kernels also have a "shared" pending queue
|
||||||
|
for delivering signals to a thread group, so check for a ShdPnd
|
||||||
|
line also.
|
||||||
|
|
||||||
|
Unfortunately some Red Hat kernels include the shared pending queue
|
||||||
|
but not the ShdPnd status field. */
|
||||||
|
|
||||||
|
if (strncmp (buffer, "SigPnd:\t", 8) == 0)
|
||||||
|
linux_proc_add_line_to_sigset (buffer + 8, pending);
|
||||||
|
else if (strncmp (buffer, "ShdPnd:\t", 8) == 0)
|
||||||
|
linux_proc_add_line_to_sigset (buffer + 8, pending);
|
||||||
|
else if (strncmp (buffer, "SigBlk:\t", 8) == 0)
|
||||||
|
linux_proc_add_line_to_sigset (buffer + 8, blocked);
|
||||||
|
else if (strncmp (buffer, "SigIgn:\t", 8) == 0)
|
||||||
|
linux_proc_add_line_to_sigset (buffer + 8, ignored);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose (procfile);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user