diff options
author | Pedro Alves <palves@redhat.com> | 2008-10-23 23:11:21 +0000 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2008-10-23 23:11:21 +0000 |
commit | 252fbfc86a997c0750804d5cdd3ae395d24bebc4 (patch) | |
tree | fdf60a6c2b8e6ca47d061cf7e987795cc9feab83 /gdb/linux-nat.c | |
parent | 3c0ed2996e2f868939b67b8b83785c5d5c114474 (diff) | |
download | gdb-252fbfc86a997c0750804d5cdd3ae395d24bebc4.zip gdb-252fbfc86a997c0750804d5cdd3ae395d24bebc4.tar.gz gdb-252fbfc86a997c0750804d5cdd3ae395d24bebc4.tar.bz2 |
gdb/
2008-10-23 Pedro Alves <pedro@codesourcery.com>
* defs.h: Mention ptid_is_pid.
* inferior.h (ptid_is_pid): Declare.
* gdbthread.h (struct thread_info) <stop_requested>: New field.
(set_stop_requested): Declare.
* infcmd.c (interrupt_target_1): Call set_stop_requested.
* infrun.c (clear_proceed_status): Clear stop_requested.
(infrun_thread_stop_requested_callback,
infrun_thread_stop_requested): New.
(handle_inferior_event): If a TARGET_SIGNAL_TRAP is reported on a
thread that had an explicit stop request, pretend we got a
TARGET_SIGNAL_0. Always stop if the thread had an explicit stop
request.
(print_stop_reason): In the SIGNAL_RECEIVED case, if we're not
outputting to MI, and we got a TARGET_SIGNAL_0, print "# Stopped",
instead of mentioning signal 0.
(ptid_is_pid): New.
* thread.c (set_stop_requested): New.
* linux-nat.c (queued_waitpid): Rename to ...
(queued_waitpid_1): ... this. Add `peek' argument. Handle it.
(queued_waitpid): New, as wrapper to queued_waitpid_1.
(push_waitpid): Push the SIGTRAP to the local event queue, to the
kernel's.
(send_sigint_callback): Delete.
(linux_nat_stop_lwp): New.
(linux_nat_stop): Use it.
gdb/doc/
2008-10-23 Pedro Alves <pedro@codesourcery.com>
* observer.texi (thread_stop_requested): New.
gdb/testsuite/
2008-10-23 Pedro Alves <pedro@codesourcery.com>
* lib/mi-support.exp (mi_expect_interrupt): Expect signal 0
instead of SIGINT.
Diffstat (limited to 'gdb/linux-nat.c')
-rw-r--r-- | gdb/linux-nat.c | 128 |
1 files changed, 100 insertions, 28 deletions
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index f76eaec..d2116e1 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -316,7 +316,6 @@ static void linux_nat_async (void (*callback) static int linux_nat_async_mask (int mask); static int kill_lwp (int lwpid, int signo); -static int send_sigint_callback (struct lwp_info *lp, void *data); static int stop_callback (struct lwp_info *lp, void *data); /* Captures the result of a successful waitpid call, along with the @@ -333,8 +332,12 @@ struct waitpid_result in the async SIGCHLD handler. */ static struct waitpid_result *waitpid_queue = NULL; +/* Similarly to `waitpid', but check the local event queue instead of + querying the kernel queue. If PEEK, don't remove the event found + from the queue. */ + static int -queued_waitpid (int pid, int *status, int flags) +queued_waitpid_1 (int pid, int *status, int flags, int peek) { struct waitpid_result *msg = waitpid_queue, *prev = NULL; @@ -370,12 +373,6 @@ QWPID: linux_nat_async_events_state(%d), linux_nat_num_queued_events(%d)\n", { int pid; - if (prev) - prev->next = msg->next; - else - waitpid_queue = msg->next; - - msg->next = NULL; if (status) *status = msg->status; pid = msg->pid; @@ -383,7 +380,17 @@ QWPID: linux_nat_async_events_state(%d), linux_nat_num_queued_events(%d)\n", if (debug_linux_nat_async) fprintf_unfiltered (gdb_stdlog, "QWPID: pid(%d), status(%x)\n", pid, msg->status); - xfree (msg); + + if (!peek) + { + if (prev) + prev->next = msg->next; + else + waitpid_queue = msg->next; + + msg->next = NULL; + xfree (msg); + } return pid; } @@ -396,6 +403,14 @@ QWPID: linux_nat_async_events_state(%d), linux_nat_num_queued_events(%d)\n", return -1; } +/* Similarly to `waitpid', but check the local event queue. */ + +static int +queued_waitpid (int pid, int *status, int flags) +{ + return queued_waitpid_1 (pid, status, flags, 0); +} + static void push_waitpid (int pid, int status, int options) { @@ -2200,11 +2215,11 @@ stop_wait_callback (struct lwp_info *lp, void *data) /* 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)); + fprintf_unfiltered (gdb_stdlog, "\ +SWC: leaving SIGTRAP in local queue of %s\n", target_pid_to_str (lp->ptid)); + push_waitpid (GET_LWP (lp->ptid), + W_STOPCODE (SIGTRAP), + lp->cloned ? __WCLONE : 0); } } else @@ -4368,15 +4383,76 @@ linux_nat_async (void (*callback) (enum inferior_event_type event_type, return; } +/* Stop an LWP, and push a TARGET_SIGNAL_0 stop status if no other + event came out. */ + static int -send_sigint_callback (struct lwp_info *lp, void *data) +linux_nat_stop_lwp (struct lwp_info *lwp, void *data) { - /* Use is_running instead of !lp->stopped, because the lwp may be - stopped due to an internal event, and we want to interrupt it in - that case too. What we want is to check if the thread is stopped - from the point of view of the user. */ - if (is_running (lp->ptid)) - kill_lwp (GET_LWP (lp->ptid), SIGINT); + ptid_t ptid = * (ptid_t *) data; + + if (ptid_equal (lwp->ptid, ptid) + || ptid_equal (minus_one_ptid, ptid) + || (ptid_is_pid (ptid) + && ptid_get_pid (ptid) == ptid_get_pid (lwp->ptid))) + { + if (!lwp->stopped) + { + int pid, status; + + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LNSL: running -> suspending %s\n", + target_pid_to_str (lwp->ptid)); + + /* Peek once, to check if we've already waited for this + LWP. */ + pid = queued_waitpid_1 (ptid_get_lwp (lwp->ptid), &status, + lwp->cloned ? __WCLONE : 0, 1 /* peek */); + + if (pid == -1) + { + ptid_t ptid = lwp->ptid; + + stop_callback (lwp, NULL); + stop_wait_callback (lwp, NULL); + + /* If the lwp exits while we try to stop it, there's + nothing else to do. */ + lwp = find_lwp_pid (ptid); + if (lwp == NULL) + return 0; + + pid = queued_waitpid_1 (ptid_get_lwp (lwp->ptid), &status, + lwp->cloned ? __WCLONE : 0, + 1 /* peek */); + } + + /* If we didn't collect any signal other than SIGSTOP while + stopping the LWP, push a SIGNAL_0 event. In either case, + the event-loop will end up calling target_wait which will + collect these. */ + if (pid == -1) + push_waitpid (ptid_get_lwp (lwp->ptid), W_STOPCODE (0), + lwp->cloned ? __WCLONE : 0); + } + else + { + /* Already known to be stopped; do nothing. */ + + if (debug_linux_nat) + { + if (find_thread_pid (lwp->ptid)->stop_requested) + fprintf_unfiltered (gdb_stdlog, "\ +LNSL: already stopped/stop_requested %s\n", + target_pid_to_str (lwp->ptid)); + else + fprintf_unfiltered (gdb_stdlog, "\ +LNSL: already stopped/no stop_requested yet %s\n", + target_pid_to_str (lwp->ptid)); + } + } + } return 0; } @@ -4385,13 +4461,9 @@ linux_nat_stop (ptid_t ptid) { if (non_stop) { - if (ptid_equal (ptid, minus_one_ptid)) - iterate_over_lwps (send_sigint_callback, &ptid); - else - { - struct lwp_info *lp = find_lwp_pid (ptid); - send_sigint_callback (lp, NULL); - } + linux_nat_async_events (sigchld_sync); + iterate_over_lwps (linux_nat_stop_lwp, &ptid); + target_async (inferior_event_handler, 0); } else linux_ops->to_stop (ptid); |