Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH v9 0/6] gdb: refine scheduler locking settings
@ 2026-09-07 11:55 Klaus Gerlicher
  2026-09-07 11:55 ` [PATCH v9 1/6] gdb: use schedlock_applies in user_visible_resume_ptid Klaus Gerlicher
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Klaus Gerlicher @ 2026-09-07 11:55 UTC (permalink / raw)
  To: gdb-patches; +Cc: tom, aburgess, eliz, guinevere

From: "Gerlicher, Klaus" <klaus.gerlicher@intel.com>

Hi Andrew, Tom, Eli,

This is version 9 of the patch series to refine scheduler locking
settings in GDB.

For this version I took the time to get fully acquainted with the
patch series.  In previous iterations my role had largely been limited
to forwarding and rebasing the work; this time I reviewed all patches
in depth, addressed Andrew's outstanding comments, and made a number
of additional fixes and documentation improvements as listed below, hoping
I covered every single one properly now.

Previous versions:
  V8: https://inbox.sourceware.org/gdb-patches/20260722102746.131536-1-klaus.gerlicher@intel.com/
  V7: https://inbox.sourceware.org/gdb-patches/20260325134328.550990-1-klaus.gerlicher@intel.com/
  V6: https://inbox.sourceware.org/gdb-patches/20260204133753.547281-1-klaus.gerlicher@intel.com/
  V5: https://inbox.sourceware.org/gdb-patches/20260129095918.2216661-1-klaus.gerlicher@intel.com/
  V4: https://inbox.sourceware.org/gdb-patches/20251205135851.2581702-1-klaus.gerlicher@intel.com/
  V3: https://inbox.sourceware.org/gdb-patches/20250811132321.486911-1-klaus.gerlicher@intel.com/

Changes since V8:
-----------------

  * Patch 3/6:
    - Fixed bug: V8 passed `arg` to the callback but `arg` had already
      been advanced by option parsing.  V9 saves `org_arg` before
      any processing and passes that instead.
    - Added set-callback infrastructure in maint-test-settings.c so
      that the callbacks print their received argument.
    - Added tests in gdb.base/settings.exp and gdb.base/with.exp
      to verify the callback receives the correct original argument.

  * Patch 5/6:
    - Restored outer parentheses in return statement of
      schedlock_applies_to_opts that were inadvertently removed.

  * Patch 6/6:
    - Merged two separate comment blocks in clear_proceed_status into one.
    - Removed default argument from schedlock_applies_to_opts; added
      explicit nullptr with explanatory comment at the call site.
    - Documented that 'eval' controls direct user inferior calls and
      GDB-triggered calls (display expressions, pretty-printers), but
      does NOT affect breakpoint/watchpoint condition evaluation, which
      always runs on the thread that triggered the breakpoint.
    - Updated introductory doc paragraph to list the three independently
      controllable categories: stepping, continuing, and inferior function
      calls.
    - Fixed TCL test loop style: for/incr idiom per GDB testsuite
      conventions.
    - Fixed duplicate test name warnings in schedlock.exp.
    - Fixed return type of some_function in schedlock.c from void to
      int to allow use in breakpoint conditions.
    - Removed stray blank lines in schedlock.c.
    - Fixed "normal mode" wording in NEWS and documentation to
      "outside replay mode" for clarity.

  * All patches:
    - Removed non-standard "Contributed-by:" tags.

Approval status:
  Patches 1-2/6: Approved-By: Andrew Burgess <aburgess@redhat.com>
                 https://inbox.sourceware.org/gdb-patches/87zfiu6omc.fsf@redhat.com/

  Patch 1/6: Also approved by Tom Tromey <tom@tromey.com>
             https://inbox.sourceware.org/gdb-patches/87a4xu9733.fsf@tromey.com/

  Patch 3/6: (Tom's approval from V8 was invalidated by the bug Andrew found;
             V9 fixes the bug and needs re-review)

  Patch 4/6: (unchanged from V5, needs review)
             https://inbox.sourceware.org/gdb-patches/20260129095918.2216661-5-klaus.gerlicher@intel.com/

  Patch 5/6: Reviewed-By: Eli Zaretskii <eliz@gnu.org> (documentation parts)
             https://inbox.sourceware.org/gdb-patches/86ttb4t6kz.fsf@gnu.org/

  Patch 6/6: Reviewed-By: Eli Zaretskii <eliz@gnu.org> (documentation parts)
             https://inbox.sourceware.org/gdb-patches/86ldx8t6ex.fsf@gnu.org/

  Overall series (V8): Reviewed-By: Guinevere Larsen <guinevere@redhat.com>
                       https://inbox.sourceware.org/gdb-patches/bc6fd851-29c1-436e-a833-a53c0cf5a18d@redhat.com/

Thanks to all reviewers for their thorough feedback.

Best regards,
Klaus

Natalia Saiapova (6):
  gdb: use schedlock_applies in user_visible_resume_ptid.
  gdb, cli: remove left-over code from "set_logging_on".
  gdb, cli: pass the argument of a set command to its callback.
  gdb: change the internal representation of scheduler locking.
  gdb: refine commands to control scheduler locking.
  gdb: add eval option to lock the scheduler during infcalls.

 gdb/NEWS                                      |  30 ++
 gdb/cli/cli-logging.c                         |   5 -
 gdb/cli/cli-setshow.c                         |   4 +-
 gdb/doc/gdb.texinfo                           |  89 +++-
 gdb/infrun.c                                  | 467 +++++++++++++++---
 gdb/maint-test-settings.c                     |  33 +-
 gdb/testsuite/gdb.base/settings.exp           | 113 +++--
 gdb/testsuite/gdb.base/with.exp               |   3 +-
 .../gdb.mi/user-selected-context-sync.exp     |  29 +-
 .../gdb.threads/hand-call-in-threads.exp      |  12 +-
 .../multiple-successive-infcall.exp           |   7 +-
 gdb/testsuite/gdb.threads/schedlock.c         |   3 +-
 gdb/testsuite/gdb.threads/schedlock.exp       | 164 +++++-
 gdb/testsuite/lib/gdb.exp                     |  77 ++-
 14 files changed, 869 insertions(+), 167 deletions(-)

--
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.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v9 1/6] gdb: use schedlock_applies in user_visible_resume_ptid.
  2026-09-07 11:55 [PATCH v9 0/6] gdb: refine scheduler locking settings Klaus Gerlicher
@ 2026-09-07 11:55 ` Klaus Gerlicher
  2026-09-07 11:55 ` [PATCH v9 2/6] gdb, cli: remove left-over code from "set_logging_on" Klaus Gerlicher
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Klaus Gerlicher @ 2026-09-07 11:55 UTC (permalink / raw)
  To: gdb-patches; +Cc: tom, aburgess, eliz, guinevere

From: Natalia Saiapova <natalia.saiapova@intel.com>

This is a refactoring.  The logic in user_visible_resume_ptid is very
similar to schedlock_applies, but uses `step` and `record_will_replay`
parameter instead of `tp->control.stepping_command`.

Refactor schedlock_applies logic into the following two overloaded methods:
  bool schedlock_applies (thread_info *tp)
and
  bool schedlock_applies (bool step, bool record_will_replay)
such that they share the logic.

Update the call-sites accordingly, where we have only the thread, use
the former, and where we have the bool step or record_will_replay use the
latter.

Approved-By: Tom Tromey <tom@tromey.com>
Approved-By: Andrew Burgess <aburgess@redhat.com>
---
 gdb/infrun.c | 38 ++++++++++++++++++++++----------------
 1 file changed, 22 insertions(+), 16 deletions(-)

diff --git a/gdb/infrun.c b/gdb/infrun.c
index b9618fb6422..cf072237f48 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -107,7 +107,8 @@ static bool start_step_over (void);
 
 static bool step_over_info_valid_p (void);
 
-static bool schedlock_applies (struct thread_info *tp);
+static bool schedlock_applies (thread_info *tp);
+static bool schedlock_applies (bool step, bool record_will_replay);
 
 static void handle_process_exited (struct execution_control_state *ecs);
 
@@ -2443,20 +2444,14 @@ user_visible_resume_ptid (int step)
 	 individually.  */
       resume_ptid = inferior_ptid;
     }
-  else if ((scheduler_mode == schedlock_on)
-	   || (scheduler_mode == schedlock_step && step))
+  else if (schedlock_applies (step,
+			      target_record_will_replay (inferior_ptid,
+							 execution_direction)))
     {
       /* User-settable 'scheduler' mode requires solo thread
 	 resume.  */
       resume_ptid = inferior_ptid;
     }
-  else if ((scheduler_mode == schedlock_replay)
-	   && target_record_will_replay (inferior_ptid, execution_direction))
-    {
-      /* User-settable 'scheduler' mode requires solo thread resume in replay
-	 mode.  */
-      resume_ptid = inferior_ptid;
-    }
   else if (inferior_ptid != null_ptid
 	   && inferior_thread ()->control.in_cond_eval)
     {
@@ -3247,17 +3242,28 @@ thread_still_needs_step_over (struct thread_info *tp)
   return what;
 }
 
+/* Returns true if scheduler locking applies to non-NULL thread TP.  */
+
+static bool
+schedlock_applies (thread_info *tp)
+{
+  gdb_assert (tp != nullptr);
+  bool step = tp->control.stepping_command;
+  bool record_will_replay
+    = target_record_will_replay (tp->ptid, execution_direction);
+  return schedlock_applies (step, record_will_replay);
+}
+
 /* Returns true if scheduler locking applies.  STEP indicates whether
-   we're about to do a step/next-like command to a thread.  */
+   we're about to do a step/next-like command and RECORD_WILL_REPLAY
+   indicates whether we're about to replay.  */
 
 static bool
-schedlock_applies (struct thread_info *tp)
+schedlock_applies (bool step, bool record_will_replay)
 {
   return (scheduler_mode == schedlock_on
-	  || (scheduler_mode == schedlock_step
-	      && tp->control.stepping_command)
-	  || (scheduler_mode == schedlock_replay
-	      && target_record_will_replay (tp->ptid, execution_direction)));
+	  || (scheduler_mode == schedlock_step && step)
+	  || (scheduler_mode == schedlock_replay && record_will_replay));
 }
 
 /* When FORCE_P is false, set process_stratum_target::COMMIT_RESUMED_STATE
-- 
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.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v9 2/6] gdb, cli: remove left-over code from "set_logging_on".
  2026-09-07 11:55 [PATCH v9 0/6] gdb: refine scheduler locking settings Klaus Gerlicher
  2026-09-07 11:55 ` [PATCH v9 1/6] gdb: use schedlock_applies in user_visible_resume_ptid Klaus Gerlicher
