2008-03-25 Pedro Alves <pedro@codesourcery.com>

* linux-nat.c (drain_queued_events): Fix comment typo.
	(linux_nat_attach): In async mode, don't rely on storing a pending
	status.  Instead place the wait status on the pipe.
	(linux_nat_resume): Remove unreacheable shortcut code in async
	mode.
	(stop_wait_callback): In async mode, don't store pending status.
	Instead, cancel breakpoints or resend the signal appropriatelly.
	(cancel_breakpoint): New, refactored from
	cancel_breakpoints_callback.
	(cancel_breakpoints_callback): Call cancel_breakpoint.
	(pipe_to_local_event_queue): Remove special token processing.
	(linux_nat_wait): Issue an internal error if a pending status is
	found in async mode.
This commit is contained in:
Pedro Alves 2008-03-25 12:20:10 +00:00
parent bd52eafbd6
commit 710151dda5
2 changed files with 119 additions and 59 deletions

View File

@ -1,3 +1,19 @@
2008-03-25 Pedro Alves <pedro@codesourcery.com>
* linux-nat.c (drain_queued_events): Fix comment typo.
(linux_nat_attach): In async mode, don't rely on storing a pending
status. Instead place the wait status on the pipe.
(linux_nat_resume): Remove unreacheable shortcut code in async
mode.
(stop_wait_callback): In async mode, don't store pending status.
Instead, cancel breakpoints or resend the signal appropriatelly.
(cancel_breakpoint): New, refactored from
cancel_breakpoints_callback.
(cancel_breakpoints_callback): Call cancel_breakpoint.
(pipe_to_local_event_queue): Remove special token processing.
(linux_nat_wait): Issue an internal error if a pending status is
found in async mode.
2008-03-24 Daniel Jacobowitz <dan@codesourcery.com>
* inflow.c (gdb_has_a_terminal): Guard access to our_process_group.

View File

