mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-01 11:59:27 +08:00
btrace: honour scheduler-locking for all-stop targets
In all-stop mode, record btrace maintains the old behaviour of an implicit scheduler-locking on. Now that we added a scheduler-locking mode to model this old behaviour, we don't need the respective code in record btrace anymore. Remove it. For all-stop targets, step inferior_ptid and continue other threads matching the argument ptid. Assert that inferior_ptid matches the argument ptid. This should make record btrace honour scheduler-locking. gdb/ * record-btrace.c (record_btrace_resume): Honour scheduler-locking. testsuite/ * gdb.btrace/multi-thread-step.exp: Test scheduler-locking on, step, and replay.
This commit is contained in:
@ -1,3 +1,7 @@
|
||||
2015-09-18 Markus Metzger <markus.t.metzger@intel.com>
|
||||
|
||||
* record-btrace.c (record_btrace_resume): Honour scheduler-locking.
|
||||
|
||||
2015-09-18 Markus Metzger <markus.t.metzger@intel.com>
|
||||
|
||||
* NEWS: Announce new scheduler-locking mode.
|
||||
|
@ -1888,33 +1888,18 @@ record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
|
||||
enum gdb_signal signal)
|
||||
{
|
||||
struct thread_info *tp;
|
||||
enum btrace_thread_flag flag;
|
||||
ptid_t orig_ptid;
|
||||
enum btrace_thread_flag flag, cflag;
|
||||
|
||||
DEBUG ("resume %s: %s%s", target_pid_to_str (ptid),
|
||||
execution_direction == EXEC_REVERSE ? "reverse-" : "",
|
||||
step ? "step" : "cont");
|
||||
|
||||
orig_ptid = ptid;
|
||||
|
||||
/* Store the execution direction of the last resume.
|
||||
|
||||
If there is more than one to_resume call, we have to rely on infrun
|
||||
to not change the execution direction in-between. */
|
||||
record_btrace_resume_exec_dir = execution_direction;
|
||||
|
||||
/* For all-stop targets we pick the current thread when asked to resume an
|
||||
entire process or everything. */
|
||||
if (!target_is_non_stop_p ())
|
||||
{
|
||||
if (ptid_equal (minus_one_ptid, ptid) || ptid_is_pid (ptid))
|
||||
ptid = inferior_ptid;
|
||||
|
||||
tp = find_thread_ptid (ptid);
|
||||
if (tp == NULL)
|
||||
error (_("Cannot find thread to resume."));
|
||||
}
|
||||
|
||||
/* As long as we're not replaying, just forward the request.
|
||||
|
||||
For non-stop targets this means that no thread is replaying. In order to
|
||||
@ -1924,20 +1909,44 @@ record_btrace_resume (struct target_ops *ops, ptid_t ptid, int step,
|
||||
&& !record_btrace_is_replaying (ops, minus_one_ptid))
|
||||
{
|
||||
ops = ops->beneath;
|
||||
return ops->to_resume (ops, orig_ptid, step, signal);
|
||||
return ops->to_resume (ops, ptid, step, signal);
|
||||
}
|
||||
|
||||
/* Compute the btrace thread flag for the requested move. */
|
||||
if (step == 0)
|
||||
flag = execution_direction == EXEC_REVERSE ? BTHR_RCONT : BTHR_CONT;
|
||||
if (execution_direction == EXEC_REVERSE)
|
||||
{
|
||||
flag = step == 0 ? BTHR_RCONT : BTHR_RSTEP;
|
||||
cflag = BTHR_RCONT;
|
||||
}
|
||||
else
|
||||
flag = execution_direction == EXEC_REVERSE ? BTHR_RSTEP : BTHR_STEP;
|
||||
{
|
||||
flag = step == 0 ? BTHR_CONT : BTHR_STEP;
|
||||
cflag = BTHR_CONT;
|
||||
}
|
||||
|
||||
/* We just indicate the resume intent here. The actual stepping happens in
|
||||
record_btrace_wait below. */
|
||||
ALL_NON_EXITED_THREADS (tp)
|
||||
if (ptid_match (tp->ptid, ptid))
|
||||
record_btrace_resume_thread (tp, flag);
|
||||
record_btrace_wait below.
|
||||
|
||||
For all-stop targets, we only step INFERIOR_PTID and continue others. */
|
||||
if (!target_is_non_stop_p ())
|
||||
{
|
||||
gdb_assert (ptid_match (inferior_ptid, ptid));
|
||||
|
||||
ALL_NON_EXITED_THREADS (tp)
|
||||
if (ptid_match (tp->ptid, ptid))
|
||||
{
|
||||
if (ptid_match (tp->ptid, inferior_ptid))
|
||||
record_btrace_resume_thread (tp, flag);
|
||||
else
|
||||
record_btrace_resume_thread (tp, cflag);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ALL_NON_EXITED_THREADS (tp)
|
||||
if (ptid_match (tp->ptid, ptid))
|
||||
record_btrace_resume_thread (tp, flag);
|
||||
}
|
||||
|
||||
/* Async support. */
|
||||
if (target_can_async_p ())
|
||||
|
@ -1,3 +1,8 @@
|
||||
2015-09-18 Markus Metzger <markus.t.metzger@intel.com>
|
||||
|
||||
* gdb.btrace/multi-thread-step.exp: Test scheduler-locking on, step,
|
||||
and replay.
|
||||
|
||||
2015-09-18 Markus Metzger <markus.t.metzger@intel.com>
|
||||
|
||||
* gdb.btrace/non-stop.c: New.
|
||||
|
@ -37,9 +37,29 @@ set bp_2 [gdb_get_line_number "bp.2" $srcfile]
|
||||
set bp_3 [gdb_get_line_number "bp.3" $srcfile]
|
||||
|
||||
proc gdb_cont_to_line { line } {
|
||||
gdb_breakpoint $line
|
||||
gdb_continue_to_breakpoint "cont to $line" ".*$line\r\n.*"
|
||||
delete_breakpoints
|
||||
gdb_breakpoint $line
|
||||
gdb_continue_to_breakpoint "cont to $line" ".*$line\r\n.*"
|
||||
delete_breakpoints
|
||||
}
|
||||
|
||||
proc check_replay_insn { thread insn } {
|
||||
gdb_test "thread apply $thread info record" \
|
||||
"Replay in progress\. At instruction $insn\."
|
||||
}
|
||||
|
||||
proc check_not_replaying { thread } {
|
||||
global gdb_prompt
|
||||
|
||||
set test "thread $thread not replaying"
|
||||
|
||||
gdb_test_multiple "thread apply $thread info record" $test {
|
||||
-re "Replay in progress" {
|
||||
fail $test
|
||||
}
|
||||
-re "$gdb_prompt $" {
|
||||
pass $test
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# trace the code between the two breakpoints
|
||||
@ -50,86 +70,145 @@ gdb_test "info threads" ".*"
|
||||
gdb_test_no_output "record btrace"
|
||||
gdb_cont_to_line $srcfile:$bp_2
|
||||
|
||||
# navigate in the trace history for both threads
|
||||
with_test_prefix "navigate" {
|
||||
gdb_test "thread 1" ".*"
|
||||
with_test_prefix "thread 1" {
|
||||
gdb_test "record goto begin" ".*"
|
||||
gdb_test "info record" ".*Replay in progress\. At instruction 1\."
|
||||
}
|
||||
gdb_test "thread 2" ".*"
|
||||
with_test_prefix "thread 2" {
|
||||
gdb_test "record goto begin" ".*"
|
||||
gdb_test "info record" ".*Replay in progress\. At instruction 1\."
|
||||
}
|
||||
proc test_navigate {} {
|
||||
with_test_prefix "navigate" {
|
||||
gdb_test "thread 1" ".*"
|
||||
with_test_prefix "thread 1" {
|
||||
gdb_test "record goto begin" ".*"
|
||||
|
||||
check_replay_insn 1 1
|
||||
check_not_replaying 2
|
||||
}
|
||||
gdb_test "thread 2" ".*"
|
||||
with_test_prefix "thread 2" {
|
||||
gdb_test "record goto begin" ".*"
|
||||
|
||||
check_replay_insn 1 1
|
||||
check_replay_insn 2 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# step both threads
|
||||
with_test_prefix "step" {
|
||||
gdb_test "thread 1" ".*"
|
||||
with_test_prefix "thread 1" {
|
||||
gdb_test "info record" ".*Replay in progress\. At instruction 1\."
|
||||
gdb_test "stepi" ".*"
|
||||
gdb_test "info record" ".*Replay in progress\. At instruction 2\."
|
||||
}
|
||||
gdb_test "thread 2" ".*"
|
||||
with_test_prefix "thread 2" {
|
||||
gdb_test "info record" ".*Replay in progress\. At instruction 1\."
|
||||
gdb_test "stepi" ".*"
|
||||
gdb_test "info record" ".*Replay in progress\. At instruction 2\."
|
||||
}
|
||||
proc test_step {} {
|
||||
with_test_prefix "step" {
|
||||
gdb_test "thread 1" ".*"
|
||||
with_test_prefix "thread 1" {
|
||||
gdb_test "stepi" ".*"
|
||||
|
||||
check_replay_insn 1 2
|
||||
check_replay_insn 2 1
|
||||
}
|
||||
gdb_test "thread 2" ".*"
|
||||
with_test_prefix "thread 2" {
|
||||
gdb_test "stepi" ".*"
|
||||
|
||||
check_replay_insn 1 2
|
||||
check_replay_insn 2 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# run to the end of the history for both threads
|
||||
with_test_prefix "cont" {
|
||||
gdb_test "thread 1" ".*"
|
||||
with_test_prefix "thread 1" {
|
||||
gdb_test "info record" ".*Replay in progress\. At instruction 2\."
|
||||
gdb_test "continue" "No more reverse-execution history.*"
|
||||
}
|
||||
gdb_test "thread 2" ".*"
|
||||
with_test_prefix "thread 2" {
|
||||
gdb_test "info record" ".*Replay in progress\. At instruction 2\."
|
||||
gdb_test "continue" "No more reverse-execution history.*"
|
||||
}
|
||||
proc test_cont {} {
|
||||
with_test_prefix "cont" {
|
||||
gdb_test "thread 1" ".*"
|
||||
with_test_prefix "thread 1" {
|
||||
gdb_test "continue" "No more reverse-execution history.*"
|
||||
|
||||
check_not_replaying 1
|
||||
check_replay_insn 2 2
|
||||
}
|
||||
gdb_test "thread 2" ".*"
|
||||
with_test_prefix "thread 2" {
|
||||
gdb_test "continue" "No more reverse-execution history.*"
|
||||
|
||||
check_not_replaying 1
|
||||
check_not_replaying 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# reverse-step both threads
|
||||
with_test_prefix "reverse-step" {
|
||||
gdb_test "thread 1" ".*"
|
||||
with_test_prefix "thread 1" {
|
||||
gdb_test "reverse-stepi" ".*"
|
||||
gdb_test "info record" ".*Replay in progress\..*"
|
||||
}
|
||||
gdb_test "thread 2" ".*"
|
||||
with_test_prefix "thread 2" {
|
||||
gdb_test "reverse-stepi" ".*"
|
||||
gdb_test "info record" ".*Replay in progress\..*"
|
||||
}
|
||||
proc test_cont_all {} {
|
||||
with_test_prefix "cont-all" {
|
||||
gdb_test "continue" "No more reverse-execution history.*"
|
||||
|
||||
# this works because we're lock-stepping threads that executed exactly
|
||||
# the same code starting from the same instruction.
|
||||
|
||||
check_not_replaying 1
|
||||
check_not_replaying 2
|
||||
}
|
||||
}
|
||||
|
||||
# both threads are still replaying
|
||||
with_test_prefix "check" {
|
||||
gdb_test "thread 1" ".*"
|
||||
with_test_prefix "thread 1" {
|
||||
gdb_test "info record" ".*Replay in progress\..*"
|
||||
}
|
||||
gdb_test "thread 2" ".*"
|
||||
with_test_prefix "thread 2" {
|
||||
gdb_test "info record" ".*Replay in progress\..*"
|
||||
}
|
||||
proc test_rstep {} {
|
||||
with_test_prefix "reverse-step" {
|
||||
gdb_test "thread apply all record goto 3"
|
||||
|
||||
gdb_test "thread 1" ".*"
|
||||
with_test_prefix "thread 1" {
|
||||
gdb_test "reverse-stepi" ".*"
|
||||
|
||||
check_replay_insn 1 2
|
||||
check_replay_insn 2 3
|
||||
}
|
||||
gdb_test "thread 2" ".*"
|
||||
with_test_prefix "thread 2" {
|
||||
gdb_test "reverse-stepi" ".*"
|
||||
|
||||
check_replay_insn 1 2
|
||||
check_replay_insn 2 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc test_goto_end {} {
|
||||
with_test_prefix "goto-end" {
|
||||
gdb_test "thread apply all record goto end"
|
||||
|
||||
check_not_replaying 1
|
||||
check_not_replaying 2
|
||||
}
|
||||
}
|
||||
|
||||
foreach schedlock { "replay" "on" "step" } {
|
||||
with_test_prefix "schedlock-$schedlock" {
|
||||
gdb_test_no_output "set scheduler-locking $schedlock"
|
||||
|
||||
test_navigate
|
||||
test_step
|
||||
if { $schedlock == "step" } {
|
||||
test_cont_all
|
||||
} else {
|
||||
test_cont
|
||||
}
|
||||
test_rstep
|
||||
test_goto_end
|
||||
}
|
||||
}
|
||||
|
||||
# schedlock-off is difficult to test since we can't really say where the other
|
||||
# thread will be when the resumed thread stops.
|
||||
|
||||
# navigate back into the history for thread 1 and continue thread 2
|
||||
with_test_prefix "cont" {
|
||||
gdb_test "thread 1" ".*"
|
||||
with_test_prefix "thread 1" {
|
||||
gdb_test "record goto begin" ".*"
|
||||
gdb_test "info record" ".*Replay in progress\. At instruction 1\."
|
||||
}
|
||||
gdb_test "thread 2" ".*"
|
||||
with_test_prefix "thread 2" {
|
||||
gdb_test "record goto end" ".*"
|
||||
gdb_cont_to_line $srcfile:$bp_3
|
||||
}
|
||||
with_test_prefix "cont-to-end" {
|
||||
# this test only works for scheduler-locking replay
|
||||
gdb_test_no_output "set scheduler-locking replay"
|
||||
|
||||
gdb_test "thread 1" ".*"
|
||||
with_test_prefix "thread 1" {
|
||||
gdb_test "record goto begin" ".*"
|
||||
|
||||
check_replay_insn 1 1
|
||||
}
|
||||
gdb_test "thread 2" ".*"
|
||||
with_test_prefix "thread 2" {
|
||||
gdb_test "record goto end" ".*"
|
||||
|
||||
check_not_replaying 2
|
||||
|
||||
# if we reach the breakpoint, thread 2 terminated...
|
||||
gdb_cont_to_line $srcfile:$bp_3
|
||||
|
||||
# and thread 1 stopped replaying
|
||||
check_not_replaying 1
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user