]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/testsuite/gdb.threads/schedlock.exp
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / testsuite / gdb.threads / schedlock.exp
index c32ed0c77887c41f084488a31da0e35283706fdf..fa095508fb9743db5e094b080483d20ee2d19ad6 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2023 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 #
 # This test covers the various forms of "set scheduler-locking".
 
+# This test requires sending ^C to interrupt the running target.
+
+if [target_info exists gdb,nointerrupts] {
+    verbose "Skipping schedlock.exp because of nointerrupts."
+    return
+}
 
 standard_testfile
 
@@ -30,8 +36,10 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab
 
 # Now we can proceed with the real testing.
 
-proc get_args { } {
-    global list_count
+# Get the current contents of the `args` array in the test program.
+# Description is appended to the test message.
+
+proc get_args { description } {
     global gdb_prompt
     global NUM
 
@@ -40,10 +48,10 @@ proc get_args { } {
        append pattern ", (\[0-9\]+)"
     }
 
-    gdb_test_multiple "print args" "listed args ($list_count)" {
+    set test "listed args ($description)"
+    gdb_test_multiple "print args" $test {
        -re "\\\$\[0-9\]+ = {$pattern}.*$gdb_prompt $" {
-           set list_count [expr $list_count + 1]
-           pass "listed args ($list_count)"
+           pass $test
 
            set result ""
            for {set i 1} {[expr $i <= $NUM]} {incr i} {
@@ -61,7 +69,7 @@ proc stop_process { description } {
   # message first, or GDB's signal handler may not be in place.
   after 1000 {send_gdb "\003"}
   gdb_expect {
-    -re "Program received signal SIGINT.*$gdb_prompt $"
+    -re "Thread .* received signal SIGINT.*$gdb_prompt $"
       {
        pass $description
       }
@@ -75,46 +83,62 @@ proc stop_process { description } {
 proc get_current_thread { description } {
     global gdb_prompt
 
-    gdb_test_multiple "bt" "$description" {
+    set test "find current thread ($description)"
+
+    gdb_test_multiple "bt" $test {
        -re "thread_function \\(arg=0x(\[0-9\])\\).*$gdb_prompt $" {
-           pass $description
+           pass $test
            return $expect_out(1,string)
        }
     }
     return ""
 }
 
+# Make sure we're stopped in the loop, in one of the non-main threads.
+
+proc goto_loop { msg } {
+    gdb_breakpoint [concat [gdb_get_line_number "schedlock.exp: main loop"] " if arg != 0"]
+
+    set test "return to loop"
+    if {$msg != ""} {
+       set test "$test ($msg)"
+    }
+    gdb_continue_to_breakpoint $test
+    delete_breakpoints
+}
+
 proc my_continue { msg } {
-    gdb_test_multiple "continue" "continuing ($msg)" {
+    set test "continue ($msg)"
+    gdb_test_multiple "continue" $test {
        -re "Continuing" {
-           pass "continue ($msg)"
+           pass $test
        }
     }
 
     stop_process "stop all threads ($msg)"
 
-    # Make sure we're in one of the non-main looping threads.
-    gdb_breakpoint [concat [gdb_get_line_number "schedlock.exp: main loop"] " if arg != 0"]
-    gdb_continue_to_breakpoint "return to loop ($msg)"
-    delete_breakpoints
+    goto_loop $msg
 }
 
-proc step_ten_loops { msg } {
+# Use CMD to step the loop 10 times.  CMD may be "step" or "next".
+
+proc step_ten_loops { cmd } {
     global gdb_prompt
 
     for {set i 0} {[expr $i < 10]} {set i [expr $i + 1]} {
        set other_step 0
-       gdb_test_multiple "step" "step to increment ($msg $i)" {
+       set test "$cmd to increment ($i)"
+       gdb_test_multiple $cmd $test {
            -re ".*myp\\) \\+\\+;\[\r\n\]+$gdb_prompt $" {
-               pass "step to increment ($msg $i)"
+               pass $test
            }
            -re "$gdb_prompt $" {
                if {$other_step == 0} {
                    set other_step 1
-                   send_gdb "step\n"
+                   send_gdb "$cmd\n"
                    exp_continue
                } else {
-                   fail "step to increment ($msg $i)"
+                   fail $test
                    # FIXME cascade?
                }
            }
@@ -158,15 +182,12 @@ gdb_test_multiple "set scheduler-locking off" "scheduler locking set to none" {
 gdb_breakpoint [gdb_get_line_number "schedlock.exp: last thread start"]
 gdb_continue_to_breakpoint "all threads started"
 
-global list_count
-set list_count 0
-
-set start_args [get_args]
+set start_args [get_args "before initial"]
 
 # First make sure that all threads are alive.
 my_continue "initial"
 
-set cont_args [get_args]
+set cont_args [get_args "after initial"]
 
 set bad 0
 for {set i 0} {[expr $i < $NUM]} {set i [expr $i + 1]} {
@@ -180,125 +201,121 @@ if { $bad == 0 } {
   fail "all threads alive ($bad/$NUM did not run)"
 }
 
-# We can't change threads, unfortunately, in current GDB.  Use
-# whichever we stopped in.
-set curthread [get_current_thread "find current thread (1)"]
-
-
+# Compare the previous thread and args with the current thread and
+# args.  Check that we didn't switch threads, and that the threads
+# incremented their args counter the amounts expected.  CMD is the
+# command being tested.  BEFORE_THREAD is the thread that was selected
+# before the command was run.  BEFORE_ARGS is the value of the
+# thread's args before the command was run.  LOCKED indicates whether
+# we expect threads other than the selected thread remained locked.
 
+proc check_result { cmd before_thread before_args locked } {
+    global NUM
 
-# Test stepping without scheduler locking.
-gdb_test_no_output "set scheduler-locking off"
-
-step_ten_loops "unlocked"
+    # Make sure we're still in the same thread.
+    set newthread [get_current_thread "after"]
 
-# Make sure we're still in the same thread.
-set newthread [get_current_thread "find current thread (2)"]
-if {$curthread == $newthread} {
-    pass "step without lock does not change thread"
-} else {
-    fail "step without lock does not change thread (switched to thread $newthread)"
-}
+    set test "$cmd does not change thread"
+    if {$before_thread == $newthread} {
+       pass "$test"
+    } else {
+       fail "$test (switched to thread $newthread)"
+    }
 
-set start_args $cont_args
-set cont_args [get_args]
+    set after_args [get_args "after"]
 
-set num_other_threads 0
-for {set i 0} {[expr $i < $NUM]} {set i [expr $i + 1]} {
-  if {[lindex $start_args $i] == [lindex $cont_args $i]} {
-    if {$i == $curthread} {
-      fail "current thread stepped (didn't run)"
+    set test "current thread advanced"
+    if { $locked } {
+       set test "$test - locked"
+    } else {
+       set test "$test - unlocked"
     }
-  } else {
-    if {$i == $curthread} {
-       if {[lindex $start_args $i] == [expr [lindex $cont_args $i] - 10]} {
-           pass "current thread stepped"
+
+    set num_other_threads 0
+    for {set i 0} {$i < $NUM} {incr i} {
+       if {[lindex $before_args $i] == [lindex $after_args $i]} {
+           if {$i == $before_thread} {
+               fail "$test (didn't run)"
+           }
        } else {
-           fail "current thread stepped (wrong amount)"
+           if {$i == $before_thread} {
+               if {$cmd == "continue"
+                   || [lindex $before_args $i] == [expr [lindex $after_args $i] - 10]} {
+                   pass "$test"
+               } else {
+                   fail "$test (wrong amount)"
+               }
+           } else {
+               incr num_other_threads
+           }
        }
+    }
+
+    if { $locked } {
+       gdb_assert {$num_other_threads == 0} "other threads didn't run - locked"
     } else {
-      set num_other_threads [expr $num_other_threads + 1]
+       gdb_assert {$num_other_threads > 0} "other threads ran - unlocked"
     }
-  }
-}
-if {$num_other_threads > 0} {
-  pass "other threads ran - unlocked"
-} else {
-  fail "other threads ran - unlocked"
 }
 
-# Test continue with scheduler locking
-gdb_test "set scheduler-locking on" ""
+with_test_prefix "schedlock=on: cmd=continue" {
+    # Use whichever we stopped in.
+    set curthread [get_current_thread "before"]
 
-my_continue "with lock"
+    # Test continue with scheduler locking.
+    gdb_test "set scheduler-locking on" ""
 
-# Make sure we're still in the same thread.
-set newthread [get_current_thread "find current thread (3)"]
-if {$curthread == $newthread} {
-    pass "continue with lock does not change thread"
-} else {
-    fail "continue with lock does not change thread (switched to thread $newthread)"
+    my_continue "with lock"
+
+    check_result "continue" $curthread $cont_args 1
 }
 
-set start_args $cont_args
-set cont_args [get_args]
+# Test stepping/nexting with different modes of scheduler locking.
+proc test_step { schedlock cmd call_function } {
+    global NUM
 
-set num_other_threads 0
-for {set i 0} {[expr $i < $NUM]} {set i [expr $i + 1]} {
-  if {[lindex $start_args $i] == [lindex $cont_args $i]} {
-    if {$i == $curthread} {
-      fail "current thread ran (didn't run)"
-    }
-  } else {
-    if {$i == $curthread} {
-      pass "current thread ran"
-    } else {
-      incr num_other_threads
+    gdb_test_no_output "set scheduler-locking off"
+    goto_loop ""
+
+    set curthread [get_current_thread "before"]
+
+    # No need to set to off again.  This avoids a duplicate message.
+    if {$schedlock != "off"} {
+       gdb_test_no_output "set scheduler-locking $schedlock"
     }
-  }
-}
-if {$num_other_threads > 0} {
-  fail "other threads didn't run - locked"
-} else {
-  pass "other threads didn't run - locked"
-}
 
-# Test stepping with scheduler locking
-step_ten_loops "locked"
+    gdb_test "print call_function = $call_function" \
+       " = $call_function"
 
-# Make sure we're still in the same thread.
-set newthread [get_current_thread "find current thread (2)"]
-if {$curthread == $newthread} {
-    pass "step with lock does not change thread"
-} else {
-    fail "step with lock does not change thread (switched to thread $newthread)"
-}
+    set before_args [get_args "before"]
 
-set start_args $cont_args
-set cont_args [get_args]
+    step_ten_loops $cmd
 
-set num_other_threads 0
-for {set i 0} {[expr $i < $NUM]} {set i [expr $i + 1]} {
-  if {[lindex $start_args $i] == [lindex $cont_args $i]} {
-    if {$i == $curthread} {
-      fail "current thread stepped locked (didn't run)"
-    }
-  } else {
-    if {$i == $curthread} {
-       if {[lindex $start_args $i] == [expr [lindex $cont_args $i] - 10]} {
-           pass "current thread stepped locked"
-       } else {
-           fail "current thread stepped locked (wrong amount)"
-       }
+    if { $schedlock == "on" || $schedlock == "step" } {
+       set locked 1
     } else {
-      incr num_other_threads
+       set locked 0
     }
-  }
-}
-if {$num_other_threads > 0} {
-  fail "other threads didn't run - step locked"
-} else {
-  pass "other threads didn't run - step locked"
+
+    check_result $cmd $curthread $before_args $locked
 }
 
-return 0
+# Test stepping/nexting with different modes of scheduler locking.
+foreach schedlock {"off" "step" "on"} {
+    with_test_prefix "schedlock=$schedlock" {
+       with_test_prefix "cmd=step" {
+           test_step $schedlock "step" 0
+       }
+       with_test_prefix "cmd=next" {
+           # In GDB <= 7.9, with schedlock "step", "next" would
+           # unlock threads when stepping over a function call.  This
+           # exercises "next" with and without a function call.  WRT
+           # "schedlock step", "next" should behave just like "step".
+           foreach call_function {0 1} {
+               with_test_prefix "call_function=$call_function" {
+                   test_step $schedlock "next" $call_function
+               }
+           }
+       }
+    }
+}