@ 2026-09-07 11:55 ` Klaus Gerlicher
  2026-09-07 11:55 ` [PATCH v9 3/6] gdb, cli: pass the argument of a set command to its callback Klaus Gerlicher
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Klaus Gerlicher @ 2026-09-07 11:55 UTC (permalink / raw)
  To: gdb-patches; +Cc: tom, aburgess, eliz, guinevere

From: Natalia Saiapova <natalia.saiapova@intel.com>

This is a refactoring.  Remove the left-over code, which rewrites
the logging filename in "set logging on" command.

The code became unused after the deprecation of "set logging (on|off)"
command.  Before the deprecation, the command could also take a file
name and rewrite the logging file, e.g.:
  (gdb) set logging on lalala
  Copying output to lalala.
  Copying debug output to lalala.

After the command was deprecated and reimplemented as an alias to "set
logging enabled on", additional input after "on" became invalid:

  (gdb) set logging on lalala
  Warning: 'set logging on', an alias for the command 'set logging enabled', is deprecated.
  Use 'set logging enabled on'.

  "on" or "off" expected.
  (gdb) set logging on lalala
  "on" or "off" expected.
  (gdb) set logging enabled on lalala
  "on" or "off" expected.
  (gdb) set logging enabled on
  Copying output to gdb.txt.
  Copying debug output to gdb.txt.

Approved-By: Andrew Burgess <aburgess@redhat.com>
---
 gdb/cli/cli-logging.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/gdb/cli/cli-logging.c b/gdb/cli/cli-logging.c
index c9482d59199..33bb42bb444 100644
--- a/gdb/cli/cli-logging.c
+++ b/gdb/cli/cli-logging.c
@@ -270,11 +270,6 @@ handle_redirections (int from_tty)
 static void
 set_logging_on (const char *args, int from_tty)
 {
-  const char *rest = args;
-
-  if (rest && *rest)
-    logging_filename = rest;
-
   handle_redirections (from_tty);
 }
 
-- 
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.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v9 3/6] gdb, cli: pass the argument of a set command to its callback.
  2026-09-07 11:55 [PATCH v9 0/6] gdb: refine scheduler locking settings Klaus Gerlicher
  2026-09-07 11:55 ` [PATCH v9 1/6] gdb: use schedlock_applies in user_visible_resume_ptid Klaus Gerlicher
  2026-09-07 11:55 ` [PATCH v9 2/6] gdb, cli: remove left-over code from "set_logging_on" Klaus Gerlicher
@ 2026-09-07 11:55 ` Klaus Gerlicher
  2026-09-07 11:55 ` [PATCH v9 4/6] gdb: change the internal representation of scheduler locking Klaus Gerlicher
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Klaus Gerlicher @ 2026-09-07 11:55 UTC (permalink / raw)
  To: gdb-patches; +Cc: tom, aburgess, eliz, guinevere

From: Natalia Saiapova <natalia.saiapova@intel.com>

Passing the original argument to the callback is useful when a command
needs to distinguish being invoked with no argument from being invoked
with a specific value.

I am going to use it in
  gdb: refine commands to control scheduler locking.
to keep the old behaviour of the
  set scheduler-locking step
which should set both
  set scheduler-locking step on
  set scheduler-locking replay step on
To do this, the set-command needs to detect that it was issued without
arguments and have a special handling for this.

Without the special handling, the command
  set scheduler-locking step
would set only
  set scheduler-locking step on
---
 gdb/cli/cli-setshow.c               |   4 +-
 gdb/maint-test-settings.c           |  33 +++++---
 gdb/testsuite/gdb.base/settings.exp | 113 +++++++++++++++++++++-------
 gdb/testsuite/gdb.base/with.exp     |   3 +-
 4 files changed, 110 insertions(+), 43 deletions(-)

diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c
index 7688da015de..1e0954a560d 100644
--- a/gdb/cli/cli-setshow.c
+++ b/gdb/cli/cli-setshow.c
@@ -335,6 +335,8 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
   if (arg == NULL)
     arg = "";
 
+  const char *org_arg = arg;
+
   gdb_assert (c->var.has_value ());
 
   switch (c->var->type ())
@@ -455,7 +457,7 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
       error (_("gdb internal error: bad var_type in do_setshow_command"));
     }
 
-  c->func (NULL, from_tty, c);
+  c->func (org_arg, from_tty, c);
 
   if (notify_command_param_changed_p (option_changed, c))
     {
diff --git a/gdb/maint-test-settings.c b/gdb/maint-test-settings.c
index f2e8a68a10f..6995f8b7bfb 100644
--- a/gdb/maint-test-settings.c
+++ b/gdb/maint-test-settings.c
@@ -67,6 +67,15 @@ static const char *const maintenance_test_settings_enums[] = {
 static const char *maintenance_test_settings_enum
   = maintenance_test_settings_xxx;
 
+/* The "maintenance set test-settings xxx" commands.  */
+
+static void
+maintenance_set_test_settings_cmd (const char *args, int from_tty,
+				   cmd_list_element *c)
+{
+  gdb_printf ("set-callback: arg='%s'\n", args == nullptr ? "" : args);
+}
+
 /* The "maintenance show test-settings xxx" commands.  */
 
 static void
@@ -96,7 +105,7 @@ Show GDB internal variables used for set/show command infrastructure testing."),
 command used for internal testing."), _("\
 command used for internal testing."),
 			   nullptr, /* help_doc */
-			   nullptr, /* set_cmd */
+			   maintenance_set_test_settings_cmd,
 			   maintenance_show_test_settings_value_cmd,
 			   &maintenance_set_test_settings_list,
 			   &maintenance_show_test_settings_list);
@@ -106,7 +115,7 @@ command used for internal testing."),
 command used for internal testing."), _("\
 command used for internal testing."),
 				nullptr, /* help_doc */
-				nullptr, /* set_cmd */
+				maintenance_set_test_settings_cmd,
 				maintenance_show_test_settings_value_cmd,
 				&maintenance_set_test_settings_list,
 				&maintenance_show_test_settings_list);
