* [PATCH v3 1/8] Defer minimal symbol name-setting
2019-05-29 21:29 [PATCH v3 0/8] Demangle minimal symbol names in worker threads Tom Tromey
@ 2019-05-29 21:29 ` Tom Tromey
2019-05-29 21:29 ` [PATCH v3 7/8] Demangle minsyms in parallel Tom Tromey
` (6 subsequent siblings)
7 siblings, 0 replies; 24+ messages in thread
From: Tom Tromey @ 2019-05-29 21:29 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
Currently the demangled name of a minimal symbol is set when creating
the symbol. However, there is no intrinsic need to do this. This
patch instead arranges for the demangling to be done just before the
minsym hash tables are filled. This will be useful in a later patch.
gdb/ChangeLog
2019-05-29 Tom Tromey <tom@tromey.com>
* symtab.h (struct minimal_symbol) <name_set>: New member.
* minsyms.c (minimal_symbol_reader::record_full): Copy name.
Don't call symbol_set_names.
(minimal_symbol_reader::install): Call symbol_set_names.
---
gdb/ChangeLog | 7 +++++++
gdb/minsyms.c | 18 +++++++++++++++++-
gdb/symtab.h | 4 ++++
3 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index 9d29d880aab..488201a1886 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -1140,7 +1140,11 @@ minimal_symbol_reader::record_full (const char *name, int name_len,
msymbol = &m_msym_bunch->contents[m_msym_bunch_index];
symbol_set_language (msymbol, language_auto,
&m_objfile->per_bfd->storage_obstack);
- symbol_set_names (msymbol, name, name_len, copy_name, m_objfile->per_bfd);
+
+ if (copy_name)
+ name = (char *) obstack_copy0 (&m_objfile->per_bfd->storage_obstack,
+ name, name_len);
+ msymbol->name = name;
SET_MSYMBOL_VALUE_ADDRESS (msymbol, address);
MSYMBOL_SECTION (msymbol) = section;
@@ -1367,6 +1371,18 @@ minimal_symbol_reader::install ()
m_objfile->per_bfd->minimal_symbol_count = mcount;
m_objfile->per_bfd->msymbols = std::move (msym_holder);
+ msymbols = m_objfile->per_bfd->msymbols.get ();
+ for (int i = 0; i < mcount; ++i)
+ {
+ if (!msymbols[i].name_set)
+ {
+ symbol_set_names (&msymbols[i], msymbols[i].name,
+ strlen (msymbols[i].name), 0,
+ m_objfile->per_bfd);
+ msymbols[i].name_set = 1;
+ }
+ }
+
build_minimal_symbol_hash_tables (m_objfile);
}
}
diff --git a/gdb/symtab.h b/gdb/symtab.h
index e4ee7271a15..cb06fe01c59 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -669,6 +669,10 @@ struct minimal_symbol : public general_symbol_info
the object file format may not carry that piece of information. */
unsigned int has_size : 1;
+ /* Non-zero if this symbol ever had its demangled name set (even if
+ it was set to NULL). */
+ unsigned int name_set : 1;
+
/* Minimal symbols with the same hash key are kept on a linked
list. This is the link. */
--
2.17.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v3 7/8] Demangle minsyms in parallel
2019-05-29 21:29 [PATCH v3 0/8] Demangle minimal symbol names in worker threads Tom Tromey
2019-05-29 21:29 ` [PATCH v3 1/8] Defer minimal symbol name-setting Tom Tromey
@ 2019-05-29 21:29 ` Tom Tromey
2019-05-30 14:19 ` Pedro Alves
2019-05-29 21:29 ` [PATCH v3 3/8] Add configure check for std::thread Tom Tromey
` (5 subsequent siblings)
7 siblings, 1 reply; 24+ messages in thread
From: Tom Tromey @ 2019-05-29 21:29 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
This patch introduces a simple parallel for_each and changes the
minimal symbol reader to use it when computing the demangled name for
a minimal symbol. This yields a speedup when reading minimal symbols.
gdb/ChangeLog
2019-05-29 Tom Tromey <tom@tromey.com>
* minsyms.c (minimal_symbol_reader::install): Use
parallel_for_each.
* common/parallel-for.h: New file.
* common/parallel-for.c: New file.
* Makefile.in (HFILES_NO_SRCDIR): Add common/parallel-for.h.
(COMMON_SFILES): Add common/parallel-for.c.
---
gdb/ChangeLog | 9 +++++
gdb/Makefile.in | 2 +
gdb/common/parallel-for.c | 27 +++++++++++++
gdb/common/parallel-for.h | 82 +++++++++++++++++++++++++++++++++++++++
gdb/minsyms.c | 23 ++++++-----
5 files changed, 133 insertions(+), 10 deletions(-)
create mode 100644 gdb/common/parallel-for.c
create mode 100644 gdb/common/parallel-for.h
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2dd69f3f0ba..15c7a6e2536 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -971,6 +971,7 @@ COMMON_SFILES = \
common/gdb_vecs.c \
common/netstuff.c \
common/new-op.c \
+ common/parallel-for.c \
common/pathstuff.c \
common/print-utils.c \
common/ptid.c \
@@ -1471,6 +1472,7 @@ HFILES_NO_SRCDIR = \
common/common-inferior.h \
common/netstuff.h \
common/host-defs.h \
+ common/parallel-for.h \
common/pathstuff.h \
common/print-utils.h \
common/ptid.h \
diff --git a/gdb/common/parallel-for.c b/gdb/common/parallel-for.c
new file mode 100644
index 00000000000..0970cea882b
--- /dev/null
+++ b/gdb/common/parallel-for.c
@@ -0,0 +1,27 @@
+/* Parallel for loops
+
+ Copyright (C) 2019 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "common/common-defs.h"
+#include "common/parallel-for.h"
+
+namespace gdb
+{
+/* See parallel-for.h. */
+int max_threads = -1;
+}
diff --git a/gdb/common/parallel-for.h b/gdb/common/parallel-for.h
new file mode 100644
index 00000000000..6770f39a05f
--- /dev/null
+++ b/gdb/common/parallel-for.h
@@ -0,0 +1,82 @@
+/* Parallel for loops
+
+ Copyright (C) 2019 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef COMMON_PARALLEL_FOR_H
+#define COMMON_PARALLEL_FOR_H
+
+#include <algorithm>
+#if CXX_STD_THREAD
+#include <thread>
+#endif
+
+namespace gdb
+{
+
+/* True if threading should be enabled. */
+
+extern int max_threads;
+
+/* A very simple "parallel for". This iterates over the elements
+ given by the range of iterators, which must be random access
+ iterators. For each element, it calls the callback function. The
+ work may or may not be done by separate threads. */
+
+template<class RandomIt, class UnaryFunction>
+void parallel_for_each (RandomIt first, RandomIt last, UnaryFunction f)
+{
+#if CXX_STD_THREAD
+ int n_threads = std::thread::hardware_concurrency ();
+ /* So we can use a local array below. */
+ const int local_max = 16;
+ /* Be sure to handle the "unlimited" case. */
+ if (max_threads >= 0 && n_threads > max_threads)
+ n_threads = max_threads;
+ if (n_threads > local_max)
+ n_threads = local_max;
+
+ if (n_threads <= 1 || last - first < 2 * n_threads)
+#endif /* CXX_STD_THREAD */
+ {
+ /* Don't bother. */
+ std::for_each (first, last, f);
+ return;
+ }
+
+#if CXX_STD_THREAD
+ auto body = [&] (RandomIt start)
+ {
+ for (; start < last; start += n_threads)
+ f (*start);
+ };
+
+ std::thread threads[local_max];
+ for (int i = 0; i < n_threads; ++i)
+ {
+ threads[i] = std::thread (body, first);
+ ++first;
+ }
+
+ for (int i = 0; i < n_threads; ++i)
+ threads[i].join ();
+#endif /* CXX_STD_THREAD */
+}
+
+}
+
+#endif /* COMMON_PARALLEL_FOR_H */
diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index 488201a1886..4c0ee11c47e 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -53,6 +53,7 @@
#include "common/symbol.h"
#include <algorithm>
#include "safe-ctype.h"
+#include "common/parallel-for.h"
/* See minsyms.h. */
@@ -1372,16 +1373,18 @@ minimal_symbol_reader::install ()
m_objfile->per_bfd->msymbols = std::move (msym_holder);
msymbols = m_objfile->per_bfd->msymbols.get ();
- for (int i = 0; i < mcount; ++i)
- {
- if (!msymbols[i].name_set)
- {
- symbol_set_names (&msymbols[i], msymbols[i].name,
- strlen (msymbols[i].name), 0,
- m_objfile->per_bfd);
- msymbols[i].name_set = 1;
- }
- }
+ gdb::parallel_for_each
+ (&msymbols[0], &msymbols[mcount],
+ [&] (minimal_symbol &msym)
+ {
+ if (!msym.name_set)
+ {
+ symbol_set_names (&msym, msym.name,
+ strlen (msym.name), 0,
+ m_objfile->per_bfd);
+ msym.name_set = 1;
+ }
+ });
build_minimal_symbol_hash_tables (m_objfile);
}
--
2.17.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v3 7/8] Demangle minsyms in parallel
2019-05-29 21:29 ` [PATCH v3 7/8] Demangle minsyms in parallel Tom Tromey
@ 2019-05-30 14:19 ` Pedro Alves
2019-05-30 22:22 ` Tom Tromey
0 siblings, 1 reply; 24+ messages in thread
From: Pedro Alves @ 2019-05-30 14:19 UTC (permalink / raw)
To: Tom Tromey, gdb-patches
On 5/29/19 10:29 PM, Tom Tromey wrote:
> This patch introduces a simple parallel for_each and changes the
> minimal symbol reader to use it when computing the demangled name for
> a minimal symbol. This yields a speedup when reading minimal symbols.
>
> gdb/ChangeLog
> 2019-05-29 Tom Tromey <tom@tromey.com>
>
> * minsyms.c (minimal_symbol_reader::install): Use
> parallel_for_each.
> * common/parallel-for.h: New file.
> * common/parallel-for.c: New file.
> * Makefile.in (HFILES_NO_SRCDIR): Add common/parallel-for.h.
> (COMMON_SFILES): Add common/parallel-for.c.
> ---
> gdb/ChangeLog | 9 +++++
> gdb/Makefile.in | 2 +
> gdb/common/parallel-for.c | 27 +++++++++++++
> gdb/common/parallel-for.h | 82 +++++++++++++++++++++++++++++++++++++++
> gdb/minsyms.c | 23 ++++++-----
> 5 files changed, 133 insertions(+), 10 deletions(-)
> create mode 100644 gdb/common/parallel-for.c
> create mode 100644 gdb/common/parallel-for.h
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 2dd69f3f0ba..15c7a6e2536 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -971,6 +971,7 @@ COMMON_SFILES = \
> common/gdb_vecs.c \
> common/netstuff.c \
> common/new-op.c \
> + common/parallel-for.c \
> common/pathstuff.c \
> common/print-utils.c \
> common/ptid.c \
> @@ -1471,6 +1472,7 @@ HFILES_NO_SRCDIR = \
> common/common-inferior.h \
> common/netstuff.h \
> common/host-defs.h \
> + common/parallel-for.h \
> common/pathstuff.h \
> common/print-utils.h \
> common/ptid.h \
> diff --git a/gdb/common/parallel-for.c b/gdb/common/parallel-for.c
> new file mode 100644
> index 00000000000..0970cea882b
> --- /dev/null
> +++ b/gdb/common/parallel-for.c
> @@ -0,0 +1,27 @@
> +/* Parallel for loops
> +
> + Copyright (C) 2019 Free Software Foundation, Inc.
> +
> + This file is part of GDB.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +#include "common/common-defs.h"
> +#include "common/parallel-for.h"
> +
> +namespace gdb
> +{
> +/* See parallel-for.h. */
> +int max_threads = -1;
> +}
> diff --git a/gdb/common/parallel-for.h b/gdb/common/parallel-for.h
> new file mode 100644
> index 00000000000..6770f39a05f
> --- /dev/null
> +++ b/gdb/common/parallel-for.h
> @@ -0,0 +1,82 @@
> +/* Parallel for loops
> +
> + Copyright (C) 2019 Free Software Foundation, Inc.
> +
> + This file is part of GDB.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +#ifndef COMMON_PARALLEL_FOR_H
> +#define COMMON_PARALLEL_FOR_H
> +
> +#include <algorithm>
> +#if CXX_STD_THREAD
> +#include <thread>
> +#endif
> +
> +namespace gdb
> +{
> +
> +/* True if threading should be enabled. */
> +
> +extern int max_threads;
> +
> +/* A very simple "parallel for". This iterates over the elements
> + given by the range of iterators, which must be random access
> + iterators. For each element, it calls the callback function. The
> + work may or may not be done by separate threads. */
> +
> +template<class RandomIt, class UnaryFunction>
> +void parallel_for_each (RandomIt first, RandomIt last, UnaryFunction f)
> +{
> +#if CXX_STD_THREAD
> + int n_threads = std::thread::hardware_concurrency ();
> + /* So we can use a local array below. */
> + const int local_max = 16;
"16 cores ought to be enough for anybody", right? :-)
Just kidding. Longer term I could see this evolving into
pulling threads out of a worker thread pool shared by all
kinds of parallel_for_each calls in the tree, but I'm super
fine with the simple initial design.
LGTM.
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v3 7/8] Demangle minsyms in parallel
2019-05-30 14:19 ` Pedro Alves
@ 2019-05-30 22:22 ` Tom Tromey
0 siblings, 0 replies; 24+ messages in thread
From: Tom Tromey @ 2019-05-30 22:22 UTC (permalink / raw)
To: Pedro Alves; +Cc: Tom Tromey, gdb-patches
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:
Pedro> "16 cores ought to be enough for anybody", right? :-)
As long as it is more than what's on my personal desktop :)
Pedro> Just kidding. Longer term I could see this evolving into
Pedro> pulling threads out of a worker thread pool shared by all
Pedro> kinds of parallel_for_each calls in the tree, but I'm super
Pedro> fine with the simple initial design.
The thread pool approach is nice because it means there isn't thread
startup overhead -- just whatever overhead there is from pushing jobs
onto a queue.
On the down side, a thread pool is somewhat more complicated.
Still, if we want it eventually, maybe we should just start with it.
One possible bad part is that if we don't have std::thread then I wonder
if the other things like futures will be available.
Tom
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v3 3/8] Add configure check for std::thread
2019-05-29 21:29 [PATCH v3 0/8] Demangle minimal symbol names in worker threads Tom Tromey
2019-05-29 21:29 ` [PATCH v3 1/8] Defer minimal symbol name-setting Tom Tromey
2019-05-29 21:29 ` [PATCH v3 7/8] Demangle minsyms in parallel Tom Tromey
@ 2019-05-29 21:29 ` Tom Tromey
2019-05-30 11:34 ` Pedro Alves
2019-05-29 21:29 ` [PATCH v3 4/8] Lock the demangled hash table Tom Tromey
` (4 subsequent siblings)
7 siblings, 1 reply; 24+ messages in thread
From: Tom Tromey @ 2019-05-29 21:29 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
This adds a configure check for std::thread. This is needed because
std::thread is not available in mingw.
gdb/ChangeLog
2019-05-29 Tom Tromey <tom@tromey.com>
* acinclude.m4: Include ax_pthread.m4.
* Makefile.in (PTHREAD_CFLAGS, PTHREAD_LIBS): New variables.
(INTERNAL_CFLAGS_BASE): Use PTHREAD_CFLAGS.
(CLIBS): Use PTHREAD_LIBS.
(aclocal_m4_deps): Add ax_pthread.m4.
* config.in, configure: Rebuild.
* common/common.m4 (GDB_AC_COMMON): Check for std::thread.
gdb/gdbserver/ChangeLog
2019-05-29 Tom Tromey <tom@tromey.com>
* acinclude.m4: Include ax_pthread.m4.
* config.in, configure: Rebuild.
---
gdb/ChangeLog | 10 +
gdb/Makefile.in | 12 +-
gdb/acinclude.m4 | 2 +
gdb/common/common.m4 | 25 ++
gdb/config.in | 3 +
gdb/configure | 766 +++++++++++++++++++++++++++++++++++++
gdb/gdbserver/ChangeLog | 5 +
gdb/gdbserver/acinclude.m4 | 2 +
gdb/gdbserver/config.in | 3 +
gdb/gdbserver/configure | 766 +++++++++++++++++++++++++++++++++++++
10 files changed, 1590 insertions(+), 4 deletions(-)
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 0f495783600..2dd69f3f0ba 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -203,6 +203,9 @@ WERROR_CFLAGS = @WERROR_CFLAGS@
GDB_WARN_CFLAGS = $(WARN_CFLAGS)
GDB_WERROR_CFLAGS = $(WERROR_CFLAGS)
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+
RDYNAMIC = @RDYNAMIC@
# Where is the INTL library? Typically in ../intl.
@@ -572,7 +575,7 @@ INTERNAL_CFLAGS_BASE = \
$(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) $(ZLIBINC) \
$(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
$(INTL_CFLAGS) $(INCGNU) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) \
- $(SRCHIGH_CFLAGS)
+ $(SRCHIGH_CFLAGS) $(PTHREAD_CFLAGS)
INTERNAL_WARN_CFLAGS = $(INTERNAL_CFLAGS_BASE) $(GDB_WARN_CFLAGS)
INTERNAL_CFLAGS = $(INTERNAL_WARN_CFLAGS) $(GDB_WERROR_CFLAGS)
@@ -586,7 +589,7 @@ LDFLAGS = @LDFLAGS@
# PROFILE_CFLAGS is _not_ included, however, because we use monstartup.
INTERNAL_LDFLAGS = \
$(CXXFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) \
- $(LDFLAGS) $(CONFIG_LDFLAGS)
+ $(LDFLAGS) $(CONFIG_LDFLAGS) $(PTHREAD_CFLAGS)
# Libraries and corresponding dependencies for compiling gdb.
# XM_CLIBS, defined in *config files, have host-dependent libs.
@@ -596,7 +599,7 @@ CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(ZLIB) $(INTL) $(LIBIBERTY) $(LIBD
@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR) \
- $(SRCHIGH_LIBS)
+ $(SRCHIGH_LIBS) $(PTHREAD_LIBS)
CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
@@ -2081,7 +2084,8 @@ aclocal_m4_deps = \
../config/depstand.m4 \
../config/lcmessage.m4 \
../config/codeset.m4 \
- ../config/zlib.m4
+ ../config/zlib.m4 \
+ ../config/ax_pthread.m4
$(srcdir)/aclocal.m4: @MAINTAINER_MODE_TRUE@ $(aclocal_m4_deps)
cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
diff --git a/gdb/acinclude.m4 b/gdb/acinclude.m4
index 0719d422a71..ff463ea3595 100644
--- a/gdb/acinclude.m4
+++ b/gdb/acinclude.m4
@@ -76,6 +76,8 @@ m4_include(ptrace.m4)
m4_include(ax_cxx_compile_stdcxx.m4)
+sinclude([../config/ax_pthread.m4])
+
## ----------------------------------------- ##
## ANSIfy the C compiler whenever possible. ##
## From Franc,ois Pinard ##
diff --git a/gdb/common/common.m4 b/gdb/common/common.m4
index 5701dd98293..90a0913c96e 100644
--- a/gdb/common/common.m4
+++ b/gdb/common/common.m4
@@ -35,6 +35,31 @@ AC_DEFUN([GDB_AC_COMMON], [
AC_CHECK_DECLS([strerror, strstr])
+ # Check for std::thread. This does not work on mingw.
+ AC_LANG_PUSH([C++])
+ AX_PTHREAD([threads=yes], [threads=no])
+ if test "$threads" = "yes"; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$PTHREAD_CFLAGS $save_CFLAGS"
+ AC_CACHE_CHECK([for std::thread],
+ gdb_cv_cxx_std_thread,
+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+ [[#include <thread>
+ void callback() { }]],
+ [[std::thread t(callback);]])],
+ gdb_cv_cxx_std_thread=yes,
+ gdb_cv_cxx_std_thread=no)])
+ LIBS="$save_LIBS"
+ CXXFLAGS="$save_CXXFLAGS"
+ fi
+ if test $gdb_cv_cxx_std_thread = yes; then
+ AC_DEFINE(CXX_STD_THREAD, 1,
+ [Define to 1 if std::thread works.])
+ fi
+ AC_LANG_POP
+
dnl Check if sigsetjmp is available. Using AC_CHECK_FUNCS won't
dnl do since sigsetjmp might only be defined as a macro.
AC_CACHE_CHECK([for sigsetjmp], gdb_cv_func_sigsetjmp,
diff --git a/gdb/config.in b/gdb/config.in
index c0291fbd9c5..8cb9289302d 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -17,6 +17,9 @@
*/
#undef CRAY_STACKSEG_END
+/* Define to 1 if std::thread works. */
+#undef CXX_STD_THREAD
+
/* Define to 1 if using `alloca.c'. */
#undef C_ALLOCA
diff --git a/gdb/configure b/gdb/configure
index 15a96afcca8..5efdfe60911 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -697,6 +697,11 @@ SYSTEM_GDBINIT
TARGET_SYSTEM_ROOT
CONFIG_LDFLAGS
RDYNAMIC
+PTHREAD_CFLAGS
+PTHREAD_LIBS
+PTHREAD_CC
+ax_pthread_config
+SED
ALLOCA
LTLIBIPT
LIBIPT
@@ -13347,6 +13352,75 @@ _ACEOF
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for ac_i in 1 2 3 4 5 6 7; do
+ ac_script="$ac_script$as_nl$ac_script"
+ done
+ echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+ { ac_script=; unset ac_script;}
+ if test -z "$SED"; then
+ ac_path_SED_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+ # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+ ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo '' >> "conftest.nl"
+ "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_SED_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_SED="$ac_path_SED"
+ ac_path_SED_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_SED_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_SED"; then
+ as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+ fi
+else
+ ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+ rm -f conftest.sed
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
$as_echo_n "checking for ANSI C header files... " >&6; }
@@ -13731,6 +13805,698 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
+ # Check for std::thread. This does not work on mingw.
+ ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ax_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on Tru64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
+ ax_pthread_save_CC="$CC"
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
+ if test "x$PTHREAD_CC" != "x"; then :
+ CC="$PTHREAD_CC"
+fi
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS" >&5
+$as_echo_n "checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_join ();
+int
+main ()
+{
+return pthread_join ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ax_pthread_ok=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5
+$as_echo "$ax_pthread_ok" >&6; }
+ if test "x$ax_pthread_ok" = "xno"; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ CC="$ax_pthread_save_CC"
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important. Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
+# (Note: HP C rejects this with "bad form for `-t' option")
+# -pthreads: Solaris/gcc (Note: HP C also rejects)
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads and
+# -D_REENTRANT too), HP C (must be checked before -lpthread, which
+# is present but should not be used directly; and before -mthreads,
+# because the compiler interprets this as "-mt" + "-hreads")
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case $host_os in
+
+ freebsd*)
+
+ # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+ # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+
+ ax_pthread_flags="-kthread lthread $ax_pthread_flags"
+ ;;
+
+ hpux*)
+
+ # From the cc(1) man page: "[-mt] Sets various -D flags to enable
+ # multi-threading and also sets -lpthread."
+
+ ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
+ ;;
+
+ openedition*)
+
+ # IBM z/OS requires a feature-test macro to be defined in order to
+ # enable POSIX threads at all, so give the user a hint if this is
+ # not set. (We don't define these ourselves, as they can affect
+ # other portions of the system API in unpredictable ways.)
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
+ AX_PTHREAD_ZOS_MISSING
+# endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "AX_PTHREAD_ZOS_MISSING" >/dev/null 2>&1; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&5
+$as_echo "$as_me: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&2;}
+fi
+rm -f conftest*
+
+ ;;
+
+ solaris*)
+
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (N.B.: The stubs are missing
+ # pthread_cleanup_push, or rather a function called by this macro,
+ # so we could check for that, but who knows whether they'll stub
+ # that too in a future libc.) So we'll check first for the
+ # standard Solaris way of linking pthreads (-mt -lpthread).
+
+ ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags"
+ ;;
+esac
+
+# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
+
+if test "x$GCC" = "xyes"; then :
+ ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"
+fi
+
+# The presence of a feature test macro requesting re-entrant function
+# definitions is, on some systems, a strong hint that pthreads support is
+# correctly enabled
+
+case $host_os in
+ darwin* | hpux* | linux* | osf* | solaris*)
+ ax_pthread_check_macro="_REENTRANT"
+ ;;
+
+ aix*)
+ ax_pthread_check_macro="_THREAD_SAFE"
+ ;;
+
+ *)
+ ax_pthread_check_macro="--"
+ ;;
+esac
+if test "x$ax_pthread_check_macro" = "x--"; then :
+ ax_pthread_check_cond=0
+else
+ ax_pthread_check_cond="!defined($ax_pthread_check_macro)"
+fi
+
+# Are we compiling with Clang?
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC is Clang" >&5
+$as_echo_n "checking whether $CC is Clang... " >&6; }
+if ${ax_cv_PTHREAD_CLANG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ax_cv_PTHREAD_CLANG=no
+ # Note that Autoconf sets GCC=yes for Clang as well as GCC
+ if test "x$GCC" = "xyes"; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
+# if defined(__clang__) && defined(__llvm__)
+ AX_PTHREAD_CC_IS_CLANG
+# endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "AX_PTHREAD_CC_IS_CLANG" >/dev/null 2>&1; then :
+ ax_cv_PTHREAD_CLANG=yes
+fi
+rm -f conftest*
+
+ fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG" >&5
+$as_echo "$ax_cv_PTHREAD_CLANG" >&6; }
+ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
+
+ax_pthread_clang_warning=no
+
+# Clang needs special handling, because older versions handle the -pthread
+# option in a rather... idiosyncratic way
+
+if test "x$ax_pthread_clang" = "xyes"; then
+
+ # Clang takes -pthread; it has never supported any other flag
+
+ # (Note 1: This will need to be revisited if a system that Clang
+ # supports has POSIX threads in a separate library. This tends not
+ # to be the way of modern systems, but it's conceivable.)
+
+ # (Note 2: On some systems, notably Darwin, -pthread is not needed
+ # to get POSIX threads support; the API is always present and
+ # active. We could reasonably leave PTHREAD_CFLAGS empty. But
+ # -pthread does define _REENTRANT, and while the Darwin headers
+ # ignore this macro, third-party headers might not.)
+
+ PTHREAD_CFLAGS="-pthread"
+ PTHREAD_LIBS=
+
+ ax_pthread_ok=yes
+
+ # However, older versions of Clang make a point of warning the user
+ # that, in an invocation where only linking and no compilation is
+ # taking place, the -pthread option has no effect ("argument unused
+ # during compilation"). They expect -pthread to be passed in only
+ # when source code is being compiled.
+ #
+ # Problem is, this is at odds with the way Automake and most other
+ # C build frameworks function, which is that the same flags used in
+ # compilation (CFLAGS) are also used in linking. Many systems
+ # supported by AX_PTHREAD require exactly this for POSIX threads
+ # support, and in fact it is often not straightforward to specify a
+ # flag that is used only in the compilation phase and not in
+ # linking. Such a scenario is extremely rare in practice.
+ #
+ # Even though use of the -pthread flag in linking would only print
+ # a warning, this can be a nuisance for well-run software projects
+ # that build with -Werror. So if the active version of Clang has
+ # this misfeature, we search for an option to squash it.
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread" >&5
+$as_echo_n "checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread... " >&6; }
+if ${ax_cv_PTHREAD_CLANG_NO_WARN_FLAG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
+ # Create an alternate version of $ac_link that compiles and
+ # links in two steps (.c -> .o, .o -> exe) instead of one
+ # (.c -> exe), because the warning occurs only in the second
+ # step
+ ax_pthread_save_ac_link="$ac_link"
+ ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
+ ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
+ ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
+ if test "x$ax_pthread_try" = "xunknown"; then :
+ break
+fi
+ CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
+ ac_link="$ax_pthread_save_ac_link"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int main(void){return 0;}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_link="$ax_pthread_2step_ac_link"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int main(void){return 0;}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ ac_link="$ax_pthread_save_ac_link"
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ if test "x$ax_pthread_try" = "x"; then :
+ ax_pthread_try=no
+fi
+ ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&5
+$as_echo "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&6; }
+
+ case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
+ no | unknown) ;;
+ *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
+ esac
+
+fi # $ax_pthread_clang = yes
+
+if test "x$ax_pthread_ok" = "xno"; then
+for ax_pthread_try_flag in $ax_pthread_flags; do
+
+ case $ax_pthread_try_flag in
+ none)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5
+$as_echo_n "checking whether pthreads work without any flags... " >&6; }
+ ;;
+
+ -mt,pthread)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with -mt -lpthread" >&5
+$as_echo_n "checking whether pthreads work with -mt -lpthread... " >&6; }
+ PTHREAD_CFLAGS="-mt"
+ PTHREAD_LIBS="-lpthread"
+ ;;
+
+ -*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $ax_pthread_try_flag" >&5
+$as_echo_n "checking whether pthreads work with $ax_pthread_try_flag... " >&6; }
+ PTHREAD_CFLAGS="$ax_pthread_try_flag"
+ ;;
+
+ pthread-config)
+ # Extract the first word of "pthread-config", so it can be a program name with args.
+set dummy pthread-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ax_pthread_config+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ax_pthread_config"; then
+ ac_cv_prog_ax_pthread_config="$ax_pthread_config" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ax_pthread_config="yes"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_prog_ax_pthread_config" && ac_cv_prog_ax_pthread_config="no"
+fi
+fi
+ax_pthread_config=$ac_cv_prog_ax_pthread_config
+if test -n "$ax_pthread_config"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_config" >&5
+$as_echo "$ax_pthread_config" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "x$ax_pthread_config" = "xno"; then :
+ continue
+fi
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$ax_pthread_try_flag" >&5
+$as_echo_n "checking for the pthreads library -l$ax_pthread_try_flag... " >&6; }
+ PTHREAD_LIBS="-l$ax_pthread_try_flag"
+ ;;
+ esac
+
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <pthread.h>
+# if $ax_pthread_check_cond
+# error "$ax_pthread_check_macro must be defined"
+# endif
+ static void routine(void *a) { a = 0; }
+ static void *start_routine(void *a) { return a; }
+int
+main ()
+{
+pthread_t th; pthread_attr_t attr;
+ pthread_create(&th, 0, start_routine, 0);
+ pthread_join(th, 0);
+ pthread_attr_init(&attr);
+ pthread_cleanup_push(routine, 0);
+ pthread_cleanup_pop(0) /* ; */
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ax_pthread_ok=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5
+$as_echo "$ax_pthread_ok" >&6; }
+ if test "x$ax_pthread_ok" = "xyes"; then :
+ break
+fi
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$ax_pthread_ok" = "xyes"; then
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5
+$as_echo_n "checking for joinable pthread attribute... " >&6; }
+if ${ax_cv_PTHREAD_JOINABLE_ATTR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ax_cv_PTHREAD_JOINABLE_ATTR=unknown
+ for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <pthread.h>
+int
+main ()
+{
+int attr = $ax_pthread_attr; return attr /* ; */
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_JOINABLE_ATTR" >&5
+$as_echo "$ax_cv_PTHREAD_JOINABLE_ATTR" >&6; }
+ if test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
+ test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
+ test "x$ax_pthread_joinable_attr_defined" != "xyes"; then :
+
+cat >>confdefs.h <<_ACEOF
+#define PTHREAD_CREATE_JOINABLE $ax_cv_PTHREAD_JOINABLE_ATTR
+_ACEOF
+
+ ax_pthread_joinable_attr_defined=yes
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether more special flags are required for pthreads" >&5
+$as_echo_n "checking whether more special flags are required for pthreads... " >&6; }
+if ${ax_cv_PTHREAD_SPECIAL_FLAGS+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ax_cv_PTHREAD_SPECIAL_FLAGS=no
+ case $host_os in
+ solaris*)
+ ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
+ ;;
+ esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_SPECIAL_FLAGS" >&5
+$as_echo "$ax_cv_PTHREAD_SPECIAL_FLAGS" >&6; }
+ if test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
+ test "x$ax_pthread_special_flags_added" != "xyes"; then :
+ PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
+ ax_pthread_special_flags_added=yes
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_PRIO_INHERIT" >&5
+$as_echo_n "checking for PTHREAD_PRIO_INHERIT... " >&6; }
+if ${ax_cv_PTHREAD_PRIO_INHERIT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <pthread.h>
+int
+main ()
+{
+int i = PTHREAD_PRIO_INHERIT;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ax_cv_PTHREAD_PRIO_INHERIT=yes
+else
+ ax_cv_PTHREAD_PRIO_INHERIT=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_PRIO_INHERIT" >&5
+$as_echo "$ax_cv_PTHREAD_PRIO_INHERIT" >&6; }
+ if test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
+ test "x$ax_pthread_prio_inherit_defined" != "xyes"; then :
+
+$as_echo "#define HAVE_PTHREAD_PRIO_INHERIT 1" >>confdefs.h
+
+ ax_pthread_prio_inherit_defined=yes
+
+fi
+
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
+
+ # More AIX lossage: compile with *_r variant
+ if test "x$GCC" != "xyes"; then
+ case $host_os in
+ aix*)
+ case "x/$CC" in #(
+ x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6) :
+ #handle absolute path differently from PATH based program lookup
+ case "x$CC" in #(
+ x/*) :
+ if as_fn_executable_p ${CC}_r; then :
+ PTHREAD_CC="${CC}_r"
+fi ;; #(
+ *) :
+ for ac_prog in ${CC}_r
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PTHREAD_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$PTHREAD_CC"; then
+ ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_PTHREAD_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+PTHREAD_CC=$ac_cv_prog_PTHREAD_CC
+if test -n "$PTHREAD_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5
+$as_echo "$PTHREAD_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$PTHREAD_CC" && break
+done
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+ ;;
+esac ;; #(
+ *) :
+ ;;
+esac
+ ;;
+ esac
+ fi
+fi
+
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+
+
+
+
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test "x$ax_pthread_ok" = "xyes"; then
+ threads=yes
+ :
+else
+ ax_pthread_ok=no
+ threads=no
+fi
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+ if test "$threads" = "yes"; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$PTHREAD_CFLAGS $save_CFLAGS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for std::thread" >&5
+$as_echo_n "checking for std::thread... " >&6; }
+if ${gdb_cv_cxx_std_thread+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <thread>
+ void callback() { }
+int
+main ()
+{
+std::thread t(callback);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ gdb_cv_cxx_std_thread=yes
+else
+ gdb_cv_cxx_std_thread=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_cxx_std_thread" >&5
+$as_echo "$gdb_cv_cxx_std_thread" >&6; }
+ LIBS="$save_LIBS"
+ CXXFLAGS="$save_CXXFLAGS"
+ fi
+ if test $gdb_cv_cxx_std_thread = yes; then
+
+$as_echo "#define CXX_STD_THREAD 1" >>confdefs.h
+
+ fi
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sigsetjmp" >&5
$as_echo_n "checking for sigsetjmp... " >&6; }
if ${gdb_cv_func_sigsetjmp+:} false; then :
diff --git a/gdb/gdbserver/acinclude.m4 b/gdb/gdbserver/acinclude.m4
index fc3e344a611..7ea43b5e762 100644
--- a/gdb/gdbserver/acinclude.m4
+++ b/gdb/gdbserver/acinclude.m4
@@ -34,6 +34,8 @@ m4_include(../ax_cxx_compile_stdcxx.m4)
dnl For GDB_AC_SELFTEST.
m4_include(../selftest.m4)
+sinclude([../../config/ax_pthread.m4])
+
dnl Check for existence of a type $1 in libthread_db.h
dnl Based on BFD_HAVE_SYS_PROCFS_TYPE in bfd/bfd.m4.
diff --git a/gdb/gdbserver/config.in b/gdb/gdbserver/config.in
index 05537df81e3..2d041ed2470 100644
--- a/gdb/gdbserver/config.in
+++ b/gdb/gdbserver/config.in
@@ -5,6 +5,9 @@
*/
#undef CRAY_STACKSEG_END
+/* Define to 1 if std::thread works. */
+#undef CXX_STD_THREAD
+
/* Define to 1 if using `alloca.c'. */
#undef C_ALLOCA
diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure
index 1ddbd6b27e0..5b50f2d249f 100755
--- a/gdb/gdbserver/configure
+++ b/gdb/gdbserver/configure
@@ -636,6 +636,11 @@ WERROR_CFLAGS
WARN_CFLAGS
ustinc
ustlibs
+PTHREAD_CFLAGS
+PTHREAD_LIBS
+PTHREAD_CC
+ax_pthread_config
+SED
ALLOCA
CCDEPMODE
CONFIG_SRC_SUBDIR
@@ -6539,6 +6544,75 @@ _ACEOF
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for ac_i in 1 2 3 4 5 6 7; do
+ ac_script="$ac_script$as_nl$ac_script"
+ done
+ echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+ { ac_script=; unset ac_script;}
+ if test -z "$SED"; then
+ ac_path_SED_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+ # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+ ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo '' >> "conftest.nl"
+ "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_SED_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_SED="$ac_path_SED"
+ ac_path_SED_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_SED_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_SED"; then
+ as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+ fi
+else
+ ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+ rm -f conftest.sed
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
$as_echo_n "checking for ANSI C header files... " >&6; }
@@ -6923,6 +6997,698 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
+ # Check for std::thread. This does not work on mingw.
+ ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ax_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on Tru64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
+ ax_pthread_save_CC="$CC"
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
+ if test "x$PTHREAD_CC" != "x"; then :
+ CC="$PTHREAD_CC"
+fi
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS" >&5
+$as_echo_n "checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_join ();
+int
+main ()
+{
+return pthread_join ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ax_pthread_ok=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5
+$as_echo "$ax_pthread_ok" >&6; }
+ if test "x$ax_pthread_ok" = "xno"; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ CC="$ax_pthread_save_CC"
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important. Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
+# (Note: HP C rejects this with "bad form for `-t' option")
+# -pthreads: Solaris/gcc (Note: HP C also rejects)
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads and
+# -D_REENTRANT too), HP C (must be checked before -lpthread, which
+# is present but should not be used directly; and before -mthreads,
+# because the compiler interprets this as "-mt" + "-hreads")
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case $host_os in
+
+ freebsd*)
+
+ # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+ # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+
+ ax_pthread_flags="-kthread lthread $ax_pthread_flags"
+ ;;
+
+ hpux*)
+
+ # From the cc(1) man page: "[-mt] Sets various -D flags to enable
+ # multi-threading and also sets -lpthread."
+
+ ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
+ ;;
+
+ openedition*)
+
+ # IBM z/OS requires a feature-test macro to be defined in order to
+ # enable POSIX threads at all, so give the user a hint if this is
+ # not set. (We don't define these ourselves, as they can affect
+ # other portions of the system API in unpredictable ways.)
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
+ AX_PTHREAD_ZOS_MISSING
+# endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "AX_PTHREAD_ZOS_MISSING" >/dev/null 2>&1; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&5
+$as_echo "$as_me: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&2;}
+fi
+rm -f conftest*
+
+ ;;
+
+ solaris*)
+
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (N.B.: The stubs are missing
+ # pthread_cleanup_push, or rather a function called by this macro,
+ # so we could check for that, but who knows whether they'll stub
+ # that too in a future libc.) So we'll check first for the
+ # standard Solaris way of linking pthreads (-mt -lpthread).
+
+ ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags"
+ ;;
+esac
+
+# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
+
+if test "x$GCC" = "xyes"; then :
+ ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"
+fi
+
+# The presence of a feature test macro requesting re-entrant function
+# definitions is, on some systems, a strong hint that pthreads support is
+# correctly enabled
+
+case $host_os in
+ darwin* | hpux* | linux* | osf* | solaris*)
+ ax_pthread_check_macro="_REENTRANT"
+ ;;
+
+ aix*)
+ ax_pthread_check_macro="_THREAD_SAFE"
+ ;;
+
+ *)
+ ax_pthread_check_macro="--"
+ ;;
+esac
+if test "x$ax_pthread_check_macro" = "x--"; then :
+ ax_pthread_check_cond=0
+else
+ ax_pthread_check_cond="!defined($ax_pthread_check_macro)"
+fi
+
+# Are we compiling with Clang?
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC is Clang" >&5
+$as_echo_n "checking whether $CC is Clang... " >&6; }
+if ${ax_cv_PTHREAD_CLANG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ax_cv_PTHREAD_CLANG=no
+ # Note that Autoconf sets GCC=yes for Clang as well as GCC
+ if test "x$GCC" = "xyes"; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
+# if defined(__clang__) && defined(__llvm__)
+ AX_PTHREAD_CC_IS_CLANG
+# endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "AX_PTHREAD_CC_IS_CLANG" >/dev/null 2>&1; then :
+ ax_cv_PTHREAD_CLANG=yes
+fi
+rm -f conftest*
+
+ fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG" >&5
+$as_echo "$ax_cv_PTHREAD_CLANG" >&6; }
+ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
+
+ax_pthread_clang_warning=no
+
+# Clang needs special handling, because older versions handle the -pthread
+# option in a rather... idiosyncratic way
+
+if test "x$ax_pthread_clang" = "xyes"; then
+
+ # Clang takes -pthread; it has never supported any other flag
+
+ # (Note 1: This will need to be revisited if a system that Clang
+ # supports has POSIX threads in a separate library. This tends not
+ # to be the way of modern systems, but it's conceivable.)
+
+ # (Note 2: On some systems, notably Darwin, -pthread is not needed
+ # to get POSIX threads support; the API is always present and
+ # active. We could reasonably leave PTHREAD_CFLAGS empty. But
+ # -pthread does define _REENTRANT, and while the Darwin headers
+ # ignore this macro, third-party headers might not.)
+
+ PTHREAD_CFLAGS="-pthread"
+ PTHREAD_LIBS=
+
+ ax_pthread_ok=yes
+
+ # However, older versions of Clang make a point of warning the user
+ # that, in an invocation where only linking and no compilation is
+ # taking place, the -pthread option has no effect ("argument unused
+ # during compilation"). They expect -pthread to be passed in only
+ # when source code is being compiled.
+ #
+ # Problem is, this is at odds with the way Automake and most other
+ # C build frameworks function, which is that the same flags used in
+ # compilation (CFLAGS) are also used in linking. Many systems
+ # supported by AX_PTHREAD require exactly this for POSIX threads
+ # support, and in fact it is often not straightforward to specify a
+ # flag that is used only in the compilation phase and not in
+ # linking. Such a scenario is extremely rare in practice.
+ #
+ # Even though use of the -pthread flag in linking would only print
+ # a warning, this can be a nuisance for well-run software projects
+ # that build with -Werror. So if the active version of Clang has
+ # this misfeature, we search for an option to squash it.
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread" >&5
+$as_echo_n "checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread... " >&6; }
+if ${ax_cv_PTHREAD_CLANG_NO_WARN_FLAG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
+ # Create an alternate version of $ac_link that compiles and
+ # links in two steps (.c -> .o, .o -> exe) instead of one
+ # (.c -> exe), because the warning occurs only in the second
+ # step
+ ax_pthread_save_ac_link="$ac_link"
+ ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
+ ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
+ ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
+ if test "x$ax_pthread_try" = "xunknown"; then :
+ break
+fi
+ CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
+ ac_link="$ax_pthread_save_ac_link"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int main(void){return 0;}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_link="$ax_pthread_2step_ac_link"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int main(void){return 0;}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ ac_link="$ax_pthread_save_ac_link"
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ if test "x$ax_pthread_try" = "x"; then :
+ ax_pthread_try=no
+fi
+ ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&5
+$as_echo "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&6; }
+
+ case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
+ no | unknown) ;;
+ *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
+ esac
+
+fi # $ax_pthread_clang = yes
+
+if test "x$ax_pthread_ok" = "xno"; then
+for ax_pthread_try_flag in $ax_pthread_flags; do
+
+ case $ax_pthread_try_flag in
+ none)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5
+$as_echo_n "checking whether pthreads work without any flags... " >&6; }
+ ;;
+
+ -mt,pthread)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with -mt -lpthread" >&5
+$as_echo_n "checking whether pthreads work with -mt -lpthread... " >&6; }
+ PTHREAD_CFLAGS="-mt"
+ PTHREAD_LIBS="-lpthread"
+ ;;
+
+ -*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $ax_pthread_try_flag" >&5
+$as_echo_n "checking whether pthreads work with $ax_pthread_try_flag... " >&6; }
+ PTHREAD_CFLAGS="$ax_pthread_try_flag"
+ ;;
+
+ pthread-config)
+ # Extract the first word of "pthread-config", so it can be a program name with args.
+set dummy pthread-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ax_pthread_config+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ax_pthread_config"; then
+ ac_cv_prog_ax_pthread_config="$ax_pthread_config" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ax_pthread_config="yes"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_prog_ax_pthread_config" && ac_cv_prog_ax_pthread_config="no"
+fi
+fi
+ax_pthread_config=$ac_cv_prog_ax_pthread_config
+if test -n "$ax_pthread_config"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_config" >&5
+$as_echo "$ax_pthread_config" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "x$ax_pthread_config" = "xno"; then :
+ continue
+fi
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$ax_pthread_try_flag" >&5
+$as_echo_n "checking for the pthreads library -l$ax_pthread_try_flag... " >&6; }
+ PTHREAD_LIBS="-l$ax_pthread_try_flag"
+ ;;
+ esac
+
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <pthread.h>
+# if $ax_pthread_check_cond
+# error "$ax_pthread_check_macro must be defined"
+# endif
+ static void routine(void *a) { a = 0; }
+ static void *start_routine(void *a) { return a; }
+int
+main ()
+{
+pthread_t th; pthread_attr_t attr;
+ pthread_create(&th, 0, start_routine, 0);
+ pthread_join(th, 0);
+ pthread_attr_init(&attr);
+ pthread_cleanup_push(routine, 0);
+ pthread_cleanup_pop(0) /* ; */
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ax_pthread_ok=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5
+$as_echo "$ax_pthread_ok" >&6; }
+ if test "x$ax_pthread_ok" = "xyes"; then :
+ break
+fi
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$ax_pthread_ok" = "xyes"; then
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5
+$as_echo_n "checking for joinable pthread attribute... " >&6; }
+if ${ax_cv_PTHREAD_JOINABLE_ATTR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ax_cv_PTHREAD_JOINABLE_ATTR=unknown
+ for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <pthread.h>
+int
+main ()
+{
+int attr = $ax_pthread_attr; return attr /* ; */
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_JOINABLE_ATTR" >&5
+$as_echo "$ax_cv_PTHREAD_JOINABLE_ATTR" >&6; }
+ if test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
+ test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
+ test "x$ax_pthread_joinable_attr_defined" != "xyes"; then :
+
+cat >>confdefs.h <<_ACEOF
+#define PTHREAD_CREATE_JOINABLE $ax_cv_PTHREAD_JOINABLE_ATTR
+_ACEOF
+
+ ax_pthread_joinable_attr_defined=yes
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether more special flags are required for pthreads" >&5
+$as_echo_n "checking whether more special flags are required for pthreads... " >&6; }
+if ${ax_cv_PTHREAD_SPECIAL_FLAGS+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ax_cv_PTHREAD_SPECIAL_FLAGS=no
+ case $host_os in
+ solaris*)
+ ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
+ ;;
+ esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_SPECIAL_FLAGS" >&5
+$as_echo "$ax_cv_PTHREAD_SPECIAL_FLAGS" >&6; }
+ if test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
+ test "x$ax_pthread_special_flags_added" != "xyes"; then :
+ PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
+ ax_pthread_special_flags_added=yes
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_PRIO_INHERIT" >&5
+$as_echo_n "checking for PTHREAD_PRIO_INHERIT... " >&6; }
+if ${ax_cv_PTHREAD_PRIO_INHERIT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <pthread.h>
+int
+main ()
+{
+int i = PTHREAD_PRIO_INHERIT;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ax_cv_PTHREAD_PRIO_INHERIT=yes
+else
+ ax_cv_PTHREAD_PRIO_INHERIT=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_PRIO_INHERIT" >&5
+$as_echo "$ax_cv_PTHREAD_PRIO_INHERIT" >&6; }
+ if test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
+ test "x$ax_pthread_prio_inherit_defined" != "xyes"; then :
+
+$as_echo "#define HAVE_PTHREAD_PRIO_INHERIT 1" >>confdefs.h
+
+ ax_pthread_prio_inherit_defined=yes
+
+fi
+
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
+
+ # More AIX lossage: compile with *_r variant
+ if test "x$GCC" != "xyes"; then
+ case $host_os in
+ aix*)
+ case "x/$CC" in #(
+ x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6) :
+ #handle absolute path differently from PATH based program lookup
+ case "x$CC" in #(
+ x/*) :
+ if as_fn_executable_p ${CC}_r; then :
+ PTHREAD_CC="${CC}_r"
+fi ;; #(
+ *) :
+ for ac_prog in ${CC}_r
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PTHREAD_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$PTHREAD_CC"; then
+ ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_PTHREAD_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+PTHREAD_CC=$ac_cv_prog_PTHREAD_CC
+if test -n "$PTHREAD_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5
+$as_echo "$PTHREAD_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$PTHREAD_CC" && break
+done
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+ ;;
+esac ;; #(
+ *) :
+ ;;
+esac
+ ;;
+ esac
+ fi
+fi
+
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+
+
+
+
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test "x$ax_pthread_ok" = "xyes"; then
+ threads=yes
+ :
+else
+ ax_pthread_ok=no
+ threads=no
+fi
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+ if test "$threads" = "yes"; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$PTHREAD_CFLAGS $save_CFLAGS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for std::thread" >&5
+$as_echo_n "checking for std::thread... " >&6; }
+if ${gdb_cv_cxx_std_thread+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <thread>
+ void callback() { }
+int
+main ()
+{
+std::thread t(callback);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ gdb_cv_cxx_std_thread=yes
+else
+ gdb_cv_cxx_std_thread=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_cxx_std_thread" >&5
+$as_echo "$gdb_cv_cxx_std_thread" >&6; }
+ LIBS="$save_LIBS"
+ CXXFLAGS="$save_CXXFLAGS"
+ fi
+ if test $gdb_cv_cxx_std_thread = yes; then
+
+$as_echo "#define CXX_STD_THREAD 1" >>confdefs.h
+
+ fi
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sigsetjmp" >&5
$as_echo_n "checking for sigsetjmp... " >&6; }
if ${gdb_cv_func_sigsetjmp+:} false; then :
--
2.17.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v3 3/8] Add configure check for std::thread
2019-05-29 21:29 ` [PATCH v3 3/8] Add configure check for std::thread Tom Tromey
@ 2019-05-30 11:34 ` Pedro Alves
0 siblings, 0 replies; 24+ messages in thread
From: Pedro Alves @ 2019-05-30 11:34 UTC (permalink / raw)
To: Tom Tromey, gdb-patches
On 5/29/19 10:29 PM, Tom Tromey wrote:
> This adds a configure check for std::thread. This is needed because
> std::thread is not available in mingw.
AFAICT, the patch actually does two things:
- Add autoconf bits (ax_pthread.m4) to make sure we build with the
right -pthread, -pthreads, -lpthread, -lpthreads, or whatever the
right spelling is on the host to pull in the pthreads library.
- Adds a configure check for std::thread, since it is not available
on some platforms, at least out of the box. I think mingw-w64
(but not mingw.org) supports std::thread OOTB nowadays. I'd guess
that DJGPP doesn't support it either, at least OOTB. Googling around
seems to confirm that.
Right?
It'll be good to extend the commit log in that direction, IMO.
On 5/29/19 10:29 PM, Tom Tromey wrote:
> $(srcdir)/aclocal.m4: @MAINTAINER_MODE_TRUE@ $(aclocal_m4_deps)
> cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
> diff --git a/gdb/acinclude.m4 b/gdb/acinclude.m4
> index 0719d422a71..ff463ea3595 100644
> --- a/gdb/acinclude.m4
> +++ b/gdb/acinclude.m4
> @@ -76,6 +76,8 @@ m4_include(ptrace.m4)
>
> m4_include(ax_cxx_compile_stdcxx.m4)
>
> +sinclude([../config/ax_pthread.m4])
Is there reason to prefer sinclude over m4_include? I never
got why we use sinclude so frequently, given it doesn't error
out if the file doesn't exist.
> --- a/gdb/common/common.m4
> +++ b/gdb/common/common.m4
> @@ -35,6 +35,31 @@ AC_DEFUN([GDB_AC_COMMON], [
>
> AC_CHECK_DECLS([strerror, strstr])
>
> + # Check for std::thread. This does not work on mingw.
Maybe mention DJGPP too.
> + AC_LANG_PUSH([C++])
> + AX_PTHREAD([threads=yes], [threads=no])
> + if test "$threads" = "yes"; then
> + save_LIBS="$LIBS"
> + LIBS="$PTHREAD_LIBS $LIBS"
> + save_CXXFLAGS="$CXXFLAGS"
> + CXXFLAGS="$PTHREAD_CFLAGS $save_CFLAGS"
I think you meant save_CXXFLAGS here.
Otherwise looks fine to me.
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v3 4/8] Lock the demangled hash table
2019-05-29 21:29 [PATCH v3 0/8] Demangle minimal symbol names in worker threads Tom Tromey
` (2 preceding siblings ...)
2019-05-29 21:29 ` [PATCH v3 3/8] Add configure check for std::thread Tom Tromey
@ 2019-05-29 21:29 ` Tom Tromey
2019-05-30 12:58 ` Pedro Alves
2019-05-29 21:29 ` [PATCH v3 5/8] Introduce run_on_main_thread Tom Tromey
` (3 subsequent siblings)
7 siblings, 1 reply; 24+ messages in thread
From: Tom Tromey @ 2019-05-29 21:29 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
This introduces a lock that is used when modifying the demangled hash
table.
gdb/ChangeLog
2019-05-29 Tom Tromey <tom@tromey.com>
* symtab.c (demangled_mutex): New global.
(symbol_set_names): Use a lock_guard.
---
gdb/ChangeLog | 5 ++
gdb/symtab.c | 134 ++++++++++++++++++++++++++++----------------------
2 files changed, 81 insertions(+), 58 deletions(-)
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 130d5cd48ff..6ad024a8a29 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -69,6 +69,9 @@
#include "arch-utils.h"
#include <algorithm>
#include "common/pathstuff.h"
+#if CXX_STD_THREAD
+#include <mutex>
+#endif
/* Forward declarations for local functions. */
@@ -709,6 +712,11 @@ symbol_set_language (struct general_symbol_info *gsymbol,
/* Functions to initialize a symbol's mangled name. */
+#if CXX_STD_THREAD
+/* Mutex that is used when modifying the demangled hash table. */
+static std::mutex demangled_mutex;
+#endif
+
/* Objects of this type are stored in the demangled name hash table. */
struct demangled_name_entry
{
@@ -837,9 +845,6 @@ symbol_set_names (struct general_symbol_info *gsymbol,
return;
}
- if (per_bfd->demangled_names_hash == NULL)
- create_demangled_names_hash (per_bfd);
-
if (linkage_name[len] != '\0')
{
char *alloc_name;
@@ -858,64 +863,77 @@ symbol_set_names (struct general_symbol_info *gsymbol,
= symbol_find_demangled_name (gsymbol, linkage_name_copy);
gdb::unique_xmalloc_ptr<char> demangled_name (demangled_name_ptr);
- entry.mangled = linkage_name_copy;
- slot = ((struct demangled_name_entry **)
- htab_find_slot (per_bfd->demangled_names_hash.get (),
- &entry, INSERT));
-
- /* If this name is not in the hash table, add it. */
- if (*slot == NULL
- /* A C version of the symbol may have already snuck into the table.
- This happens to, e.g., main.init (__go_init_main). Cope. */
- || (gsymbol->language == language_go
- && (*slot)->demangled[0] == '\0'))
- {
- int demangled_len = demangled_name ? strlen (demangled_name.get ()) : 0;
-
- /* Suppose we have demangled_name==NULL, copy_name==0, and
- linkage_name_copy==linkage_name. In this case, we already have the
- mangled name saved, and we don't have a demangled name. So,
- you might think we could save a little space by not recording
- this in the hash table at all.
+ struct demangled_name_entry *found_entry;
+
+ {
+#if CXX_STD_THREAD
+ std::lock_guard<std::mutex> guard (demangled_mutex);
+#endif
+
+ if (per_bfd->demangled_names_hash == NULL)
+ create_demangled_names_hash (per_bfd);
+
+ entry.mangled = linkage_name_copy;
+ slot = ((struct demangled_name_entry **)
+ htab_find_slot (per_bfd->demangled_names_hash.get (),
+ &entry, INSERT));
+
+ /* If this name is not in the hash table, add it. */
+ if (*slot == NULL
+ /* A C version of the symbol may have already snuck into the table.
+ This happens to, e.g., main.init (__go_init_main). Cope. */
+ || (gsymbol->language == language_go
+ && (*slot)->demangled[0] == '\0'))
+ {
+ int demangled_len = demangled_name ? strlen (demangled_name.get ()) : 0;
+
+ /* Suppose we have demangled_name==NULL, copy_name==0, and
+ linkage_name_copy==linkage_name. In this case, we already have the
+ mangled name saved, and we don't have a demangled name. So,
+ you might think we could save a little space by not recording
+ this in the hash table at all.
- It turns out that it is actually important to still save such
- an entry in the hash table, because storing this name gives
- us better bcache hit rates for partial symbols. */
- if (!copy_name && linkage_name_copy == linkage_name)
- {
- *slot
- = ((struct demangled_name_entry *)
- obstack_alloc (&per_bfd->storage_obstack,
- offsetof (struct demangled_name_entry, demangled)
- + demangled_len + 1));
- (*slot)->mangled = linkage_name;
- }
- else
- {
- char *mangled_ptr;
-
- /* If we must copy the mangled name, put it directly after
- the demangled name so we can have a single
- allocation. */
- *slot
- = ((struct demangled_name_entry *)
- obstack_alloc (&per_bfd->storage_obstack,
- offsetof (struct demangled_name_entry, demangled)
- + len + demangled_len + 2));
- mangled_ptr = &((*slot)->demangled[demangled_len + 1]);
- strcpy (mangled_ptr, linkage_name_copy);
- (*slot)->mangled = mangled_ptr;
- }
+ It turns out that it is actually important to still save such
+ an entry in the hash table, because storing this name gives
+ us better bcache hit rates for partial symbols. */
+ if (!copy_name && linkage_name_copy == linkage_name)
+ {
+ *slot
+ = ((struct demangled_name_entry *)
+ obstack_alloc (&per_bfd->storage_obstack,
+ offsetof (struct demangled_name_entry, demangled)
+ + demangled_len + 1));
+ (*slot)->mangled = linkage_name;
+ }
+ else
+ {
+ char *mangled_ptr;
+
+ /* If we must copy the mangled name, put it directly after
+ the demangled name so we can have a single
+ allocation. */
+ *slot
+ = ((struct demangled_name_entry *)
+ obstack_alloc (&per_bfd->storage_obstack,
+ offsetof (struct demangled_name_entry, demangled)
+ + len + demangled_len + 2));
+ mangled_ptr = &((*slot)->demangled[demangled_len + 1]);
+ strcpy (mangled_ptr, linkage_name_copy);
+ (*slot)->mangled = mangled_ptr;
+ }
- if (demangled_name != NULL)
- strcpy ((*slot)->demangled, demangled_name.get());
- else
- (*slot)->demangled[0] = '\0';
- }
+ if (demangled_name != NULL)
+ strcpy ((*slot)->demangled, demangled_name.get());
+ else
+ (*slot)->demangled[0] = '\0';
+ }
+
+ found_entry = *slot;
+ }
- gsymbol->name = (*slot)->mangled;
- if ((*slot)->demangled[0] != '\0')
- symbol_set_demangled_name (gsymbol, (*slot)->demangled,
+ gsymbol->name = found_entry->mangled;
+ if (found_entry->demangled[0] != '\0')
+ symbol_set_demangled_name (gsymbol, found_entry->demangled,
&per_bfd->storage_obstack);
else
symbol_set_demangled_name (gsymbol, NULL, &per_bfd->storage_obstack);
--
2.17.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v3 4/8] Lock the demangled hash table
2019-05-29 21:29 ` [PATCH v3 4/8] Lock the demangled hash table Tom Tromey
@ 2019-05-30 12:58 ` Pedro Alves
2019-05-30 14:03 ` Pedro Alves
2019-05-30 21:58 ` Tom Tromey
0 siblings, 2 replies; 24+ messages in thread
From: Pedro Alves @ 2019-05-30 12:58 UTC (permalink / raw)
To: Tom Tromey, gdb-patches
On 5/29/19 10:29 PM, Tom Tromey wrote:
> This introduces a lock that is used when modifying the demangled hash
> table.
>
> gdb/ChangeLog
> 2019-05-29 Tom Tromey <tom@tromey.com>
>
> * symtab.c (demangled_mutex): New global.
> (symbol_set_names): Use a lock_guard.
> ---
> gdb/ChangeLog | 5 ++
> gdb/symtab.c | 134 ++++++++++++++++++++++++++++----------------------
> 2 files changed, 81 insertions(+), 58 deletions(-)
>
> diff --git a/gdb/symtab.c b/gdb/symtab.c
> index 130d5cd48ff..6ad024a8a29 100644
> --- a/gdb/symtab.c
> +++ b/gdb/symtab.c
> @@ -69,6 +69,9 @@
> #include "arch-utils.h"
> #include <algorithm>
> #include "common/pathstuff.h"
> +#if CXX_STD_THREAD
> +#include <mutex>
> +#endif
>
> /* Forward declarations for local functions. */
>
> @@ -709,6 +712,11 @@ symbol_set_language (struct general_symbol_info *gsymbol,
>
> /* Functions to initialize a symbol's mangled name. */
>
> +#if CXX_STD_THREAD
> +/* Mutex that is used when modifying the demangled hash table. */
> +static std::mutex demangled_mutex;
> +#endif
Not just modifying but when accessing as well.
There's only a single mutex, and the comment says _THE_ demangled
hash table, but AFAICS, each per_bfd has its own table, right?
A single lock for every table compared to a lock per table might be
a good approach, but I'd welcome extended comments to explain
that design choice.
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v3 4/8] Lock the demangled hash table
2019-05-30 12:58 ` Pedro Alves
@ 2019-05-30 14:03 ` Pedro Alves
2019-05-30 21:58 ` Tom Tromey
1 sibling, 0 replies; 24+ messages in thread
From: Pedro Alves @ 2019-05-30 14:03 UTC (permalink / raw)
To: Tom Tromey, gdb-patches
On 5/30/19 1:58 PM, Pedro Alves wrote:
> A single lock for every table compared to a lock per table might be
> a good approach, but I'd welcome extended comments to explain
> that design choice.
Just to be sure something wasn't lost in translation here:
by "extended" above, I just meant that I'd like to see comments
extended in that direction, not that I'd like to see super mega long
comments. :-)
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v3 4/8] Lock the demangled hash table
2019-05-30 12:58 ` Pedro Alves
2019-05-30 14:03 ` Pedro Alves
@ 2019-05-30 21:58 ` Tom Tromey
1 sibling, 0 replies; 24+ messages in thread
From: Tom Tromey @ 2019-05-30 21:58 UTC (permalink / raw)
To: Pedro Alves; +Cc: Tom Tromey, gdb-patches
>> This introduces a lock that is used when modifying the demangled hash
>> table.
Pedro> There's only a single mutex, and the comment says _THE_ demangled
Pedro> hash table, but AFAICS, each per_bfd has its own table, right?
Yes, that's correct. I'll fix the comment.
Pedro> A single lock for every table compared to a lock per table might be
Pedro> a good approach, but I'd welcome extended comments to explain
Pedro> that design choice.
I didn't want to put a mutex into the per-bfd object, mostly because it
uses space for the entire lifetime of that, while the mutex is only used
while demangling minsym names; and that can (currently) only be done for
one objfile at a time.
Tom
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v3 5/8] Introduce run_on_main_thread
2019-05-29 21:29 [PATCH v3 0/8] Demangle minimal symbol names in worker threads Tom Tromey
` (3 preceding siblings ...)
2019-05-29 21:29 ` [PATCH v3 4/8] Lock the demangled hash table Tom Tromey
@ 2019-05-29 21:29 ` Tom Tromey
2019-05-30 13:12 ` Pedro Alves
2019-05-29 21:29 ` [PATCH v3 2/8] Remove static buffer from ada_decode Tom Tromey
` (2 subsequent siblings)
7 siblings, 1 reply; 24+ messages in thread
From: Tom Tromey @ 2019-05-29 21:29 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
This introduces a way for a callback to be run on the main thread.
gdb/ChangeLog
2019-05-29 Tom Tromey <tom@tromey.com>
* ser-event.h (run_on_main_thread): Declare.
* ser-event.c (runnable_event, runnables, runnable_mutex): New
globals.
(run_events, run_on_main_thread, _initialize_ser_event): New
functions.
---
gdb/ChangeLog | 8 ++++++
gdb/ser-event.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++
gdb/ser-event.h | 6 +++++
3 files changed, 83 insertions(+)
diff --git a/gdb/ser-event.c b/gdb/ser-event.c
index d3956346246..4870433b287 100644
--- a/gdb/ser-event.c
+++ b/gdb/ser-event.c
@@ -20,6 +20,10 @@
#include "ser-event.h"
#include "serial.h"
#include "common/filestuff.h"
+#if CXX_STD_THREAD
+#include <mutex>
+#endif
+#include "event-loop.h"
/* On POSIX hosts, a serial_event is basically an abstraction for the
classical self-pipe trick.
@@ -217,3 +221,68 @@ serial_event_clear (struct serial_event *event)
ResetEvent (state->event);
#endif
}
+
+\f
+
+/* The serial event used when posting runnables. */
+
+static struct serial_event *runnable_event;
+
+/* Runnables that have been posted. */
+
+static std::vector<std::function<void ()>> runnables;
+
+#if CXX_STD_THREAD
+
+/* Mutex to hold when handling runnable_event or runnables. */
+
+static std::mutex runnable_mutex;
+
+#endif
+
+/* Run all the queued runnables. */
+
+static void
+run_events (int error, gdb_client_data client_data)
+{
+ std::vector<std::function<void ()>> local;
+
+ /* Hold the lock while changing the globals, but not while running
+ the runnables. */
+ {
+#if CXX_STD_THREAD
+ std::lock_guard<std::mutex> lock (runnable_mutex);
+#endif
+
+ /* Clear the event fd. Do this before flushing the events list,
+ so that any new event post afterwards is sure to re-awaken the
+ event loop. */
+ serial_event_clear (runnable_event);
+
+ /* Move the vector in case running a runnable pushes a new
+ runnable. */
+ std::swap (local, runnables);
+ }
+
+ for (auto &item : local)
+ item ();
+}
+
+/* See ser-event.h. */
+
+void
+run_on_main_thread (std::function<void ()> &&func)
+{
+#if CXX_STD_THREAD
+ std::lock_guard<std::mutex> lock (runnable_mutex);
+#endif
+ runnables.emplace_back (std::move (func));
+ serial_event_set (runnable_event);
+}
+
+void
+_initialize_ser_event ()
+{
+ runnable_event = make_serial_event ();
+ add_file_handler (serial_event_fd (runnable_event), run_events, nullptr);
+}
diff --git a/gdb/ser-event.h b/gdb/ser-event.h
index 137348557f9..61a84f9cc79 100644
--- a/gdb/ser-event.h
+++ b/gdb/ser-event.h
@@ -19,6 +19,8 @@
#ifndef SER_EVENT_H
#define SER_EVENT_H
+#include <functional>
+
/* This is used to be able to signal the event loop (or any other
select/poll) of events, in a race-free manner.
@@ -48,4 +50,8 @@ extern void serial_event_set (struct serial_event *event);
call is made. */
extern void serial_event_clear (struct serial_event *event);
+/* Send a runnable to the main thread. */
+
+extern void run_on_main_thread (std::function<void ()> &&);
+
#endif
--
2.17.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v3 5/8] Introduce run_on_main_thread
2019-05-29 21:29 ` [PATCH v3 5/8] Introduce run_on_main_thread Tom Tromey
@ 2019-05-30 13:12 ` Pedro Alves
2019-05-30 13:20 ` Tom Tromey
0 siblings, 1 reply; 24+ messages in thread
From: Pedro Alves @ 2019-05-30 13:12 UTC (permalink / raw)
To: Tom Tromey, gdb-patches
On 5/29/19 10:29 PM, Tom Tromey wrote:
> This introduces a way for a callback to be run on the main thread.
Can Python's gdb.post_event be built on top of this?
It would fix that nasty "atomically enough" race in gdbpy_run_events,
I guess.
>
> gdb/ChangeLog
> 2019-05-29 Tom Tromey <tom@tromey.com>
>
> * ser-event.h (run_on_main_thread): Declare.
> * ser-event.c (runnable_event, runnables, runnable_mutex): New
> globals.
> (run_events, run_on_main_thread, _initialize_ser_event): New
> functions.
> ---
> gdb/ChangeLog | 8 ++++++
> gdb/ser-event.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++
> gdb/ser-event.h | 6 +++++
> 3 files changed, 83 insertions(+)
>
> diff --git a/gdb/ser-event.c b/gdb/ser-event.c
> index d3956346246..4870433b287 100644
> --- a/gdb/ser-event.c
> +++ b/gdb/ser-event.c
> @@ -20,6 +20,10 @@
> #include "ser-event.h"
> #include "serial.h"
> #include "common/filestuff.h"
> +#if CXX_STD_THREAD
> +#include <mutex>
> +#endif
> +#include "event-loop.h"
>
> /* On POSIX hosts, a serial_event is basically an abstraction for the
> classical self-pipe trick.
> @@ -217,3 +221,68 @@ serial_event_clear (struct serial_event *event)
> ResetEvent (state->event);
> #endif
> }
> +
> +\f
> +
> +/* The serial event used when posting runnables. */
> +
> +static struct serial_event *runnable_event;
> +
> +/* Runnables that have been posted. */
> +
> +static std::vector<std::function<void ()>> runnables;
> +
> +#if CXX_STD_THREAD
> +
> +/* Mutex to hold when handling runnable_event or runnables. */
> +
> +static std::mutex runnable_mutex;
> +
> +#endif
> +
> +/* Run all the queued runnables. */
> +
> +static void
> +run_events (int error, gdb_client_data client_data)
> +{
> + std::vector<std::function<void ()>> local;
> +
> + /* Hold the lock while changing the globals, but not while running
> + the runnables. */
> + {
> +#if CXX_STD_THREAD
> + std::lock_guard<std::mutex> lock (runnable_mutex);
> +#endif
> +
> + /* Clear the event fd. Do this before flushing the events list,
> + so that any new event post afterwards is sure to re-awaken the
> + event loop. */
> + serial_event_clear (runnable_event);
> +
> + /* Move the vector in case running a runnable pushes a new
> + runnable. */
> + std::swap (local, runnables);
> + }
> +
> + for (auto &item : local)
> + item ();
I'd think this should swallow errors when calling
each item, instead of letting an exception escape and
discard all other items, since each item call should be
in principle logically unrelated?
Maybe we could unit test this code.
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v3 5/8] Introduce run_on_main_thread
2019-05-30 13:12 ` Pedro Alves
@ 2019-05-30 13:20 ` Tom Tromey
2019-05-30 13:57 ` Pedro Alves
2019-05-30 14:01 ` Pedro Alves
0 siblings, 2 replies; 24+ messages in thread
From: Tom Tromey @ 2019-05-30 13:20 UTC (permalink / raw)
To: Pedro Alves; +Cc: Tom Tromey, gdb-patches
Pedro> Can Python's gdb.post_event be built on top of this?
Pedro> It would fix that nasty "atomically enough" race in gdbpy_run_events,
Pedro> I guess.
Yes, and actually I wrote a patch to do this once, but I dropped it from
this series because it was unrelated.
>> + for (auto &item : local)
>> + item ();
Pedro> I'd think this should swallow errors when calling
Pedro> each item, instead of letting an exception escape and
Pedro> discard all other items, since each item call should be
Pedro> in principle logically unrelated?
Pedro> Maybe we could unit test this code.
I wasn't sure how. But for this maybe the callback should be noexcept.
Tom
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v3 5/8] Introduce run_on_main_thread
2019-05-30 13:20 ` Tom Tromey
@ 2019-05-30 13:57 ` Pedro Alves
2019-05-30 14:01 ` Pedro Alves
1 sibling, 0 replies; 24+ messages in thread
From: Pedro Alves @ 2019-05-30 13:57 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 5/30/19 2:20 PM, Tom Tromey wrote:
> Pedro> Can Python's gdb.post_event be built on top of this?
> Pedro> It would fix that nasty "atomically enough" race in gdbpy_run_events,
> Pedro> I guess.
>
> Yes, and actually I wrote a patch to do this once, but I dropped it from
> this series because it was unrelated.
>
>>> + for (auto &item : local)
>>> + item ();
>
> Pedro> I'd think this should swallow errors when calling
> Pedro> each item, instead of letting an exception escape and
> Pedro> discard all other items, since each item call should be
> Pedro> in principle logically unrelated?
>
> Pedro> Maybe we could unit test this code.
>
> I wasn't sure how.
In a unit test, the main thread code could spawn a thread that calls
run_on_main_thread. The main thread would then nest an event loop
to run the main-thread events.
The posted event would write to a global that would unlock the nested
event loop. Something similar to wait_sync_command_done.
> But for this maybe the callback should be noexcept.
Hmm, maybe. But then if someone forgets to try/catch, we end up
aborting gdb. Pick what you prefer, as long as we decide and document
something.
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v3 5/8] Introduce run_on_main_thread
2019-05-30 13:20 ` Tom Tromey
2019-05-30 13:57 ` Pedro Alves
@ 2019-05-30 14:01 ` Pedro Alves
1 sibling, 0 replies; 24+ messages in thread
From: Pedro Alves @ 2019-05-30 14:01 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 5/30/19 2:20 PM, Tom Tromey wrote:
> Pedro> Can Python's gdb.post_event be built on top of this?
> Pedro> It would fix that nasty "atomically enough" race in gdbpy_run_events,
> Pedro> I guess.
>
> Yes, and actually I wrote a patch to do this once, but I dropped it from
> this series because it was unrelated.
Forgot to say: I wouldn't call it unrelated. You could use it as yet-another
proof that run_on_main_thread is a useful abstraction, which even fixes
a race/bug. I'd be happy to see such a patch. ( but no rush :-) )
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v3 2/8] Remove static buffer from ada_decode
2019-05-29 21:29 [PATCH v3 0/8] Demangle minimal symbol names in worker threads Tom Tromey
` (4 preceding siblings ...)
2019-05-29 21:29 ` [PATCH v3 5/8] Introduce run_on_main_thread Tom Tromey
@ 2019-05-29 21:29 ` Tom Tromey
2019-05-30 0:08 ` Pedro Alves
2019-05-29 21:29 ` [PATCH v3 8/8] Add maint set/show max-worker-threads Tom Tromey
2019-05-29 22:03 ` [PATCH v3 6/8] Introduce thread-safe way to handle SIGSEGV Tom Tromey
7 siblings, 1 reply; 24+ messages in thread
From: Tom Tromey @ 2019-05-29 21:29 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
ada_decode has a static buffer, which means it is not thread-safe.
This patch removes the buffer and adds a parameter so that the storage
can be managed by the caller.
gdb/ChangeLog
2019-05-29 Tom Tromey <tom@tromey.com>
* ada-varobj.c (ada_varobj_describe_simple_array_child): Update.
* ada-lang.h (ada_decode): Add "storage" parameter.
* ada-lang.c (ada_decode): Add "storage" parameter.
(ada_decode_symbol, ada_la_decode, ada_sniff_from_mangled_name)
(is_valid_name_for_wild_match, name_matches_regex)
(ada_add_global_exceptions): Update.
* ada-exp.y (write_object_renaming): Update.
---
gdb/ChangeLog | 10 +++++++++
gdb/ada-exp.y | 6 +++++-
gdb/ada-lang.c | 55 ++++++++++++++++++++++++++++++------------------
gdb/ada-lang.h | 3 ++-
gdb/ada-varobj.c | 3 ++-
5 files changed, 54 insertions(+), 23 deletions(-)
diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
index f7ce27aca35..4771ec0ed56 100644
--- a/gdb/ada-exp.y
+++ b/gdb/ada-exp.y
@@ -816,7 +816,11 @@ write_object_renaming (struct parser_state *par_state,
renamed_entity_len);
ada_lookup_encoded_symbol (name, orig_left_context, VAR_DOMAIN, &sym_info);
if (sym_info.symbol == NULL)
- error (_("Could not find renamed variable: %s"), ada_decode (name));
+ {
+ gdb::unique_xmalloc_ptr<char> storage;
+ error (_("Could not find renamed variable: %s"),
+ ada_decode (name, &storage));
+ }
else if (SYMBOL_CLASS (sym_info.symbol) == LOC_TYPEDEF)
/* We have a renaming of an old-style renaming symbol. Don't
trust the block information. */
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 99c099aa07d..75325100dc9 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -1106,22 +1106,18 @@ ada_remove_po_subprogram_suffix (const char *encoded, int *len)
/* If ENCODED follows the GNAT entity encoding conventions, then return
the decoded form of ENCODED. Otherwise, return "<%s>" where "%s" is
- replaced by ENCODED.
-
- The resulting string is valid until the next call of ada_decode.
- If the string is unchanged by decoding, the original string pointer
- is returned. */
+ replaced by ENCODED. */
const char *
-ada_decode (const char *encoded)
+ada_decode (const char *encoded, gdb::unique_xmalloc_ptr<char> *storage)
{
int i, j;
int len0;
const char *p;
char *decoded;
int at_start_name;
- static char *decoding_buffer = NULL;
- static size_t decoding_buffer_size = 0;
+ char *decoding_buffer = NULL;
+ size_t decoding_buffer_size = 0;
/* With function descriptors on PPC64, the value of a symbol named
".FN", if it exists, is the entry point of the function "FN". */
@@ -1349,9 +1345,15 @@ ada_decode (const char *encoded)
goto Suppress;
if (strcmp (decoded, encoded) == 0)
- return encoded;
+ {
+ xfree (decoding_buffer);
+ return encoded;
+ }
else
- return decoded;
+ {
+ storage->reset (decoded);
+ return decoded;
+ }
Suppress:
GROW_VECT (decoding_buffer, decoding_buffer_size, strlen (encoded) + 3);
@@ -1360,8 +1362,8 @@ Suppress:
strcpy (decoded, encoded);
else
xsnprintf (decoded, decoding_buffer_size, "<%s>", encoded);
+ storage->reset (decoded);
return decoded;
-
}
/* Table for keeping permanent unique copies of decoded names. Once
@@ -1390,7 +1392,8 @@ ada_decode_symbol (const struct general_symbol_info *arg)
if (!gsymbol->ada_mangled)
{
- const char *decoded = ada_decode (gsymbol->name);
+ gdb::unique_xmalloc_ptr<char> storage;
+ const char *decoded = ada_decode (gsymbol->name, &storage);
struct obstack *obstack = gsymbol->language_specific.obstack;
gsymbol->ada_mangled = 1;
@@ -1420,7 +1423,8 @@ ada_decode_symbol (const struct general_symbol_info *arg)
static char *
ada_la_decode (const char *encoded, int options)
{
- return xstrdup (ada_decode (encoded));
+ gdb::unique_xmalloc_ptr<char> storage;
+ return xstrdup (ada_decode (encoded, &storage));
}
/* Implement la_sniff_from_mangled_name for Ada. */
@@ -1428,7 +1432,8 @@ ada_la_decode (const char *encoded, int options)
static int
ada_sniff_from_mangled_name (const char *mangled, char **out)
{
- const char *demangled = ada_decode (mangled);
+ gdb::unique_xmalloc_ptr<char> storage;
+ const char *demangled = ada_decode (mangled, &storage);
*out = NULL;
@@ -6001,7 +6006,8 @@ is_name_suffix (const char *str)
static int
is_valid_name_for_wild_match (const char *name0)
{
- const char *decoded_name = ada_decode (name0);
+ gdb::unique_xmalloc_ptr<char> storage;
+ const char *decoded_name = ada_decode (name0, &storage);
int i;
/* If the decoded name starts with an angle bracket, it means that
@@ -6249,8 +6255,9 @@ ada_lookup_name_info::matches
is not a suitable completion. */
const char *sym_name_copy = sym_name;
bool has_angle_bracket;
+ gdb::unique_xmalloc_ptr<char> storage;
- sym_name = ada_decode (sym_name);
+ sym_name = ada_decode (sym_name, &storage);
has_angle_bracket = (sym_name[0] == '<');
match = (has_angle_bracket == m_verbatim_p);
sym_name = sym_name_copy;
@@ -6272,12 +6279,14 @@ ada_lookup_name_info::matches
/* Second: Try wild matching... */
+ gdb::unique_xmalloc_ptr<char> sym_name_storage;
if (!match && m_wild_match_p)
{
/* Since we are doing wild matching, this means that TEXT
may represent an unqualified symbol name. We therefore must
also compare TEXT against the unqualified name of the symbol. */
- sym_name = ada_unqualified_name (ada_decode (sym_name));
+ sym_name = ada_unqualified_name (ada_decode (sym_name,
+ &sym_name_storage));
if (strncmp (sym_name, text, text_len) == 0)
match = true;
@@ -6293,7 +6302,10 @@ ada_lookup_name_info::matches
std::string &match_str = comp_match_res->match.storage ();
if (!m_encoded_p)
- match_str = ada_decode (sym_name);
+ {
+ gdb::unique_xmalloc_ptr<char> storage;
+ match_str = ada_decode (sym_name, &storage);
+ }
else
{
if (m_verbatim_p)
@@ -13416,8 +13428,9 @@ ada_add_exceptions_from_frame (compiled_regex *preg,
static bool
name_matches_regex (const char *name, compiled_regex *preg)
{
+ gdb::unique_xmalloc_ptr<char> storage;
return (preg == NULL
- || preg->exec (ada_decode (name), 0, NULL, 0) == 0);
+ || preg->exec (ada_decode (name, &storage), 0, NULL, 0) == 0);
}
/* Add all exceptions defined globally whose name name match
@@ -13450,7 +13463,9 @@ ada_add_global_exceptions (compiled_regex *preg,
lookup_name_info::match_any (),
[&] (const char *search_name)
{
- const char *decoded = ada_decode (search_name);
+ gdb::unique_xmalloc_ptr<char> storage;
+ const char *decoded = ada_decode (search_name,
+ &storage);
return name_matches_regex (decoded, preg);
},
NULL,
diff --git a/gdb/ada-lang.h b/gdb/ada-lang.h
index ff6c3399eaf..d0fc87c23a9 100644
--- a/gdb/ada-lang.h
+++ b/gdb/ada-lang.h
@@ -227,7 +227,8 @@ extern struct type *ada_get_decoded_type (struct type *type);
extern const char *ada_decode_symbol (const struct general_symbol_info *);
-extern const char *ada_decode (const char*);
+extern const char *ada_decode (const char *,
+ gdb::unique_xmalloc_ptr<char> *storage);
extern enum language ada_update_initial_language (enum language);
diff --git a/gdb/ada-varobj.c b/gdb/ada-varobj.c
index a4d553d3786..29a4c86cc5f 100644
--- a/gdb/ada-varobj.c
+++ b/gdb/ada-varobj.c
@@ -624,6 +624,7 @@ ada_varobj_describe_simple_array_child (struct value *parent_value,
of the array index type when such type qualification is
needed. */
const char *index_type_name = NULL;
+ gdb::unique_xmalloc_ptr<char> storage;
/* If the index type is a range type, find the base type. */
while (TYPE_CODE (index_type) == TYPE_CODE_RANGE)
@@ -634,7 +635,7 @@ ada_varobj_describe_simple_array_child (struct value *parent_value,
{
index_type_name = ada_type_name (index_type);
if (index_type_name)
- index_type_name = ada_decode (index_type_name);
+ index_type_name = ada_decode (index_type_name, &storage);
}
if (index_type_name != NULL)
--
2.17.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v3 2/8] Remove static buffer from ada_decode
2019-05-29 21:29 ` [PATCH v3 2/8] Remove static buffer from ada_decode Tom Tromey
@ 2019-05-30 0:08 ` Pedro Alves
0 siblings, 0 replies; 24+ messages in thread
From: Pedro Alves @ 2019-05-30 0:08 UTC (permalink / raw)
To: Tom Tromey, gdb-patches
On 5/29/19 10:29 PM, Tom Tromey wrote:
> ada_decode has a static buffer, which means it is not thread-safe.
> This patch removes the buffer and adds a parameter so that the storage
> can be managed by the caller.
Is there a reason the buffer is a unique_ptr instead of a std::string?
Or a reason that a std::string could be better? Wondering
out loud -- the small string optimization crossed my mind, though
probably Ada symbol names rarely fit in it.
I wonder whether an interface like the below be preferred?
class ada_decoder_storage
{
public:
ada_decoder_storage () = default;
/* May return a pointer to m_storage, therefore the result
is only guaranteed valid for as long as this
ada_decoder_storage object is live, or until the next
decode call. */
const char *decode (const char *encoded);
private:
gdb::unique_xmalloc_ptr<char> m_storage;
};
That would allow hiding the storage type from clients, like:
ada_sniff_from_mangled_name (const char *mangled, char **out)
{
- const char *demangled = ada_decode (mangled);
+ ada_decoder_storage decoder;
+ const char *demangled = decoder.decode (mangled);
With that, sometimes you wouldn't need to name a temp, like in:
error (_("Could not find renamed variable: %s"),
ada_decode_storage ().decode (name));
Note: while I was working on the C++ wildmatching stuff a couple years
back, I ran into pretty simple C/C++ use case that consistently showed
ada_decode on top of perf profiles, I think coming from sniffing the
minsym's language. I wrote some patches optimizing it, but in the end since
they weren't required for the wildmatching stuff, I didn't include them
in the upstream submission back then and never found the time to submit
them since:
https://github.com/palves/gdb/commits/palves/ada-decode-speedups
Unfortunately apparently I didn't write down anywhere that the usecase
was... And worse, that branch is causing regressions now, but I'm quite
sure that it didn't back then... Oh well. Just a FYI anyway.
The reason I'm bringing this up, is that your patch will introduce
heap allocations for the storage, and that reminded me of the desire to
optimize ada_decode. I would hope that the buffer/storage
can be reused when we need to decode many symbols.
Anyway, again I don't have a testcase handy, so take it as a FYI.
Might be the recent-ish glibc malloc improvements manage to reuse
the same heap block in such case, making the issue moot in practice.
Thanks,
Pedro Alves
>
> gdb/ChangeLog
> 2019-05-29 Tom Tromey <tom@tromey.com>
>
> * ada-varobj.c (ada_varobj_describe_simple_array_child): Update.
> * ada-lang.h (ada_decode): Add "storage" parameter.
> * ada-lang.c (ada_decode): Add "storage" parameter.
> (ada_decode_symbol, ada_la_decode, ada_sniff_from_mangled_name)
> (is_valid_name_for_wild_match, name_matches_regex)
> (ada_add_global_exceptions): Update.
> * ada-exp.y (write_object_renaming): Update.
> ---
> gdb/ChangeLog | 10 +++++++++
> gdb/ada-exp.y | 6 +++++-
> gdb/ada-lang.c | 55 ++++++++++++++++++++++++++++++------------------
> gdb/ada-lang.h | 3 ++-
> gdb/ada-varobj.c | 3 ++-
> 5 files changed, 54 insertions(+), 23 deletions(-)
>
> diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
> index f7ce27aca35..4771ec0ed56 100644
> --- a/gdb/ada-exp.y
> +++ b/gdb/ada-exp.y
> @@ -816,7 +816,11 @@ write_object_renaming (struct parser_state *par_state,
> renamed_entity_len);
> ada_lookup_encoded_symbol (name, orig_left_context, VAR_DOMAIN, &sym_info);
> if (sym_info.symbol == NULL)
> - error (_("Could not find renamed variable: %s"), ada_decode (name));
> + {
> + gdb::unique_xmalloc_ptr<char> storage;
> + error (_("Could not find renamed variable: %s"),
> + ada_decode (name, &storage));
> + }
> else if (SYMBOL_CLASS (sym_info.symbol) == LOC_TYPEDEF)
> /* We have a renaming of an old-style renaming symbol. Don't
> trust the block information. */
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 99c099aa07d..75325100dc9 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -1106,22 +1106,18 @@ ada_remove_po_subprogram_suffix (const char *encoded, int *len)
>
> /* If ENCODED follows the GNAT entity encoding conventions, then return
> the decoded form of ENCODED. Otherwise, return "<%s>" where "%s" is
> - replaced by ENCODED.
> -
> - The resulting string is valid until the next call of ada_decode.
> - If the string is unchanged by decoding, the original string pointer
> - is returned. */
> + replaced by ENCODED. */
>
> const char *
> -ada_decode (const char *encoded)
> +ada_decode (const char *encoded, gdb::unique_xmalloc_ptr<char> *storage)
> {
> int i, j;
> int len0;
> const char *p;
> char *decoded;
> int at_start_name;
> - static char *decoding_buffer = NULL;
> - static size_t decoding_buffer_size = 0;
> + char *decoding_buffer = NULL;
> + size_t decoding_buffer_size = 0;
>
> /* With function descriptors on PPC64, the value of a symbol named
> ".FN", if it exists, is the entry point of the function "FN". */
> @@ -1349,9 +1345,15 @@ ada_decode (const char *encoded)
> goto Suppress;
>
> if (strcmp (decoded, encoded) == 0)
> - return encoded;
> + {
> + xfree (decoding_buffer);
> + return encoded;
> + }
> else
> - return decoded;
> + {
> + storage->reset (decoded);
> + return decoded;
> + }
>
> Suppress:
> GROW_VECT (decoding_buffer, decoding_buffer_size, strlen (encoded) + 3);
> @@ -1360,8 +1362,8 @@ Suppress:
> strcpy (decoded, encoded);
> else
> xsnprintf (decoded, decoding_buffer_size, "<%s>", encoded);
> + storage->reset (decoded);
> return decoded;
> -
> }
>
> /* Table for keeping permanent unique copies of decoded names. Once
> @@ -1390,7 +1392,8 @@ ada_decode_symbol (const struct general_symbol_info *arg)
>
> if (!gsymbol->ada_mangled)
> {
> - const char *decoded = ada_decode (gsymbol->name);
> + gdb::unique_xmalloc_ptr<char> storage;
> + const char *decoded = ada_decode (gsymbol->name, &storage);
> struct obstack *obstack = gsymbol->language_specific.obstack;
>
> gsymbol->ada_mangled = 1;
> @@ -1420,7 +1423,8 @@ ada_decode_symbol (const struct general_symbol_info *arg)
> static char *
> ada_la_decode (const char *encoded, int options)
> {
> - return xstrdup (ada_decode (encoded));
> + gdb::unique_xmalloc_ptr<char> storage;
> + return xstrdup (ada_decode (encoded, &storage));
> }
>
> /* Implement la_sniff_from_mangled_name for Ada. */
> @@ -1428,7 +1432,8 @@ ada_la_decode (const char *encoded, int options)
> static int
> ada_sniff_from_mangled_name (const char *mangled, char **out)
> {
> - const char *demangled = ada_decode (mangled);
> + gdb::unique_xmalloc_ptr<char> storage;
> + const char *demangled = ada_decode (mangled, &storage);
>
> *out = NULL;
>
> @@ -6001,7 +6006,8 @@ is_name_suffix (const char *str)
> static int
> is_valid_name_for_wild_match (const char *name0)
> {
> - const char *decoded_name = ada_decode (name0);
> + gdb::unique_xmalloc_ptr<char> storage;
> + const char *decoded_name = ada_decode (name0, &storage);
> int i;
>
> /* If the decoded name starts with an angle bracket, it means that
> @@ -6249,8 +6255,9 @@ ada_lookup_name_info::matches
> is not a suitable completion. */
> const char *sym_name_copy = sym_name;
> bool has_angle_bracket;
> + gdb::unique_xmalloc_ptr<char> storage;
>
> - sym_name = ada_decode (sym_name);
> + sym_name = ada_decode (sym_name, &storage);
> has_angle_bracket = (sym_name[0] == '<');
> match = (has_angle_bracket == m_verbatim_p);
> sym_name = sym_name_copy;
> @@ -6272,12 +6279,14 @@ ada_lookup_name_info::matches
>
> /* Second: Try wild matching... */
>
> + gdb::unique_xmalloc_ptr<char> sym_name_storage;
> if (!match && m_wild_match_p)
> {
> /* Since we are doing wild matching, this means that TEXT
> may represent an unqualified symbol name. We therefore must
> also compare TEXT against the unqualified name of the symbol. */
> - sym_name = ada_unqualified_name (ada_decode (sym_name));
> + sym_name = ada_unqualified_name (ada_decode (sym_name,
> + &sym_name_storage));
>
> if (strncmp (sym_name, text, text_len) == 0)
> match = true;
> @@ -6293,7 +6302,10 @@ ada_lookup_name_info::matches
> std::string &match_str = comp_match_res->match.storage ();
>
> if (!m_encoded_p)
> - match_str = ada_decode (sym_name);
> + {
> + gdb::unique_xmalloc_ptr<char> storage;
> + match_str = ada_decode (sym_name, &storage);
> + }
> else
> {
> if (m_verbatim_p)
> @@ -13416,8 +13428,9 @@ ada_add_exceptions_from_frame (compiled_regex *preg,
> static bool
> name_matches_regex (const char *name, compiled_regex *preg)
> {
> + gdb::unique_xmalloc_ptr<char> storage;
> return (preg == NULL
> - || preg->exec (ada_decode (name), 0, NULL, 0) == 0);
> + || preg->exec (ada_decode (name, &storage), 0, NULL, 0) == 0);
> }
>
> /* Add all exceptions defined globally whose name name match
> @@ -13450,7 +13463,9 @@ ada_add_global_exceptions (compiled_regex *preg,
> lookup_name_info::match_any (),
> [&] (const char *search_name)
> {
> - const char *decoded = ada_decode (search_name);
> + gdb::unique_xmalloc_ptr<char> storage;
> + const char *decoded = ada_decode (search_name,
> + &storage);
> return name_matches_regex (decoded, preg);
> },
> NULL,
> diff --git a/gdb/ada-lang.h b/gdb/ada-lang.h
> index ff6c3399eaf..d0fc87c23a9 100644
> --- a/gdb/ada-lang.h
> +++ b/gdb/ada-lang.h
> @@ -227,7 +227,8 @@ extern struct type *ada_get_decoded_type (struct type *type);
>
> extern const char *ada_decode_symbol (const struct general_symbol_info *);
>
> -extern const char *ada_decode (const char*);
> +extern const char *ada_decode (const char *,
> + gdb::unique_xmalloc_ptr<char> *storage);
>
> extern enum language ada_update_initial_language (enum language);
>
> diff --git a/gdb/ada-varobj.c b/gdb/ada-varobj.c
> index a4d553d3786..29a4c86cc5f 100644
> --- a/gdb/ada-varobj.c
> +++ b/gdb/ada-varobj.c
> @@ -624,6 +624,7 @@ ada_varobj_describe_simple_array_child (struct value *parent_value,
> of the array index type when such type qualification is
> needed. */
> const char *index_type_name = NULL;
> + gdb::unique_xmalloc_ptr<char> storage;
>
> /* If the index type is a range type, find the base type. */
> while (TYPE_CODE (index_type) == TYPE_CODE_RANGE)
> @@ -634,7 +635,7 @@ ada_varobj_describe_simple_array_child (struct value *parent_value,
> {
> index_type_name = ada_type_name (index_type);
> if (index_type_name)
> - index_type_name = ada_decode (index_type_name);
> + index_type_name = ada_decode (index_type_name, &storage);
> }
>
> if (index_type_name != NULL)
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v3 8/8] Add maint set/show max-worker-threads
2019-05-29 21:29 [PATCH v3 0/8] Demangle minimal symbol names in worker threads Tom Tromey
` (5 preceding siblings ...)
2019-05-29 21:29 ` [PATCH v3 2/8] Remove static buffer from ada_decode Tom Tromey
@ 2019-05-29 21:29 ` Tom Tromey
2019-05-30 2:36 ` Eli Zaretskii
2019-05-30 14:20 ` Pedro Alves
2019-05-29 22:03 ` [PATCH v3 6/8] Introduce thread-safe way to handle SIGSEGV Tom Tromey
7 siblings, 2 replies; 24+ messages in thread
From: Tom Tromey @ 2019-05-29 21:29 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
This adds maint commands to control the maximum number of worker
threads that gdb can use.
gdb/ChangeLog
2019-05-29 Tom Tromey <tom@tromey.com>
* NEWS: Add entry.
* maint.c (_initialize_maint_cmds): Add "max-worker-threads" maint
commands.
gdb/doc/ChangeLog
2019-05-29 Tom Tromey <tom@tromey.com>
* gdb.texinfo (Maintenance Commands): Document new maint
commands.
---
gdb/ChangeLog | 6 ++++++
gdb/NEWS | 6 ++++++
gdb/doc/ChangeLog | 5 +++++
gdb/doc/gdb.texinfo | 14 ++++++++++++++
gdb/maint.c | 12 ++++++++++++
5 files changed, 43 insertions(+)
diff --git a/gdb/NEWS b/gdb/NEWS
index 6546b7243a9..84b2ea52cec 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -50,6 +50,12 @@ set logging debugredirect [on|off]
By default, GDB debug output will go to both the terminal and the logfile.
Set if you want debug output to go only to the log file.
+maint set max-worker-threads
+maint show max-worker-threads
+ Control the maximum number of worker threads that can be used by GDB.
+ The default is "unlimited". Currently worker threads are only used when
+ demangling the names of linker symbols.
+
* New MI commands
-complete
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 3c4535ec506..ccbb770a027 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -36928,6 +36928,20 @@ with the DWARF frame unwinders enabled.
If DWARF frame unwinders are not supported for a particular target
architecture, then enabling this flag does not cause them to be used.
+
+@kindex maint set max-worker-threads
+@kindex maint show max-worker-threads
+@item maint set max-worker-threads
+@item maint show max-worker-threads
+Control the number of worker threads that may be used by @value{GDBN}.
+On capable hosts, @value{GDBN} may use multiple threads to speed up
+certain CPU-intensive operations, such as demangling symbol names.
+While the number of threads used by @value{GDBN} may vary, this
+command can be used to set an upper bound on this number. The default
+is @code{unlimited}. Note that this only controls worker threads
+started by @value{GDBN} itself; libraries used by @value{GDBN} may
+start threads of their own.
+
@kindex maint set profile
@kindex maint show profile
@cindex profiling GDB
diff --git a/gdb/maint.c b/gdb/maint.c
index 328d6026a34..cb52d323795 100644
--- a/gdb/maint.c
+++ b/gdb/maint.c
@@ -39,6 +39,7 @@
#include "top.h"
#include "maint.h"
#include "common/selftest.h"
+#include "common/parallel-for.h"
#include "cli/cli-decode.h"
#include "cli/cli-utils.h"
@@ -1143,4 +1144,15 @@ When enabled GDB is profiled."),
show_maintenance_profile_p,
&maintenance_set_cmdlist,
&maintenance_show_cmdlist);
+
+ add_setshow_zuinteger_unlimited_cmd ("max-worker-threads",
+ class_maintenance,
+ &gdb::max_threads, _("\
+Set the maximum number of worker threads GDB can use."), _("\
+Set the maximum number of worker threads GDB can use."), _("\
+GDB may use multiple threads to speed up certain CPU-intensive operations,\n\
+such as demangling symbol names."),
+ NULL, NULL,
+ &maintenance_set_cmdlist,
+ &maintenance_show_cmdlist);
}
--
2.17.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH v3 6/8] Introduce thread-safe way to handle SIGSEGV
2019-05-29 21:29 [PATCH v3 0/8] Demangle minimal symbol names in worker threads Tom Tromey
` (6 preceding siblings ...)
2019-05-29 21:29 ` [PATCH v3 8/8] Add maint set/show max-worker-threads Tom Tromey
@ 2019-05-29 22:03 ` Tom Tromey
2019-05-30 13:40 ` Pedro Alves
7 siblings, 1 reply; 24+ messages in thread
From: Tom Tromey @ 2019-05-29 22:03 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey
The gdb demangler installs a SIGSEGV handler in order to protect gdb
from demangler bugs. However, this is not thread-safe, as signal
handlers are global to the process.
This patch changes gdb to always install a global SIGSEGV handler, and
then lets thread indicate their interest in handling the signal by
setting a thread-local variable.
This patch then arranges for the demangler code to use this; being
sure to arrange for calls to warning and the like to be done on the
main thread.
gdb/ChangeLog
2019-05-29 Tom Tromey <tom@tromey.com>
* event-top.h (segv_handler): Declare.
* event-top.c (segv_handler): New global.
(handle_sigsegv): New function.
(async_init_signals): Install SIGSEGV handler.
* cp-support.c (gdb_demangle_jmp_buf): Change type. Now
thread-local.
(report_failed_demangle): New function.
(gdb_demangle): Make core_dump_allowed atomic. Remove signal
handler-setting code, instead use segv_handler. Run warning code
on main thread.
---
gdb/ChangeLog | 13 ++++++
gdb/cp-support.c | 114 +++++++++++++++++++++++------------------------
gdb/event-top.c | 37 +++++++++++++++
gdb/event-top.h | 3 ++
4 files changed, 109 insertions(+), 58 deletions(-)
diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index 4afb79a4ea9..60bbbc23ec3 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -37,6 +37,9 @@
#include "common/gdb_setjmp.h"
#include "safe-ctype.h"
#include "common/selftest.h"
+#include <atomic>
+#include "event-top.h"
+#include "ser-event.h"
#define d_left(dc) (dc)->u.s_binary.left
#define d_right(dc) (dc)->u.s_binary.right
@@ -1480,7 +1483,7 @@ static int catch_demangler_crashes = 1;
/* Stack context and environment for demangler crash recovery. */
-static SIGJMP_BUF gdb_demangle_jmp_buf;
+static thread_local SIGJMP_BUF *gdb_demangle_jmp_buf;
/* If nonzero, attempt to dump core from the signal handler. */
@@ -1499,7 +1502,43 @@ gdb_demangle_signal_handler (int signo)
gdb_demangle_attempt_core_dump = 0;
}
- SIGLONGJMP (gdb_demangle_jmp_buf, signo);
+ SIGLONGJMP (*gdb_demangle_jmp_buf, signo);
+}
+
+/* A helper for gdb_demangle that reports a demangling failure. */
+
+static void
+report_failed_demangle (const char *name, int core_dump_allowed,
+ int crash_signal)
+{
+ static int error_reported = 0;
+
+ if (!error_reported)
+ {
+ std::string short_msg
+ = string_printf (_("unable to demangle '%s' "
+ "(demangler failed with signal %d)"),
+ name, crash_signal);
+
+ std::string long_msg
+ = string_printf ("%s:%d: %s: %s", __FILE__, __LINE__,
+ "demangler-warning", short_msg.c_str ());
+
+ target_terminal::scoped_restore_terminal_state term_state;
+ target_terminal::ours_for_output ();
+
+ begin_line ();
+ if (core_dump_allowed)
+ fprintf_unfiltered (gdb_stderr,
+ _("%s\nAttempting to dump core.\n"),
+ long_msg.c_str ());
+ else
+ warn_cant_dump_core (long_msg.c_str ());
+
+ demangler_warning (__FILE__, __LINE__, "%s", short_msg.c_str ());
+
+ error_reported = 1;
+ }
}
#endif
@@ -1513,12 +1552,7 @@ gdb_demangle (const char *name, int options)
int crash_signal = 0;
#ifdef HAVE_WORKING_FORK
-#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
- struct sigaction sa, old_sa;
-#else
- sighandler_t ofunc;
-#endif
- static int core_dump_allowed = -1;
+ static std::atomic<int> core_dump_allowed (-1);
if (core_dump_allowed == -1)
{
@@ -1528,23 +1562,15 @@ gdb_demangle (const char *name, int options)
gdb_demangle_attempt_core_dump = 0;
}
- if (catch_demangler_crashes)
- {
-#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
- sa.sa_handler = gdb_demangle_signal_handler;
- sigemptyset (&sa.sa_mask);
-#ifdef HAVE_SIGALTSTACK
- sa.sa_flags = SA_ONSTACK;
-#else
- sa.sa_flags = 0;
-#endif
- sigaction (SIGSEGV, &sa, &old_sa);
-#else
- ofunc = signal (SIGSEGV, gdb_demangle_signal_handler);
-#endif
+ scoped_restore restore_segv
+ = make_scoped_restore (&segv_handler,
+ catch_demangler_crashes
+ ? gdb_demangle_signal_handler
+ : nullptr);
- crash_signal = SIGSETJMP (gdb_demangle_jmp_buf);
- }
+ SIGJMP_BUF jmp_buf;
+ if (catch_demangler_crashes)
+ crash_signal = SIGSETJMP (jmp_buf);
#endif
if (crash_signal == 0)
@@ -1553,42 +1579,14 @@ gdb_demangle (const char *name, int options)
#ifdef HAVE_WORKING_FORK
if (catch_demangler_crashes)
{
-#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
- sigaction (SIGSEGV, &old_sa, NULL);
-#else
- signal (SIGSEGV, ofunc);
-#endif
-
if (crash_signal != 0)
{
- static int error_reported = 0;
-
- if (!error_reported)
- {
- std::string short_msg
- = string_printf (_("unable to demangle '%s' "
- "(demangler failed with signal %d)"),
- name, crash_signal);
-
- std::string long_msg
- = string_printf ("%s:%d: %s: %s", __FILE__, __LINE__,
- "demangler-warning", short_msg.c_str ());
-
- target_terminal::scoped_restore_terminal_state term_state;
- target_terminal::ours_for_output ();
-
- begin_line ();
- if (core_dump_allowed)
- fprintf_unfiltered (gdb_stderr,
- _("%s\nAttempting to dump core.\n"),
- long_msg.c_str ());
- else
- warn_cant_dump_core (long_msg.c_str ());
-
- demangler_warning (__FILE__, __LINE__, "%s", short_msg.c_str ());
-
- error_reported = 1;
- }
+ std::string copy = name;
+ run_on_main_thread ([=] ()
+ {
+ report_failed_demangle (copy.c_str (), core_dump_allowed,
+ crash_signal);
+ });
result = NULL;
}
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 93b7d2d28bc..f1466c0c2ba 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -849,6 +849,29 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
}
\f
+/* See event-top.h. */
+
+thread_local void (*segv_handler) (int);
+
+/* Handler for SIGSEGV. */
+
+static void
+handle_sigsegv (int sig)
+{
+ if (segv_handler == nullptr)
+ {
+ signal (sig, nullptr);
+ raise (sig);
+ }
+ else
+ {
+ signal (sig, handle_sigsegv);
+ segv_handler (sig);
+ }
+}
+
+\f
+
/* The serial event associated with the QUIT flag. set_quit_flag sets
this, and check_quit_flag clears it. Used by interruptible_select
to be able to do interruptible I/O with no race with the SIGINT
@@ -916,6 +939,20 @@ async_init_signals (void)
sigtstp_token =
create_async_signal_handler (async_sigtstp_handler, NULL);
#endif
+
+#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
+ struct sigaction sa, old_sa;
+ sa.sa_handler = handle_sigsegv;
+ sigemptyset (&sa.sa_mask);
+#ifdef HAVE_SIGALTSTACK
+ sa.sa_flags = SA_ONSTACK;
+#else
+ sa.sa_flags = 0;
+#endif
+ sigaction (SIGSEGV, &sa, &old_sa);
+#else
+ signal (SIGSEGV, handle_sigsegv);
+#endif
}
/* See defs.h. */
diff --git a/gdb/event-top.h b/gdb/event-top.h
index 4c3e6cb8612..849f40d9192 100644
--- a/gdb/event-top.h
+++ b/gdb/event-top.h
@@ -70,4 +70,7 @@ extern void gdb_rl_callback_handler_install (const char *prompt);
currently installed. */
extern void gdb_rl_callback_handler_reinstall (void);
+/* The SIGSEGV handler for this thread, or NULL if there is none. */
+extern thread_local void (*segv_handler) (int);
+
#endif
--
2.17.2
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH v3 6/8] Introduce thread-safe way to handle SIGSEGV
2019-05-29 22:03 ` [PATCH v3 6/8] Introduce thread-safe way to handle SIGSEGV Tom Tromey
@ 2019-05-30 13:40 ` Pedro Alves
2019-06-09 15:43 ` Tom Tromey
0 siblings, 1 reply; 24+ messages in thread
From: Pedro Alves @ 2019-05-30 13:40 UTC (permalink / raw)
To: Tom Tromey, gdb-patches
On 5/29/19 10:29 PM, Tom Tromey wrote:
> The gdb demangler installs a SIGSEGV handler in order to protect gdb
> from demangler bugs. However, this is not thread-safe, as signal
> handlers are global to the process.
>
> This patch changes gdb to always install a global SIGSEGV handler, and
> then lets thread indicate their interest in handling the signal by
"lets threads"
> setting a thread-local variable.
>
> This patch then arranges for the demangler code to use this; being
> sure to arrange for calls to warning and the like to be done on the
> main thread.
The design is explained here, but the patch itself doesn't include
any comment in that direction. I think future readers of the code
would benefit a lot such commentary.
>
> gdb/ChangeLog
> 2019-05-29 Tom Tromey <tom@tromey.com>
>
> * event-top.h (segv_handler): Declare.
> * event-top.c (segv_handler): New global.
> (handle_sigsegv): New function.
> (async_init_signals): Install SIGSEGV handler.
> * cp-support.c (gdb_demangle_jmp_buf): Change type. Now
> thread-local.
> (report_failed_demangle): New function.
> (gdb_demangle): Make core_dump_allowed atomic. Remove signal
> handler-setting code, instead use segv_handler. Run warning code
> on main thread.
> ---
> gdb/ChangeLog | 13 ++++++
> gdb/cp-support.c | 114 +++++++++++++++++++++++------------------------
> gdb/event-top.c | 37 +++++++++++++++
> gdb/event-top.h | 3 ++
> 4 files changed, 109 insertions(+), 58 deletions(-)
>
> diff --git a/gdb/cp-support.c b/gdb/cp-support.c
> index 4afb79a4ea9..60bbbc23ec3 100644
> --- a/gdb/cp-support.c
> +++ b/gdb/cp-support.c
> @@ -37,6 +37,9 @@
> #include "common/gdb_setjmp.h"
> #include "safe-ctype.h"
> #include "common/selftest.h"
> +#include <atomic>
> +#include "event-top.h"
> +#include "ser-event.h"
>
> #define d_left(dc) (dc)->u.s_binary.left
> #define d_right(dc) (dc)->u.s_binary.right
> @@ -1480,7 +1483,7 @@ static int catch_demangler_crashes = 1;
>
> /* Stack context and environment for demangler crash recovery. */
>
> -static SIGJMP_BUF gdb_demangle_jmp_buf;
> +static thread_local SIGJMP_BUF *gdb_demangle_jmp_buf;
>
> /* If nonzero, attempt to dump core from the signal handler. */
>
> @@ -1499,7 +1502,43 @@ gdb_demangle_signal_handler (int signo)
> gdb_demangle_attempt_core_dump = 0;
> }
>
> - SIGLONGJMP (gdb_demangle_jmp_buf, signo);
> + SIGLONGJMP (*gdb_demangle_jmp_buf, signo);
> +}
> +
> +/* A helper for gdb_demangle that reports a demangling failure. */
> +
> +static void
> +report_failed_demangle (const char *name, int core_dump_allowed,
> + int crash_signal)
> +{
> + static int error_reported = 0;
bool, while at it?
> +
> + if (!error_reported)
> + {
> + std::string short_msg
> + = string_printf (_("unable to demangle '%s' "
> + "(demangler failed with signal %d)"),
> + name, crash_signal);
> +
> + std::string long_msg
> + = string_printf ("%s:%d: %s: %s", __FILE__, __LINE__,
> + "demangler-warning", short_msg.c_str ());
> +
> + target_terminal::scoped_restore_terminal_state term_state;
> + target_terminal::ours_for_output ();
> +
> + begin_line ();
> + if (core_dump_allowed)
> + fprintf_unfiltered (gdb_stderr,
> + _("%s\nAttempting to dump core.\n"),
> + long_msg.c_str ());
> + else
> + warn_cant_dump_core (long_msg.c_str ());
> +
> + demangler_warning (__FILE__, __LINE__, "%s", short_msg.c_str ());
> +
> + error_reported = 1;
> + }
> }
>
> #endif
> @@ -1513,12 +1552,7 @@ gdb_demangle (const char *name, int options)
> int crash_signal = 0;
>
> #ifdef HAVE_WORKING_FORK
> -#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
> - struct sigaction sa, old_sa;
> -#else
> - sighandler_t ofunc;
> -#endif
> - static int core_dump_allowed = -1;
> + static std::atomic<int> core_dump_allowed (-1);
>
> if (core_dump_allowed == -1)
> {
> @@ -1528,23 +1562,15 @@ gdb_demangle (const char *name, int options)
> gdb_demangle_attempt_core_dump = 0;
Are accesses to gdb_demangle_attempt_core_dump going to be racy?
Maybe not, didn't think that much about it. If they are, I wonder whether it
wouldn't be better if this whole can_dump_core check block were moved to the
main thread, before threads are spun? Say, to a gdb_demangle_init() function?
Not sure, might not be convenient form an abstraction-hiding perspective.
> }
>
> - if (catch_demangler_crashes)
> - {
> -#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
> - sa.sa_handler = gdb_demangle_signal_handler;
> - sigemptyset (&sa.sa_mask);
> -#ifdef HAVE_SIGALTSTACK
> - sa.sa_flags = SA_ONSTACK;
> -#else
> - sa.sa_flags = 0;
> -#endif
> - sigaction (SIGSEGV, &sa, &old_sa);
> -#else
> - ofunc = signal (SIGSEGV, gdb_demangle_signal_handler);
> -#endif
> + scoped_restore restore_segv
> + = make_scoped_restore (&segv_handler,
> + catch_demangler_crashes
> + ? gdb_demangle_signal_handler
> + : nullptr);
>
> - crash_signal = SIGSETJMP (gdb_demangle_jmp_buf);
> - }
> + SIGJMP_BUF jmp_buf;
> + if (catch_demangler_crashes)
> + crash_signal = SIGSETJMP (jmp_buf);
> #endif
gdb_demangle_jmp_buf is now a pointer, but I'm not seeing
anything set it?
>
> if (crash_signal == 0)
> @@ -1553,42 +1579,14 @@ gdb_demangle (const char *name, int options)
> #ifdef HAVE_WORKING_FORK
> if (catch_demangler_crashes)
> {
> -#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
> - sigaction (SIGSEGV, &old_sa, NULL);
> -#else
> - signal (SIGSEGV, ofunc);
> -#endif
> -
> if (crash_signal != 0)
> {
> - static int error_reported = 0;
> -
> - if (!error_reported)
> - {
> - std::string short_msg
> - = string_printf (_("unable to demangle '%s' "
> - "(demangler failed with signal %d)"),
> - name, crash_signal);
> -
> - std::string long_msg
> - = string_printf ("%s:%d: %s: %s", __FILE__, __LINE__,
> - "demangler-warning", short_msg.c_str ());
> -
> - target_terminal::scoped_restore_terminal_state term_state;
> - target_terminal::ours_for_output ();
> -
> - begin_line ();
> - if (core_dump_allowed)
> - fprintf_unfiltered (gdb_stderr,
> - _("%s\nAttempting to dump core.\n"),
> - long_msg.c_str ());
> - else
> - warn_cant_dump_core (long_msg.c_str ());
> -
> - demangler_warning (__FILE__, __LINE__, "%s", short_msg.c_str ());
> -
> - error_reported = 1;
> - }
> + std::string copy = name;
I don't think you need this copy, because ...
> + run_on_main_thread ([=] ()
... you're already copying here, with "[=]".
> + {
tabs vs spaces.
> + report_failed_demangle (copy.c_str (), core_dump_allowed,
> + crash_signal);
> + });
>
> result = NULL;
> }
> diff --git a/gdb/event-top.c b/gdb/event-top.c
> index 93b7d2d28bc..f1466c0c2ba 100644
> --- a/gdb/event-top.c
> +++ b/gdb/event-top.c
> @@ -849,6 +849,29 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
> }
> \f
>
> +/* See event-top.h. */
> +
> +thread_local void (*segv_handler) (int);
I think it'd help readability if this were named something
that indicates it's thread-local, like e.g., thr_segv_handler.
> +
> +/* Handler for SIGSEGV. */
> +
> +static void
> +handle_sigsegv (int sig)
> +{
> + if (segv_handler == nullptr)
> + {
> + signal (sig, nullptr);
> + raise (sig);
> + }
> + else
> + {
> + signal (sig, handle_sigsegv);
Doesn't this lose the SA_ONSTACK?
> + segv_handler (sig);
> + }
> +}
> +
> +\f
> +
> /* The serial event associated with the QUIT flag. set_quit_flag sets
> this, and check_quit_flag clears it. Used by interruptible_select
> to be able to do interruptible I/O with no race with the SIGINT
> @@ -916,6 +939,20 @@ async_init_signals (void)
> sigtstp_token =
> create_async_signal_handler (async_sigtstp_handler, NULL);
> #endif
> +
> +#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
> + struct sigaction sa, old_sa;
> + sa.sa_handler = handle_sigsegv;
> + sigemptyset (&sa.sa_mask);
> +#ifdef HAVE_SIGALTSTACK
> + sa.sa_flags = SA_ONSTACK;
> +#else
> + sa.sa_flags = 0;
> +#endif
> + sigaction (SIGSEGV, &sa, &old_sa);
> +#else
> + signal (SIGSEGV, handle_sigsegv);
> +#endif
> }
>
> /* See defs.h. */
> diff --git a/gdb/event-top.h b/gdb/event-top.h
> index 4c3e6cb8612..849f40d9192 100644
> --- a/gdb/event-top.h
> +++ b/gdb/event-top.h
> @@ -70,4 +70,7 @@ extern void gdb_rl_callback_handler_install (const char *prompt);
> currently installed. */
> extern void gdb_rl_callback_handler_reinstall (void);
>
> +/* The SIGSEGV handler for this thread, or NULL if there is none. */
> +extern thread_local void (*segv_handler) (int);
> +
> #endif
>
Thanks,
Pedro Alves
^ permalink raw reply [flat|nested] 24+ messages in thread