[gdbserver] linux-low.c: better starvation avoidance, handle non-stop mode too

This patch applies the same starvation avoidance improvements of the
previous patch to the Linux gdbserver side.

Without this, the test added by the following commit
(gdb.threads/non-stop-fair-events.exp) always fails with time outs.

gdb/gdbserver/
2015-01-09  Pedro Alves  <palves@redhat.com>

	* linux-low.c (step_over_bkpt): Move higher up in the file.
	(handle_extended_wait): Don't store the stop_pc here.
	(get_stop_pc): Adjust comments and rename to ...
	(check_stopped_by_breakpoint): ... this.  Record whether the LWP
	stopped for a software breakpoint or hardware breakpoint.
	(thread_still_has_status_pending_p): New function.
	(status_pending_p_callback): Use
	thread_still_has_status_pending_p.  If the event is no longer
	interesting, resume the LWP.
	(handle_tracepoints): Add assert.
	(maybe_move_out_of_jump_pad): Remove cancel_breakpoints call.
	(wstatus_maybe_breakpoint): New function.
	(cancel_breakpoint): Delete function.
	(check_stopped_by_watchpoint): New function, factored out from
	linux_low_filter_event.
	(lp_status_maybe_breakpoint): Delete function.
	(linux_low_filter_event): Remove filter_ptid argument.
	Leave thread group exits pending here.	Store the LWP's stop PC.
	Always leave events pending.
	(linux_wait_for_event_filtered): Pull all events out of the
	kernel, and leave them all pending.
	(count_events_callback, select_event_lwp_callback): Consider all
	events.
	(cancel_breakpoints_callback, linux_cancel_breakpoints): Delete.
	(select_event_lwp): Only give preference to the stepping LWP in
	all-stop mode.	Adjust comments.
	(ignore_event): New function.
	(linux_wait_1): Delete 'retry' label.  Use ignore_event.  Remove
	references to cancel_breakpoints.  Adjust to renames.  Also give
	equal priority to all LWPs that have had events in non-stop mode.
	If reporting a software breakpoint event, unadjust the LWP's PC.
	(linux_wait): If linux_wait_1 returned an ignored event, retry.
	(stuck_in_jump_pad_callback, move_out_of_jump_pad_callback):
	Adjust.
	(linux_resume_one_lwp): Store the LWP's PC.  Adjust.
	(resume_status_pending_p): Use thread_still_has_status_pending_p.
	(linux_stopped_by_watchpoint): Adjust.
	(linux_target_ops): Remove reference to linux_cancel_breakpoints.
	* linux-low.h (enum lwp_stop_reason): New.
	(struct lwp_info) <stop_pc>: Adjust comment.
	<stopped_by_watchpoint>: Delete field.
	<stop_reason>: New field.
	* linux-x86-low.c (x86_linux_prepare_to_resume): Adjust.
	* mem-break.c (software_breakpoint_inserted_here)
	(hardware_breakpoint_inserted_here): New function.
	* mem-break.h (software_breakpoint_inserted_here)
	(hardware_breakpoint_inserted_here): Declare.
	* target.h (struct target_ops) <cancel_breakpoints>: Remove field.
	(cancel_breakpoints): Delete.
	* tracepoint.c (clear_installed_tracepoints, stop_tracing)
	(upload_fast_traceframes): Remove references to
	cancel_breakpoints.
This commit is contained in:
Pedro Alves 2014-12-29 19:41:07 +00:00
parent 9c02b52532
commit 582511be69
8 changed files with 518 additions and 358 deletions

View file