@@ -116,7 +125,7 @@ command used for internal testing."),
 command used for internal testing."), _("\
 command used for internal testing."),
 			    nullptr, /* help_doc */
-			    nullptr, /* set_cmd */
+			    maintenance_set_test_settings_cmd,
 			    maintenance_show_test_settings_value_cmd,
 			    &maintenance_set_test_settings_list,
 			    &maintenance_show_test_settings_list);
@@ -126,7 +135,7 @@ command used for internal testing."),
 command used for internal testing."), _("\
 command used for internal testing."),
 			   nullptr, /* help_doc */
-			   nullptr, /* set_cmd */
+			   maintenance_set_test_settings_cmd,
 			   maintenance_show_test_settings_value_cmd,
 			   &maintenance_set_test_settings_list,
 			   &maintenance_show_test_settings_list);
@@ -136,7 +145,7 @@ command used for internal testing."),
 command used for internal testing."), _("\
 command used for internal testing."),
      nullptr, /* help_doc */
-     nullptr, /* set_cmd */
+     maintenance_set_test_settings_cmd,
 			  maintenance_show_test_settings_value_cmd,
 			  &maintenance_set_test_settings_list,
 			  &maintenance_show_test_settings_list);
@@ -147,7 +156,7 @@ command used for internal testing."),
 command used for internal testing."), _("\
 command used for internal testing."),
      nullptr, /* help_doc */
-     nullptr, /* set_cmd */
+     maintenance_set_test_settings_cmd,
      maintenance_show_test_settings_value_cmd,
      &maintenance_set_test_settings_list,
      &maintenance_show_test_settings_list);
@@ -158,7 +167,7 @@ command used for internal testing."),
 command used for internal testing."), _("\
 command used for internal testing."),
      nullptr, /* help_doc */
-     nullptr, /* set_cmd */
+     maintenance_set_test_settings_cmd,
      maintenance_show_test_settings_value_cmd,
      &maintenance_set_test_settings_list,
      &maintenance_show_test_settings_list);
@@ -168,7 +177,7 @@ command used for internal testing."),
 command used for internal testing."), _("\
 command used for internal testing."),
 			    nullptr, /* help_doc */
-			    nullptr, /* set_cmd */
+			    maintenance_set_test_settings_cmd,
 			    maintenance_show_test_settings_value_cmd,
 			    &maintenance_set_test_settings_list,
 			    &maintenance_show_test_settings_list);
@@ -178,7 +187,7 @@ command used for internal testing."),
 command used for internal testing."), _("\
 command used for internal testing."),
 			    nullptr, /* help_doc */
-			    nullptr, /* set_cmd */
+			    maintenance_set_test_settings_cmd,
 			    maintenance_show_test_settings_value_cmd,
 			    &maintenance_set_test_settings_list,
 			    &maintenance_show_test_settings_list);
@@ -188,7 +197,7 @@ command used for internal testing."),
 command used for internal testing."), _("\
 command used for internal testing."),
 			     nullptr, /* help_doc */
-			     nullptr, /* set_cmd */
+			     maintenance_set_test_settings_cmd,
 			     maintenance_show_test_settings_value_cmd,
 			     &maintenance_set_test_settings_list,
 			     &maintenance_show_test_settings_list);
@@ -199,7 +208,7 @@ command used for internal testing."),
 command used for internal testing."), _("\
 command used for internal testing."),
      nullptr, /* help_doc */
-     nullptr, /* set_cmd */
+     maintenance_set_test_settings_cmd,
      maintenance_show_test_settings_value_cmd,
      &maintenance_set_test_settings_list,
      &maintenance_show_test_settings_list);
@@ -210,7 +219,7 @@ command used for internal testing."),
 command used for internal testing."), _("\
 command used for internal testing."),
 			nullptr, /* help_doc */
-			nullptr, /* set_cmd */
+			maintenance_set_test_settings_cmd,
 			maintenance_show_test_settings_value_cmd,
 			&maintenance_set_test_settings_list,
 			&maintenance_show_test_settings_list);
diff --git a/gdb/testsuite/gdb.base/settings.exp b/gdb/testsuite/gdb.base/settings.exp
index 2da8d47405b..54408bb64f4 100644
--- a/gdb/testsuite/gdb.base/settings.exp
+++ b/gdb/testsuite/gdb.base/settings.exp
@@ -34,6 +34,14 @@ if { ![readline_is_used] } {
     return
 }
 
+# Run a "maint set test-settings ..." command and expect the callback output.
+proc set_setting {cmd {test_name ""}} {
+    if {$test_name eq ""} {
+	set test_name $cmd
+    }
+    gdb_test $cmd "set-callback: arg='.*'" $test_name
+}
+
 # Test the show command SHOW_CMD.  EXPECTED_RE is the expected output.
 # Also verifies that $_gdb_maint_setting_str produces an equivalent output,
 # matching it with EXPECTED_RE.  EXPECTED_RE double quotes are escaped
@@ -52,6 +60,7 @@ if { ![readline_is_used] } {
 # This procedure makes it easier to make the test
 # name/message unique, since we test the "show" commands many times.
 # EXPECTED_RE is made part of the test name.
+
 proc show_setting {show_cmd expected_re {expected_re_escaped 0} {reset_value 0}} {
     global gdb_prompt
 
@@ -78,8 +87,8 @@ proc show_setting {show_cmd expected_re {expected_re_escaped 0} {reset_value 0}}
 
 	# Change the setting value to RESET_VALUE, set it back to setting_str_value
 	# and check we still have the original value.
-	gdb_test_no_output "maintenance set $maint_setting $reset_value" "str reset $reset_value"
-	gdb_test_no_output "maintenance set $maint_setting $setting_str_value" "str set again"
+	set_setting "maintenance set $maint_setting $reset_value" "str reset $reset_value"
+	set_setting "maintenance set $maint_setting $setting_str_value" "str set again"
 	gdb_test "$show_cmd" $expected_re "str show after reset+set again"
 
 	# Same test, but with value captured from $_gdb_maint_setting.
@@ -97,8 +106,8 @@ proc show_setting {show_cmd expected_re {expected_re_escaped 0} {reset_value 0}}
 	    }
 	}
 
-	gdb_test_no_output "maintenance set $maint_setting $reset_value" "reset $reset_value"
-	gdb_test_no_output "maintenance set $maint_setting $setting_value" "set again"
+	set_setting "maintenance set $maint_setting $reset_value" "reset $reset_value"
+	set_setting "maintenance set $maint_setting $setting_value" "set again"
 	gdb_test "$show_cmd" $expected_re "show after reset+set again"
     }
 }
@@ -152,20 +161,20 @@ proc test-integer {variant} {
 	check_type "test-settings $variant" "type = unsigned int"
     } else {
 	# Negative values are not accepted.
-	gdb_test_no_output "$set_cmd -1"
+	set_setting "$set_cmd -1"
 	show_setting "$show_cmd" "-1"
-	gdb_test_no_output "$set_cmd -2"
+	set_setting "$set_cmd -2"
 	show_setting "$show_cmd" "-2"
 	check_type "test-settings $variant" "type = int"
     }
 
     # Regular integer is accepted.
