From d2939ba2b40daa89b501d4b81484ea888ef17139 Mon Sep 17 00:00:00 2001 From: Markus Metzger Date: Wed, 16 Sep 2015 09:05:22 +0200 Subject: [PATCH] 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. --- gdb/ChangeLog | 4 + gdb/record-btrace.c | 57 +++-- gdb/testsuite/ChangeLog | 5 + .../gdb.btrace/multi-thread-step.exp | 227 ++++++++++++------ 4 files changed, 195 insertions(+), 98 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ee90a762b4c..61e435e9d9b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,7 @@ +2015-09-18 Markus Metzger + + * record-btrace.c (record_btrace_resume): Honour scheduler-locking. + 2015-09-18 Markus Metzger * NEWS: Announce new scheduler-locking mode. diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c index 42195d1a1ec..d14e6cf09cf 100644 --- a/gdb/record-btrace.c +++ b/gdb/record-btrace.c @@ -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 ()) diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 23a957b93c9..1b8e0e8df2c 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2015-09-18 Markus Metzger + + * gdb.btrace/multi-thread-step.exp: Test scheduler-locking on, step, + and replay. + 2015-09-18 Markus Metzger * gdb.btrace/non-stop.c: New. diff --git a/gdb/testsuite/gdb.btrace/multi-thread-step.exp b/gdb/testsuite/gdb.btrace/multi-thread-step.exp index 2295f71047c..74748cc0c14 100644 --- a/gdb/testsuite/gdb.btrace/multi-thread-step.exp +++ b/gdb/testsuite/gdb.btrace/multi-thread-step.exp @@ -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 + } } -- 2.30.2