@ -1,3 +1,58 @@
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (step_over_bkpt): Move higher up in the file.
(handle_extended_wait): Don't store the stop_pc here.
(get_stop_pc): Adjust comments and rename to ...
(check_stopped_by_breakpoint): ... this. Record whether the LWP
stopped for a software breakpoint or hardware breakpoint.
(thread_still_has_status_pending_p): New function.
(status_pending_p_callback): Use
thread_still_has_status_pending_p. If the event is no longer
interesting, resume the LWP.
(handle_tracepoints): Add assert.
(maybe_move_out_of_jump_pad): Remove cancel_breakpoints call.
(wstatus_maybe_breakpoint): New function.
(cancel_breakpoint): Delete function.
(check_stopped_by_watchpoint): New function, factored out from
linux_low_filter_event.
(lp_status_maybe_breakpoint): Delete function.
(linux_low_filter_event): Remove filter_ptid argument.
Leave thread group exits pending here. Store the LWP's stop PC.
Always leave events pending.
(linux_wait_for_event_filtered): Pull all events out of the
kernel, and leave them all pending.
(count_events_callback, select_event_lwp_callback): Consider all
events.
(cancel_breakpoints_callback, linux_cancel_breakpoints): Delete.
(select_event_lwp): Only give preference to the stepping LWP in
all-stop mode. Adjust comments.
(ignore_event): New function.
(linux_wait_1): Delete 'retry' label. Use ignore_event. Remove
references to cancel_breakpoints. Adjust to renames. Also give
equal priority to all LWPs that have had events in non-stop mode.
If reporting a software breakpoint event, unadjust the LWP's PC.
(linux_wait): If linux_wait_1 returned an ignored event, retry.
(stuck_in_jump_pad_callback, move_out_of_jump_pad_callback):
Adjust.
(linux_resume_one_lwp): Store the LWP's PC. Adjust.
(resume_status_pending_p): Use thread_still_has_status_pending_p.
(linux_stopped_by_watchpoint): Adjust.
(linux_target_ops): Remove reference to linux_cancel_breakpoints.
* linux-low.h (enum lwp_stop_reason): New.
(struct lwp_info) <stop_pc>: Adjust comment.
<stopped_by_watchpoint>: Delete field.
<stop_reason>: New field.
* linux-x86-low.c (x86_linux_prepare_to_resume): Adjust.
* mem-break.c (software_breakpoint_inserted_here)
(hardware_breakpoint_inserted_here): New function.
* mem-break.h (software_breakpoint_inserted_here)
(hardware_breakpoint_inserted_here): Declare.
* target.h (struct target_ops) <cancel_breakpoints>: Remove field.
(cancel_breakpoints): Delete.
* tracepoint.c (clear_installed_tracepoints, stop_tracing)
(upload_fast_traceframes): Remove references to
cancel_breakpoints.
2015-01-09 Pedro Alves <palves@redhat.com> 2015-01-09 Pedro Alves <palves@redhat.com>
* thread-db.c (find_new_threads_callback): Ignore thread if the * thread-db.c (find_new_threads_callback): Ignore thread if the

File diff suppressed because it is too large Load diff

View file