-    gdb_test_no_output "$set_cmd 999"
+    set_setting "$set_cmd 999"
     show_setting "$show_cmd" "999"
 
     if {$variant == "zinteger" || $variant == "zuinteger"} {
 	# 0 means 0.
-	gdb_test_no_output "$set_cmd 0"
+	set_setting "$set_cmd 0"
 	show_setting "$show_cmd" "0"
     } else {
 	# Either 0 or -1 mean unlimited.  Test both the number and
@@ -173,9 +182,9 @@ proc test-integer {variant} {
 	# abbreviations.
 
 	if {$variant == "zuinteger-unlimited"} {
-	    gdb_test_no_output "$set_cmd -1"
+	    set_setting "$set_cmd -1"
 	} else {
-	    gdb_test_no_output "$set_cmd 0"
+	    set_setting "$set_cmd 0"
 	}
 	show_setting "$show_cmd" "unlimited"
 
@@ -192,10 +201,10 @@ proc test-integer {variant} {
 	} {
 	    # Alternate between integer and unlimited, to make sure the
 	    # setting really took effect.
-	    gdb_test_no_output "$set_cmd 1"
+	    set_setting "$set_cmd 1"
 	    show_setting "$show_cmd" "1"
 
-	    gdb_test_no_output "$set_cmd $value"
+	    set_setting "$set_cmd $value"
 	    show_setting "$show_cmd" "unlimited"
 	}
     }
@@ -312,10 +321,10 @@ proc_with_prefix test-boolean {} {
 	"enabl"
 	"enable"
     } {
-	gdb_test_no_output "$set_cmd off"
+	set_setting "$set_cmd off"
 	show_setting "$show_cmd" "off"
 
-	gdb_test_no_output "$set_cmd $value"
+	set_setting "$set_cmd $value"
 	show_setting "$show_cmd" "on"
     }
 
@@ -335,10 +344,10 @@ proc_with_prefix test-boolean {} {
 	"disabl"
 	"disable"
     } {
-	gdb_test_no_output "$set_cmd on"
+	set_setting "$set_cmd on"
 	show_setting "$show_cmd" "on"
 
-	gdb_test_no_output "$set_cmd $value"
+	set_setting "$set_cmd $value"
 	show_setting "$show_cmd" "off"
     }
 
@@ -399,10 +408,10 @@ proc_with_prefix test-auto-boolean {} {
 	"enabl"
 	"enable"
     } {
-	gdb_test_no_output "$set_cmd off"
+	set_setting "$set_cmd off"
 	show_setting "$show_cmd" "off"
 
-	gdb_test_no_output "$set_cmd $value"
+	set_setting "$set_cmd $value"
 	show_setting "$show_cmd" "on"
     }
 
@@ -420,10 +429,10 @@ proc_with_prefix test-auto-boolean {} {
 	"disabl"
 	"disable"
     } {
-	gdb_test_no_output "$set_cmd on"
+	set_setting "$set_cmd on"
 	show_setting "$show_cmd" "on"
 
-	gdb_test_no_output "$set_cmd $value"
+	set_setting "$set_cmd $value"
 	show_setting "$show_cmd" "off"
     }
 
@@ -434,10 +443,10 @@ proc_with_prefix test-auto-boolean {} {
 	"auto"
 	"-1"
     } {
-	gdb_test_no_output "$set_cmd on"
+	set_setting "$set_cmd on"
 	show_setting "$show_cmd" "on"
 
-	gdb_test_no_output "$set_cmd $value"
+	set_setting "$set_cmd $value"
 	show_setting "$show_cmd" "auto"
     }
 
@@ -497,11 +506,11 @@ proc_with_prefix test-enum {} {
 
     # Various valid values.  Test both full value names and
     # abbreviations.
-    gdb_test_no_output "$set_cmd x"
+    set_setting "$set_cmd x"
     show_setting "$show_cmd" "xxx" 0 "zzz"
-    gdb_test_no_output "$set_cmd yy"
+    set_setting "$set_cmd yy"
     show_setting "$show_cmd" "yyy" 0 "zzz"
-    gdb_test_no_output "$set_cmd zzz"
+    set_setting "$set_cmd zzz"
     show_setting "$show_cmd" "zzz" 0 "yyy"
 
     check_type "test-settings enum" "type = char \\\[4\\\]"
@@ -548,17 +557,17 @@ proc test-string {variant} {
     }
 
     # A string value.
-    gdb_test_no_output "$set_cmd hello world"
+    set_setting "$set_cmd hello world"
     show_setting "$show_cmd" "hello world"
 
     check_type "test-settings $variant" "type = char \\\[$::positive\\\]"
 
     # A quoted string value.
     if {$variant == "string"} {
-	gdb_test_no_output "$set_cmd \"hello world\""
+	set_setting "$set_cmd \"hello world\""
 	show_setting "$show_cmd" "\\\\\"hello world\\\\\"" 1
     } else {
-	gdb_test_no_output "$set_cmd \"hello world\""
+	set_setting "$set_cmd \"hello world\""
 	show_setting "$show_cmd" "\"hello world\""
     }
 
@@ -571,7 +580,7 @@ proc test-string {variant} {
 	    # Check the value didn't change.
 	    show_setting "$show_cmd" "\"hello world\""
 	} else {
-	    gdb_test_no_output "$set_cmd"
+	    set_setting "$set_cmd"
 	    # This odd expected output here is because we expect GDB to
 	    # emit a single blank line as a result of this command.
 	    gdb_test -nonl "$show_cmd" "^\r\n" "$show_cmd: empty second time"
@@ -666,3 +675,49 @@ foreach variant {
 }
 
 test-setting-error
+
+# Verify that the set-command callback receives the original argument
+# string, including for integer settings where parse_cli_var_integer
+# advances the internal pointer.
+proc_with_prefix test-set-callback {} {
+    # Integer types: the original arg string must reach the callback
+    # unchanged even though parse_cli_var_integer moves the pointer.
+    foreach_with_prefix variant {
+	uinteger integer zinteger zuinteger zuinteger-unlimited
+    } {
+	set set_cmd "maint set test-settings $variant"
+
+	gdb_test "$set_cmd 999" \
+	    "set-callback: arg='999'" \
+	    "integer arg passed through"
+
+	if {$variant == "uinteger" || $variant == "integer"
+	    || $variant == "zuinteger-unlimited"} {
+	    gdb_test "$set_cmd unlimited" \
+		"set-callback: arg='unlimited'" \
+		"unlimited arg passed through"
+	}
+    }
+
+    # Boolean: empty arg (no argument given) must arrive as "".
+    gdb_test "maint set test-settings boolean" \
+	"set-callback: arg=''" \
+	"boolean no-arg callback"
+
+    # Boolean: explicit value.
+    gdb_test "maint set test-settings boolean on" \
+	"set-callback: arg='on'" \
+	"boolean on arg passed through"
+
+    # Enum: arg must be the full original token.
+    gdb_test "maint set test-settings enum yyy" \
+	"set-callback: arg='yyy'" \
+	"enum arg passed through"
+
+    # String: arg must be the literal string typed.
+    gdb_test "maint set test-settings string hello" \
+	"set-callback: arg='hello'" \
+	"string arg passed through"
+}
+
+test-set-callback
diff --git a/gdb/testsuite/gdb.base/with.exp b/gdb/testsuite/gdb.base/with.exp
index 101c6dcccf9..aa44a23c8c0 100644
--- a/gdb/testsuite/gdb.base/with.exp
+++ b/gdb/testsuite/gdb.base/with.exp
@@ -35,11 +35,12 @@ clean_restart $testfile
 # level, but maps to -1 internally.
 
 proc test_with {setting values} {
+    set cb "set-callback: arg='.*'"
     foreach val1 $values {
 	foreach val2 $values {
 	    gdb_test \
 		"maint with test-settings $setting $val1 -- maint with test-settings $setting $val2 -- p 1" \
-		" = 1"
+		"${cb}\r\n${cb}\r\n\\$\[0-9\]+ = 1\r\n${cb}\r\n${cb}"
 	}
     }
 }
-- 
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.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v9 4/6] gdb: change the internal representation of scheduler locking.
  2026-09-07 11:55 [PATCH v9 0/6] gdb: refine scheduler locking settings Klaus Gerlicher
                   ` (2 preceding siblings ...)
  2026-09-07 11:55 ` [PATCH v9 3/6] gdb, cli: pass the argument of a set command to its callback Klaus Gerlicher
@ 2026-09-07 11:55 ` Klaus Gerlicher
  2026-09-07 11:55 ` [PATCH v9 5/6] gdb: refine commands to control " Klaus Gerlicher
  2026-09-07 11:55 ` [PATCH v9 6/6] gdb: add eval option to lock the scheduler during infcalls Klaus Gerlicher
  5 siblings, 0 replies; 7+ messages in thread
From: Klaus Gerlicher @ 2026-09-07 11:55 UTC (permalink / raw)
  To: gdb-patches; +Cc: tom, aburgess, eliz, guinevere

From: Natalia Saiapova <natalia.saiapova@intel.com>

Introduce a new structure to manage different options of the scheduler
locking.  The options can coexist together and be set individually.
In the next patch

  gdb: refine commands to control scheduler locking.

we introduce the commands to control these options.  In this patch we do
not introduce new commands and keep the previous API.

New scheduler locking options are:
replay continue -- control continuing commands during replay mode.
replay step -- control stepping commands during replay mode.
continue -- control continuing commands during normal execution.
step -- control stepping commands during normal execution.

Internally they hold a bool value, when true the locking is enabled.

Mapping to the old settings

Old Settings      |  New settings
-----------------------------------
off               | all are false
                  |
replay            | continue = false, step = false,
                  | replay continue = true, replay step = true
                  |
step              | continue = false, step = true,
                  | replay continue = false, replay step = true
                  |
on                | all are true

Behaviour change in clear_proceed_status:

Previously, the convenience feature that stops replaying other threads
when we're not replaying the selected thread was gated on
"scheduler_mode == schedlock_replay", i.e. it only fired for the
"replay" shortcut.  It is now gated on schedlock_applies_to_opts on the
replay options, which also evaluates to true for "scheduler-locking
on", and for "scheduler-locking step" while stepping.  This means
threads that are mid-replay now get pulled out of replay under "on"
and "step" as well, not just under "replay".  This is intentional: any
setting that locks the scheduler for replay-mode commands should also
stop other threads from silently continuing to replay behind the
user's back.
---
 gdb/infrun.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 146 insertions(+), 15 deletions(-)

diff --git a/gdb/infrun.c b/gdb/infrun.c
index cf072237f48..a501c8a1ebd 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -107,8 +107,12 @@ static bool start_step_over (void);
 
 static bool step_over_info_valid_p (void);
 
+struct schedlock_mode_options;
 static bool schedlock_applies (thread_info *tp);
-static bool schedlock_applies (bool step, bool record_will_replay);
+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 void handle_process_exited (struct execution_control_state *ecs);
 
@@ -2374,7 +2378,70 @@ infrun_thread_ptid_changed (process_stratum_target *target,
     inferior_ptid = new_ptid;
 }
 
-\f
+/* A single scheduler locking option, holding a name and boolean value.  */
+struct schedlock_option
+{
+  schedlock_option () = delete;
+  schedlock_option (std::string name, bool value)
+    : m_name (std::move (name)), m_value (value)
+  {}
+
+  DISABLE_COPY_AND_ASSIGN (schedlock_option);
+  schedlock_option (schedlock_option &&) = default;
+  schedlock_option &operator= (schedlock_option &&) = default;
+
+  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.  */
+  bool set (bool new_value);
+
+private:
+  const std::string m_name;
+  bool m_value;
+};
+
+bool
+schedlock_option::set (bool new_value)
+{
+  if (m_value != new_value)
+    {
+      m_value = new_value;
+      return true;
+    }
+
+  return false;
+}
+
+/* Scheduler locking settings for a mode (replay or normal).  */
+struct schedlock_mode_options
+{
+  schedlock_mode_options () = delete;
+  schedlock_mode_options (schedlock_option cont, schedlock_option step)
+    : cont (std::move (cont)), step (std::move (step))
+  {}
+
+  DISABLE_COPY_AND_ASSIGN (schedlock_mode_options);
+  schedlock_mode_options (schedlock_mode_options &&) = default;
+  schedlock_mode_options &operator= (schedlock_mode_options &&) = default;
+
+  /* If true, the scheduler is locked during continuing.  */
+  schedlock_option cont;
+  /* If true, the scheduler is locked during stepping.  */
+  schedlock_option step;
+};
+
+/* All scheduler locking options for both normal execution and replay mode.  */
+struct schedlock_state
+{
+  schedlock_state (schedlock_mode_options normal_opts,
+		   schedlock_mode_options replay_opts)
+    : normal (std::move (normal_opts)), replay (std::move (replay_opts))
+  {}
+
+  schedlock_mode_options normal;
+  schedlock_mode_options replay;
+};
 
 static const char schedlock_off[] = "off";
 static const char schedlock_on[] = "on";
@@ -2387,7 +2454,43 @@ static const char *const scheduler_enums[] = {
   schedlock_replay,
   nullptr
 };
+
 static const char *scheduler_mode = schedlock_replay;
+
+/* Global scheduler locking state.  */
+static schedlock_state scheduler_locking_state {
+  {
+    {"cont", false},
+    {"step", false}
+  },
+  {
+    {"replay cont", true},
+    {"replay step", true}
+  }
+};
+
+/* A helper function to set scheduler locking shortcuts:
+   set scheduler-locking on: all options are on.
+   set scheduler-locking off: all options are off.
+   set scheduler-locking replay: only replay options are on.
+   set scheduler-locking step: only "step" and "replay step" are on.  */
+
+static void
+set_schedlock_shortcut_option (const char *shortcut)
+{
+  bool is_on = (shortcut == schedlock_on);
+  bool is_step = (shortcut == schedlock_step);
+  bool is_replay = (shortcut == schedlock_replay);
+  bool is_off = (shortcut == schedlock_off);
+  /* 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);
+}
+
 static void
 show_scheduler_mode (struct ui_file *file, int from_tty,
 		     struct cmd_list_element *c, const char *value)
@@ -2404,9 +2507,13 @@ set_schedlock_func (const char *args, int from_tty, struct 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 ());
     }
+
+  set_schedlock_shortcut_option (scheduler_mode);
 }
 
 /* True if execution commands resume all threads of all processes by
@@ -2437,6 +2544,10 @@ ptid_t
 user_visible_resume_ptid (int step)
 {
   ptid_t resume_ptid;
+  thread_info *tp = nullptr;
+
+  if (inferior_ptid != null_ptid)
+    tp = inferior_thread ();
 
   if (non_stop)
     {
@@ -2446,14 +2557,14 @@ user_visible_resume_ptid (int step)
     }
   else if (schedlock_applies (step,
 			      target_record_will_replay (inferior_ptid,
-							 execution_direction)))
+							 execution_direction),
+			      tp))
     {
       /* User-settable 'scheduler' mode requires solo thread
 	 resume.  */
       resume_ptid = inferior_ptid;
     }
-  else if (inferior_ptid != null_ptid
-	   && inferior_thread ()->control.in_cond_eval)
+  else if (tp != nullptr && tp->control.in_cond_eval)
     {
       /* The inferior thread is evaluating a BP condition.  Other threads
 	 might be stopped or running and we do not want to change their
@@ -3159,14 +3270,22 @@ notify_about_to_proceed ()
 void
 clear_proceed_status (int step, bool about_to_proceed)
 {
-  /* With scheduler-locking replay, stop replaying other threads in the
-     same process if we're not replaying the selected thread.
+  /* When scheduler locking applies to replay mode, stop replaying other
+     threads in the same process if we're not replaying the selected thread.
 
      This is a convenience feature to not require the user to explicitly
      stop replaying the other threads.  We're assuming that the user's
-     intent is to resume tracing the recorded process.  */
-  if (!non_stop && scheduler_mode == schedlock_replay
-      && !target_record_will_replay (inferior_ptid, execution_direction))
+     intent is to resume tracing the recorded process.
+
+     This check uses schedlock_applies_to_opts on the replay mode options,
+     which means it applies not only for "set scheduler-locking replay",
+     but also for "set scheduler-locking on" and (when stepping)
+     "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)
+      && !target_record_will_replay (inferior_ptid,
+				     execution_direction))
     target_record_stop_replaying ();
 
   if (!non_stop && inferior_ptid != null_ptid)
@@ -3242,6 +3361,17 @@ thread_still_needs_step_over (struct thread_info *tp)
   return what;
 }
 
+/* Return true if OPTS lock the scheduler.
+   STEP indicates whether a thread is about to step.
+   This function does not take into account the mode (replay or
+   normal execution).  */
+
+static bool
+schedlock_applies_to_opts (const schedlock_mode_options &opts, bool step)
+{
+  return ((opts.cont && !step) || (opts.step && step));
+}
+
 /* Returns true if scheduler locking applies to non-NULL thread TP.  */
 
 static bool
@@ -3251,7 +3381,7 @@ schedlock_applies (thread_info *tp)
   bool step = tp->control.stepping_command;
   bool record_will_replay
     = target_record_will_replay (tp->ptid, execution_direction);
-  return schedlock_applies (step, record_will_replay);
+  return schedlock_applies (step, record_will_replay, tp);
 }
 
 /* Returns true if scheduler locking applies.  STEP indicates whether
@@ -3259,11 +3389,12 @@ schedlock_applies (thread_info *tp)
    indicates whether we're about to replay.  */
 
 static bool
-schedlock_applies (bool step, bool record_will_replay)
+schedlock_applies (bool step, bool record_will_replay, thread_info *tp)
 {
-  return (scheduler_mode == schedlock_on
-	  || (scheduler_mode == schedlock_step && step)
-	  || (scheduler_mode == schedlock_replay && record_will_replay));
+  schedlock_mode_options &opts
+    = record_will_replay ? scheduler_locking_state.replay
+			 : scheduler_locking_state.normal;
+  return schedlock_applies_to_opts (opts, step);
 }
 
 /* When FORCE_P is false, set process_stratum_target::COMMIT_RESUMED_STATE
-- 
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.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v9 5/6] gdb: refine commands to control scheduler locking.
  2026-09-07 11:55 [PATCH v9 0/6] gdb: refine scheduler locking settings Klaus Gerlicher
                   ` (3 preceding siblings ...)
  2026-09-07 11:55 ` [PATCH v9 4/6] gdb: change the internal representation of scheduler locking Klaus Gerlicher
@ 2026-09-07 11:55 ` Klaus Gerlicher
  2026-09-07 11:55 ` [PATCH v9 6/6] gdb: add eval option to lock the scheduler during infcalls Klaus Gerlicher
  5 siblings, 0 replies; 7+ messages in thread
From: Klaus Gerlicher @ 2026-09-07 11:55 UTC (permalink / raw)
  To: gdb-patches; +Cc: tom, aburgess, eliz, guinevere

From: Natalia Saiapova <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 <continue | replay step | replay continue | step> <on | off>
show scheduler-locking <continue | replay step | replay continue | 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 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 <eliz@gnu.org>
---
 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 <command type> (on|off)
+show scheduler-locking <command type>
+  Where <command type> 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 <opt>:  ...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.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v9 6/6] gdb: add eval option to lock the scheduler during infcalls.
  2026-09-07 11:55 [PATCH v9 0/6] gdb: refine scheduler locking settings Klaus Gerlicher
                   ` (4 preceding siblings ...)
  2026-09-07 11:55 ` [PATCH v9 5/6] gdb: refine commands to control " Klaus Gerlicher
@ 2026-09-07 11:55 ` Klaus Gerlicher
  5 siblings, 0 replies; 7+ messages in thread
From: Klaus Gerlicher @ 2026-09-07 11:55 UTC (permalink / raw)
  To: gdb-patches; +Cc: tom, aburgess, eliz, guinevere

From: Natalia Saiapova <natalia.saiapova@intel.com>

This patch adds an "eval" scheduler locking setting to control inferior
function calls separately from other continuing commands.

"continue" handles continuing commands, such as continue, until, return,
finish, jump.
"eval" handles inferior calls.

Show scheduler locking:
  (gdb) show scheduler-locking
  scheduler-locking continue:  "off"  Scheduler locking for continuing
  commands is "off" during normal execution.
  scheduler-locking eval:  "off"  Scheduler locking for function calls
  is "off" during normal execution.
  scheduler-locking replay continue:  "on"  Scheduler locking for
  continuing commands is "on" during replay mode.
  scheduler-locking replay eval:  "on"  Scheduler locking for function
  calls 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.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
---
 gdb/NEWS                                      | 21 +++--
 gdb/doc/gdb.texinfo                           | 37 ++++++--
 gdb/infrun.c                                  | 73 +++++++++++++---
 .../gdb.mi/user-selected-context-sync.exp     | 29 ++++---
 .../gdb.threads/hand-call-in-threads.exp      |  8 +-
 .../multiple-successive-infcall.exp           |  3 +-
 gdb/testsuite/gdb.threads/schedlock.c         |  3 +-
 gdb/testsuite/gdb.threads/schedlock.exp       | 86 +++++++++++++------
 gdb/testsuite/lib/gdb.exp                     |  2 +-
 9 files changed, 194 insertions(+), 68 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 09926ae0b2e..4e59eb5e8a4 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -931,19 +931,28 @@ list .
 set scheduler-locking <command type> (on|off)
 show scheduler-locking <command type>
   Where <command type> 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,
+    continue | eval | replay continue | replay eval | 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,
+  continuing and evaluating commands.  Stepping commands include step, stepi,
   next.  Continuing commands include continue, finish, until, jump, return.
+  The evaluating commands are those which invoke inferior calls, such as
+  direct user calls (e.g., 'print some_func()') and other inferior calls
+  triggered by GDB (e.g., Python pretty-printers, display expressions).
+  Note: Breakpoint and watchpoint condition evaluation always runs on the
+  thread that triggered the breakpoint, regardless of the 'eval' setting.
     'continue' -- when on, the scheduler is locked during continuing commands
-    during normal execution (not replay mode).
+    outside replay mode.
+    'eval' -- when on, the scheduler is locked during inferior calls
+    outside replay mode.
     'replay continue' -- when on, the scheduler is locked during continuing
     commands in replay mode.
+    'replay eval' -- when on, the scheduler is locked during inferior calls
+    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).
+    outside 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
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 7767c399fa4..56005144149 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -7462,10 +7462,14 @@ locking the OS scheduler to allow only a single thread to run.
 @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.
+for stepping commands, continuing commands, and inferior function calls.
+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}.
+Inferior function calls include direct user calls (e.g., @code{print func()})
+and calls triggered by @value{GDBN} such as @code{display} expressions.
+Breakpoint and watchpoint condition evaluation always runs on the thread
+that triggered the breakpoint and is not affected by these settings.
 
 The following @var{type}-settings are available.  When a setting is
 @samp{on}, the scheduler is locked: other threads may not preempt the
