public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Natalia Saiapova <natalia.saiapova@intel.com>
To: gdb-patches@sourceware.org
Subject: [PATCH v2 5/6] gdb: refine commands to control scheduler locking.
Date: Tue,  9 Jul 2024 15:04:09 +0000	[thread overview]
Message-ID: <20240709150410.34624-6-natalia.saiapova@intel.com> (raw)
In-Reply-To: <20240709150410.34624-1-natalia.saiapova@intel.com>

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 <non-step | replay step | replay non-step> | step> <on | off>
show scheduler-locking <non-step | replay step | replay non-step| step>

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 non-step off
  set scheduler-locking replay non-step off
  set scheduler-locking replay step on
  set scheduler-locking step on

  set scheduler-locking on
is equivalent to
  set scheduler-locking non-step on
  set scheduler-locking replay non-step on
  set scheduler-locking replay step on
  set scheduler-locking step on

  set scheduler-locking replay
is equivalent to
  set scheduler-locking non-step off
  set scheduler-locking replay non-step on
  set scheduler-locking replay step on
  set scheduler-locking step off

  set scheduler-locking off
is equivalent to
  set scheduler-locking non-step off
  set scheduler-locking replay non-step 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 non-step:  "off"  Scheduler locking for non-stepping
  commands is "off" during normal execution.
  scheduler-locking replay non-step:  "on"  Scheduler locking for
  non-stepping commands is "on" during replay mode.
  scheduler-locking replay step:  "on"  Scheduler locking for stepping
  commands is "on" during replay mode.
  scheduler-locking step:  "off"  Scheduler locking for stepping commands
  is "off" during normal execution.

  (gdb) show scheduler-locking replay
  scheduler-locking replay non-step:  "on"  Scheduler locking for
  non-stepping commands is "on" during replay mode.
  scheduler-locking replay step:  "on"  Scheduler locking for stepping
  commands is "on" during replay mode.

  (gdb) show scheduler-locking replay step
  "on"  Scheduler locking for stepping commands is "on" during replay mode.

  (gdb) show scheduler-locking non-step
  "off"  Scheduler locking for non-stepping commands is "off" during
  normal execution.

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

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
---
 gdb/NEWS                                      |  20 ++
 gdb/doc/gdb.texinfo                           |  70 +++++-
 gdb/infrun.c                                  | 224 ++++++++++++++----
 .../gdb.mi/user-selected-context-sync.exp     |  22 +-
 .../gdb.threads/hand-call-in-threads.exp      |  10 +-
 .../multiple-successive-infcall.exp           |   6 +-
 gdb/testsuite/gdb.threads/schedlock.exp       |  80 ++++++-
 gdb/testsuite/lib/gdb.exp                     |  70 ++++--
 8 files changed, 400 insertions(+), 102 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 47677cb773a..188596b20e7 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -58,6 +58,26 @@ list .
   lines.  This makes it more obvious that there is no information, as opposed
   to implying there is no inferior loaded.
 
