Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

# Copyright (C) 2019-2020 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
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

standard_testfile

if {[build_executable "failed to prepare" $testfile $srcfile {debug pthreads}] == -1} {
    return -1
}

# At this point GDB will be busy handling the breakpoint hits and
# re-resuming the program.  Even if GDB internally switches thread
# context, the user should not notice it.  The following part of the
# testcase ensures that.

# Switch to thread EXPECTED_THR, and then confirm that the thread
# stays selected.

proc test_current_thread {expected_thr} {
    global decimal
    global gdb_prompt
    global binfile

    clean_restart $binfile

    if {![runto "all_started"]} {
	fail "could not run to all_started"
	return
    }

    # Set a breakpoint that continuously fires but doeesn't cause a stop.
    gdb_breakpoint [concat [gdb_get_line_number "set breakpoint here"] " if 0"]

    gdb_test "thread $expected_thr" "Switching to thread $expected_thr .*" \
	"switch to thread $expected_thr"

    # Continue the program in the background.
    set test "continue&"
    gdb_test_multiple "continue&" $test {
	-re "Continuing\\.\r\n$gdb_prompt " {
	    pass $test
	}
    }

    set test "current thread is $expected_thr"
    set fails 0
    for {set i 0} {$i < 10} {incr i} {
	after 200

	set cur_thread 0
	gdb_test_multiple "thread" $test {
	    -re "Current thread is ($decimal) .*$gdb_prompt " {
		set cur_thread $expect_out(1,string)
	    }
	}

	if {$cur_thread != $expected_thr} {
	    incr fails
	}
    }

    gdb_assert {$fails == 0} $test

    # Explicitly interrupt the target, because in all-stop/remote,
    # that's all we can do when the target is running.  If we don't do
    # this, we'd time out trying to kill the target, while bringing
    # down gdb & gdbserver.
    set test "interrupt"
    gdb_test_multiple $test $test {
	-re "^interrupt\r\n$gdb_prompt " {
	    gdb_test_multiple "" $test {
		-re "Thread .* received signal SIGINT, Interrupt\\." {
		    pass $test
		}
	    }
	}
    }
}

# Try once with each thread as current, to avoid missing a bug just
# because some part of GDB manages to switch to the right thread by
# chance.
for {set thr 1} {$thr <= 3} {incr thr} {
    with_test_prefix "thread $thr" {
	test_current_thread $thr
    }
}