@@ -7476,10 +7480,25 @@ current thread, so that the focus of debugging does not change unexpectedly.
 Applies to continuing commands during normal execution and record modes.
 This setting is @samp{off} by default.
 
+@item eval
+When @samp{on}, the scheduler is locked during inferior calls in normal
+execution mode, such that other threads may not preempt the current thread.
+This applies to direct user calls (e.g., @code{print some_func()}) and
+other inferior calls triggered by @value{GDBN} such as Python
+pretty-printers and @code{display} expressions.
+This setting is @samp{off} by default.
+Note: Breakpoint and watchpoint condition evaluation always runs on the
+thread that triggered the breakpoint, regardless of this setting.
+
 @item replay continue
 Applies to continuing commands during replay mode.  This setting is
 @samp{on} by default.
 
+@item replay eval
+When @samp{on}, the scheduler is locked during inferior calls in replay
+mode, such that other threads may not preempt the current thread.
+This setting is @samp{on} by default.
+
 @item replay step
 Applies to stepping commands during replay mode.  This setting is
 @samp{on} by default.
@@ -7509,7 +7528,7 @@ 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.
+Behaves like @samp{on} when stepping, and @samp{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 continuing
 commands.
@@ -7526,12 +7545,12 @@ This is equivalent to setting @samp{scheduler-locking step} and
 are @samp{off}.
 
 @item replay
-Behaves like @code{on} in replay mode, and @code{off} in either record
+Behaves like @samp{on} in replay mode, and @samp{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}.
+This is equivalent to setting @samp{scheduler-locking replay continue},
+@samp{scheduler-locking replay eval} and @samp{scheduler-locking replay step}
+to @samp{on}, while other settings are @samp{off}.
 
 @end table
 
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 327ab12fbba..f190fef50b0 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -112,9 +112,9 @@ struct schedlock_mode_options;
 static bool schedlock_applies (thread_info *tp);
 static bool schedlock_applies (bool step,
 			       bool record_will_replay,
-			       thread_info *tp = nullptr);
+			       thread_info *tp);
 static bool schedlock_applies_to_opts (const schedlock_mode_options &,
-				       bool step);
+				       bool step, thread_info *tp);
 
 static void handle_process_exited (struct execution_control_state *ecs);
 