+set scheduler-locking <command type> (on|off)
+show scheduler-locking <command type>
+  where <command-type> is one of the following:
+    non-step | replay non-step | 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 non-stepping commands. Stepping commands include step, stepi, next.
+  Non-stepping commands include continue, finish, until, jump, return.
+    'non-step' -- when on, the scheduler is locked during non-stepping commands
+    in normal mode.
+    'replay non-step' -- when on, the scheduler is locked during non-stepping
+    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
+    in normal 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 86cd420832a..32e2703414d 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -7175,28 +7175,67 @@ 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} [@code{on}|@code{off}]
+@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 non-stepping commands.  Examples of stepping commands are:
+@samp{step}, @samp{stepi}, @samp{next}.  Examples of non-stepping commands are
+@samp{continue}, @samp{finish}, @samp{jump}, @samp{until}, @samp{return} or
+inferior function calls.
+
+The following @var{type}-settings are available:
+
+@table @code
+@item non-step
+When @code{on}, the scheduler is locked for non-stepping commands during
+normal execution and record modes.  For non-stepping commands other threads
+may not preempt the current thread.  This setting is @code{off} by default.
+
+@item replay non-step
+When @code{on}, the scheduler is locked for non-stepping commands during
+replay mode.  For non-stepping commands other threads may not preempt
+the current thread.  This setting is @code{on} by default.
+
+@item replay step
+When @code{on}, the scheduler is locked for stepping commands during replay
+mode.  While stepping, other threads may not preempt the current thread,
+so that the focus of debugging does not change unexpectedly.  This setting
+is @code{on} by default.
+
+@item step
+When @code{on}, the scheduler is locked for stepping commands during
+normal execution and record modes.  While stepping, other threads may not
+preempt the current thread, so that the focus of debugging does not change
+unexpectedly.  This setting is @code{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 @code{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 @code{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 non-stepping
+commands.
 
 This mode optimizes for single-stepping; it prevents other threads
 from preempting the current thread while you are stepping, so that the
@@ -7205,9 +7244,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 set @samp{scheduler-locking step} and
+@samp{scheduler-locking replay step} to @code{on}, while other settings
+are @code{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 set @samp{scheduler-locking replay non-step} and
+@samp{scheduler-locking replay step} to @code{on}, while other settings
+are @code{off}.
+
 @end table
 
 @item show scheduler-locking
@@ -34171,7 +34219,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 21b7b7c7806..b02966a8afa 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -77,6 +77,8 @@
 #include "extension.h"
 #include "disasm.h"
 #include "interps.h"
+#include "cli/cli-decode.h"
+#include <set>
 
 /* Prototypes for local functions */
 
@@ -112,6 +114,12 @@ static bool schedlock_applies (thread_info *);
 static bool schedlock_applies (thread_info *, bool);
 static bool schedlock_applies_to_opts (const schedlock_options &, bool);
 
+/* 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;
@@ -2346,7 +2354,8 @@ struct schedlock_options
 
     operator bool () const { return value; }
     const char *c_str () const { return 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);
   };
 
@@ -2373,6 +2382,9 @@ schedlock_options::option::set (bool new_value)
   if (value != new_value)
     {
       value = new_value;
+      std::string param_name = "scheduler-locking " + name;
+
+      interps_notify_param_changed (param_name.c_str (), c_str ());
       return true;
     }
 
@@ -2393,15 +2405,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;
 
 schedlock schedlock {{{"non-step", false}, {"step", false}},
 		     {{"replay non-step", true}, {"replay step", true}}};
@@ -2422,35 +2425,89 @@ 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);
 
-  schedlock.normal.non_step.set (is_on);
-  schedlock.normal.step.set (is_on || is_step);
-  schedlock.replay.non_step.set (is_on || is_replay);
-  schedlock.replay.step.set (is_on || is_replay || is_step);
+  bool any_changed = schedlock.normal.non_step.set (is_on);
+  any_changed = schedlock.normal.step.set (is_on || is_step) || any_changed;
+  any_changed = schedlock.replay.non_step.set (is_on || is_replay) || any_changed;
+  any_changed = schedlock.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_func (const char *args, int from_tty, struct cmd_list_element *c)
+set_schedlock_step (const char *args, int from_tty, cmd_list_element *c)
 {
-  if (!target_can_lock_scheduler ())
-    {
-      scheduler_mode = schedlock_off;
-      /* Set scheduler locking off.  */
-      set_schedlock_shortcut_option (schedlock_off);
-      error (_("Target '%s' cannot support this command."),
-	     target_shortname ());
-    }
+  if (!args || !*args)
+    set_schedlock_shortcut_option (schedlock_step);
+  set_schedlock_callback (args, from_tty, nullptr);
+}
 
-  set_schedlock_shortcut_option (scheduler_mode);
+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
+show_schedlock_option (ui_file *file, int from_tty,
+		       cmd_list_element *c, const char *value)
+{
+  gdb_assert (c->prefix != nullptr);
+  const char *mode;
+  if (strcmp (c->prefix->name, "replay") == 0)
+    mode = "replay mode";
+  else if (strcmp (c->prefix->name, "scheduler-locking") == 0)
+    mode = "normal execution";
+  else
+    gdb_assert_not_reached ("Unexpected command prefix.");
+
+  const char *type;
+  if (strcmp (c->name, "step") == 0)
+    type = "stepping commands";
+  else if (strcmp (c->name, "non-step") == 0)
+    type = "non-stepping commands";
+  else
+    gdb_assert_not_reached ("Unexpected command name.");
+
+  gdb_printf (file, _("\"%s\"  Scheduler locking for %s is "
+		      "\"%s\" during the %s.\n"), value, type, value, mode);
 }
 
 /* True if execution commands resume all threads of all processes by
@@ -8466,15 +8523,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;
@@ -10771,21 +10820,92 @@ 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);
 
+  add_setshow_boolean_cmd ("non-step", class_run, &schedlock.normal.non_step.value, _("\
+Scheduler locking for non-stepping commands during normal execution."), _("\
+Show scheduler locking for non-stepping commands during normal execution."),
+			   _("\
+Controls scheduler locking for non-stepping commands during normal execution.\n\
+Commands include continue, until, finish.  The setting does not affect \
+stepping."),
+			   set_schedlock_callback,
+			   show_schedlock_option,
+			   &schedlock_set_cmdlist,
+			   &schedlock_show_cmdlist);
+
+  add_setshow_boolean_cmd ("step", class_run, &schedlock.normal.step.value, _("\
+Scheduler locking for stepping commands.  W/o 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,
+			   show_schedlock_option,
+			   &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. \
+W/o arguments completely locks the scheduler in replay mode."),
+		  &schedlock_set_replay_cmdlist,
+	   0, &schedlock_set_cmdlist);
+
+  add_setshow_boolean_cmd ("non-step", class_run, &schedlock.replay.non_step.value, _("\
+Set scheduler locking for non-stepping commands in replay mode."), _("\
+Show scheduler locking for non-stepping commands in replay mode."), _("\
+Controls scheduler locking for non-stepping commands in replay mode.\n\
+Commands include continue, until, finish.  The setting does not affect \
+stepping."),
+			   set_schedlock_callback,
+			   show_schedlock_option,
+			   &schedlock_set_replay_cmdlist,
+			   &schedlock_show_replay_cmdlist);
+
+  add_setshow_boolean_cmd ("step", class_run, &schedlock.replay.step.value, _("\
+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."),
+			   set_schedlock_callback,
+			   show_schedlock_option,
+			   &schedlock_set_replay_cmdlist,
+			   &schedlock_show_replay_cmdlist);
+
+/* Commands "set scheduler-locking on" and "set scheduler-locking off"
+   are provided for backward compatibility.  */
+  c = add_cmd ("on", class_run, set_schedlock_on, _("\
+[Shortcut] Full locking (no thread except the current thread may run).\n\
+This applies to both normal execution and replay mode."),
+	   &schedlock_set_cmdlist);
+
+  c = add_cmd ("off", class_run, set_schedlock_off, _("\
+[Shortcut] No 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.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
index 93b91b42f92..c21748def9d 100644
--- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
+++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
@@ -255,17 +255,12 @@ proc make_cli_in_mi_re { command cli_in_mi_mode mode event inf cli_thread
 # Return the current value of the "scheduler-locking" parameter.
 
 proc show_scheduler_locking { } {
-    global gdb_prompt
-    global expect_out
-
-    set any "\[^\r\n\]*"
-
     set test "show scheduler-locking"
-    gdb_test_multiple $test $test {
-	-re ".*Mode for locking scheduler during execution is \"(${any})\".\r\n$gdb_prompt " {
-	    pass $test
-	    return $expect_out(1,string)
-	}
+    set schedlock [get_scheduler_locking $test]
+
+    if {$schedlock ne "unknown"} {
+	pass $test
+	return $schedlock
     }
 
     error "Couldn't get current scheduler-locking value."
@@ -311,7 +306,7 @@ proc test_continue_to_start { mode inf } {
 	    }
 
 	    if { $mode == "all-stop" } {
-		set previous_schedlock_val [show_scheduler_locking]
+		set previous_schedlock [show_scheduler_locking]
 
 		# Set scheduler-locking on, so that we can control threads
 		# independently.
@@ -342,7 +337,10 @@ proc test_continue_to_start { mode inf } {
 		}
 
 		# Restore scheduler-locking to its original value.
-		gdb_test_no_output "set scheduler-locking $previous_schedlock_val"
+		foreach opt {"non-step" "replay non-step" "replay step" "step"} {
+		    gdb_test_no_output \
+			"set scheduler-locking $opt [dict get $previous_schedlock $opt]"
+		}
 	    } else { # $mode == "non-stop"
 		# Put a thread-specific breakpoint for thread 2 of the current
 		# inferior.  We don't put a breakpoint for thread 3, since we
diff --git a/gdb/testsuite/gdb.threads/hand-call-in-threads.exp b/gdb/testsuite/gdb.threads/hand-call-in-threads.exp
index cde2b2d98ac..36c839990e2 100644
--- a/gdb/testsuite/gdb.threads/hand-call-in-threads.exp
+++ b/gdb/testsuite/gdb.threads/hand-call-in-threads.exp
@@ -68,7 +68,10 @@ 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 "non-step" "on" "replay non-step" "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 +142,10 @@ 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 "non-step" "off" "replay non-step" "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 4a97179a5b4..c0f786e6389 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 "non-step" "on" "replay non-step" "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 bd5d5d2cff3..b81cb8a9907 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 != ""} {
@@ -264,16 +265,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"
     }
 
@@ -284,16 +290,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" {
@@ -312,3 +320,57 @@ foreach schedlock {"off" "step" "on"} {
 	}
     }
 }
+
+proc test_schedlock_opts {non_step step} {
+    set test "show scheduler-locking"
+    if {[get_scheduler_locking $test \
+			 [dict create "non-step" $non_step "replay non-step" "off" \
+				  "replay step" "off" "step" $step]] eq "unknown"} {
+	fail $test
+    } else {
+	pass $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 {$non_step 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
+    }
+}
+
+gdb_test_no_output "set scheduler-locking off"
+
+# Test different options of scheduler locking.
+foreach non_step {"off" "on"} {
+    foreach step {"off" "on"} {
+	with_test_prefix "non-step=$non_step step=$step" {
+	    gdb_test_no_output "set scheduler-locking non-step $non_step"
+	    gdb_test_no_output "set scheduler-locking step $step"
+	    test_schedlock_opts $non_step $step
+	}
+    }
+}
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index dfe19c9410d..6d313c2a9a1 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -8966,6 +8966,52 @@ gdb_caching_proc gdb_target_symbol_prefix {} {
     return $prefix
 }
 
+# Return a dictionary of scheduler locking settings with keys:
+# non-step, replay non-step, 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 {"non-step" "replay non-step" "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 ""
+    foreach opt $opts {
+	set opt_regex \
+	    "${any}$opt: +\"\([dict get $expected $opt]\)\"${any}"
+	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 {} {
@@ -8984,28 +9030,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.25.1

Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928


  parent reply	other threads:[~2024-07-09 15:06 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-07-09 15:04 [PATCH v2 0/6] Refinement of scheduler-locking settings Natalia Saiapova
2024-07-09 15:04 ` [PATCH v2 1/6] gdb: use schedlock_applies in user_visible_resume_ptid Natalia Saiapova
2024-07-09 15:04 ` [PATCH v2 2/6] gdb, cli: remove left-over code from "set_logging_on" Natalia Saiapova
2024-07-09 15:04 ` [PATCH v2 3/6] gdb, cli: pass the argument of a set command to its callback Natalia Saiapova
2024-07-09 15:04 ` [PATCH v2 4/6] gdb: change the internal representation of scheduler locking Natalia Saiapova
2024-07-09 15:04 ` Natalia Saiapova [this message]
2024-07-09 15:57   ` [PATCH v2 5/6] gdb: refine commands to control " Eli Zaretskii
2024-07-09 15:04 ` [PATCH v2 6/6] gdb: add eval option to lock the scheduler during infcalls Natalia Saiapova
2024-07-09 16:00   ` Eli Zaretskii
2024-07-12 11:13 ` [PATCH v2 0/6] Refinement of scheduler-locking settings Saiapova, Natalia
2024-08-20 14:42   ` [PING][PATCH " Gerlicher, Klaus
2024-09-10 14:43     ` [PING V2][PATCH " Gerlicher, Klaus
2024-10-02 14:14       ` [PING V3][PATCH " Gerlicher, Klaus
2024-10-22 11:59         ` [PING V4][PATCH " Gerlicher, Klaus

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240709150410.34624-6-natalia.saiapova@intel.com \
    --to=natalia.saiapova@intel.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).