@ -230,6 +230,24 @@ extern struct linux_target_ops the_low_target;
#define get_thread_lwp(thr) ((struct lwp_info *) (inferior_target_data (thr))) #define get_thread_lwp(thr) ((struct lwp_info *) (inferior_target_data (thr)))
#define get_lwp_thread(lwp) ((lwp)->thread) #define get_lwp_thread(lwp) ((lwp)->thread)
/* Reasons an LWP last stopped. */
enum lwp_stop_reason
{
/* Either not stopped, or stopped for a reason that doesn't require
special tracking. */
LWP_STOPPED_BY_NO_REASON,
/* Stopped by a software breakpoint. */
LWP_STOPPED_BY_SW_BREAKPOINT,
/* Stopped by a hardware breakpoint. */
LWP_STOPPED_BY_HW_BREAKPOINT,
/* Stopped by a watchpoint. */
LWP_STOPPED_BY_WATCHPOINT
};
/* This struct is recorded in the target_data field of struct thread_info. /* This struct is recorded in the target_data field of struct thread_info.
On linux ``all_threads'' is keyed by the LWP ID, which we use as the On linux ``all_threads'' is keyed by the LWP ID, which we use as the
@ -269,8 +287,9 @@ struct lwp_info
/* When stopped is set, the last wait status recorded for this lwp. */ /* When stopped is set, the last wait status recorded for this lwp. */
int last_status; int last_status;
/* When stopped is set, this is where the lwp stopped, with /* When stopped is set, this is where the lwp last stopped, with
decr_pc_after_break already accounted for. */ decr_pc_after_break already accounted for. If the LWP is
running, this is the address at which the lwp was resumed. */
CORE_ADDR stop_pc; CORE_ADDR stop_pc;
/* If this flag is set, STATUS_PENDING is a waitstatus that has not yet /* If this flag is set, STATUS_PENDING is a waitstatus that has not yet
@ -278,9 +297,9 @@ struct lwp_info
int status_pending_p; int status_pending_p;
int status_pending; int status_pending;
/* STOPPED_BY_WATCHPOINT is non-zero if this LWP stopped with a data /* The reason the LWP last stopped, if we need to track it
watchpoint trap. */ (breakpoint, watchpoint, etc.) */
int stopped_by_watchpoint; enum lwp_stop_reason stop_reason;
/* On architectures where it is possible to know the data address of /* On architectures where it is possible to know the data address of
a triggered watchpoint, STOPPED_DATA_ADDRESS is non-zero, and a triggered watchpoint, STOPPED_DATA_ADDRESS is non-zero, and

View file

@ -805,7 +805,7 @@ x86_linux_prepare_to_resume (struct lwp_info *lwp)
lwp->arch_private->debug_registers_changed = 0; lwp->arch_private->debug_registers_changed = 0;
} }
if (clear_status || lwp->stopped_by_watchpoint) if (clear_status || lwp->stop_reason == LWP_STOPPED_BY_WATCHPOINT)
x86_linux_dr_set (ptid, DR_STATUS, 0); x86_linux_dr_set (ptid, DR_STATUS, 0);
} }

View file

@ -1610,6 +1610,40 @@ breakpoint_inserted_here (CORE_ADDR addr)
return 0; return 0;
} }
/* See mem-break.h. */
int
software_breakpoint_inserted_here (CORE_ADDR addr)
{
struct process_info *proc = current_process ();
struct raw_breakpoint *bp;
for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
if (bp->raw_type == raw_bkpt_type_sw
&& bp->pc == addr
&& bp->inserted)
return 1;
return 0;
}
/* See mem-break.h. */
int
hardware_breakpoint_inserted_here (CORE_ADDR addr)
{
struct process_info *proc = current_process ();
struct raw_breakpoint *bp;
for (bp = proc->raw_breakpoints; bp != NULL; bp = bp->next)
if (bp->raw_type == raw_bkpt_type_hw
&& bp->pc == addr
&& bp->inserted)
return 1;
return 0;
}
static int static int
validate_inserted_breakpoint (struct raw_breakpoint *bp) validate_inserted_breakpoint (struct raw_breakpoint *bp)
{ {

View file

@ -90,6 +90,16 @@ int breakpoint_here (CORE_ADDR addr);
int breakpoint_inserted_here (CORE_ADDR addr); int breakpoint_inserted_here (CORE_ADDR addr);
/* Returns TRUE if there's any inserted software breakpoint at
ADDR. */
int software_breakpoint_inserted_here (CORE_ADDR addr);
/* Returns TRUE if there's any inserted hardware (code) breakpoint at
ADDR. */
int hardware_breakpoint_inserted_here (CORE_ADDR addr);
/* Clear all breakpoint conditions and commands associated with a /* Clear all breakpoint conditions and commands associated with a
breakpoint. */ breakpoint. */

View file

@ -304,9 +304,6 @@ struct target_ops
the pause call. */ the pause call. */
void (*unpause_all) (int unfreeze); void (*unpause_all) (int unfreeze);
/* Cancel all pending breakpoints hits in all threads. */
void (*cancel_breakpoints) (void);
/* Stabilize all threads. That is, force them out of jump pads. */ /* Stabilize all threads. That is, force them out of jump pads. */
void (*stabilize_threads) (void); void (*stabilize_threads) (void);
@ -453,13 +450,6 @@ int kill_inferior (int);
(*the_target->unpause_all) (unfreeze); \ (*the_target->unpause_all) (unfreeze); \
} while (0) } while (0)
#define cancel_breakpoints() \
do \
{ \
if (the_target->cancel_breakpoints) \
(*the_target->cancel_breakpoints) (); \
} while (0)
#define stabilize_threads() \ #define stabilize_threads() \
do \ do \
{ \ { \

View file

@ -2443,7 +2443,6 @@ clear_installed_tracepoints (void)
struct tracepoint *prev_stpoint; struct tracepoint *prev_stpoint;
pause_all (1); pause_all (1);
cancel_breakpoints ();
prev_stpoint = NULL; prev_stpoint = NULL;
@ -3433,9 +3432,6 @@ stop_tracing (void)
We can't now, since we may be getting here due to the inferior We can't now, since we may be getting here due to the inferior
agent calling us. */ agent calling us. */
pause_all (1); pause_all (1);
/* Since we're removing breakpoints, cancel breakpoint hits,
possibly related to the breakpoints we're about to delete. */
cancel_breakpoints ();
/* Stop logging. Tracepoints can still be hit, but they will not be /* Stop logging. Tracepoints can still be hit, but they will not be
recorded. */ recorded. */
@ -6538,7 +6534,6 @@ upload_fast_traceframes (void)
trace_debug ("Done uploading traceframes [%d]\n", curr_tbctrl_idx); trace_debug ("Done uploading traceframes [%d]\n", curr_tbctrl_idx);
pause_all (1); pause_all (1);
cancel_breakpoints ();
delete_breakpoint (about_to_request_buffer_space_bkpt); delete_breakpoint (about_to_request_buffer_space_bkpt);
about_to_request_buffer_space_bkpt = NULL; about_to_request_buffer_space_bkpt = NULL;