From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id KZZ9I4umnmqA6jMAWB0awg (envelope-from ) for ; Mon, 07 Sep 2026 07:56:59 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=IWzZz69K; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 8AEEE1E09E; Mon, 07 Sep 2026 07:56:59 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-6.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 25D241E091 for ; Mon, 07 Sep 2026 07:56:55 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id ADF2C490030A for ; Mon, 7 Sep 2026 11:56:53 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org ADF2C490030A Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=IWzZz69K Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) by sourceware.org (Postfix) with ESMTPS id D44CD4C91762 for ; Mon, 7 Sep 2026 11:55:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D44CD4C91762 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org D44CD4C91762 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1788782160; cv=none; b=v+BF7NLnCfJ3f17ldWfgZbB4kWCvnnARES9faAT9thwHkSkhh82n5eDDPiAgtFC04laNFnqF5mBL/p+MxdECV0khE+bPiojclY27CT/XCwMlb5HXZl0nA8c/XI+sCTV/uE8Nfocmi5m7BDzq4gl2VqD7YTIMdbNLeKY0guxzeoQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1788782160; c=relaxed/simple; bh=6oZZma2K23Z5bjD50kHxtsmpXwQSFDqm9GNlbwcOyNQ=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=jM5sk3YOno0itqebD7sva8sSaxy7aZ8zhOdYzvNLprjulj/oHbiHD+Tap2gtkN8XRbrH5dTSy7JLZfvwG2M/TlcjmTC2UDImvJA3XYL3MqCa0/tQdoLGY/m2Px2HRgRz/wXlaFra7kwD8YXciLEYUCFo45lmF6dqEI+9GR31Ld0= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=IWzZz69K DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D44CD4C91762 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1788782160; x=1820318160; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=6oZZma2K23Z5bjD50kHxtsmpXwQSFDqm9GNlbwcOyNQ=; b=IWzZz69KePMMlgQin60+e4IO1f6aqeTcZEWFR9FwCkB5/4wffjE1d2e3 0/hNUXued4oF+07QyVUXeuTRcdRajvAwjckJQwqKfqePbnqwijvVlf2Oo H5z3Dp7KG6fueblUivBdKEoGgyybIuekgmvIgGcYLPPhWI7+BzBMomW9a DNlNx1UypBf7v/MQlIJgLRrv2JvJl0utoxboRYWZ6GPmPP8QgJ17sJIWb 5+iZeve9alggXdt4MqA2xIXTyICKvaQjp6GYIYB0yyTXAMzL3MrZqdSaw ogzjWytEKU4+xx1EIBY5pnG1TF5yWM8zbSDfrDVUpweezEF4NYSxQrXxH g==; X-CSE-ConnectionGUID: lPo4Nv9TQVG0Kvc/XfM3ew== X-CSE-MsgGUID: rxSAcEcDS+2nfOuTUo0T5A== X-IronPort-AV: E=McAfee;i="6800,10657,11898"; a="99517567" X-IronPort-AV: E=Sophos;i="6.25,267,1779174000"; d="scan'208";a="99517567" Received: from fmviesa009.fm.intel.com ([10.60.135.149]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Sep 2026 04:56:00 -0700 X-CSE-ConnectionGUID: E0rLdff9T6+3deMJmINe/A== X-CSE-MsgGUID: Uj6H/K5jRP6cWHQkm663BQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,267,1779174000"; d="scan'208";a="264496082" Received: from dut1583dg2frd.igk.intel.com (HELO localhost) ([10.211.179.243]) by fmviesa009-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Sep 2026 04:55:58 -0700 From: Klaus Gerlicher To: gdb-patches@sourceware.org Cc: tom@tromey.com, aburgess@redhat.com, eliz@gnu.org, guinevere@redhat.com Subject: [PATCH v9 5/6] gdb: refine commands to control scheduler locking. Date: Mon, 7 Sep 2026 11:55:36 +0000 Message-Id: <20260907115537.307049-6-klaus.gerlicher@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260907115537.307049-1-klaus.gerlicher@intel.com> References: <20260907115537.307049-1-klaus.gerlicher@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org From: Natalia Saiapova In this patch, we introduce new command options for set/show scheduler locking. New options give the user a finer control over the scheduler. Introduce set scheduler-locking show scheduler-locking For example, with these commands a user can get a combined scheduler locking for stepping commands during the normal execution and for all commands in replay mode. The existing scheduler-locking settings still exist and work as shortcuts. set scheduler-locking step is equivalent to set scheduler-locking continue off set scheduler-locking replay continue off set scheduler-locking replay step on set scheduler-locking step on set scheduler-locking on is equivalent to set scheduler-locking continue on set scheduler-locking replay continue on set scheduler-locking replay step on set scheduler-locking step on set scheduler-locking replay is equivalent to set scheduler-locking continue off set scheduler-locking replay continue on set scheduler-locking replay step on set scheduler-locking step off set scheduler-locking off is equivalent to set scheduler-locking continue off set scheduler-locking replay continue off set scheduler-locking replay step off set scheduler-locking step off This is bound to the structure we introduced in the previous commit: gdb: change the internal representation of scheduler locking. To introduce it under scheduler-locking I had to change the way the show command works. (gdb) show scheduler-locking scheduler-locking continue: Scheduler locking for continuing commands in normal execution is "off". scheduler-locking replay continue: Scheduler locking for continuing commands in replay mode is "on". scheduler-locking replay step: Scheduler locking for stepping commands in replay mode is "on". scheduler-locking step: Scheduler locking for stepping commands in normal execution is "off". (gdb) show scheduler-locking replay step Scheduler locking for stepping commands in replay mode is "on". (gdb) show scheduler-locking continue Scheduler locking for continuing commands in normal execution is "off". Note, there is a small inconsistency with the "set scheduler-locking step". If we did not keep the older way of setting the scheduler locking, command set scheduler-locking step would be the same as set scheduler-locking step on while to be backward compatible, we have it as set scheduler-locking step on set scheduler-locking replay step on The early-return optimization via schedlock_applies in switch_back_to_stepped_thread is removed. Previously, when scheduler locking applied unconditionally (not just for stepping), there was no need to check other threads. With fine-grained scheduler locking, the continue and step settings are independent, so we can no longer short-circuit based on the event thread alone. The remaining code already handles the case correctly by walking the thread list. Reviewed-By: Eli Zaretskii --- gdb/NEWS | 21 ++ gdb/doc/gdb.texinfo | 66 ++++- gdb/infrun.c | 253 ++++++++++++++---- .../gdb.threads/hand-call-in-threads.exp | 12 +- .../multiple-successive-infcall.exp | 6 +- gdb/testsuite/gdb.threads/schedlock.exp | 124 ++++++++- gdb/testsuite/lib/gdb.exp | 77 +++++- 7 files changed, 468 insertions(+), 91 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index 28c3d081ea8..09926ae0b2e 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -928,6 +928,27 @@ list . lines. This makes it more obvious that there is no information, as opposed to implying there is no inferior loaded. +set scheduler-locking (on|off) +show scheduler-locking + Where is one of the following: + continue | replay continue | replay step | step. + Extend the scheduler locking settings with a set of set/show + commands, which can be used individually to control the scheduler during + stepping and continuing commands. Stepping commands include step, stepi, + next. Continuing commands include continue, finish, until, jump, return. + 'continue' -- when on, the scheduler is locked during continuing commands + during normal execution (not replay mode). + 'replay continue' -- when on, the scheduler is locked during continuing + commands in replay mode. + 'replay step' -- when on, the scheduler is locked during stepping + commands in replay mode. + 'step' -- when on, the scheduler is locked during stepping commands + during normal execution (not replay mode). + The older scheduler locking settings can be used as shortcuts, their behavior + is preserved. + The output of "show scheduler-locking" has changed to support the new + settings. + * New commands info missing-debug-handler diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 09080ccdad9..7767c399fa4 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -7456,28 +7456,63 @@ On some OSes, you can modify @value{GDBN}'s default behavior by locking the OS scheduler to allow only a single thread to run. @table @code -@item set scheduler-locking @var{mode} @cindex scheduler-locking +@item set scheduler-locking @var{type} @r{[}@samp{on}@r{|}@samp{off}@r{]} +@cindex scheduler locking type +@cindex lock scheduler +Set the scheduler locking settings. It applies to normal execution, +record mode, and replay mode. You can configure scheduler locking separately +for stepping and continuing commands. Examples of stepping commands are: +@samp{step}, @samp{stepi}, @samp{next}. Examples of continuing commands are +@samp{continue}, @samp{finish}, @samp{jump}, @samp{until}, @samp{return} or +inferior function calls. + +The following @var{type}-settings are available. When a setting is +@samp{on}, the scheduler is locked: other threads may not preempt the +current thread, so that the focus of debugging does not change unexpectedly. + +@table @code +@item continue +Applies to continuing commands during normal execution and record modes. +This setting is @samp{off} by default. + +@item replay continue +Applies to continuing commands during replay mode. This setting is +@samp{on} by default. + +@item replay step +Applies to stepping commands during replay mode. This setting is +@samp{on} by default. + +@item step +Applies to stepping commands during normal execution and record modes. +This setting is @samp{off} by default. + +@end table + +@item set scheduler-locking @var{shortcut-mode} @cindex scheduler locking mode @cindex lock scheduler -Set the scheduler locking mode. It applies to normal execution, -record mode, and replay mode. @var{mode} can be one of -the following: +Set the scheduler locking mode. It applies to normal execution, record mode, +and replay mode. @var{shortcut-mode} is a shortcut to set several scheduler +locking types at once and can be one of the following: @table @code @item off -There is no locking and any thread may run at any time. +There is no locking and any thread may run at any time. This is +equivalent to setting all type options to @samp{off}. @item on -Only the current thread may run when the inferior is resumed. New -threads created by the resumed thread are held stopped at their entry -point, before they execute any instruction. +Only the current thread may run when the inferior is resumed. New threads +created by the resumed thread are held stopped at their entry point, before +they execute any instruction. This is equivalent to setting all type options +to @samp{on}. @item step Behaves like @code{on} when stepping, and @code{off} otherwise. Threads other than the current never get a chance to run when you -step, and they are completely free to run when you use commands like -@samp{continue}, @samp{until}, or @samp{finish}. +step, and they are completely free to run when you use continuing +commands. This mode optimizes for single-stepping; it prevents other threads from preempting the current thread while you are stepping, so that the @@ -7486,9 +7521,18 @@ another thread hits a breakpoint during its timeslice, @value{GDBN} does not change the current thread away from the thread that you are debugging. +This is equivalent to setting @samp{scheduler-locking step} and +@samp{scheduler-locking replay step} to @samp{on}, while other settings +are @samp{off}. + @item replay Behaves like @code{on} in replay mode, and @code{off} in either record mode or during normal execution. This is the default mode. + +This is equivalent to setting @samp{scheduler-locking replay continue} and +@samp{scheduler-locking replay step} to @samp{on}, while other settings +are @samp{off}. + @end table @item show scheduler-locking @@ -34712,7 +34756,7 @@ the end or beginning of a replay log if one is being used. @end itemize In all-stop mode (@pxref{All-Stop Mode}), may resume only one thread, or all threads, depending on the -value of the @samp{scheduler-locking} variable. If @samp{--all} is +value of the @samp{scheduler-locking} variables. If @samp{--all} is specified, all threads (in all inferiors) will be resumed. The @samp{--all} option is ignored in all-stop mode. If the @samp{--thread-group} options is specified, then all threads in that thread group are resumed. diff --git a/gdb/infrun.c b/gdb/infrun.c index a501c8a1ebd..327ab12fbba 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -75,6 +75,7 @@ #include "extension.h" #include "disasm.h" #include "interps.h" +#include "cli/cli-decode.h" #include "finish-thread-state.h" #include "buffered-streams.h" @@ -112,10 +113,17 @@ static bool schedlock_applies (thread_info *tp); static bool schedlock_applies (bool step, bool record_will_replay, thread_info *tp = nullptr); -static bool schedlock_applies_to_opts (const schedlock_mode_options &, bool step); +static bool schedlock_applies_to_opts (const schedlock_mode_options &, + bool step); static void handle_process_exited (struct execution_control_state *ecs); +/* Command lists for the scheduler locking. */ +static cmd_list_element *schedlock_set_cmdlist; +static cmd_list_element *schedlock_show_cmdlist; +static cmd_list_element *schedlock_set_replay_cmdlist; +static cmd_list_element *schedlock_show_replay_cmdlist; + /* Asynchronous signal handler registered as event loop source for when we have pending events ready to be passed to the core. */ static struct async_event_handler *infrun_async_inferior_event_token; @@ -2378,6 +2386,12 @@ infrun_thread_ptid_changed (process_stratum_target *target, inferior_ptid = new_ptid; } +/* Forward declarations for use in schedlock_option::make_cli_option. */ +static void set_schedlock_callback (const char *, int, cmd_list_element *); +static void set_schedlock_step (const char *, int, cmd_list_element *); +static void show_schedlock_option (ui_file *, int, cmd_list_element *, + const char *); + /* A single scheduler locking option, holding a name and boolean value. */ struct schedlock_option { @@ -2393,9 +2407,33 @@ struct schedlock_option operator bool () const { return m_value; } const char *c_str () const { return m_value ? "on" : "off"; } - /* Set new value. Return true if the value has changed. */ + /* Set new value. Return true if the value has changed. + Also notifies the observer if the value has changed. */ bool set (bool new_value); + /* Register this option as a boolean CLI command. */ + void make_cli_option (const char *name, const char *set_doc, + const char *show_doc, const char *help_doc, + cmd_func_ftype *set_func, + cmd_list_element **set_list, + cmd_list_element **show_list) + { + add_setshow_boolean_cmd (name, class_run, &m_value, + set_doc, show_doc, help_doc, + set_func, + show_schedlock_option, + set_list, show_list); + } + + void make_cli_option (const char *name, const char *set_doc, + const char *show_doc, const char *help_doc, + cmd_list_element **set_list, + cmd_list_element **show_list) + { + make_cli_option (name, set_doc, show_doc, help_doc, + set_schedlock_callback, set_list, show_list); + } + private: const std::string m_name; bool m_value; @@ -2407,6 +2445,9 @@ schedlock_option::set (bool new_value) if (m_value != new_value) { m_value = new_value; + std::string param_name = "scheduler-locking " + m_name; + + interps_notify_param_changed (param_name.c_str (), c_str ()); return true; } @@ -2447,15 +2488,6 @@ static const char schedlock_off[] = "off"; static const char schedlock_on[] = "on"; static const char schedlock_step[] = "step"; static const char schedlock_replay[] = "replay"; -static const char *const scheduler_enums[] = { - schedlock_off, - schedlock_on, - schedlock_step, - schedlock_replay, - nullptr -}; - -static const char *scheduler_mode = schedlock_replay; /* Global scheduler locking state. */ static schedlock_state scheduler_locking_state { @@ -2485,35 +2517,94 @@ set_schedlock_shortcut_option (const char *shortcut) /* Check that we got a valid shortcut option. */ gdb_assert (is_on || is_step || is_replay || is_off); - scheduler_locking_state.normal.cont.set (is_on); - scheduler_locking_state.normal.step.set (is_on || is_step); - scheduler_locking_state.replay.cont.set (is_on || is_replay); - scheduler_locking_state.replay.step.set (is_on || is_replay || is_step); + bool any_changed = scheduler_locking_state.normal.cont.set (is_on); + any_changed = scheduler_locking_state.normal.step.set (is_on || is_step) || any_changed; + any_changed = scheduler_locking_state.replay.cont.set (is_on || is_replay) || any_changed; + any_changed = scheduler_locking_state.replay.step.set (is_on || is_replay || is_step) + || any_changed; + + /* If at least one parameter has changed, notify the observer + in the old-fashioned way. */ + if (any_changed) + interps_notify_param_changed ("scheduler-locking", shortcut); } +/* Default callback for set methods of scheduler locking options. + Checks that the scheduler locking is supported. + If no, it reverts all options to "off" and throws an error. */ + static void -show_scheduler_mode (struct ui_file *file, int from_tty, - struct cmd_list_element *c, const char *value) +set_schedlock_callback (const char *args, int from_tty, cmd_list_element *c) { - gdb_printf (file, - _("Mode for locking scheduler " - "during execution is \"%s\".\n"), - value); + if (target_can_lock_scheduler ()) + return; + + /* Set scheduler locking off and error out. */ + set_schedlock_shortcut_option (schedlock_off); + error (_("Target '%s' cannot support this command."), target_shortname ()); +} + +/* Support for shortcut schedlock options: "on", "off", "step", "replay". */ + +static void +set_schedlock_step (const char *args, int from_tty, cmd_list_element *c) +{ + if (!args || !*args) + set_schedlock_shortcut_option (schedlock_step); + set_schedlock_callback (args, from_tty, nullptr); +} + +static void +set_schedlock_replay (const char *args, int from_tty) +{ + set_schedlock_shortcut_option (schedlock_replay); + set_schedlock_callback (args, from_tty, nullptr); +} + +static void +set_schedlock_on (const char *args, int from_tty) +{ + set_schedlock_shortcut_option (schedlock_on); + set_schedlock_callback (args, from_tty, nullptr); +} + +static void +set_schedlock_off (const char *args, int from_tty) +{ + set_schedlock_shortcut_option (schedlock_off); + set_schedlock_callback (args, from_tty, nullptr); } +/* Default method to show a single option of scheduler locking. */ + static void -set_schedlock_func (const char *args, int from_tty, struct cmd_list_element *c) +show_schedlock_option (ui_file *file, int from_tty, + cmd_list_element *c, const char *value) { - if (!target_can_lock_scheduler ()) + gdb_assert (c->prefix != nullptr); + + bool is_replay = (strcmp (c->prefix->name, "replay") == 0); + + if (strcmp (c->name, "step") == 0) { - scheduler_mode = schedlock_off; - /* Set scheduler locking off. */ - set_schedlock_shortcut_option (schedlock_off); - error (_("Target '%s' cannot support this command."), - target_shortname ()); + if (is_replay) + gdb_printf (file, _("Scheduler locking for stepping commands " + "in replay mode is \"%s\".\n"), value); + else + gdb_printf (file, _("Scheduler locking for stepping commands " + "in normal execution is \"%s\".\n"), value); } - - set_schedlock_shortcut_option (scheduler_mode); + else if (strcmp (c->name, "continue") == 0) + { + if (is_replay) + gdb_printf (file, _("Scheduler locking for continuing commands " + "in replay mode is \"%s\".\n"), value); + else + gdb_printf (file, _("Scheduler locking for continuing commands " + "in normal execution is \"%s\".\n"), value); + } + else + gdb_assert_not_reached ("Unexpected command name."); } /* True if execution commands resume all threads of all processes by @@ -3283,7 +3374,8 @@ clear_proceed_status (int step, bool about_to_proceed) "set scheduler-locking step". This ensures that when any form of scheduler locking is active that would affect replay mode, we stop replaying threads that have finished their replay. */ - if (!non_stop && schedlock_applies_to_opts (scheduler_locking_state.replay, step) + if (!non_stop && schedlock_applies_to_opts (scheduler_locking_state.replay, + step) && !target_record_will_replay (inferior_ptid, execution_direction)) target_record_stop_replaying (); @@ -8655,15 +8747,7 @@ switch_back_to_stepped_thread (struct execution_control_state *ecs) return true; } - /* If scheduler locking applies even if not stepping, there's no - need to walk over threads. Above we've checked whether the - current thread is stepping. If some other thread not the - event thread is stepping, then it must be that scheduler - locking is not in effect. */ - if (schedlock_applies (ecs->event_thread)) - return false; - - /* Otherwise, we no longer expect a trap in the current thread. + /* We no longer expect a trap in the current thread. Clear the trap_expected flag before switching back -- this is what keep_going does as well, if we call it. */ ecs->event_thread->control.trap_expected = 0; @@ -11030,21 +11114,84 @@ By default, the debugger will use the same inferior."), show_follow_exec_mode_string, &setlist, &showlist); - add_setshow_enum_cmd ("scheduler-locking", class_run, - scheduler_enums, &scheduler_mode, _("\ -Set mode for locking scheduler during execution."), _("\ -Show mode for locking scheduler during execution."), _("\ -off == no locking (threads may preempt at any time)\n\ -on == full locking (no thread except the current thread may run)\n\ - This applies to both normal execution and replay mode.\n\ -step == scheduler locked during stepping commands (step, next, stepi, nexti).\n\ - In this mode, other threads may run during other commands.\n\ - This applies to both normal execution and replay mode.\n\ -replay == scheduler locked in replay mode and unlocked during normal execution."), - set_schedlock_func, /* traps on target vector */ - show_scheduler_mode, + /* Commands for set/show scheduler-locking. */ + + add_setshow_prefix_cmd ("scheduler-locking", class_run, _("\ +Scheduler locking settings.\n\ +Configure scheduler locking settings in various conditions."), _("\ +Show scheduler locking settings in various conditions."), + &schedlock_set_cmdlist, + &schedlock_show_cmdlist, &setlist, &showlist); + scheduler_locking_state.normal.cont.make_cli_option + ("continue", + _("Scheduler locking for continuing commands during normal execution."), + _("Show scheduler locking for continuing commands during normal execution."), + _("Controls scheduler locking for continuing commands during normal execution.\n\ +Commands include continue, until, finish. The setting does not affect\n\ +stepping and function calls."), + &schedlock_set_cmdlist, &schedlock_show_cmdlist); + + scheduler_locking_state.normal.step.make_cli_option + ("step", + _("Scheduler locking for stepping commands.\n\ +Without arguments locks the scheduler for stepping."), + _("Show scheduler locking for stepping commands during normal execution."), + _("If argument \"on\" or \"off\", sets scheduler locking behavior for stepping\n\ +commands only during normal execution.\n\ +Commands include step, next, stepi, nexti."), + set_schedlock_step, + &schedlock_set_cmdlist, &schedlock_show_cmdlist); + + /* Commands for set/show scheduler-locking in replay mode. + The base command adds support for the shortcut + set scheduler-locking replay + command. */ + + add_setshow_prefix_cmd ("replay", class_run, _("\ +Scheduler locking settings for replay mode.\n\ +Configure scheduler locking in various conditions such as during continuing\n\ +or stepping."), + _("Show scheduler locking in replay mode."), + &schedlock_set_replay_cmdlist, + &schedlock_show_replay_cmdlist, + &schedlock_set_cmdlist, + &schedlock_show_cmdlist); + add_prefix_cmd ("replay", class_run, set_schedlock_replay, _("\ +Scheduler locking settings for replay mode.\n\ +Without arguments completely locks the scheduler."), + &schedlock_set_replay_cmdlist, + 0, &schedlock_set_cmdlist); + + scheduler_locking_state.replay.cont.make_cli_option + ("continue", + _("Set scheduler locking for continuing commands in replay mode."), + _("Show scheduler locking for continuing commands in replay mode."), + _("Controls scheduler locking for continuing commands in replay mode.\n\ +Commands include continue, until, finish. The setting does not affect\n\ +stepping and function calls."), + &schedlock_set_replay_cmdlist, &schedlock_show_replay_cmdlist); + + scheduler_locking_state.replay.step.make_cli_option + ("step", + _("Set scheduler locking for stepping commands in replay mode."), + _("Show scheduler locking for stepping commands in replay mode."), + _("Controls scheduler locking for stepping commands in replay mode.\n\ +Commands include step, next, stepi, nexti."), + &schedlock_set_replay_cmdlist, &schedlock_show_replay_cmdlist); + + /* Commands "set scheduler-locking on" and "set scheduler-locking off" + are provided for backward compatibility. */ + add_cmd ("on", class_run, set_schedlock_on, _("\ +Full scheduler locking (no thread except the current thread may run).\n\ +This applies to both normal execution and replay mode."), + &schedlock_set_cmdlist); + + add_cmd ("off", class_run, set_schedlock_off, _("\ +No scheduler locking (threads may preempt at any time)."), + &schedlock_set_cmdlist); + add_setshow_boolean_cmd ("schedule-multiple", class_run, &sched_multi, _("\ Set mode for resuming threads of all processes."), _("\ Show mode for resuming threads of all processes."), _("\ diff --git a/gdb/testsuite/gdb.threads/hand-call-in-threads.exp b/gdb/testsuite/gdb.threads/hand-call-in-threads.exp index 2f5eaa5405b..06ec22e1138 100644 --- a/gdb/testsuite/gdb.threads/hand-call-in-threads.exp +++ b/gdb/testsuite/gdb.threads/hand-call-in-threads.exp @@ -68,7 +68,11 @@ gdb_test "continue" \ # Before we start making hand function calls, turn on scheduler locking. gdb_test_no_output "set scheduler-locking on" "enable scheduler locking" -gdb_test "show scheduler-locking" ".* locking scheduler .* is \"on\"." "show scheduler locking on" +set test "show scheduler-locking on" +gdb_assert {[get_scheduler_locking $test \ + [dict create "continue" "on" \ + "replay continue" "on" \ + "replay step" "on" "step" "on"]] ne "unknown"} $test # Now hand-call a function in each thread, having the function # stop without returning. @@ -139,7 +143,11 @@ gdb_test_multiple "maint print dummy-frames" "all dummies popped" { # Before we resume the full program, turn off scheduler locking. gdb_test_no_output "set scheduler-locking off" "disable scheduler locking" -gdb_test "show scheduler-locking" ".* locking scheduler .* is \"off\"." "show scheduler locking off" +set test "show scheduler-locking off" +gdb_assert {[get_scheduler_locking $test \ + [dict create "continue" "off" \ + "replay continue" "off" \ + "replay step" "off" "step" "off"]] ne "unknown"} $test # Continue one last time, the program should exit normally. # diff --git a/gdb/testsuite/gdb.threads/multiple-successive-infcall.exp b/gdb/testsuite/gdb.threads/multiple-successive-infcall.exp index fdcbaa47c7f..4bda757027b 100644 --- a/gdb/testsuite/gdb.threads/multiple-successive-infcall.exp +++ b/gdb/testsuite/gdb.threads/multiple-successive-infcall.exp @@ -49,8 +49,10 @@ foreach_with_prefix thread {5 4 3} { gdb_breakpoint [gdb_get_line_number "testmarker01"] gdb_continue_to_breakpoint "testmarker01" gdb_test_no_output "set scheduler-locking on" -gdb_test "show scheduler-locking" \ - "Mode for locking scheduler during execution is \"on\"." +set test "show scheduler-locking" +gdb_assert {[get_scheduler_locking $test \ + [dict create "continue" "on" "replay continue" "on" \ + "replay step" "on" "step" "on"]] ne "unknown"} $test foreach_with_prefix thread {5 4 3 2 1} { gdb_test "thread ${thread}" "Switching to .*" diff --git a/gdb/testsuite/gdb.threads/schedlock.exp b/gdb/testsuite/gdb.threads/schedlock.exp index 572e1f9a715..5fd52acbf91 100644 --- a/gdb/testsuite/gdb.threads/schedlock.exp +++ b/gdb/testsuite/gdb.threads/schedlock.exp @@ -94,7 +94,8 @@ proc get_current_thread { description } { # 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"] + global srcfile + gdb_breakpoint [concat "$srcfile:" [gdb_get_line_number "schedlock.exp: main loop"] " if arg != 0"] set test "return to loop" if {$msg != ""} { @@ -267,16 +268,21 @@ with_test_prefix "schedlock=on: cmd=continue" { } # Test stepping/nexting with different modes of scheduler locking. -proc test_step { schedlock cmd call_function } { +# Do scheduler-locking off setting before the test if PRESET_SCHEDLOCK_OFF is 1. +# LOCKED defines whether we expect the thread to be locked. If -1, then +# determine it first. +proc test_step { schedlock cmd call_function { preset_schedlock_off 1 } { locked -1 } } { global NUM - gdb_test_no_output "set scheduler-locking off" + if {$preset_schedlock_off} { + 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"} { + if {$preset_schedlock_off && $schedlock != "off"} { gdb_test_no_output "set scheduler-locking $schedlock" } @@ -287,16 +293,18 @@ proc test_step { schedlock cmd call_function } { step_ten_loops $cmd - if { $schedlock == "on" || $schedlock == "step" } { - set locked 1 - } else { - set locked 0 + if { $locked == -1 } { + if { $schedlock == "on" || $schedlock == "step"} { + set locked 1 + } else { + set locked 0 + } } check_result $cmd $curthread $before_args $locked } -# Test stepping/nexting with different modes of scheduler locking. +# Test stepping/nexting with different shortcut modes of scheduler locking. foreach schedlock {"off" "step" "on"} { with_test_prefix "schedlock=$schedlock" { with_test_prefix "cmd=step" { @@ -315,3 +323,101 @@ foreach schedlock {"off" "step" "on"} { } } } + +# Test scheduler locking with specific option values. +# CONT and STEP are the expected values ("on" or "off") for the +# normal execution scheduler-locking options: continue and step. +# This proc verifies the options are set correctly, then runs stepping +# and continuing tests to ensure the locking behavior matches expectations. +# Replay options are assumed to be "off" for these tests. +proc test_schedlock_opts {cont step} { + set test "show scheduler-locking" + gdb_assert {[get_scheduler_locking $test \ + [dict create "continue" $cont "replay continue" "off" \ + "replay step" "off" "step" $step]] ne "unknown"} $test + + set locked 0 + if {$step eq "on"} { + set locked 1 + } + + # Stepping tests. + with_test_prefix "cmd=step" { + test_step "" "step" 0 0 $locked + } + with_test_prefix "cmd=next" { + foreach call_function {0 1} { + with_test_prefix "call_function=$call_function" { + test_step "" "next" $call_function 0 $locked + } + } + } + + # Continuing tests. + set locked 0 + if {$cont eq "on"} { + set locked 1 + } + with_test_prefix "cmd=continue" { + # Use whichever we stopped in. + set curthread [get_current_thread "before"] + set cont_args [get_args "before"] + my_continue "continue" + check_result "continue" $curthread $cont_args $locked + } +} + +# Test different options of scheduler locking. +with_test_prefix "option combinations" { + gdb_test_no_output "set scheduler-locking off" + + foreach cont {"off" "on"} { + foreach step {"off" "on"} { + with_test_prefix "continue=$cont step=$step" { + gdb_test_no_output "set scheduler-locking continue $cont" + gdb_test_no_output "set scheduler-locking step $step" + test_schedlock_opts $cont $step + } + } + } +} + +# Test that replay options can be set individually. +with_test_prefix "replay options" { + gdb_test_no_output "set scheduler-locking off" + foreach replay_cont {"off" "on"} { + foreach replay_step {"off" "on"} { + with_test_prefix "replay: continue=$replay_cont step=$replay_step" { + gdb_test_no_output "set scheduler-locking replay continue $replay_cont" + gdb_test_no_output "set scheduler-locking replay step $replay_step" + set test "verify replay options" + gdb_assert {[get_scheduler_locking $test \ + [dict create "continue" "off" \ + "replay continue" $replay_cont \ + "replay step" $replay_step \ + "step" "off"]] ne "unknown"} $test + } + } + } +} + +# Test that each normal execution option can be set independently. +with_test_prefix "individual options" { + gdb_test_no_output "set scheduler-locking off" "reset for continue test" + # Test setting only 'continue'. + gdb_test_no_output "set scheduler-locking continue on" + gdb_assert {[get_scheduler_locking "continue only" \ + [dict create "continue" "on" \ + "replay continue" "off" \ + "replay step" "off" "step" "off"]] ne "unknown"} \ + "continue only" + + # Reset and test setting only 'step'. + gdb_test_no_output "set scheduler-locking off" "reset for step test" + gdb_test_no_output "set scheduler-locking step on" + gdb_assert {[get_scheduler_locking "step only" \ + [dict create "continue" "off" \ + "replay continue" "off" \ + "replay step" "off" "step" "on"]] ne "unknown"} \ + "step only" +} diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 867d8b7dfd7..7de75265513 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -10424,6 +10424,59 @@ gdb_caching_proc gdb_target_symbol_prefix {} { return $prefix } +# Return a dictionary of scheduler locking settings with keys: +# continue, replay continue, replay step, step. +# TEST is an optional test name. +# EXPECTED is a dictionary of expected values for scheduler locking with +# the same keys. If EXPECTED has less elements than scheduler locking +# settings, that means that both on and off can be expected for missing +# settings. +proc get_scheduler_locking {{test ""} {expected ""}} { + global gdb_prompt + if {$test eq ""} { + set test "reading current scheduler-locking mode" + } + + set opts {"continue" "replay continue" "replay step" "step"} + + # Fill the missing entries in EXPECTED list. + foreach opt $opts { + if {![dict exists $expected $opt]} { + dict set expected $opt "\(?:on|off\)" + } + } + + set any "\[^\r\n\]+" + set schedlock_regex "" + set first 1 + foreach opt $opts { + # Match: scheduler-locking : ...is "value". + set opt_regex \ + "scheduler-locking $opt:\[^\"\]*\"\([dict get $expected $opt]\)\"\\\." + if {$first} { + set schedlock_regex "${any}\[\r\n\]+$opt_regex" + set first 0 + } else { + set schedlock_regex "$schedlock_regex\[\r\n\]+$opt_regex" + } + } + + set current_schedlock_mode "unknown" + gdb_test_multiple "show scheduler-locking" $test { + -re -wrap $schedlock_regex { + set current_schedlock_mode [dict create] + set i 1 + foreach opt $opts { + dict set current_schedlock_mode $opt $expect_out($i,string) + incr i + } + } + -re -wrap "" {} + timeout {} + } + return $current_schedlock_mode +} + # Return 1 if target supports scheduler locking, otherwise return 0. gdb_caching_proc target_supports_scheduler_locking {} { @@ -10443,28 +10496,24 @@ gdb_caching_proc target_supports_scheduler_locking {} { } set supports_schedule_locking -1 - set current_schedule_locking_mode "" set test "reading current scheduler-locking mode" - gdb_test_multiple "show scheduler-locking" $test { - -re "Mode for locking scheduler during execution is \"(\[\^\"\]*)\".*$gdb_prompt" { - set current_schedule_locking_mode $expect_out(1,string) - } - -re "$gdb_prompt $" { - set supports_schedule_locking 0 - } - timeout { - set supports_schedule_locking 0 - } + set current_schedlock [get_scheduler_locking $test] + if { $current_schedlock eq "unknown" } { + set supports_schedule_locking 0 } if { $supports_schedule_locking == -1 } { set test "checking for scheduler-locking support" - gdb_test_multiple "set scheduler-locking $current_schedule_locking_mode" $test { - -re "Target '\[^'\]+' cannot support this command\..*$gdb_prompt $" { + set regex_schedlock \ + "set scheduler-locking step [dict get $current_schedlock step]" + + # Try to set scheduler-locking run. + gdb_test_multiple $regex_schedlock $test { + -re -wrap "Target '\[^'\]+' cannot support this command\..*" { set supports_schedule_locking 0 } - -re "$gdb_prompt $" { + -re -wrap "" { set supports_schedule_locking 1 } timeout { -- 2.34.1 ________________________________________ Intel Deutschland GmbH Registered Address: Dornacher Strasse 1, 85622 Feldkirchen, Germany Tel: +49 (89) 99143-0 www.intel.de Managing Directors: Candice Moore, Jeffrey Schneiderman, Ramachandran Sitaraman Chairperson of the Supervisory Board: Sonja Pierer Registered Seat: Munich Commercial Register B: Amtsgericht Munich HRB 186928 This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.