@@ -2458,14 +2458,17 @@ schedlock_option::set (bool new_value)
 struct schedlock_mode_options
 {
   schedlock_mode_options () = delete;
-  schedlock_mode_options (schedlock_option cont, schedlock_option step)
-    : cont (std::move (cont)), step (std::move (step))
+  schedlock_mode_options (schedlock_option eval, schedlock_option cont,
+			  schedlock_option step)
+    : eval (std::move (eval)), cont (std::move (cont)), step (std::move (step))
   {}
 
   DISABLE_COPY_AND_ASSIGN (schedlock_mode_options);
   schedlock_mode_options (schedlock_mode_options &&) = default;
   schedlock_mode_options &operator= (schedlock_mode_options &&) = default;
 
+  /* If true, the scheduler is locked during inferior calls.  */
+  schedlock_option eval;
   /* If true, the scheduler is locked during continuing.  */
   schedlock_option cont;
   /* If true, the scheduler is locked during stepping.  */
@@ -2492,10 +2495,12 @@ static const char schedlock_replay[] = "replay";
 /* Global scheduler locking state.  */
 static schedlock_state scheduler_locking_state {
   {
+    {"eval", false},
     {"cont", false},
     {"step", false}
   },
   {
+    {"replay eval", true},
     {"replay cont", true},
     {"replay step", true}
   }
@@ -2519,9 +2524,11 @@ set_schedlock_shortcut_option (const char *shortcut)
 
   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.normal.eval.set (is_on) || 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;
+  any_changed = scheduler_locking_state.replay.eval.set (is_on || is_replay) || any_changed;
 
   /* If at least one parameter has changed, notify the observer
      in the old-fashioned way.  */
@@ -2603,6 +2610,15 @@ show_schedlock_option (ui_file *file, int from_tty,
 	gdb_printf (file, _("Scheduler locking for continuing commands "
 			    "in normal execution is \"%s\".\n"), value);
     }
+  else if (strcmp (c->name, "eval") == 0)
+    {
+      if (is_replay)
+	gdb_printf (file, _("Scheduler locking for function calls "
+			    "in replay mode is \"%s\".\n"), value);
+      else
+	gdb_printf (file, _("Scheduler locking for function calls "
+			    "in normal execution is \"%s\".\n"), value);
+    }
   else
     gdb_assert_not_reached ("Unexpected command name.");
 }
@@ -3373,9 +3389,13 @@ clear_proceed_status (int step, bool about_to_proceed)
      but also for "set scheduler-locking on" and (when stepping)
      "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.  */
+     replaying threads that have finished their replay.
+
+     Pass nullptr for the thread_info because clear_proceed_status runs
+     before any specific thread has been selected for execution, so
+     there is no meaningful infcall state to check.  */
   if (!non_stop && schedlock_applies_to_opts (scheduler_locking_state.replay,
-					      step)
+					      step, nullptr)
       && !target_record_will_replay (inferior_ptid,
 				     execution_direction))
     target_record_stop_replaying ();
