* breakpoint.c (moribund_locations): New.
(bpstat_stop_status): Process moribund locations. (update_global_location_list): Add removed locations to moribund_locations. (breakpoint_retire_moribund): New. * breakpoint.h (struct bp_location): New field events_till_retirement. (breakpoint_retire_moribund): Declare. * thread.c (thread_count): New. * infrun.c (handle_inferior_event): Call breakpoint_retire_moribund. * gdbthread.h (thread_count): Declare.
This commit is contained in:
parent
2a9bd7a88c
commit
20874c92f8
6 changed files with 131 additions and 19 deletions
|
@ -1,3 +1,18 @@
|
|||
2008-06-28 Vladimir Prus <vladimir@codesourcery.com>
|
||||
|
||||
* breakpoint.c (moribund_locations): New.
|
||||
(bpstat_stop_status): Process moribund locations.
|
||||
(update_global_location_list): Add removed
|
||||
locations to moribund_locations.
|
||||
(breakpoint_retire_moribund): New.
|
||||
* breakpoint.h (struct bp_location): New field
|
||||
events_till_retirement.
|
||||
(breakpoint_retire_moribund): Declare.
|
||||
* thread.c (thread_count): New.
|
||||
* infrun.c (handle_inferior_event): Call
|
||||
breakpoint_retire_moribund.
|
||||
* gdbthread.h (thread_count): Declare.
|
||||
|
||||
2008-06-27 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
* dfp.c (decimal_convert): Call match_endianness before and after
|
||||
|
|
|
@ -308,6 +308,11 @@ struct breakpoint *breakpoint_chain;
|
|||
|
||||
struct bp_location *bp_location_chain;
|
||||
|
||||
/* The locations that no longer correspond to any breakpoint,
|
||||
unlinked from bp_location_chain, but for which a hit
|
||||
may still be reported by a target. */
|
||||
VEC(bp_location_p) *moribund_locations = NULL;
|
||||
|
||||
/* Number of last breakpoint made. */
|
||||
|
||||
int breakpoint_count;
|
||||
|
@ -3003,10 +3008,12 @@ bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid)
|
|||
{
|
||||
struct breakpoint *b = NULL;
|
||||
const struct bp_location *bl;
|
||||
struct bp_location *loc;
|
||||
/* Root of the chain of bpstat's */
|
||||
struct bpstats root_bs[1];
|
||||
/* Pointer to the last thing in the chain currently. */
|
||||
bpstat bs = root_bs;
|
||||
int ix;
|
||||
|
||||
ALL_BP_LOCATIONS (bl)
|
||||
{
|
||||
|
@ -3075,6 +3082,18 @@ bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid)
|
|||
bs->print_it = print_it_noop;
|
||||
}
|
||||
|
||||
for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
|
||||
{
|
||||
if (loc->address == bp_addr)
|
||||
{
|
||||
bs = bpstat_alloc (loc, bs);
|
||||
/* For hits of moribund locations, we should just proceed. */
|
||||
bs->stop = 0;
|
||||
bs->print = 0;
|
||||
bs->print_it = print_it_noop;
|
||||
}
|
||||
}
|
||||
|
||||
bs->next = NULL; /* Terminate the chain */
|
||||
bs = root_bs->next; /* Re-grab the head of the chain */
|
||||
|
||||
|
@ -3089,6 +3108,7 @@ bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid)
|
|||
if (bs == NULL)
|
||||
for (bs = root_bs->next; bs != NULL; bs = bs->next)
|
||||
if (!bs->stop
|
||||
&& bs->breakpoint_at->owner
|
||||
&& (bs->breakpoint_at->owner->type == bp_hardware_watchpoint
|
||||
|| bs->breakpoint_at->owner->type == bp_read_watchpoint
|
||||
|| bs->breakpoint_at->owner->type == bp_access_watchpoint))
|
||||
|
@ -3253,6 +3273,9 @@ bpstat_what (bpstat bs)
|
|||
/* I suspect this can happen if it was a momentary breakpoint
|
||||
which has since been deleted. */
|
||||
continue;
|
||||
if (bs->breakpoint_at->owner == NULL)
|
||||
bs_class = bp_nostop;
|
||||
else
|
||||
switch (bs->breakpoint_at->owner->type)
|
||||
{
|
||||
case bp_none:
|
||||
|
@ -6956,7 +6979,9 @@ breakpoint_auto_delete (bpstat bs)
|
|||
struct breakpoint *b, *temp;
|
||||
|
||||
for (; bs; bs = bs->next)
|
||||
if (bs->breakpoint_at && bs->breakpoint_at->owner->disposition == disp_del
|
||||
if (bs->breakpoint_at
|
||||
&& bs->breakpoint_at->owner
|
||||
&& bs->breakpoint_at->owner->disposition == disp_del
|
||||
&& bs->stop)
|
||||
delete_breakpoint (bs->breakpoint_at->owner);
|
||||
|
||||
|
@ -7004,6 +7029,9 @@ update_global_location_list (void)
|
|||
/* Tells if 'loc' is found amoung the new locations. If not, we
|
||||
have to free it. */
|
||||
int found_object = 0;
|
||||
/* Tells if the location should remain inserted in the target. */
|
||||
int keep_in_target = 0;
|
||||
int removed = 0;
|
||||
for (loc2 = bp_location_chain; loc2; loc2 = loc2->global_next)
|
||||
if (loc2 == loc)
|
||||
{
|
||||
|
@ -7020,13 +7048,12 @@ update_global_location_list (void)
|
|||
if (loc->inserted)
|
||||
{
|
||||
/* If the location is inserted now, we might have to remove it. */
|
||||
int keep = 0;
|
||||
|
||||
if (found_object && should_be_inserted (loc))
|
||||
{
|
||||
/* The location is still present in the location list, and still
|
||||
should be inserted. Don't do anything. */
|
||||
keep = 1;
|
||||
keep_in_target = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -7044,13 +7071,14 @@ update_global_location_list (void)
|
|||
{
|
||||
loc2->inserted = 1;
|
||||
loc2->target_info = loc->target_info;
|
||||
keep = 1;
|
||||
keep_in_target = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!keep)
|
||||
if (!keep_in_target)
|
||||
{
|
||||
if (remove_breakpoint (loc, mark_uninserted))
|
||||
{
|
||||
/* This is just about all we can do. We could keep this
|
||||
|
@ -7064,11 +7092,33 @@ update_global_location_list (void)
|
|||
printf_filtered (_("warning: Error removing breakpoint %d\n"),
|
||||
loc->owner->number);
|
||||
}
|
||||
removed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_object)
|
||||
{
|
||||
if (removed)
|
||||
{
|
||||
/* This location was removed from the targets. In non-stop mode,
|
||||
a race condition is possible where we've removed a breakpoint,
|
||||
but stop events for that breakpoint are already queued and will
|
||||
arrive later. To suppress spurious SIGTRAPs reported to user,
|
||||
we keep this breakpoint location for a bit, and will retire it
|
||||
after we see 3 * thread_count events.
|
||||
The theory here is that reporting of events should,
|
||||
"on the average", be fair, so after that many event we'll see
|
||||
events from all threads that have anything of interest, and no
|
||||
longer need to keep this breakpoint. This is just a
|
||||
heuristic, but if it's wrong, we'll report unexpected SIGTRAP,
|
||||
which is usability issue, but not a correctness problem. */
|
||||
loc->events_till_retirement = 3 * (thread_count () + 1);
|
||||
loc->owner = NULL;
|
||||
}
|
||||
|
||||
free_bp_location (loc);
|
||||
}
|
||||
}
|
||||
|
||||
ALL_BREAKPOINTS (b)
|
||||
{
|
||||
|
@ -7079,6 +7129,21 @@ update_global_location_list (void)
|
|||
insert_breakpoint_locations ();
|
||||
}
|
||||
|
||||
void
|
||||
breakpoint_retire_moribund (void)
|
||||
{
|
||||
struct bp_location *loc;
|
||||
int ix;
|
||||
|
||||
for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
|
||||
if (--(loc->events_till_retirement) == 0)
|
||||
{
|
||||
free_bp_location (loc);
|
||||
VEC_unordered_remove (bp_location_p, moribund_locations, ix);
|
||||
--ix;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update_global_location_list_nothrow (void)
|
||||
{
|
||||
|
|
|
@ -298,6 +298,17 @@ struct bp_location
|
|||
|
||||
/* Similarly, for the breakpoint at an overlay's LMA, if necessary. */
|
||||
struct bp_target_info overlay_target_info;
|
||||
|
||||
/* In a non-stop mode, it's possible that we delete a breakpoint,
|
||||
but as we do that, some still running thread hits that breakpoint.
|
||||
For that reason, we need to keep locations belonging to deleted
|
||||
breakpoints for a bit, so that don't report unexpected SIGTRAP.
|
||||
We can't keep such locations forever, so we use a heuristic --
|
||||
after we process certain number of inferior events since
|
||||
breakpoint was deleted, we retire all locations of that breakpoint.
|
||||
This variable keeps a number of events still to go, when
|
||||
it becomes 0 this location is retired. */
|
||||
int events_till_retirement;
|
||||
};
|
||||
|
||||
/* This structure is a collection of function pointers that, if available,
|
||||
|
@ -865,4 +876,9 @@ void breakpoint_restore_shadows (gdb_byte *buf, ULONGEST memaddr,
|
|||
|
||||
extern int breakpoints_always_inserted_mode (void);
|
||||
|
||||
/* Called each time new event from target is processed.
|
||||
Retires previously deleted breakpoint locations that
|
||||
in our opinion won't ever trigger. */
|
||||
extern void breakpoint_retire_moribund (void);
|
||||
|
||||
#endif /* !defined (BREAKPOINT_H) */
|
||||
|
|
|
@ -118,6 +118,8 @@ extern struct thread_info *find_thread_pid (ptid_t ptid);
|
|||
typedef int (*thread_callback_func) (struct thread_info *, void *);
|
||||
extern struct thread_info *iterate_over_threads (thread_callback_func, void *);
|
||||
|
||||
extern int thread_count (void);
|
||||
|
||||
/* infrun context switch: save the debugger state for the given thread. */
|
||||
extern void save_infrun_state (ptid_t ptid,
|
||||
CORE_ADDR prev_pc,
|
||||
|
|
|
@ -1705,6 +1705,8 @@ handle_inferior_event (struct execution_control_state *ecs)
|
|||
int stopped_by_watchpoint;
|
||||
int stepped_after_stopped_by_watchpoint = 0;
|
||||
|
||||
breakpoint_retire_moribund ();
|
||||
|
||||
/* Cache the last pid/waitstatus. */
|
||||
target_last_wait_ptid = ecs->ptid;
|
||||
target_last_waitstatus = *ecs->wp;
|
||||
|
|
12
gdb/thread.c
12
gdb/thread.c
|
@ -229,6 +229,18 @@ iterate_over_threads (int (*callback) (struct thread_info *, void *),
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
thread_count (void)
|
||||
{
|
||||
int result = 0;
|
||||
struct thread_info *tp;
|
||||
|
||||
for (tp = thread_list; tp; tp = tp->next)
|
||||
++result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
valid_thread_id (int num)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue