From 710151dda51c86ee63e65409f87ad3b0ccc54936 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Tue, 25 Mar 2008 12:20:10 +0000 Subject: [PATCH] 2008-03-25 Pedro Alves * 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. --- gdb/ChangeLog | 16 +++++ gdb/linux-nat.c | 162 ++++++++++++++++++++++++++++++------------------ 2 files changed, 119 insertions(+), 59 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 971ac43b00a..04792dfdd93 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,19 @@ +2008-03-25 Pedro Alves + + * 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 * inflow.c (gdb_has_a_terminal): Guard access to our_process_group. diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index b097408a900..e2ef962e125 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -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; -- 2.30.2