@@ -3455,13 +3475,32 @@ thread_still_needs_step_over (struct thread_info *tp)
 
 /* Return true if OPTS lock the scheduler.
    STEP indicates whether a thread is about to step.
+   While the stepping info we take from STEP argument, the inferior call
+   state we get from the thread TP.  TP may be nullptr, in which case the
+   scheduler is treated as not being in an inferior call.
    This function does not take into account the mode (replay or
-   normal execution).  */
+   normal execution).
+
+   Note: When stepping during an inferior call (e.g., evaluating a
+   conditional breakpoint's condition that calls a function during a step
+   command), both the 'step' and 'eval' settings are checked independently.
+   The scheduler is locked if either setting is on.  The 'cont' setting is
+   excluded during inferior calls; those are handled by the 'eval'
+   setting.  */
 
 static bool
-schedlock_applies_to_opts (const schedlock_mode_options &opts, bool step)
+schedlock_applies_to_opts (const schedlock_mode_options &opts, bool step,
+			   thread_info *tp)
 {
-  return ((opts.cont && !step) || (opts.step && step));
+  bool in_infcall = (tp != nullptr) && tp->control.in_infcall;
+
+  return (opts.cont && !step && !in_infcall)
+	  /* Intentionally no in_infcall check here: step protection
+	     applies even during inferior calls.  Both step and eval
+	     settings are checked independently; scheduler is locked if
+	     either is on.  */
+	  || (opts.step && step)
+	  || (opts.eval && in_infcall);
 }
 
 /* Returns true if scheduler locking applies to non-NULL thread TP.  */
@@ -3486,7 +3525,7 @@ schedlock_applies (bool step, bool record_will_replay, thread_info *tp)
   schedlock_mode_options &opts
     = record_will_replay ? scheduler_locking_state.replay
 			 : scheduler_locking_state.normal;
