]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #310 from opensourcerouting/thread-prep
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 5 Apr 2017 16:39:25 +0000 (12:39 -0400)
committerGitHub <noreply@github.com>
Wed, 5 Apr 2017 16:39:25 +0000 (12:39 -0400)
MT preparations

configure.ac
lib/Makefile.am
lib/frratomic.h [new file with mode: 0644]
lib/log.c
lib/memory.c
lib/memory.h
lib/sigevent.c
m4/.gitignore
m4/ax_pthread.m4 [new file with mode: 0644]

index 6eac0e3c865170a1934a2c65008f17e914d12e46..b4a3e37fd25fef1367c4b4b70dcfac4d06774c3a 100755 (executable)
@@ -73,6 +73,10 @@ LIBS="$LIBS -ltcmalloc_minimal"
 esac],[tcmalloc_enabled=false])
 
 
+dnl Thanks autoconf, but we don't want a default -g -O2.  We have our own
+dnl flag determination logic.
+CFLAGS="${CFLAGS:-}"
+
 dnl --------------------
 dnl Check CC and friends
 dnl --------------------
@@ -85,6 +89,7 @@ AM_PROG_CC_C_O
 dnl remove autoconf default "-g -O2"
 CFLAGS="$orig_cflags"
 AC_PROG_CC_C99
+dnl NB: see C11 below
 
 AC_PROG_EGREP
 PKG_PROG_PKG_CONFIG
@@ -96,7 +101,7 @@ AC_CHECK_PROG([SED],[sed],[sed],[/bin/false])
 dnl try and enable CFLAGS that are useful for Quagga
 dnl - specifically, options to control warnings
 