@ -288,7 +288,7 @@ push_waitpid (int pid, int status, int options)
waitpid_queue = new_event;
}
/* Drain all queued event of PID. If PID is -1, the effect is of
/* Drain all queued events of PID. If PID is -1, the effect is of
draining all events. */
static void
drain_queued_events (int pid)
@ -799,6 +799,8 @@ static struct sigaction async_sigchld_action;
static int stop_wait_callback (struct lwp_info *lp, void *data);
static int linux_nat_thread_alive (ptid_t ptid);
static char *linux_child_pid_to_exec_file (int pid);
static int cancel_breakpoint (struct lwp_info *lp);
/* Convert wait status STATUS to a string. Used for printing debug
messages only. */
@ -1134,6 +1136,7 @@ linux_nat_attach (char *args, int from_tty)
pid_t pid;
int status;
int cloned = 0;
int options = 0;
/* FIXME: We should probably accept a list of process id's, and
attach all of them. */
@ -1151,13 +1154,14 @@ linux_nat_attach (char *args, int from_tty)
/* Make sure the initial process is stopped. The user-level threads
layer might want to poke around in the inferior, and that won't
work if things haven't stabilized yet. */
pid = my_waitpid (GET_PID (inferior_ptid), &status, 0);
pid = my_waitpid (GET_PID (inferior_ptid), &status, options);
if (pid == -1 && errno == ECHILD)
{
warning (_("%s is a cloned process"), target_pid_to_str (inferior_ptid));
/* Try again with __WCLONE to check cloned processes. */
pid = my_waitpid (GET_PID (inferior_ptid), &status, __WCLONE);
options = __WCLONE;
pid = my_waitpid (GET_PID (inferior_ptid), &status, options);
cloned = 1;
}
@ -1170,17 +1174,22 @@ linux_nat_attach (char *args, int from_tty)
lp->cloned = cloned;
lp->stopped = 1;
/* Fake the SIGSTOP that core GDB expects. */
lp->status = W_STOPCODE (SIGSTOP);
lp->resumed = 1;
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LNA: waitpid %ld, faking SIGSTOP\n", (long) pid);
if (target_can_async_p ())
if (!target_can_async_p ())
{
/* Wake event loop with special token, to get to WFI. */
linux_nat_event_pipe_push (-1, -1, -1);
/* Fake the SIGSTOP that core GDB expects. */
lp->status = W_STOPCODE (SIGSTOP);
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"LNA: waitpid %ld, faking SIGSTOP\n", (long) pid);
}
else
{
/* We already waited for this LWP, so put the wait result on the
pipe. The event loop will wake up and gets us to handling
this event. */
linux_nat_event_pipe_push (pid, status, options);
/* Register in the event loop. */
target_async (inferior_event_handler, 0);
}
@ -1358,6 +1367,10 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
other threads. This bit of code needs to be synchronized
with linux_nat_wait. */
/* In async mode, we never have pending wait status. */
if (target_can_async_p () && lp->status)
internal_error (__FILE__, __LINE__, "Pending status in async mode");
if (lp->status && WIFSTOPPED (lp->status))
{
int saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
@ -1390,13 +1403,6 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
"LLR: Short circuiting for status 0x%x\n",
lp->status);
if (target_can_async_p ())
{
/* Wake event loop with special token, to get to WFI. */
linux_nat_event_pipe_push (-1, -1, -1);
target_async (inferior_event_handler, 0);
}
return;
}
@ -1752,22 +1758,44 @@ stop_wait_callback (struct lwp_info *lp, void *data)
"SWC: Candidate SIGTRAP event in %s\n",
target_pid_to_str (lp->ptid));
}
/* Hold the SIGTRAP for handling by linux_nat_wait. */
/* Hold this event/waitstatus while we check to see if
there are any more (we still want to get that SIGSTOP). */
stop_wait_callback (lp, data);
/* If there's another event, throw it back into the queue. */
if (lp->status)
if (target_can_async_p ())
{
if (debug_linux_nat)
/* Don't leave a pending wait status in async mode.
Retrigger the breakpoint. */
if (!cancel_breakpoint (lp))
{
fprintf_unfiltered (gdb_stdlog,
"SWC: kill %s, %s\n",
target_pid_to_str (lp->ptid),
status_to_str ((int) status));
/* There was no gdb breakpoint set at pc. Put
the event back in the queue. */
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"SWC: kill %s, %s\n",
target_pid_to_str (lp->ptid),
status_to_str ((int) status));
kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
}
kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
}
/* Save the sigtrap event. */
lp->status = status;
else
{
/* Hold the SIGTRAP for handling by
linux_nat_wait. */
/* If there's another event, throw it back into the
queue. */
if (lp->status)
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"SWC: kill %s, %s\n",
target_pid_to_str (lp->ptid),
status_to_str ((int) status));
kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
}
/* Save the sigtrap event. */
lp->status = status;
}
return 0;
}
else
@ -1794,12 +1822,11 @@ stop_wait_callback (struct lwp_info *lp, void *data)
/* Hold this event/waitstatus while we check to see if
there are any more (we still want to get that SIGSTOP). */
stop_wait_callback (lp, data);
/* If the lp->status field is still empty, use it to hold
this event. If not, then this event must be returned
to the event queue of the LWP. */
if (lp->status == 0)
lp->status = status;
else
/* If the lp->status field is still empty, use it to
hold this event. If not, then this event must be
returned to the event queue of the LWP. */
if (lp->status || target_can_async_p ())
{
if (debug_linux_nat)
{
@ -1810,6 +1837,8 @@ stop_wait_callback (struct lwp_info *lp, void *data)
}
kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
}
else
lp->status = status;
return 0;
}
}
@ -1979,6 +2008,37 @@ select_event_lwp_callback (struct lwp_info *lp, void *data)
return 0;
}
static int
cancel_breakpoint (struct lwp_info *lp)
{
/* Arrange for a breakpoint to be hit again later. We don't keep
the SIGTRAP status and don't forward the SIGTRAP signal to the
LWP. We will handle the current event, eventually we will resume
this LWP, and this breakpoint will trap again.
If we do not do this, then we run the risk that the user will
delete or disable the breakpoint, but the LWP will have already
tripped on it. */
if (breakpoint_inserted_here_p (read_pc_pid (lp->ptid) -
gdbarch_decr_pc_after_break
(current_gdbarch)))
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"CB: Push back breakpoint for %s\n",
target_pid_to_str (lp->ptid));
/* Back up the PC if necessary. */
if (gdbarch_decr_pc_after_break (current_gdbarch))
write_pc_pid (read_pc_pid (lp->ptid) - gdbarch_decr_pc_after_break
(current_gdbarch),
lp->ptid);
return 1;
}
return 0;
}
static int
cancel_breakpoints_callback (struct lwp_info *lp, void *data)
{
@ -2001,24 +2061,9 @@ cancel_breakpoints_callback (struct lwp_info *lp, void *data)
if (lp->status != 0
&& WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP
&& breakpoint_inserted_here_p (read_pc_pid (lp->ptid) -
gdbarch_decr_pc_after_break
(current_gdbarch)))
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"CBC: Push back breakpoint for %s\n",
target_pid_to_str (lp->ptid));
/* Back up the PC if necessary. */
if (gdbarch_decr_pc_after_break (current_gdbarch))
write_pc_pid (read_pc_pid (lp->ptid) - gdbarch_decr_pc_after_break
(current_gdbarch),
lp->ptid);
/* Throw away the SIGTRAP. */
lp->status = 0;
}
&& cancel_breakpoint (lp))
/* Throw away the SIGTRAP. */
lp->status = 0;
return 0;
}
@ -2288,12 +2333,7 @@ pipe_to_local_event_queue (void)
while (linux_nat_num_queued_events)
{
int lwpid, status, options;
lwpid = linux_nat_event_pipe_pop (&status, &options);
if (lwpid == -1 && status == -1 && options == -1)
/* Special wake up event loop token. */
continue;
gdb_assert (lwpid > 0);
push_waitpid (lwpid, status, options);
}
@ -2367,6 +2407,10 @@ retry:
lp = iterate_over_lwps (status_callback, NULL);
if (lp)
{
if (target_can_async_p ())
internal_error (__FILE__, __LINE__,
"Found an LWP with a pending status in async mode.");
status = lp->status;
lp->status = 0;