-  return schedlock_applies_to_opts (opts, step);
+  return schedlock_applies_to_opts (opts, step, tp);
 }
 
 /* When FORCE_P is false, set process_stratum_target::COMMIT_RESUMED_STATE
@@ -11144,6 +11183,13 @@ Commands include step, next, stepi, nexti."),
      set_schedlock_step,
      &schedlock_set_cmdlist, &schedlock_show_cmdlist);
 
+  scheduler_locking_state.normal.eval.make_cli_option
+    ("eval",
+     _("Scheduler locking for function calls during normal execution."),
+     _("Show scheduler locking for function calls during normal execution."),
+     _("Controls scheduler locking for function calls during normal execution."),
+     &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
@@ -11181,6 +11227,13 @@ stepping and function calls."),
 Commands include step, next, stepi, nexti."),
      &schedlock_set_replay_cmdlist, &schedlock_show_replay_cmdlist);
 
+  scheduler_locking_state.replay.eval.make_cli_option
+    ("eval",
+     _("Set scheduler locking for function calls in replay mode."),
+     _("Show scheduler locking for function calls in replay mode."),
+     _("Controls scheduler locking for function calls in replay mode."),
+     &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, _("\
diff --git a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
index 7555469b579..9cb132d1c47 100644
--- a/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
+++ b/gdb/testsuite/gdb.mi/user-selected-context-sync.exp
@@ -257,17 +257,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."
@@ -313,7 +308,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.
@@ -344,7 +339,17 @@ 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 {"continue" "eval" "replay continue" \
+				 "replay eval" "replay step" "step"} {
+		    gdb_test_no_output \
+			"set scheduler-locking $opt [dict get $previous_schedlock $opt]"
+		}
+
+		# Verify the restore above actually put every sub-option back
+		# to what it was, not just the "continue" one.
+		set test "scheduler-locking restored to previous value"
+		gdb_assert {[get_scheduler_locking $test $previous_schedlock] \
+				ne "unknown"} $test
 	    } 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 06ec22e1138..1f7d5c8e937 100644
--- a/gdb/testsuite/gdb.threads/hand-call-in-threads.exp
+++ b/gdb/testsuite/gdb.threads/hand-call-in-threads.exp
@@ -70,8 +70,8 @@ gdb_test "continue" \
 gdb_test_no_output "set scheduler-locking on" "enable scheduler locking"
 set test "show scheduler-locking on"
 gdb_assert {[get_scheduler_locking $test \
-		[dict create "continue" "on" \
-		     "replay continue" "on" \
+		[dict create "continue" "on" "eval" "on" \
+		     "replay continue" "on" "replay eval" "on" \
 		     "replay step" "on" "step" "on"]] ne "unknown"} $test
 
 # Now hand-call a function in each thread, having the function
@@ -145,8 +145,8 @@ gdb_test_multiple "maint print dummy-frames" "all dummies popped" {
 gdb_test_no_output "set scheduler-locking off" "disable scheduler locking"
 set test "show scheduler-locking off"
 gdb_assert {[get_scheduler_locking $test \
-		[dict create "continue" "off" \
-		     "replay continue" "off" \
+		[dict create "continue" "off" "eval" "off" \
+		     "replay continue" "off" "replay eval" "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 4bda757027b..98e50c92713 100644
--- a/gdb/testsuite/gdb.threads/multiple-successive-infcall.exp
+++ b/gdb/testsuite/gdb.threads/multiple-successive-infcall.exp
@@ -51,7 +51,8 @@ gdb_continue_to_breakpoint "testmarker01"
 gdb_test_no_output "set scheduler-locking on"
 set test "show scheduler-locking"
 gdb_assert {[get_scheduler_locking $test \
-		 [dict create "continue" "on" "replay continue" "on" \
+		 [dict create "continue" "on" "eval" "on" \
+		      "replay continue" "on" "replay eval" "on" \
 		      "replay step" "on" "step" "on"]] ne "unknown"} $test
 
 foreach_with_prefix thread {5 4 3 2 1}  {
diff --git a/gdb/testsuite/gdb.threads/schedlock.c b/gdb/testsuite/gdb.threads/schedlock.c
index d1dd91ba4ce..afab01b1d7e 100644
--- a/gdb/testsuite/gdb.threads/schedlock.c
+++ b/gdb/testsuite/gdb.threads/schedlock.c
@@ -50,12 +50,13 @@ int main() {
     exit(EXIT_SUCCESS);
 }
 
-void some_function (void) {
+int some_function (void) {
   /* Sleep a bit to give the other threads a chance to run, if not
      locked.  This also ensure that even if the compiler optimizes out
      or inlines some_function, there's still be some function that
      needs to be stepped over.  */
   usleep (1);
+  return 1;
 }
 
 /* When testing "next", this is set to have the loop call
diff --git a/gdb/testsuite/gdb.threads/schedlock.exp b/gdb/testsuite/gdb.threads/schedlock.exp
index 5fd52acbf91..3c17a9dbcbc 100644
--- a/gdb/testsuite/gdb.threads/schedlock.exp
+++ b/gdb/testsuite/gdb.threads/schedlock.exp
@@ -227,7 +227,7 @@ proc check_result { cmd before_thread before_args locked } {
     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} {
+	    if {$i == $before_thread && $cmd ne "infcall"} {
 		fail "$test (didn't run)"
 	    }
 	} else {
@@ -325,15 +325,16 @@ 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.
+# CONT, EVAL, and STEP are the expected values ("on" or "off") for the
+# normal execution scheduler-locking options: continue, eval, 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} {
+proc test_schedlock_opts {cont eval step} {
     set test "show scheduler-locking"
     gdb_assert {[get_scheduler_locking $test \
-		     [dict create "continue" $cont "replay continue" "off" \
+		     [dict create "continue" $cont "eval" $eval \
+			  "replay continue" "off" "replay eval" "off" \
 			  "replay step" "off" "step" $step]] ne "unknown"} $test
 
     set locked 0
@@ -365,6 +366,25 @@ proc test_schedlock_opts {cont step} {
 	my_continue "continue"
 	check_result "continue" $curthread $cont_args $locked
     }
+
+    # Infcall tests.
+    set locked 0
+    if {$eval eq "on"} {
+	set locked 1
+    }
+    with_test_prefix "cmd=infcall" {
+	# Use whichever we stopped in.
+	set curthread [get_current_thread "before-infcall"]
+	set cont_args [get_args "before-infcall"]
+
+	for { set i 0 } { $i < 10 } { incr i } {
+	    with_test_prefix "infcall #$i" {
+		gdb_test "print some_function()" ".*"
+	    }
+	}
+
+	check_result "infcall" $curthread $cont_args $locked
+    }
 }
 
 # Test different options of scheduler locking.
@@ -372,11 +392,14 @@ 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
+	foreach eval {"off" "on"} {
+	    foreach step {"off" "on"} {
+		with_test_prefix "continue=$cont eval=$eval step=$step" {
+		    gdb_test_no_output "set scheduler-locking continue $cont"
+		    gdb_test_no_output "set scheduler-locking eval $eval"
+		    gdb_test_no_output "set scheduler-locking step $step"
+		    test_schedlock_opts $cont $eval $step
+		}
 	    }
 	}
     }
@@ -386,16 +409,20 @@ with_test_prefix "option combinations" {
 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
+	foreach replay_eval {"off" "on"} {
+	    foreach replay_step {"off" "on"} {
+		with_test_prefix "replay: continue=$replay_cont eval=$replay_eval step=$replay_step" {
+		    gdb_test_no_output "set scheduler-locking replay continue $replay_cont"
+		    gdb_test_no_output "set scheduler-locking replay eval $replay_eval"
+		    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" "eval" "off" \
+					  "replay continue" $replay_cont \
+					  "replay eval" $replay_eval \
+					  "replay step" $replay_step \
+					  "step" "off"]] ne "unknown"} $test
+		}
 	    }
 	}
     }
@@ -407,17 +434,28 @@ with_test_prefix "individual options" {
     # 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" \
+		     [dict create "continue" "on" "eval" "off" \
+			  "replay continue" "off" "replay eval" "off" \
 			  "replay step" "off" "step" "off"]] ne "unknown"} \
 	"continue only"
 
+    # Reset and test setting only 'eval'.
+    gdb_test_no_output "set scheduler-locking off"
+    gdb_test_no_output "set scheduler-locking eval on"
+    gdb_assert {[get_scheduler_locking "eval only" \
+		     [dict create "continue" "off" "eval" "on" \
+			  "replay continue" "off" "replay eval" "off" \
+			  "replay step" "off" "step" "off"]] ne "unknown"} \
+	"eval 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" \
+		     [dict create "continue" "off" "eval" "off" \
+			  "replay continue" "off" "replay eval" "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 7de75265513..cf7f98e2918 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -10437,7 +10437,7 @@ proc get_scheduler_locking {{test ""} {expected ""}} {
 	set test "reading current scheduler-locking mode"
     }
 
-    set opts {"continue" "replay continue" "replay step" "step"}
+    set opts {"continue" "eval" "replay continue" "replay eval" "replay step" "step"}
 
     # Fill the missing entries in EXPECTED list.
     foreach opt $opts {
-- 
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.


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-09-07 11:58 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-07 11:55 [PATCH v9 0/6] gdb: refine scheduler locking settings Klaus Gerlicher
2026-09-07 11:55 ` [PATCH v9 1/6] gdb: use schedlock_applies in user_visible_resume_ptid Klaus Gerlicher
2026-09-07 11:55 ` [PATCH v9 2/6] gdb, cli: remove left-over code from "set_logging_on" Klaus Gerlicher
2026-09-07 11:55 ` [PATCH v9 3/6] gdb, cli: pass the argument of a set command to its callback Klaus Gerlicher
2026-09-07 11:55 ` [PATCH v9 4/6] gdb: change the internal representation of scheduler locking Klaus Gerlicher
2026-09-07 11:55 ` [PATCH v9 5/6] gdb: refine commands to control " Klaus Gerlicher
2026-09-07 11:55 ` [PATCH v9 6/6] gdb: add eval option to lock the scheduler during infcalls Klaus Gerlicher

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox