+2010-05-03 Pedro Alves <pedro@codesourcery.com>
+
+ * linux-low.c (linux_kill, linux_detach): Adjust.
+ (status_pending_p_callback): Remove redundant statement. Check
+ for !TARGET_WAITIKIND_IGNORE, instead of
+ TARGET_WAITKIND_STOPPED.
+ (handle_tracepoints): Make sure LWP is locked. Adjust.
+ (linux_wait_for_event_1): Adjust.
+ (linux_cancel_breakpoints): New.
+ (unsuspend_one_lwp): New.
+ (unsuspend_all_lwps): New.
+ (linux_wait_1): If finishing a step-over, unsuspend all lwps.
+ (send_sigstop_callback): Change return type to int, add new
+ `except' parameter and handle it.
+ (suspend_and_send_sigstop_callback): New.
+ (stop_all_lwps): Add new `suspend' and `expect' parameters, and
+ pass them down. If SUSPEND, also increment the lwp's suspend
+ count.
+ (linux_resume_one_lwp): Add notice about resuming a suspended LWP.
+ (need_step_over_p): Don't consider suspended LWPs.
+ (start_step_over): Adjust.
+ (proceed_one_lwp): Change return type to int, add new `except'
+ parameter and handle it.
+ (unsuspend_and_proceed_one_lwp): New.
+ (proceed_all_lwps): Use find_inferior instead of
+ for_each_inferior.
+ (unstop_all_lwps): Add `unsuspend' parameter. If UNSUSPEND, them
+ also decrement the suspend count of LWPs. Pass `except' down,
+ instead of hacking its suspend count.
+ (linux_pause_all): Add `freeze' parameter. Adjust.
+ (linux_unpause_all): New.
+ (linux_target_ops): Install linux_unpause_all.
+ * server.c (handle_status): Adjust.
+ * target.h (struct target_ops): New fields `unpause_all' and
+ `cancel_breakpoints'. Add new parameter to `pause_all'.
+ (pause_all): Add new `freeze' parameter.
+ (unpause_all): New.
+ (cancel_breakpoints): New.
+ * tracepoint.c (clear_installed_tracepoints): Pause threads, and
+ cancel breakpoints.
+ (cmd_qtstart): Pause threads.
+ (stop_tracing): Pause threads, and cancel breakpoints.
+ * win32-low.c (win32_target_ops): Adjust.
+
2010-05-03 Pedro Alves <pedro@codesourcery.com>
* linux-low.c (linux_wait_for_event_1): Move passing the signal to
static void linux_resume_one_lwp (struct lwp_info *lwp,
int step, int signal, siginfo_t *info);
static void linux_resume (struct thread_resume *resume_info, size_t n);
-static void stop_all_lwps (void);
+static void stop_all_lwps (int suspend, struct lwp_info *except);
+static void unstop_all_lwps (int unsuspend, struct lwp_info *except);
static int linux_wait_for_event (ptid_t ptid, int *wstat, int options);
static void *add_lwp (ptid_t ptid);
static int linux_stopped_by_watchpoint (void);
static void mark_lwp_dead (struct lwp_info *lwp, int wstat);
static int linux_core_of_thread (ptid_t ptid);
static void proceed_all_lwps (void);
-static void unstop_all_lwps (struct lwp_info *except);
static int finish_step_over (struct lwp_info *lwp);
static CORE_ADDR get_stop_pc (struct lwp_info *lwp);
static int kill_lwp (unsigned long lwpid, int signo);
/* If we're killing a running inferior, make sure it is stopped
first, as PTRACE_KILL will not work otherwise. */
- stop_all_lwps ();
+ stop_all_lwps (0, NULL);
find_inferior (&all_threads, linux_kill_one_lwp, &pid);
/* Since we presently can only stop all lwps of all processes, we
need to unstop lwps of other processes. */
- unstop_all_lwps (NULL);
+ unstop_all_lwps (0, NULL);
return 0;
}
the thread is stopped to sucessfully detach. Second, thread_db
may need to uninstall thread event breakpoints from memory, which
only works with a stopped process anyway. */
- stop_all_lwps ();
+ stop_all_lwps (0, NULL);
#ifdef USE_THREAD_DB
thread_db_detach (process);
/* Since we presently can only stop all lwps of all processes, we
need to unstop lwps of other processes. */
- unstop_all_lwps (NULL);
+ unstop_all_lwps (0, NULL);
return 0;
}
{
struct lwp_info *lwp = (struct lwp_info *) entry;
ptid_t ptid = * (ptid_t *) arg;
- struct thread_info *thread = get_lwp_thread (lwp);
+ struct thread_info *thread;
/* Check if we're only interested in events from a specific process
or its lwps. */
/* If we got a `vCont;t', but we haven't reported a stop yet, do
report any status pending the LWP may have. */
if (thread->last_resume_kind == resume_stop
- && thread->last_status.kind == TARGET_WAITKIND_STOPPED)
+ && thread->last_status.kind != TARGET_WAITKIND_IGNORE)
return 0;
return lwp->status_pending_p;
struct thread_info *tinfo = get_lwp_thread (lwp);
int tpoint_related_event = 0;
+ /* If this tracepoint hit causes a tracing stop, we'll immediately
+ uninsert tracepoints. To do this, we temporarily pause all
+ threads, unpatch away, and then unpause threads. We need to make
+ sure the unpausing doesn't resume LWP too. */
+ lwp->suspended++;
+
/* And we need to be sure that any all-threads-stopping doesn't try
to move threads out of the jump pads, as it could deadlock the
inferior (LWP could be in the jump pad, maybe even holding the
actions. */
tpoint_related_event |= tracepoint_was_hit (tinfo, lwp->stop_pc);
+ lwp->suspended--;
+
+ gdb_assert (lwp->suspended == 0);
+
if (tpoint_related_event)
{
if (debug_threads)
/* Cancel the step-over operation --- the thread that
started it is gone. */
if (finish_step_over (event_child))
- unstop_all_lwps (event_child);
+ unstop_all_lwps (1, event_child);
delete_lwp (event_child);
return lwpid;
}
return 0;
}
+static void
+linux_cancel_breakpoints (void)
+{
+ find_inferior (&all_lwps, cancel_breakpoints_callback, NULL);
+}
+
/* Select one LWP out of those that have events pending. */
static void
thread->last_resume_kind = resume_stop;
}
+/* Decrement the suspend count of an LWP. */
+
+static int
+unsuspend_one_lwp (struct inferior_list_entry *entry, void *except)
+{
+ struct lwp_info *lwp = (struct lwp_info *) entry;
+
+ /* Ignore EXCEPT. */
+ if (lwp == except)
+ return 0;
+
+ lwp->suspended--;
+
+ gdb_assert (lwp->suspended >= 0);
+ return 0;
+}
+
+/* Decrement the suspend count of all LWPs, except EXCEPT, if non
+ NULL. */
+
+static void
+unsuspend_all_lwps (struct lwp_info *except)
+{
+ find_inferior (&all_lwps, unsuspend_one_lwp, except);
+}
+
/* Set all LWP's states as "want-stopped". */
static void
(*the_low_target.set_pc) (regcache, event_child->stop_pc);
}
- /* We've finished stepping over a breakpoint. We've stopped all
- LWPs momentarily except the stepping one. This is where we
- resume them all again. We're going to keep waiting, so use
- proceed, which handles stepping over the next breakpoint. */
+ /* We may have finished stepping over a breakpoint. If so,
+ we've stopped and suspended all LWPs momentarily except the
+ stepping one. This is where we resume them all again. We're
+ going to keep waiting, so use proceed, which handles stepping
+ over the next breakpoint. */
if (debug_threads)
fprintf (stderr, "proceeding all threads.\n");
+
+ if (step_over_finished)
+ unsuspend_all_lwps (event_child);
+
proceed_all_lwps ();
goto retry;
}
if (!non_stop)
{
/* In all-stop, stop all threads. */
- stop_all_lwps ();
+ stop_all_lwps (0, NULL);
/* If we're not waiting for a specific LWP, choose an event LWP
from among those that have had events. Giving equal priority
threads stopped by now anyway. In non-stop, we need to
re-resume threads that GDB wanted to be running. */
if (step_over_finished)
- unstop_all_lwps (event_child);
+ unstop_all_lwps (1, event_child);
}
ourstatus->kind = TARGET_WAITKIND_STOPPED;
ourstatus->kind,
ourstatus->value.sig);
- get_lwp_thread (event_child)->last_status = *ourstatus;
+ current_inferior->last_status = *ourstatus;
+
return ptid_of (event_child);
}
kill_lwp (pid, SIGSTOP);
}
-static void
-send_sigstop_callback (struct inferior_list_entry *entry)
+static int
+send_sigstop_callback (struct inferior_list_entry *entry, void *except)
{
struct lwp_info *lwp = (struct lwp_info *) entry;
+ /* Ignore EXCEPT. */
+ if (lwp == except)
+ return 0;
+
if (lwp->stopped)
- return;
+ return 0;
send_sigstop (lwp);
+ return 0;
+}
+
+/* Increment the suspend count of an LWP, and stop it, if not stopped
+ yet. */
+static int
+suspend_and_send_sigstop_callback (struct inferior_list_entry *entry,
+ void *except)
+{
+ struct lwp_info *lwp = (struct lwp_info *) entry;
+
+ /* Ignore EXCEPT. */
+ if (lwp == except)
+ return 0;
+
+ lwp->suspended++;
+
+ return send_sigstop_callback (entry, except);
}
static void
}
}
+/* Stop all lwps that aren't stopped yet, except EXCEPT, if not NULL.
+ If SUSPEND, then also increase the suspend count of every LWP,
+ except EXCEPT. */
+
static void
-stop_all_lwps (void)
+stop_all_lwps (int suspend, struct lwp_info *except)
{
stopping_threads = 1;
- for_each_inferior (&all_lwps, send_sigstop_callback);
+
+ if (suspend)
+ find_inferior (&all_lwps, suspend_and_send_sigstop_callback, except);
+ else
+ find_inferior (&all_lwps, send_sigstop_callback, except);
for_each_inferior (&all_lwps, wait_for_sigstop);
stopping_threads = 0;
}
{
if (step == 0)
fprintf (stderr, "BAD - reinserting but not stepping.\n");
+ if (lwp->suspended)
+ fprintf (stderr, "BAD - reinserting and suspended(%d).\n",
+ lwp->suspended);
step = 1;
}
return 0;
}
+ gdb_assert (lwp->suspended >= 0);
+
+ if (lwp->suspended)
+ {
+ if (debug_threads)
+ fprintf (stderr,
+ "Need step over [LWP %ld]? Ignoring, suspended\n",
+ lwpid_of (lwp));
+ return 0;
+ }
+
if (!lwp->need_step_over)
{
if (debug_threads)
"Starting step-over on LWP %ld. Stopping all threads\n",
lwpid_of (lwp));
- stop_all_lwps ();
+ stop_all_lwps (1, lwp);
+ gdb_assert (lwp->suspended == 0);
if (debug_threads)
fprintf (stderr, "Done stopping all threads for step-over.\n");
breakpoint that needs stepping over, we start a step-over operation
on that particular thread, and leave all others stopped. */
-static void
-proceed_one_lwp (struct inferior_list_entry *entry)
+static int
+proceed_one_lwp (struct inferior_list_entry *entry, void *except)
{
- struct lwp_info *lwp;
+ struct lwp_info *lwp = (struct lwp_info *) entry;
struct thread_info *thread;
int step;
- lwp = (struct lwp_info *) entry;
+ if (lwp == except)
+ return 0;
if (debug_threads)
fprintf (stderr,
{
if (debug_threads)
fprintf (stderr, " LWP %ld already running\n", lwpid_of (lwp));
- return;
+ return 0;
}
thread = get_lwp_thread (lwp);
if (debug_threads)
fprintf (stderr, " client wants LWP to remain %ld stopped\n",
lwpid_of (lwp));
- return;
+ return 0;
}
if (lwp->status_pending_p)
if (debug_threads)
fprintf (stderr, " LWP %ld has pending status, leaving stopped\n",
lwpid_of (lwp));
- return;
+ return 0;
}
+ gdb_assert (lwp->suspended >= 0);
+
if (lwp->suspended)
{
if (debug_threads)
fprintf (stderr, " LWP %ld is suspended\n", lwpid_of (lwp));
- return;
+ return 0;
}
if (thread->last_resume_kind == resume_stop)
step = thread->last_resume_kind == resume_step;
linux_resume_one_lwp (lwp, step, 0, NULL);
+ return 0;
+}
+
+static int
+unsuspend_and_proceed_one_lwp (struct inferior_list_entry *entry, void *except)
+{
+ struct lwp_info *lwp = (struct lwp_info *) entry;
+
+ if (lwp == except)
+ return 0;
+
+ lwp->suspended--;
+ gdb_assert (lwp->suspended >= 0);
+
+ return proceed_one_lwp (entry, except);
}
/* When we finish a step-over, set threads running again. If there's
if (debug_threads)
fprintf (stderr, "Proceeding, no step-over needed\n");
- for_each_inferior (&all_lwps, proceed_one_lwp);
+ find_inferior (&all_lwps, proceed_one_lwp, NULL);
}
/* Stopped LWPs that the client wanted to be running, that don't have
NULL. This undoes a stop_all_lwps call. */
static void
-unstop_all_lwps (struct lwp_info *except)
+unstop_all_lwps (int unsuspend, struct lwp_info *except)
{
if (debug_threads)
{
"unstopping all lwps\n");
}
- /* Make sure proceed_one_lwp doesn't try to resume this thread. */
- if (except != NULL)
- ++except->suspended;
-
- for_each_inferior (&all_lwps, proceed_one_lwp);
-
- if (except != NULL)
- --except->suspended;
+ if (unsuspend)
+ find_inferior (&all_lwps, unsuspend_and_proceed_one_lwp, except);
+ else
+ find_inferior (&all_lwps, proceed_one_lwp, except);
}
#ifdef HAVE_LINUX_USRREGS
/* This exposes stop-all-threads functionality to other modules. */
static void
-linux_pause_all (void)
+linux_pause_all (int freeze)
{
- stop_all_lwps ();
+ stop_all_lwps (freeze, NULL);
+}
+
+/* This exposes unstop-all-threads functionality to other gdbserver
+ modules. */
+
+static void
+linux_unpause_all (int unfreeze)
+{
+ unstop_all_lwps (unfreeze, NULL);
}
static struct target_ops linux_target_ops = {
linux_read_pc,
linux_write_pc,
linux_thread_stopped,
+ NULL,
linux_pause_all,
- NULL, /* get_tib_address (Windows OS specific). */
+ linux_unpause_all,
+ linux_cancel_breakpoints
};
static void