From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id KfWfM/KCqmrnOBIAWB0awg (envelope-from ) for ; Wed, 16 Sep 2026 07:52:18 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20251104 header.b=i0Kaf1wp; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id CE58F1E06B; Wed, 16 Sep 2026 07:52:18 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-2.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 887501E01F for ; Wed, 16 Sep 2026 07:52:17 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C34A64BA79B3 for ; Wed, 16 Sep 2026 11:52:16 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C34A64BA79B3 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20251104 header.b=i0Kaf1wp Received: from mail-pj2-x10.google.com (mail-pj2-x10.google.com [IPv6:2607:f8b0:4864:39::10]) by sourceware.org (Postfix) with ESMTPS id F3A2D4BA9017 for ; Wed, 16 Sep 2026 11:51:11 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F3A2D4BA9017 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org F3A2D4BA9017 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:39::10 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1789559472; cv=none; b=WoRvR8BwdNe9Le8PvskMkcdMUiWeZZN3jWSuwfcQi6IEcicqZWGCQcSGBNBEd69rLGZKtNthX8HO+SUOEFLJ+xIfIS+BSh2gVoIHs4LfbuyLTjgYxG7h63/nJ5OzBYB8dm3LJVHSwlWyRMWCbm/1qwzuaqD/dYFBFHXb8xBAoRs= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1789559472; c=relaxed/simple; bh=DEt+RmYGjzZnZVGpnH5Afm31hHLMcGmjG1deaofah70=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Y+tFyjawqEldi8NeaQCgNwLM7r6j9I9F5rkrz1FKQPvEDSauYEKSBqJDHJOjV8aViVhGCnRaWNmz7WvXmJ+m9Oxn3TwkGj6Ncd2jF0i4UdNH+Ow2wETNBhRvzY3nyJ9xzzXKDdhcE5vjHKVMo1kk0kwH+c1FYSail9eRHQMliP4= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20251104 header.b=i0Kaf1wp DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F3A2D4BA9017 Received: by mail-pj2-x10.google.com with SMTP id 98e67ed59e1d1-39b9184fa80so724106a91.2 for ; Wed, 16 Sep 2026 04:51:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1789559471; x=1790164271; darn=sourceware.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=tuyG9TnjYr/6q7Q3K8u2JxVuAHfWd3artCPhvYs7flg=; b=i0Kaf1wpN0AagcN7FI76vqi1KWDz3VGk4/Ccq4jkTb1zDA9Tqlfq/JCeosj7wRWSkR IGoV/MuKioZdssiKN1iT5wyKYkJejFZ/K1K0NGCgDDMAjk9zzzDXjnV69QMl4rT5hFnP N9A+2kZD7j56PyYC8v1cKPWTpGwG+qOPvwBlSLWf5GUWqpSJcN3MXEwMDUzkB5F4fW/x WojqBym/l4LF3ZgV4YW0akqmSvT9xIKs8zaKrv15csV11iSNHz6lRWcz7pzYYqmWNuSD /9T0WJYyAKdhyKIhwD5vgTq3umOt2iKJXIHkhQklRH4ImFpQVigeucjaKM1RIGfxaHPS RIZA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789559471; x=1790164271; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=tuyG9TnjYr/6q7Q3K8u2JxVuAHfWd3artCPhvYs7flg=; b=n/e/MVuV4H3poXx2UaDhbZEXBkCg8H0qQgxR5OWScrcBot9QOv3xQPCNN2y3GGMpjd fWwTFz51ft/iQbe64jg2erJqacFlcYP1706FJlAIYdEpWGbCwxMNVZkIr1MDJopoDHnW SXaFhmMdGZ41BWocJT4a9LKj2CxLMpSXwyqvvfBXYZj8zVamKFevhYmEbohH3I57ZPhZ /+n4yiptp2Y8mrM9YkZvcuoWRGpGfLSzBhB7JSzAbWsrOjRPgvpW96DacCnf7U/qCn7k T+2mehcF9Ve8k6PNuwy050nxDob/3C8+VyLgB7fkIAddFethCeJ01Bk1o2U224Y/5ya0 O7YA== X-Gm-Message-State: AFuF++meHUYkUx5A3xuimlJIFTa4uxyBMOskZ+ocXQBLV3wuvsob4fib onFj3OgkzW4RGnoZN/5boiXBAwIyIKqLpkKCqwJF8fx7Tc1Ae7l86m5j X-Gm-Gg: AYBFou1RQkhwISTGzXEkyE0Ac7nussqPaH5hiTXJNeC3/ovXDBQwGT6I2htsc6o2JZA JANRuUTHa2ZrYL01EVsEqBMTNQTBbWF3yJNBoBryDgr9SdNjpk06Vdy3onaQ5vSH3m8+Ah/w7G8 xEk6Xj4b57/eex2QLBPcWjH2JlkYe1q6Bbx00viY7DI2GJIe3YvMhSL0i+CspSJDXSzRIGm2B6s VQOCBT29Dk5CYPvmK23Y6jN4SyqffObBoQLElqMXxk5cCEne0VsVSsl0/9FvLVRUvbvYUWdhXzN K7KTaeMcpgcI6uu238zQMIUDo92TIetNbPlN1EWgxc5MfT41vpAl/3YDbTVsvqJC1VD3hpWQeRX BZLM/Gf5E3Qn1S0mwL6Sj0R9guwXq3WKpQ3cWdhkS3Qssw3cZ1hmTfg6g+4qjB8wXQw1f7c6Wgt OBW71R5vsZPff8hKj5WBgpbsL/G2k4Nye0j2OIhyTRNHm7YcXYCWgztMVUYNLH+4aWdy522Qtw7 uxhDcmJIUa3JnGq1AEQ6FhzdIXN X-Received: by 2002:a17:90b:2744:b0:38e:bbf1:de3f with SMTP id 98e67ed59e1d1-39e1e4907ddmr6048274a91.12.1789559470613; Wed, 16 Sep 2026 04:51:10 -0700 (PDT) Received: from localhost.localdomain ([122.171.19.232]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-33bf5af6593sm7289212eec.25.2026.09.16.04.51.07 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Wed, 16 Sep 2026 04:51:10 -0700 (PDT) From: Aditya Vidyadhar Kamath To: ulrich.weigand@de.ibm.com, simon.marchi@polymtl.ca, tom@tromey.com Cc: gdb-patches@sourceware.org, Aditya.Kamath1@ibm.com, sangamesh.swamy@in.ibm.com, Aditya Vidyadhar Kamath Subject: [PATCH v3 3/3][RFC] Speed up next/step while debugging multithreaded programs on AIX. Date: Wed, 16 Sep 2026 17:19:33 +0530 Message-ID: <20260916114931.17516-3-akamath996@gmail.com> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org From: Aditya Vidyadhar Kamath During go compiler debugging on AIX my collegue and I noticed that the next command was pretty slow compared to Linux - around 7 seconds per step when program has atleast 3 or more threads running. Debugging 10 - 12 line function took around a minute. In compiler codes this is slow. To measure this properly I wrote a benchmark pasted below. The program spawns 3 worker threads , then stops inside a function with 10 simple that GDB steps over one by one. The GDB batch script breaks at that function and issues 10 next commands and then quits. Timing the whole run gives a fair picture of how much overhead each next carries. Both the .c file and batch file are pasted below. Before this patch, on AIX 7.3 ppc64 with 20 background threads: real 1m10.05s user 0m17.59s sys 0m20.43s That is roughly 7 seconds per `next` step. After this patch: real 0m20.37s user 0m5.94s sys 0m6.53s About 2 seconds per step. 3.5x faster for the same workload. Every stop including single-step traps from next/step called pd_update(), which unconditionally ran pthdb_session_update() followed by sync_threadlists(). The scoped_time_it instrumentation added in the previous commit shows that the entire cost is in sync_threadlists(), dominated by the first pthdb_pthread(PTHDB_LIST_FIRST) call. This cost is the same regardless of thread count. So it is a fixed per-stop overhead paid on every single-step trap. During a next/step sequence I assume, the stepped thread is running a single instruction, so it cannot call pthread_create or pthread_exit. It is therefore safe to skip both pthdb_session_update() and sync_threadlists() when we know this stop is the result of a software single-step. In AIX, single-stepping is implemented in software: GDB inserts breakpoints at the next instruction before resuming with step=0. A completed software single-step and a user breakpoint both arrive as TARGET_WAITKIND_STOPPED/GDB_SIGNAL_TRAP and are otherwise indistinguishable at the target layer. The only reliable indicator is whether single-step breakpoints were inserted for the resumed thread just before the resume. Which the code is doing. For now this patch is request for comment / draft. Once feedback is recieved from maintainers I will remove this paragraph and benchmark results pasted below. ================== Benchmark program (bench_next.c): /* Spawns NUM_THREADS worker threads that spin, then steps through 10 assignments in do_steps() so GDB can time each next. Also tests two scenarios from the bug report: 1. "next" over a call that spawns a thread (spawn_thread_here()). 2. A background thread exits while "next" is in progress (exit_thread_here()). */ #include #include #include #include #ifndef NUM_THREADS #define NUM_THREADS 3 #endif static volatile int keep_running = 1; static volatile int extra_thread_started = 0; static void * worker (void *arg) { while (keep_running) sched_yield (); return NULL; } /* Thread that exits on its own after signalling it has started. */ static void * short_lived (void *arg) { extra_thread_started = 1; return NULL; } /* GDB will "next" over this call -- a new thread is spawned inside. */ static void spawn_thread_here (void) { pthread_t t; pthread_create (&t, NULL, short_lived, NULL); pthread_join (t, NULL); } /* GDB will "next" over this call -- the short-lived background thread is in the process of exiting while we step. */ static void exit_thread_here (void) { /* Just a visible marker so GDB can stop here. */ volatile int x = 42; (void)x; } void do_steps (void) { volatile int a = 1; volatile int b = 2; volatile int c = a + b; volatile int d = c * 2; volatile int e = d - a; volatile int f = e + c; volatile int g = f / 2; volatile int h = g + 1; volatile int i2 = h * h; volatile int j = i2 - b; (void)j; } int main (void) { pthread_t threads[NUM_THREADS]; pthread_t bg; int i; /* Start background spinning threads. */ for (i = 0; i < NUM_THREADS; i++) pthread_create (&threads[i], NULL, worker, NULL); /* Next over a call that spawns a thread */ spawn_thread_here (); /* Next while a background thread is exiting Launch a thread that exits quickly; "next" through exit_thread_here() while that exit is in flight. */ pthread_create (&bg, NULL, short_lived, NULL); exit_thread_here (); pthread_join (bg, NULL); do_steps (); keep_running = 0; for (i = 0; i < NUM_THREADS; i++) pthread_join (threads[i], NULL); return 0; } ==================== Build done with gcc -O0 -g -gdwarf -maix64 -DNUM_THREADS=3 -o bench_next_bin bench_next.c -lpthread ===================== GDB batch script (bench_next.gdb): set pagination off set confirm off maintenance set per-command time on # Scenario 1: next over a call that spawns a thread break spawn_thread_here run next # Scenario 2: next while a background thread is exiting break exit_thread_here continue next break do_steps continue next next next next next next next next next next quit ======================== Then run, time gdb -batch -x bench_next.gdb ./bench_next_bin ========================================= Time for "pthdb_session_update": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "sync_threadlists": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pthdb_session_update": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "sync_threadlists": wall 0.941, user 0.094, sys 0.096, user+sys 0.190, 20.2 % CPU Time for "pd_update total": wall 0.941, user 0.094, sys 0.096, user+sys 0.190, 20.2 % CPU 25 volatile int a = 1; Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pthdb_session_update": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "sync_threadlists": wall 0.938, user 0.093, sys 0.096, user+sys 0.189, 20.1 % CPU Time for "pd_update total": wall 0.938, user 0.093, sys 0.096, user+sys 0.189, 20.1 % CPU 26 volatile int b = 2; Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pthdb_session_update": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "sync_threadlists": wall 1.149, user 0.082, sys 0.090, user+sys 0.172, 15.0 % CPU Time for "pd_update total": wall 1.149, user 0.082, sys 0.090, user+sys 0.172, 15.0 % CPU 27 volatile int c = a + b; Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pthdb_session_update": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "sync_threadlists": wall 1.262, user 0.075, sys 0.087, user+sys 0.162, 12.8 % CPU Time for "pd_update total": wall 1.262, user 0.075, sys 0.087, user+sys 0.162, 12.8 % CPU 28 volatile int d = c * 2; Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pthdb_session_update": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "sync_threadlists": wall 1.281, user 0.078, sys 0.091, user+sys 0.169, 13.2 % CPU Time for "pd_update total": wall 1.281, user 0.078, sys 0.091, user+sys 0.169, 13.2 % CPU 29 volatile int e = d - a; Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pthdb_session_update": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "sync_threadlists": wall 1.264, user 0.076, sys 0.087, user+sys 0.163, 12.9 % CPU Time for "pd_update total": wall 1.264, user 0.076, sys 0.087, user+sys 0.163, 12.9 % CPU 30 volatile int f = e + c; Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pthdb_session_update": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "sync_threadlists": wall 1.262, user 0.075, sys 0.086, user+sys 0.161, 12.8 % CPU Time for "pd_update total": wall 1.262, user 0.075, sys 0.086, user+sys 0.161, 12.8 % CPU 31 volatile int g = f / 2; Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pthdb_session_update": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "sync_threadlists": wall 1.220, user 0.086, sys 0.098, user+sys 0.184, 15.1 % CPU Time for "pd_update total": wall 1.220, user 0.086, sys 0.098, user+sys 0.184, 15.1 % CPU 32 volatile int h = g + 1; Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pthdb_session_update": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "sync_threadlists": wall 1.071, user 0.091, sys 0.098, user+sys 0.189, 17.6 % CPU Time for "pd_update total": wall 1.071, user 0.091, sys 0.098, user+sys 0.189, 17.6 % CPU 33 volatile int i2 = h * h; Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pthdb_session_update": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "sync_threadlists": wall 1.276, user 0.077, sys 0.089, user+sys 0.166, 13.0 % CPU Time for "pd_update total": wall 1.276, user 0.077, sys 0.089, user+sys 0.166, 13.0 % CPU 34 volatile int j = i2 - b; Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pd_update total": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "pthdb_session_update": wall 0.000, user 0.000, sys 0.000, user+sys 0.000, NaNQ % CPU Time for "sync_threadlists": wall 1.278, user 0.077, sys 0.091, user+sys 0.168, 13.1 % CPU Time for "pd_update total": wall 1.278, user 0.077, sys 0.091, user+sys 0.168, 13.1 % CPU real 0m20.29s user 0m2.01s sys 0m2.59s --- gdb/aix-thread.c | 75 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 18 deletions(-) diff --git a/gdb/aix-thread.c b/gdb/aix-thread.c index 2355f87db54..72a26153aae 100644 --- a/gdb/aix-thread.c +++ b/gdb/aix-thread.c @@ -165,6 +165,11 @@ static pthdb_callbacks_t pd_callbacks = { /* Aix variable structure. */ struct aix_thread_variables { + aix_thread_variables () + : pd_able (0), pd_active (0), pd_session (0), pd_brk_addr (0), + arch64 (0), last_resume_step (0) + {} + /* Whether the current application is debuggable by pthdb. */ int pd_able; @@ -184,6 +189,14 @@ struct aix_thread_variables /* Describes the number of thread exit events reported. */ std::unordered_set exited_threads; + + /* Set to non-zero by resume() when the resume was a software + single-step, i.e. single-step breakpoints were inserted for the + resumed thread before the inferior was set running. Cleared to + zero for any other kind of resume. Used by wait() to distinguish + a SIGTRAP from a completed single-step from one caused by a + breakpoint, since both look identical at the signal level. */ + int last_resume_step; }; /* Key to our per-inferior data. */ @@ -854,11 +867,16 @@ sync_threadlists (pid_t pid) /* Synchronize libpthdebug's state with the inferior and with GDB, generate a composite process/thread for the current thread, - Return the ptid of the event thread if one can be found, else - return a pid-only ptid with PID. */ + return the ptid of the event thread if one can be found, else + return a pid-only ptid with PID. + + STEP_STOP is non-zero when the stop is known to be a completed + single-step (software single-step breakpoint trap) for a single + thread. In that case pthdb_session_update() and sync_threadlists() + are skipped because the thread population cannot have changed. */ static ptid_t -pd_update (pid_t pid) +pd_update (pid_t pid, bool step_stop = false) { int status; ptid_t ptid; @@ -873,20 +891,23 @@ pd_update (pid_t pid) scoped_time_it total_time_it ("pd_update total"); - { - scoped_time_it time_it ("pthdb_session_update"); - status = pthdb_session_update (data->pd_session); - } - if (status != PTHDB_SUCCESS) - return ptid_t (pid); - - /* Attempt to sync_threadlists () only when debugging object files - and not core files since list of threads never change for core - files. */ - if (target_has_execution ()) + if (!step_stop) { - scoped_time_it time_it ("sync_threadlists"); - sync_threadlists (pid); + { + scoped_time_it time_it ("pthdb_session_update"); + status = pthdb_session_update (data->pd_session); + } + if (status != PTHDB_SUCCESS) + return ptid_t (pid); + + /* Attempt to sync_threadlists () only when debugging object + files and not core files since list of threads never change + for core files. */ + if (target_has_execution ()) + { + scoped_time_it time_it ("sync_threadlists"); + sync_threadlists (pid); + } } /* Define "current thread" as one that just received a trap signal. */ @@ -920,7 +941,10 @@ pd_activate (pid_t pid) PTHDB_FLAG_REGS, &pd_callbacks, &data->pd_session); if (status == PTHDB_SUCCESS) - data->pd_active = 1; + { + data->pd_active = 1; + data->last_resume_step = 0; + } } /* AIX implementation of update_thread_list. */ @@ -1057,6 +1081,11 @@ aix_thread_target::resume (ptid_t ptid, int step, enum gdb_signal sig) if (ptid.tid () == 0) { + /* Resuming all threads: we cannot attribute a single-step to any + one thread, so clear the flag. */ + if (data != nullptr) + data->last_resume_step = 0; + scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid); inferior_ptid = ptid_t (inferior_ptid.pid ()); @@ -1069,6 +1098,10 @@ aix_thread_target::resume (ptid_t ptid, int step, enum gdb_signal sig) error (_("aix-thread resume: unknown pthread %ld"), ptid.lwp ()); + if (data != nullptr) + data->last_resume_step + = thread_has_single_step_breakpoints_set (thread); + aix_thread_info *priv = get_aix_thread_info (thread); tid[0] = ptid.lwp (); @@ -1124,7 +1157,13 @@ aix_thread_target::wait (ptid_t ptid, struct target_waitstatus *status, pd_activate (ptid.pid ()); } - return pd_update (ptid.pid ()); + /* A SIGTRAP stop after a software single-step is a completed step: + the thread population cannot have changed, so skip the expensive + pthdb_session_update() and sync_threadlists() calls. */ + bool step_stop = (data->last_resume_step + && status->kind () == TARGET_WAITKIND_STOPPED + && status->sig () == GDB_SIGNAL_TRAP); + return pd_update (ptid.pid (), step_stop); } /* Supply AIX altivec registers, both 64 and 32 bit. */ -- 2.51.2