-AC_USE_SYSTEM_EXTENSIONS()
+AC_USE_SYSTEM_EXTENSIONS
 AC_DEFUN([AC_C_FLAG], [{
        AC_LANG_PUSH(C)
        ac_c_flag_save="$CFLAGS"
@@ -122,6 +127,13 @@ dnl ICC won't bail on unknown options without -diag-error 10006
 dnl need to do this first so we get useful results for the other options
 AC_C_FLAG([-diag-error 10006])
 
+dnl AC_PROG_CC_C99 may change CC to include -std=gnu99 or something
+ac_cc="$CC"
+CC="${CC% -std=gnu99}"
+CC="${CC% -std=c99}"
+
+AC_C_FLAG([-std=gnu11], [CC="$ac_cc"], [CC="$CC -std=gnu11"])
+
 dnl if the user specified any CFLAGS, we don't add "-g -Os/-O2" here
 if test "z$orig_cflags" = "z"; then
   AC_C_FLAG([-g])
@@ -177,6 +189,18 @@ AC_LINK_IFELSE(
        ])
 AC_LANG_POP(C)
 
+dnl ----------
+dnl Essentials
+dnl ----------
+
+AX_PTHREAD([
+  CC="$PTHREAD_CC"
+  CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+  LIBS="$PTHREAD_LIBS $LIBS"
+], [
+  AC_MSG_FAILURE([This Quagga version needs pthreads])
+])
+
 dnl --------------
 dnl Check programs
 dnl --------------
@@ -539,6 +563,72 @@ AC_CHECK_HEADERS([stropts.h sys/ksym.h \
        linux/version.h asm/types.h \
        sys/cdefs.h])
 
+ac_stdatomic_ok=false
+AC_DEFINE(FRR_AUTOCONF_ATOMIC, 1, [did autoconf checks for atomic funcs])
+AC_CHECK_HEADER([stdatomic.h],[
+
+  AC_MSG_CHECKING([whether _Atomic qualifier works])
+  AC_LINK_IFELSE([AC_LANG_SOURCE([[
+#include <stdatomic.h>
+int main(int argc, char **argv) {
+  _Atomic int i = 0;
+  return i;
+}
+]])], [
+    AC_DEFINE(HAVE_STDATOMIC_H, 1, [found stdatomic.h])
+    AC_MSG_RESULT([yes])
+    ac_stdatomic_ok=true
+  ], [
+    AC_MSG_RESULT([no])
+  ])
+])
+
+AS_IF([$ac_stdatomic_ok], [true], [
+  AC_MSG_CHECKING([for __atomic_* builtins])
+  AC_LINK_IFELSE([AC_LANG_SOURCE([[
+int main(int argc, char **argv) {
+  volatile int i = 1;
+  __atomic_store_n (&i, 0, __ATOMIC_RELEASE);
+  return __atomic_load_n (&i, __ATOMIC_ACQUIRE);
+}
+]])], [
+    AC_DEFINE(HAVE___ATOMIC, 1, [found __atomic builtins])
+    AC_MSG_RESULT([yes])
+  ], [
+    AC_MSG_RESULT([no])
+
+    dnl FreeBSD 9 has a broken stdatomic.h where _Atomic doesn't work
+    AC_MSG_CHECKING([for __sync_* builtins])
+    AC_LINK_IFELSE([AC_LANG_SOURCE([[
+int main(int argc, char **argv) {
+  volatile int i = 1;
+  __sync_fetch_and_sub (&i, 1);
+  return __sync_val_compare_and_swap (&i, 0, 1);
+}
+]])], [
+      AC_DEFINE(HAVE___SYNC, 1, [found __sync builtins])
+      AC_MSG_RESULT([yes])
+
+      AC_MSG_CHECKING([for __sync_swap builtin])
+      AC_LINK_IFELSE([AC_LANG_SOURCE([[
+int main(int argc, char **argv) {
+  volatile int i = 1;
+  return __sync_swap (&i, 2);
+}
+]])], [
+        AC_DEFINE(HAVE___SYNC_SWAP, 1, [found __sync_swap builtin])
+        AC_MSG_RESULT([yes])
+      ], [
+        AC_MSG_RESULT([no])
+      ])
+
+    ], [
+      AC_MSG_RESULT([no])
+      AC_MSG_FAILURE([stdatomic.h unavailable and $CC has neither __atomic nor __sync builtins])
+    ])
+  ])
+])
+
 dnl Utility macro to avoid retyping includes all the time
 m4_define([FRR_INCLUDES],
 [#ifdef SUNOS_5
index 14b7130c8a8d796ccff52eb65c256fa968ef1f09..75947e61465f1a7c2e3d26dedbd2a28a97ca113e 100644 (file)
@@ -54,6 +54,7 @@ libfrrsnmp_la_SOURCES = \
        #end
 
 pkginclude_HEADERS = \
+       frratomic.h \
        buffer.h checksum.h filter.h getopt.h hash.h \
        if.h linklist.h log.h \
        graph.h command_match.h \
diff --git a/lib/frratomic.h b/lib/frratomic.h
new file mode 100644 (file)
index 0000000..183790a
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2015-16  David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FRRATOMIC_H
+#define _FRRATOMIC_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef FRR_AUTOCONF_ATOMIC
+#error autoconf checks for atomic functions were not properly run
+#endif
+
+/* ISO C11 */
+#ifdef HAVE_STDATOMIC_H
+#include <stdatomic.h>
+
+/* gcc 4.7 and newer */
+#elif defined(HAVE___ATOMIC)
+
+#define _Atomic volatile
+
+#define memory_order_relaxed __ATOMIC_RELAXED
+#define memory_order_consume __ATOMIC_CONSUME
+#define memory_order_acquire __ATOMIC_ACQUIRE
+#define memory_order_release __ATOMIC_RELEASE
+#define memory_order_acq_rel __ATOMIC_ACQ_REL
+#define memory_order_seq_cst __ATOMIC_SEQ_CST
+
+#define atomic_load_explicit __atomic_load_n
+#define atomic_store_explicit __atomic_store_n
+#define atomic_exchange_explicit __atomic_exchange_n
+#define atomic_fetch_add_explicit __atomic_fetch_add
+#define atomic_fetch_sub_explicit __atomic_fetch_sub
+
+#define atomic_compare_exchange_weak_explicit(atom, expect, desire, mem1, mem2) \
+       __atomic_compare_exchange_n(atom, expect, desire, 1, mem1, mem2)
+
+/* gcc 4.1 and newer,
+ * clang 3.3 (possibly older)
+ *
+ * __sync_swap isn't in gcc's documentation, but clang has it
+ *
+ * note __sync_synchronize() 
+ */
+#elif defined(HAVE___SYNC)
+
+#define _Atomic volatile
+
+#define memory_order_relaxed 0
+#define memory_order_consume 0
+#define memory_order_acquire 0
+#define memory_order_release 0
+#define memory_order_acq_rel 0
+#define memory_order_seq_cst 0
+
+#define atomic_load_explicit(ptr, mem) \
+       ({ __sync_synchronize(); \
+          typeof(*ptr) rval = __sync_fetch_and_add((ptr), 0); \
+          __sync_synchronize(); rval; })
+#define atomic_store_explicit(ptr, val, mem) \
+       ({ __sync_synchronize(); \
+          *(ptr) = (val); \
+          __sync_synchronize(); (void)0; })
+#ifdef HAVE___SYNC_SWAP
+#define atomic_exchange_explicit(ptr, val, mem) \
+       ({ __sync_synchronize(); \
+          typeof(*ptr) rval = __sync_swap((ptr, val), 0); \
+          __sync_synchronize(); rval; })
+#else /* !HAVE___SYNC_SWAP */
+#define atomic_exchange_explicit(ptr, val, mem) \
+       ({ typeof(ptr) _ptr = (ptr); typeof(val) _val = (val); \
+          __sync_synchronize(); \
+          typeof(*ptr) old1, old2 = __sync_fetch_and_add(_ptr, 0); \
+          do { \
+               old1 = old2; \
+               old2 = __sync_val_compare_and_swap (_ptr, old1, _val); \
+          } while (old1 != old2); \
+          __sync_synchronize(); \
+          old2; \
+       })
+#endif /* !HAVE___SYNC_SWAP */
+#define atomic_fetch_add_explicit(ptr, val, mem) \
+       ({ __sync_synchronize(); \
+          typeof(*ptr) rval = __sync_fetch_and_add((ptr), (val)); \
+          __sync_synchronize(); rval; })
+#define atomic_fetch_sub_explicit(ptr, val, mem) \
+       ({ __sync_synchronize(); \
+          typeof(*ptr) rval = __sync_fetch_and_sub((ptr), (val)); \
+          __sync_synchronize(); rval; })
+
+#define atomic_compare_exchange_weak_explicit(atom, expect, desire, mem1, mem2) \
+       ({ typeof(atom) _atom = (atom); typeof(expect) _expect = (expect); \
+          typeof(desire) _desire = (desire); \
+          __sync_synchronize(); \
+          typeof(*atom) rval = __sync_val_compare_and_swap(_atom, *_expect, _desire); \
+          __sync_synchronize(); \
+          bool ret = (rval == *_expect); *_expect = rval; ret; })
+
+#else /* !HAVE___ATOMIC && !HAVE_STDATOMIC_H */
+#error no atomic functions...
+#endif
+
+#endif /* _FRRATOMIC_H */
index c7d4ca2d97fb201331cc6663213d267db47eb469..0f2a5800281cc927c0c4447a76016edd2234ebc6 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -734,6 +734,17 @@ openzlog (const char *progname, const char *protoname, u_short instance,
 
   openlog (progname, syslog_flags, zl->facility);
   zlog_default = zl;
+
+#ifdef HAVE_GLIBC_BACKTRACE
+  /* work around backtrace() using lazily resolved dynamically linked
+   * symbols, which will otherwise cause funny breakage in the SEGV handler.
+   * (particularly, the dynamic linker can call malloc(), which uses locks
+   * in programs linked with -pthread, thus can deadlock.) */
+  void *bt[4];
+  backtrace (bt, array_size(bt));
+  free (backtrace_symbols (bt, 0));
+  backtrace_symbols_fd (bt, 0, 0);
+#endif
 }
 
 void
index ad55366f64a15a040547b41666753f49222bb04f..c6207adb981f1ef32f9ab233608cb51c0caaa358 100644 (file)
@@ -27,119 +27,107 @@ struct memgroup **mg_insert = &mg_first;
 DEFINE_MGROUP(LIB, "libfrr")
 DEFINE_MTYPE(LIB, TMP, "Temporary memory")
 
-static inline void
-mt_count_alloc (struct memtype *mt, size_t size)
+static inline void mt_count_alloc(struct memtype *mt, size_t size)
 {
-  mt->n_alloc++;
+       size_t oldsize;
 
-  if (mt->size == 0)
-    mt->size = size;
-  else if (mt->size != size)
-    mt->size = SIZE_VAR;
+       atomic_fetch_add_explicit(&mt->n_alloc, 1, memory_order_relaxed);
+
+       oldsize = atomic_load_explicit(&mt->size, memory_order_relaxed);
+       if (oldsize == 0)
+               oldsize = atomic_exchange_explicit(&mt->size, size, memory_order_relaxed);
+       if (oldsize != 0 && oldsize != size && oldsize != SIZE_VAR)
+               atomic_store_explicit(&mt->size, SIZE_VAR, memory_order_relaxed);
 }
 
-static inline void
-mt_count_free (struct memtype *mt)
+static inline void mt_count_free(struct memtype *mt)
 {
-  assert(mt->n_alloc);
-  mt->n_alloc--;
+       assert(mt->n_alloc);
+       atomic_fetch_sub_explicit(&mt->n_alloc, 1, memory_order_relaxed);
 }
 
-static inline void *
-mt_checkalloc (struct memtype *mt, void *ptr, size_t size)
+static inline void *mt_checkalloc(struct memtype *mt, void *ptr, size_t size)
 {
-  if (__builtin_expect(ptr == NULL, 0))
-    {
-      memory_oom (size, mt->name);
-      return NULL;
-    }
-  mt_count_alloc (mt, size);
-  return ptr;
+       if (__builtin_expect(ptr == NULL, 0)) {
+               memory_oom(size, mt->name);
+               return NULL;
+       }
+       mt_count_alloc(mt, size);
+       return ptr;
 }
 
-void *
-qmalloc (struct memtype *mt, size_t size)
+void *qmalloc(struct memtype *mt, size_t size)
 {
-  return mt_checkalloc (mt, malloc (size), size);
+       return mt_checkalloc(mt, malloc(size), size);
 }
 
-void *
-qcalloc (struct memtype *mt, size_t size)
+void *qcalloc(struct memtype *mt, size_t size)
 {
-  return mt_checkalloc (mt, calloc (size, 1), size);
+       return mt_checkalloc(mt, calloc(size, 1), size);
 }
 
-void *
-qrealloc (struct memtype *mt, void *ptr, size_t size)
+void *qrealloc(struct memtype *mt, void *ptr, size_t size)
 {
-  if (ptr)
-    mt_count_free (mt);
-  return mt_checkalloc (mt, ptr ? realloc (ptr, size) : malloc (size), size);
+       if (ptr)
+               mt_count_free(mt);
+       return mt_checkalloc(mt, ptr ? realloc(ptr, size) : malloc(size), size);
 }
 
-void *
-qstrdup (struct memtype *mt, const char *str)
+void *qstrdup(struct memtype *mt, const char *str)
 {
-  return mt_checkalloc (mt, strdup (str), strlen (str) + 1);
+       return mt_checkalloc(mt, strdup(str), strlen(str) + 1);
 }
 
-void
-qfree (struct memtype *mt, void *ptr)
+void qfree(struct memtype *mt, void *ptr)
 {
-  if (ptr)
-    mt_count_free (mt);
-  free (ptr);
+       if (ptr)
+               mt_count_free(mt);
+       free(ptr);
 }
 
-int
-qmem_walk (qmem_walk_fn *func, void *arg)
+int qmem_walk(qmem_walk_fn *func, void *arg)
 {
-  struct memgroup *mg;
-  struct memtype *mt;
-  int rv;
-
-  for (mg = mg_first; mg; mg = mg->next)
-    {
-      if ((rv = func (arg, mg, NULL)))
-        return rv;
-      for (mt = mg->types; mt; mt = mt->next)
-        if ((rv = func (arg, mg, mt)))
-          return rv;
-    }
-  return 0;
+       struct memgroup *mg;
+       struct memtype *mt;
+       int rv;
+
+       for (mg = mg_first; mg; mg = mg->next) {
+               if ((rv = func(arg, mg, NULL)))
+                       return rv;
+               for (mt = mg->types; mt; mt = mt->next)
+                       if ((rv = func(arg, mg, mt)))
+                               return rv;
+       }
+       return 0;
 }
 
-struct exit_dump_args
-{
-  const char *prefix;
-  int error;
+struct exit_dump_args {
+       const char *prefix;
+       int error;
 };
 
-static int
-qmem_exit_walker (void *arg, struct memgroup *mg, struct memtype *mt)
+static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt)
 {
-  struct exit_dump_args *eda = arg;
-
-  if (!mt)
-    {
-      fprintf (stderr, "%s: showing active allocations in memory group %s\n",
-               eda->prefix, mg->name);
-    }
-  else if (mt->n_alloc)
-    {
-      char size[32];
-      eda->error++;
-      snprintf (size, sizeof (size), "%10zu", mt->size);
-      fprintf (stderr, "%s: memstats:  %-30s: %6zu * %s\n",
-               eda->prefix, mt->name, mt->n_alloc,
-               mt->size == SIZE_VAR ? "(variably sized)" : size);
-    }
-  return 0;
+       struct exit_dump_args *eda = arg;
+
+       if (!mt) {
+               fprintf(stderr, "%s: showing active allocations in "
+                               "memory group %s\n",
+                               eda->prefix, mg->name);
+
+       } else if (mt->n_alloc) {
+               char size[32];
+               eda->error++;
+               snprintf(size, sizeof(size), "%10zu", mt->size);
+               fprintf(stderr, "%s: memstats:  %-30s: %6zu * %s\n",
+                               eda->prefix, mt->name, mt->n_alloc,
+                               mt->size == SIZE_VAR ? "(variably sized)" : size);
+       }
+       return 0;
 }
 
-void
-log_memstats_stderr (const char *prefix)
+void log_memstats_stderr(const char *prefix)
 {
-  struct exit_dump_args eda = { .prefix = prefix, .error = 0 };
-  qmem_walk (qmem_exit_walker, &eda);
+       struct exit_dump_args eda = { .prefix = prefix, .error = 0 };
+       qmem_walk(qmem_exit_walker, &eda);
 }
index 477a6162dc45960aa0be35c66269a38227af33d6..9e8803a8b2a6dbc1881df66e050cfe83c2072c4a 100644 (file)
 #define _QUAGGA_MEMORY_H
 
 #include <stdlib.h>
+#include <frratomic.h>
 
 #define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
 
 #define SIZE_VAR ~0UL
-struct memtype
-{
-  struct memtype *next, **ref;
-  const char *name;
-  size_t n_alloc;
-  size_t size;
+struct memtype {
+       struct memtype *next, **ref;
+       const char *name;
+       _Atomic size_t n_alloc;
+       _Atomic size_t size;
 };
 
-struct memgroup
-{
-  struct memgroup *next, **ref;
-  struct memtype *types, **insert;
-  const char *name;
+struct memgroup {
+       struct memgroup *next, **ref;
+       struct memtype *types, **insert;
+       const char *name;
 };
 
 #if defined(__clang__)
@@ -82,14 +81,14 @@ struct memgroup
  *    DEFINE_MGROUP(MYDAEMON, "my daemon memory")
  *    DEFINE_MTYPE(MYDAEMON, MYDAEMON_COMMON,
  *                   "this mtype is used in multiple files in mydaemon")
- *    foo = qmalloc (MTYPE_MYDAEMON_COMMON, sizeof (*foo))
+ *    foo = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*foo))
  *
  *  mydaemon_io.c
- *    bar = qmalloc (MTYPE_MYDAEMON_COMMON, sizeof (*bar))
+ *    bar = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*bar))
  *
  *    DEFINE_MTYPE_STATIC(MYDAEMON, MYDAEMON_IO,
  *                          "this mtype is used only in this file")
- *    baz = qmalloc (MTYPE_MYDAEMON_IO, sizeof (*baz))
+ *    baz = qmalloc(MTYPE_MYDAEMON_IO, sizeof(*baz))
  *
  *  Note:  Naming conventions (MGROUP_ and MTYPE_ prefixes are enforced
  *         by not having these as part of the macro arguments)
@@ -155,15 +154,15 @@ DECLARE_MGROUP(LIB)
 DECLARE_MTYPE(TMP)
 
 
-extern void *qmalloc (struct memtype *mt, size_t size)
+extern void *qmalloc(struct memtype *mt, size_t size)
        __attribute__ ((malloc, _ALLOC_SIZE(2), nonnull (1) _RET_NONNULL));
-extern void *qcalloc (struct memtype *mt, size_t size)
+extern void *qcalloc(struct memtype *mt, size_t size)
        __attribute__ ((malloc, _ALLOC_SIZE(2), nonnull (1) _RET_NONNULL));
-extern void *qrealloc (struct memtype *mt, void *ptr, size_t size)
+extern void *qrealloc(struct memtype *mt, void *ptr, size_t size)
        __attribute__ ((_ALLOC_SIZE(3), nonnull (1) _RET_NONNULL));
 extern void *qstrdup (struct memtype *mt, const char *str)
        __attribute__ ((malloc, nonnull (1) _RET_NONNULL));
-extern void qfree (struct memtype *mt, void *ptr)
+extern void qfree(struct memtype *mt, void *ptr)
        __attribute__ ((nonnull (1)));
 
 #define XMALLOC(mtype, size)           qmalloc(mtype, size)
@@ -183,10 +182,10 @@ static inline size_t mtype_stats_alloc(struct memtype *mt)
  *
  * return value: 0: continue, !0: abort walk.  qmem_walk will return the
  * last value from qmem_walk_fn. */
-typedef int qmem_walk_fn (void *arg, struct memgroup *mg, struct memtype *mt);
-extern int qmem_walk (qmem_walk_fn *func, void *arg);
-extern void log_memstats_stderr (const char *);
+typedef int qmem_walk_fn(void *arg, struct memgroup *mg, struct memtype *mt);
+extern int qmem_walk(qmem_walk_fn *func, void *arg);
+extern void log_memstats_stderr(const char *);
 
-extern void memory_oom (size_t size, const char *name);
+extern void memory_oom(size_t size, const char *name);
 
 #endif /* _QUAGGA_MEMORY_H */
index 09f07180cec884d406196ccdfd8959dd1335e6c9..b2059a17bf6104de35a54a847fa1f04c41fbbac7 100644 (file)
@@ -233,6 +233,18 @@ core_handler(int signo
 #endif
            )
 {
+  /* make sure we don't hang in here.  default for SIGALRM is terminate.
+   * - if we're in backtrace for more than a second, abort. */
+  struct sigaction sa_default = { .sa_handler = SIG_DFL };
+  sigaction (SIGALRM, &sa_default, NULL);
+
+  sigset_t sigset;
+  sigemptyset (&sigset);
+  sigaddset (&sigset, SIGALRM);
+  sigprocmask (SIG_UNBLOCK, &sigset, NULL);
+
+  alarm (1);
+
   zlog_signal(signo, "aborting..."
 #ifdef SA_SIGINFO
              , siginfo, program_counter(context)
@@ -326,6 +338,11 @@ trap_default_signals(void)
 #else
                  act.sa_handler = sigmap[i].handler;
                  act.sa_flags = 0;
+#endif
+#ifdef SA_RESETHAND
+                  /* don't try to print backtraces recursively */
+                  if (sigmap[i].handler == core_handler)
+                    act.sa_flags |= SA_RESETHAND;
 #endif
                }
              if (sigaction(sigmap[i].sigs[j],&act,NULL) < 0)
index 3f3bd0a73574620a2ba5b3b7dc04cb74a2369aaf..798188b0b93d284c066bf7845fd74f23040fde0d 100644 (file)
@@ -4,4 +4,5 @@ Makefile.in
 .arch-ids
 *~
 *.loT
-
+!ax_pthread.m4
+!ax_sys_weak_alias.m4
diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4
new file mode 100644 (file)
index 0000000..d383ad5
--- /dev/null
@@ -0,0 +1,332 @@
+# ===========================================================================
+#        http://www.gnu.org/software/autoconf-archive/ax_pthread.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+#
+# DESCRIPTION
+#
+#   This macro figures out how to build C programs using POSIX threads. It
+#   sets the PTHREAD_LIBS output variable to the threads library and linker
+#   flags, and the PTHREAD_CFLAGS output variable to any special C compiler
+#   flags that are needed. (The user can also force certain compiler
+#   flags/libs to be tested by setting these environment variables.)
+#
+#   Also sets PTHREAD_CC to any special C compiler that is needed for
+#   multi-threaded programs (defaults to the value of CC otherwise). (This
+#   is necessary on AIX to use the special cc_r compiler alias.)
+#
+#   NOTE: You are assumed to not only compile your program with these flags,
+#   but also link it with them as well. e.g. you should link with
+#   $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
+#
+#   If you are only building threads programs, you may wish to use these
+#   variables in your default LIBS, CFLAGS, and CC:
+#
+#     LIBS="$PTHREAD_LIBS $LIBS"
+#     CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+#     CC="$PTHREAD_CC"
+#
+#   In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
+#   has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
+#   (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+#
+#   Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
+#   PTHREAD_PRIO_INHERIT symbol is defined when compiling with
+#   PTHREAD_CFLAGS.
+#
+#   ACTION-IF-FOUND is a list of shell commands to run if a threads library
+#   is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
+#   is not found. If ACTION-IF-FOUND is not specified, the default action
+#   will define HAVE_PTHREAD.
+#
+#   Please let the authors know if this macro fails on any platform, or if
+#   you have any other suggestions or comments. This macro was based on work
+#   by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
+#   from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
+#   Alejandro Forero Cuervo to the autoconf macro repository. We are also
+#   grateful for the helpful feedback of numerous users.
+#
+#   Updated for Autoconf 2.68 by Daniel Richard G.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
+#   Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
+#
+#   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/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 21
+
+AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
+AC_DEFUN([AX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_PUSH([C])
+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 True64 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_LIBS$PTHREAD_CFLAGS" != x; then
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+        AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes])
+        AC_MSG_RESULT([$ax_pthread_ok])
+        if test x"$ax_pthread_ok" = xno; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+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 -kthread lthread -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)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads too;
+#      also defines -D_REENTRANT)
+#      ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case ${host_os} in
+        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.  (We need to link with -pthreads/-mt/
+        # -lpthread.)  (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 just look for -pthreads and -lpthread first:
+
+        ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
+        ;;
+
+        darwin*)
+        ax_pthread_flags="-pthread $ax_pthread_flags"
+        ;;
+esac
+
+# Clang doesn't consider unrecognized options an error unless we specify
+# -Werror. We throw in some extra Clang-specific options to ensure that
+# this doesn't happen for GCC, which also accepts -Werror.
+
+AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
+save_CFLAGS="$CFLAGS"
+ax_pthread_extra_flags="-Werror"
+CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
+                  [AC_MSG_RESULT([yes])],
+                  [ax_pthread_extra_flags=
+                   AC_MSG_RESULT([no])])
+CFLAGS="$save_CFLAGS"
+
+if test x"$ax_pthread_ok" = xno; then
+for flag in $ax_pthread_flags; do
+
+        case $flag in
+                none)
+                AC_MSG_CHECKING([whether pthreads work without any flags])
+                ;;
+
+                -*)
+                AC_MSG_CHECKING([whether pthreads work with $flag])
+                PTHREAD_CFLAGS="$flag"
+                ;;
+
+                pthread-config)
+                AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
+                if test x"$ax_pthread_config" = xno; then continue; fi
+                PTHREAD_CFLAGS="`pthread-config --cflags`"
+                PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+                ;;
+
+                *)
+                AC_MSG_CHECKING([for the pthreads library -l$flag])
+                PTHREAD_LIBS="-l$flag"
+                ;;
+        esac
+
+        save_LIBS="$LIBS"
+        save_CFLAGS="$CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags"
+
+        # 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.
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
+                        static void routine(void *a) { a = 0; }
+                        static void *start_routine(void *a) { return a; }],
+                       [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) /* ; */])],
+                [ax_pthread_ok=yes],
+                [])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        AC_MSG_RESULT([$ax_pthread_ok])
+        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
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+        AC_MSG_CHECKING([for joinable pthread attribute])
+        attr_name=unknown
+        for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+            AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
+                           [int attr = $attr; return attr /* ; */])],
+                [attr_name=$attr; break],
+                [])
+        done
+        AC_MSG_RESULT([$attr_name])
+        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+            AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name],
+                               [Define to necessary symbol if this constant
+                                uses a non-standard name on your system.])
+        fi
+
+        AC_MSG_CHECKING([if more special flags are required for pthreads])
+        flag=no
+        case ${host_os} in
+            aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
+            osf* | hpux*) flag="-D_REENTRANT";;
+            solaris*)
+            if test "$GCC" = "yes"; then
+                flag="-D_REENTRANT"
+            else
+                # TODO: What about Clang on Solaris?
+                flag="-mt -D_REENTRANT"
+            fi
+            ;;
+        esac
+        AC_MSG_RESULT([$flag])
+        if test "x$flag" != xno; then
+            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+        fi
+
+        AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
+            [ax_cv_PTHREAD_PRIO_INHERIT], [
+                AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
+                                                [[int i = PTHREAD_PRIO_INHERIT;]])],
+                    [ax_cv_PTHREAD_PRIO_INHERIT=yes],
+                    [ax_cv_PTHREAD_PRIO_INHERIT=no])
+            ])
+        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
+            [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        # More AIX lossage: compile with *_r variant
+        if test "x$GCC" != xyes; then
+            case $host_os in
+                aix*)
+                AS_CASE(["x/$CC"],
+                  [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
+                   AS_CASE(["x$CC"],
+                     [x/*],
+                     [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
+                     [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
+                ;;
+            esac
+        fi
+fi
+
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+
+AC_SUBST([PTHREAD_LIBS])
+AC_SUBST([PTHREAD_CFLAGS])
+AC_SUBST([PTHREAD_CC])
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$ax_pthread_ok" = xyes; then
+        ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
+        :
+else
+        ax_pthread_ok=no
+        $2
+fi
+AC_LANG_POP
+])dnl AX_PTHREAD