[tree-ssa libmudflap long] multithreading fixes, build reorg, testsuite extensions
Frank Ch. Eigler
fche@redhat.com
Fri Jul 4 23:09:00 GMT 2003
Hi -
This omnibus patch includes several distinct changes, all related to
the problem of debugging multithreading bugs in libmudflap. The key
piece of it was that a reentrancy-detection state variable had to
become per-thread rather than global.
It turned out that using thread-specific pthreads keys for this was
not workable, due to unanticipated memory allocation/deallocation
happening within glibc when these keys are used. (These operations
seemed unworkable to intercept and reentrancy-detect properly.) So
instead the per-thread reentrancy state is in the __mf_threadinfo
lookup table (which has become a hash table).
In order to debug all this yuck, which sometimes hung and usually
behaved inconsistently from run to run, it was necessary to extend
the dejagnu mfdg driver to be able to set a timeout on testcase
execution, and to request that it be rerun a couple of times (to
try to flush out heisenbugs). These patches to libmudflap's variant
of mfdg.exp are also in this batch. Perhaps they would be useful
to port to dejagnu in general.
Another organizational change was to break up the mf-hooks.c file into
a few (three), so isolate memory-management (mf-hooks1.c),
basic isolated stdlib/unistd wrappers (mf-hooks2.c), and multithreading
support (mf-hooks3.c). This allows much faster rebuilds when only one
of the bigger subsystems is broken. I don't include below the bodies of
those split files that had only trivial changes (the first two).
- FChE
+2003-07-04 Frank Ch. Eigler <fche@redhat.com>
+
+ * mf-hooks1.c, 2.c, 3.c: New file, splits up content from old ...
+ * mf-hooks: Removed.
+ * mf-impl.h (MF_VALIDATE_EXTENT, BEGIN_PROTECT, END_PROTECT):
+ Move these macros from old mf-hooks.c here.
+ * Makefile.am: Adapt to split-up hook sources for faster builds.
+ * Makefile.in: Regenerated.
+
+ * mf-heuristics.c: Remove #if-0 block.
+
+ * mf-impl.h (__mf_state): Reorganize declaration and implementation.
+ (__mf_starting_p): New state only for use while dlsym bootstrapping.
+ (CALL_REAL, __mf_init): Corresponding changes.
+ (TRACE, VERBOSE_TRACE): Include thread id and "mf:" prefix. Update
+ all callers to remove redundant "mf:" prefix.
+ * mf-runtime.h.in: #define a few reentrancy macros for libmudflapth.
+ * mf-hooks3.c: Rewrite chunks to support per-thread __mf_state value.
+ (__mf_pthread_info): Become a hash table.
+
+ * testsuite/lib/mfdg.exp: Support new "dg-timeout" and
+ "dg-repetitions" directives to control test case execution.
+ * testsuite/libmudflap.cth/pass37-frag.c: Add timeout and repeat
+ options.
+ * testsuite/libmudflap.cth/pass39-frag.c: Ditto for this new test.
+
Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/Attic/Makefile.am,v
retrieving revision 1.1.2.30
diff -u -p -w -s -r1.1.2.30 Makefile.am
--- Makefile.am 18 Jun 2003 17:08:32 -0000 1.1.2.30
+++ Makefile.am 4 Jul 2003 22:59:49 -0000
@@ -23,11 +23,16 @@ libmudflap_la_SOURCES = \
mf-runtime.c \
mf-heuristics.c
-HOOKOBJS = \
+HOOK1OBJS = \
malloc-hook.lo \
free-hook.lo \
calloc-hook.lo \
realloc-hook.lo \
+ mmap-hook.lo \
+ munmap-hook.lo \
+ alloca-hook.lo
+
+HOOK2OBJS = \
memcpy-hook.lo \
memmove-hook.lo \
memset-hook.lo \
@@ -55,9 +60,6 @@ HOOKOBJS = \
bcmp-hook.lo \
index-hook.lo \
rindex-hook.lo \
- mmap-hook.lo \
- munmap-hook.lo \
- alloca-hook.lo \
asctime-hook.lo \
ctime-hook.lo \
gmtime-hook.lo \
@@ -141,17 +143,29 @@ HOOKOBJS = \
shmctl-hook.lo \
shmat-hook.lo \
shmdt-hook.lo
+HOOK3OBJS =
-$(HOOKOBJS): mf-hooks.c mf-runtime.h mf-impl.h
+$(HOOK1OBJS): mf-hooks1.c mf-runtime.h mf-impl.h
+ hook=`basename $@ -hook.lo`; \
+ $(LTCOMPILE) -DWRAP_$$hook -c $(srcdir)/mf-hooks1.c -o $@
+$(HOOK2OBJS): mf-hooks2.c mf-runtime.h mf-impl.h
hook=`basename $@ -hook.lo`; \
- $(LTCOMPILE) -DWRAP_$$hook -c $(srcdir)/mf-hooks.c -o $@
+ $(LTCOMPILE) -DWRAP_$$hook -c $(srcdir)/mf-hooks2.c -o $@
+$(HOOK3OBJS): mf-hooks3.c mf-runtime.h mf-impl.h
+ hook=`basename $@ -hook.lo`; \
+ $(LTCOMPILE) -DWRAP_$$hook -c $(srcdir)/mf-hooks3.c -o $@
# Hook objects only for libmudflapth use
-PTHHOOKOBJS= \
+PTHHOOK1OBJS= \
pth/malloc-hook.lo \
pth/free-hook.lo \
pth/calloc-hook.lo \
pth/realloc-hook.lo \
+ pth/mmap-hook.lo \
+ pth/munmap-hook.lo \
+ pth/alloca-hook.lo
+
+PTHHOOK2OBJS= \
pth/memcpy-hook.lo \
pth/memmove-hook.lo \
pth/memset-hook.lo \
@@ -179,14 +193,10 @@ PTHHOOKOBJS= \
pth/bcmp-hook.lo \
pth/index-hook.lo \
pth/rindex-hook.lo \
- pth/mmap-hook.lo \
- pth/munmap-hook.lo \
- pth/alloca-hook.lo \
pth/asctime-hook.lo \
pth/ctime-hook.lo \
pth/gmtime-hook.lo \
pth/localtime-hook.lo \
- pth/pthreadstuff-hook.lo \
pth/time-hook.lo \
pth/strerror-hook.lo \
pth/fopen-hook.lo \
@@ -267,6 +277,10 @@ PTHHOOKOBJS= \
pth/shmat-hook.lo \
pth/shmdt-hook.lo
+PTHHOOK3OBJS= \
+ pth/pthreadstuff-hook.lo
+
+
clean-local:
rm -f pth/*.o pth/*.lo
@@ -275,14 +289,21 @@ pth/mf-runtime.lo: mf-runtime.c mf-runti
$(LTCOMPILE) -DLIBMUDFLAPTH -c $(srcdir)/mf-runtime.c -o $@
pth/mf-heuristics.lo: mf-heuristics.c mf-runtime.h mf-impl.h
$(LTCOMPILE) -DLIBMUDFLAPTH -c $(srcdir)/mf-heuristics.c -o $@
-$(PTHHOOKOBJS): mf-hooks.c mf-runtime.h mf-impl.h
+$(PTHHOOK1OBJS): mf-hooks1.c mf-runtime.h mf-impl.h
+ hook=`basename $@ -hook.lo`; \
+ $(LTCOMPILE) -DLIBMUDFLAPTH -DWRAP_$$hook -c $(srcdir)/mf-hooks1.c -o $@
+$(PTHHOOK2OBJS): mf-hooks2.c mf-runtime.h mf-impl.h
+ hook=`basename $@ -hook.lo`; \
+ $(LTCOMPILE) -DLIBMUDFLAPTH -DWRAP_$$hook -c $(srcdir)/mf-hooks2.c -o $@
+$(PTHHOOK3OBJS): mf-hooks3.c mf-runtime.h mf-impl.h
hook=`basename $@ -hook.lo`; \
- $(LTCOMPILE) -DLIBMUDFLAPTH -DWRAP_$$hook -c $(srcdir)/mf-hooks.c -o $@
+ $(LTCOMPILE) -DLIBMUDFLAPTH -DWRAP_$$hook -c $(srcdir)/mf-hooks3.c -o $@
-libmudflap_la_LIBADD = $(HOOKOBJS)
+libmudflap_la_LIBADD = $(HOOK1OBJS) $(HOOK2OBJS) $(HOOK3OBJS)
libmudflap_la_DEPENDENCIES = $(libmudflap_la_LIBADD)
-libmudflapth_la_LIBADD = pth/mf-runtime.lo pth/mf-heuristics.lo $(PTHHOOKOBJS)
+libmudflapth_la_LIBADD = pth/mf-runtime.lo pth/mf-heuristics.lo \
+ $(PTHHOOK1OBJS) $(PTHHOOK2OBJS) $(PTHHOOK3OBJS)
libmudflapth_la_DEPENDENCIES = $(libmudflapth_la_LIBADD)
Index: mf-heuristics.c
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/Attic/mf-heuristics.c,v
retrieving revision 1.1.2.15
diff -u -p -w -s -r1.1.2.15 mf-heuristics.c
--- mf-heuristics.c 11 Jun 2003 18:15:55 -0000 1.1.2.15
+++ mf-heuristics.c 4 Jul 2003 22:59:49 -0000
@@ -148,69 +148,5 @@ __mf_heuristic_check (uintptr_t ptr, uin
if (ptr >= (uintptr_t) & _start && ptr_high <= (uintptr_t) & _end)
return 1; /* uncacheable */
-#if 0
- /* The fourth heuristic adds the startup argv/environ strings to the
- list of GUESS regions. */
- if (__mf_opts.heur_argv_environ)
- {
- static unsigned done;
- if (! done)
- {
- done = 1;
-
- /* Register the environment string sequence. */
- if (system_envp)
- {
- int envp_length = 0;
- int i;
- while (system_envp[envp_length]) envp_length ++;
- if (envp_length)
- __mfu_register ((uintptr_t) system_envp,
- (uintptr_t) (sizeof (char*) * (envp_length + 1)),
- __MF_TYPE_GUESS, "environ[]");
-
- for (i=0; i<envp_length; i++)
- {
- char * env = system_envp[i];
- if (env)
- {
- unsigned len = strlen (env);
- __mfu_register ((uintptr_t) env,
- (uintptr_t) len+1,
- __MF_TYPE_GUESS,
- "envp[i]");
- }
- }
- }
-
- /* Register the argument vector. */
- if (system_argv)
- {
- int i;
-
- __mfu_register ((uintptr_t) system_argv,
- (uintptr_t) (sizeof (char *) * (system_argc + 1)),
- __MF_TYPE_GUESS,
- "argv");
-
- for (i=0; i<system_argc; i++)
- {
- char * arg = system_argv[i];
- if (arg)
- {
- unsigned len = strlen (arg);
- __mfu_register ((uintptr_t) arg,
- (uintptr_t) (len + 1),
- __MF_TYPE_GUESS,
- "argv[i]");
- }
- }
- }
-
- return 0;
- }
- }
-#endif
-
return 0; /* unknown */
}
Index: mf-hooks3.c
===================================================================
RCS file: mf-hooks3.c
diff -N mf-hooks3.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ mf-hooks3.c 4 Jul 2003 22:59:49 -0000
@@ -0,0 +1,345 @@
+/* Mudflap: narrow-pointer bounds-checking by tree rewriting.
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ Contributed by Frank Ch. Eigler <fche@redhat.com>
+ and Graydon Hoare <graydon@redhat.com>
+
+This file is part of GCC.
+XXX: libgcc license?
+*/
+
+#include "config.h"
+
+/* These attempt to coax various unix flavours to declare all our
+ needed tidbits in the system headers. */
+#define _POSIX_SOURCE
+#define _GNU_SOURCE
+#define _XOPEN_SOURCE
+#define _BSD_TYPES
+#define __EXTENSIONS__
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <time.h>
+
+#include "mf-runtime.h"
+#include "mf-impl.h"
+
+#ifdef _MUDFLAP
+#error "Do not compile this file with -fmudflap!"
+#endif
+
+
+/* Multithreading support hooks. */
+
+
+#ifdef WRAP_pthreadstuff
+
+#ifndef LIBMUDFLAPTH
+#error "pthreadstuff is to be included only in libmudflapth"
+#endif
+
+
+
+/* Describes a thread (dead or alive). */
+struct pthread_info
+{
+ short used_p; /* Is this slot in use? */
+
+ pthread_t self; /* The thread id. */
+ short dead_p; /* Has thread died? */
+
+ /* The user's thread entry point and argument. */
+ void * (*user_fn)(void *);
+ void *user_arg;
+
+ /* If libmudflapth allocated the stack, store its base/size. */
+ void *stack;
+ size_t stack_size;
+
+ int *thread_errno;
+ enum __mf_state_enum state;
+};
+
+
+/* To avoid dynamic memory allocation, use static array.
+ It is used as a simple hash table. */
+#define LIBMUDFLAPTH_THREADS_MAX 1024
+static struct pthread_info __mf_pthread_info[LIBMUDFLAPTH_THREADS_MAX];
+#define PTHREAD_HASH(p) ((unsigned) (p) % LIBMUDFLAPTH_THREADS_MAX)
+/* XXX: locking required? */
+
+
+/* Find and return the pthread_info struct for the running thread. */
+struct pthread_info*
+__mf_find_threadinfo ()
+{
+ pthread_t self = pthread_self ();
+ unsigned hash = PTHREAD_HASH (self);
+ unsigned i;
+ struct pthread_info *result = NULL;
+
+ for (i = hash;
+ (i+1) % LIBMUDFLAPTH_THREADS_MAX != hash;
+ i = (i+1) % LIBMUDFLAPTH_THREADS_MAX)
+ {
+ struct pthread_info* pi = & __mf_pthread_info [i];
+ if (pi->used_p && pi->self == self)
+ {
+ result = pi;
+ break;
+ }
+ }
+
+ /* XXX: This is too slow for the main thread. It will not show up
+ in the table since it was not created with pthread_create(), but
+ will have to search the entire table. */
+
+ return result;
+}
+
+
+struct pthread_info*
+__mf_create_threadinfo ()
+{
+ pthread_t self = pthread_self ();
+ unsigned hash = PTHREAD_HASH (self);
+ unsigned i;
+ struct pthread_info *result = NULL;
+
+ for (i = hash;
+ (i+1) % LIBMUDFLAPTH_THREADS_MAX != hash;
+ i = (i+1) % LIBMUDFLAPTH_THREADS_MAX)
+ {
+ struct pthread_info* pi = & __mf_pthread_info [i];
+ if (! pi->used_p)
+ {
+ pi->used_p = 1;
+ pi->self = self;
+ result = pi;
+ break;
+ }
+ }
+
+ return result;
+}
+
+
+
+enum __mf_state_enum *
+__mf_state_perthread ()
+{
+ static enum __mf_state_enum __mf_state_global = active;
+ struct pthread_info *pi = __mf_find_threadinfo ();
+
+ if (pi == NULL)
+ return & __mf_state_global;
+ else
+ return & pi->state;
+}
+
+
+static void
+__mf_pthread_cleanup (void *arg)
+{
+ struct pthread_info *pi = arg;
+
+ /* XXX: This unregistration is not safe on platforms where distinct
+ threads share errno (or at least its virtual address). */
+ if (__mf_opts.heur_std_data)
+ __mf_unregister (pi->thread_errno, sizeof (int));
+ pi->dead_p = 1;
+
+ /* Some subsequent pthread_create will garbage_collect our stack. */
+}
+
+
+
+static void *
+__mf_pthread_spawner (void *arg)
+{
+ struct pthread_info *pi = arg;
+ void *result = NULL;
+
+ pi->self = pthread_self ();
+
+ if (__mf_opts.heur_std_data)
+ {
+ pi->thread_errno = & errno;
+ __mf_register (pi->thread_errno, sizeof (int),
+ __MF_TYPE_GUESS, "errno area (thread)");
+ /* NB: we could use __MF_TYPE_STATIC above, but we guess that
+ the thread errno is coming out of some dynamically allocated
+ pool that we already know of as __MF_TYPE_HEAP. */
+ }
+
+ /* We considered using pthread_key_t objects instead of these
+ cleanup stacks, but they were less cooperative with the
+ interposed malloc hooks in libmudflap. */
+ pthread_cleanup_push (& __mf_pthread_cleanup, arg);
+
+ /* Call user thread */
+ result = pi->user_fn (pi->user_arg);
+
+ pthread_cleanup_pop (1 /* execute */);
+
+ /* NB: there is a slight race here. The pthread_info field will now
+ say this thread is dead, but it may still be running .. right
+ here. We try to check for this possibility using the
+ pthread_kill test below. */
+
+ return result;
+}
+
+
+#if PIC
+/* A special bootstrap variant. */
+int
+__mf_0fn_pthread_create (pthread_t *thr, pthread_attr_t *attr,
+ void * (*start) (void *), void *arg)
+{
+ return -1;
+}
+#endif
+
+
+#undef pthread_create
+WRAPPER(int, pthread_create, pthread_t *thr, const pthread_attr_t *attr,
+ void * (*start) (void *), void *arg)
+{
+ DECLARE(void, free, void *p);
+ DECLARE(void *, malloc, size_t c);
+ DECLARE(int, pthread_create, pthread_t *thr, const pthread_attr_t *attr,
+ void * (*start) (void *), void *arg);
+ int result;
+ struct pthread_info *pi;
+ pthread_attr_t override_attr;
+ void *override_stack;
+ size_t override_stacksize;
+ unsigned i;
+
+ TRACE ("pthread_create\n");
+
+ /* Garbage collect dead thread stacks. */
+ for (i = 0; i < LIBMUDFLAPTH_THREADS_MAX; i++)
+ {
+ pi = & __mf_pthread_info [i];
+ if (pi->used_p
+ && pi->dead_p
+ && !pthread_kill (pi->self, 0)) /* Really dead? XXX: safe? */
+ {
+ if (pi->stack != NULL)
+ CALL_REAL (free, pi->stack);
+
+ pi->stack = NULL;
+ pi->stack_size = 0;
+ pi->used_p = 0;
+ }
+ }
+
+ /* Find a slot in __mf_pthread_info to track this thread. */
+ pi = __mf_create_threadinfo ();
+ if (pi == NULL) /* no slots free - simulated out-of-memory. */
+ {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ /* Let's allocate a stack for this thread, if one is not already
+ supplied by the caller. We don't want to let e.g. the
+ linuxthreads manager thread do this allocation. */
+ if (attr != NULL)
+ override_attr = *attr;
+ else
+ pthread_attr_init (& override_attr);
+
+ /* Get supplied attributes, if any. */
+ /* XXX: consider using POSIX2K attr_getstack() */
+ if (pthread_attr_getstackaddr (& override_attr, & override_stack) != 0 ||
+ pthread_attr_getstacksize (& override_attr, & override_stacksize) != 0)
+ {
+ override_stack = NULL;
+ override_stacksize = 0;
+ }
+
+ /* Do we need to allocate the new thread's stack? */
+ if (override_stack == NULL)
+ {
+ uintptr_t alignment = 256; /* power of two */
+
+ /* Perturb the initial stack addresses slightly, to encourage
+ threads to have nonconflicting entries in the lookup cache
+ for their tracked stack objects. */
+ static unsigned perturb = 0;
+ const unsigned perturb_delta = 0; /* 32; */
+ const unsigned perturb_count = 16;
+ perturb += perturb_delta;
+ if (perturb > perturb_delta*perturb_count) perturb = 0;
+
+ /* Use glibc x86 defaults */
+ if (override_stacksize < alignment)
+/* Should have been defined in <limits.h> */
+#ifndef PTHREAD_STACK_MIN
+#define PTHREAD_STACK_MIN 65536
+#endif
+ override_stacksize = max (PTHREAD_STACK_MIN, 2 * 1024 * 1024);
+
+ override_stack = CALL_REAL (malloc, override_stacksize);
+ if (override_stack == NULL)
+ {
+ errno = EAGAIN;
+ pi->used_p = 0;
+ return -1;
+ }
+
+ pi->stack = override_stack;
+ pi->stack_size = override_stacksize;
+
+ /* The stackaddr pthreads attribute is a candidate stack pointer.
+ It must point near the top or the bottom of this buffer, depending
+ on whether stack grows downward or upward, and suitably aligned.
+ On the x86, it grows down, so we set stackaddr near the top. */
+ override_stack = (void *)
+ (((uintptr_t) override_stack + override_stacksize - alignment - perturb)
+ & (~(uintptr_t)(alignment-1)));
+
+ /* XXX: consider using POSIX2K attr_setstack() */
+ if (pthread_attr_setstackaddr (& override_attr, override_stack) != 0 ||
+ pthread_attr_setstacksize (& override_attr,
+ override_stacksize - alignment - perturb) != 0)
+ {
+ /* This should not happen. */
+ CALL_REAL (free, pi->stack);
+ pi->stack = NULL;
+ errno = EAGAIN;
+ pi->used_p = 0;
+ return -1;
+ }
+
+ }
+
+ /* Fill in remaining fields. */
+ pi->user_fn = start;
+ pi->user_arg = arg;
+ pi->dead_p = 0;
+ pi->state = active;
+
+ /* Actually create the thread. */
+ result = CALL_REAL (pthread_create, thr, & override_attr,
+ & __mf_pthread_spawner, (void *) pi);
+
+ /* May need to clean up if we created a pthread_attr_t of our own. */
+ if (attr == NULL)
+ pthread_attr_destroy (& override_attr); /* NB: this shouldn't deallocate stack */
+
+ return result;
+}
+
+
+#endif /* pthreadstuff */
Index: mf-impl.h
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/Attic/mf-impl.h,v
retrieving revision 1.1.2.23
diff -u -p -w -s -r1.1.2.23 mf-impl.h
--- mf-impl.h 25 Jun 2003 20:37:38 -0000 1.1.2.23
+++ mf-impl.h 4 Jul 2003 22:59:49 -0000
@@ -71,13 +71,7 @@ extern int __mf_heuristic_check (uintptr
/* The mf_state type codes describe recursion and initialization order. */
-enum __mf_state
- {
- inactive,
- starting,
- active,
- reentrant
- };
+enum __mf_state_enum { active, reentrant };
/* The __mf_options structure records optional or tunable aspects of the
mudflap library's behavior. There is a single global instance of this
@@ -212,7 +206,14 @@ extern pthread_mutex_t __mf_biglock;
#define UNLOCKTH() do {} while (0)
#endif
-extern /* volatile? */ enum __mf_state __mf_state;
+#ifdef LIBMUDFLAPTH
+extern enum __mf_state_enum *__mf_state_perthread ();
+#define __mf_state (* __mf_state_perthread ())
+#else
+extern enum __mf_state_enum __mf_state;
+#endif
+extern int __mf_starting_p;
+
extern struct __mf_options __mf_opts;
/* ------------------------------------------------------------------------ */
@@ -223,16 +224,30 @@ extern struct __mf_options __mf_opts;
#define LIKELY(e) (__builtin_expect (!!(e), 1))
#define STRINGIFY2(e) #e
#define STRINGIFY(e) STRINGIFY2(e)
+
+#ifdef LIBMUDFLAPTH
#define VERBOSE_TRACE(...) \
- if (UNLIKELY (__mf_opts.verbose_trace)) \
- { \
+ do { if (UNLIKELY (__mf_opts.verbose_trace)) { \
+ fprintf (stderr, "mf(%u): ", (unsigned) pthread_self ()); \
fprintf (stderr, __VA_ARGS__); \
- }
+ } } while (0)
#define TRACE(...) \
- if (UNLIKELY (__mf_opts.trace_mf_calls)) \
- { \
+ do { if (UNLIKELY (__mf_opts.trace_mf_calls)) { \
+ fprintf (stderr, "mf(%u): ", (unsigned) pthread_self ()); \
fprintf (stderr, __VA_ARGS__); \
- }
+ } } while (0)
+#else
+#define VERBOSE_TRACE(...) \
+ do { if (UNLIKELY (__mf_opts.verbose_trace)) { \
+ fprintf (stderr, "mf: "); \
+ fprintf (stderr, __VA_ARGS__); \
+ } } while (0)
+#define TRACE(...) \
+ do { if (UNLIKELY (__mf_opts.trace_mf_calls)) { \
+ fprintf (stderr, "mf: "); \
+ fprintf (stderr, __VA_ARGS__); \
+ } } while (0)
+#endif
#define __MF_PERSIST_MAX 256
@@ -283,7 +298,7 @@ ret fname (__VA_ARGS__)
typedef ty (*__mf_fn_ ## fname) (__VA_ARGS__); \
extern ty __mf_0fn_ ## fname (__VA_ARGS__);
#define CALL_REAL(fname, ...) \
- ({(__mf_state == starting) \
+ ({__mf_starting_p \
? __mf_0fn_ ## fname (__VA_ARGS__) \
: (__mf_resolve_single_dynamic (& __mf_dynamic[dyn_ ## fname]), \
(((__mf_fn_ ## fname)(__mf_dynamic[dyn_ ## fname].pointer)) (__VA_ARGS__)));})
@@ -306,6 +321,39 @@ ret __wrap_ ## fname (__VA_ARGS__)
/* WRAPPER2 is for functions intercepted via macros at compile time. */
#define WRAPPER2(ret, fname, ...) \
ret __mfwrap_ ## fname (__VA_ARGS__)
+
+
+/* Utility macros for mf-hooks*.c */
+
+#define MF_VALIDATE_EXTENT(value,size,acc,context) \
+ do { \
+ if (UNLIKELY (size > 0 && __MF_CACHE_MISS_P (value, size))) \
+ __mf_check ((void *) (value), (size), acc, "(" context ")"); \
+ } while (0)
+#define BEGIN_PROTECT(ty, fname, ...) \
+ ty result; \
+ if (UNLIKELY (__mf_state == reentrant)) \
+ { \
+ extern unsigned long __mf_reentrancy; \
+ if (UNLIKELY (__mf_opts.verbose_trace)) { \
+ write (2, "mf: reentrancy detected in `", 28); \
+ write (2, __PRETTY_FUNCTION__, strlen(__PRETTY_FUNCTION__)); \
+ write (2, "'\n", 2); } \
+ __mf_reentrancy ++; \
+ return CALL_REAL(fname, __VA_ARGS__); \
+ } \
+ else if (UNLIKELY (__mf_starting_p)) \
+ { \
+ return CALL_BACKUP(fname, __VA_ARGS__); \
+ } \
+ else \
+ { \
+ TRACE ("%s\n", __PRETTY_FUNCTION__); \
+ }
+
+#define END_PROTECT(ty, fname, ...) \
+ result = (ty) CALL_REAL(fname, __VA_ARGS__); \
+ return result;
/* Unlocked variants of main entry points from mf-runtime.h. */
Index: mf-runtime.c
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/Attic/mf-runtime.c,v
retrieving revision 1.1.2.42
diff -u -p -w -s -r1.1.2.42 mf-runtime.c
--- mf-runtime.c 25 Jun 2003 20:37:38 -0000 1.1.2.42
+++ mf-runtime.c 4 Jul 2003 22:59:49 -0000
@@ -85,7 +85,14 @@ unsigned char __mf_lc_shift = LOOKUP_CAC
#define LOOKUP_CACHE_SIZE (__mf_lc_mask + 1)
struct __mf_options __mf_opts;
-enum __mf_state __mf_state = starting;
+
+int __mf_starting_p = 1;
+#ifndef LIBMUDFLAPTH
+enum __mf_state_enum __mf_state = active;
+#else
+/* See __mf_state_perthread() in mf-hooks.c. */
+#endif
+
#ifdef LIBMUDFLAPTH
pthread_mutex_t __mf_biglock =
@@ -165,19 +172,6 @@ static __mf_object_tree_t *__mf_object_r
static unsigned __mf_object_dead_head[__MF_TYPE_MAX_CEM+1]; /* next empty spot */
static __mf_object_tree_t *__mf_object_cemetary[__MF_TYPE_MAX_CEM+1][__MF_PERSIST_MAX];
-/* Deferred registration/unregistration requests. */
-typedef struct {
- int register_p; /* or else unregister */
- void *base;
- size_t size;
- int type;
- char *name;
-} deferred_request_t;
-
-#define MAX_DEFERRED_REQUESTS 2000
-static deferred_request_t __mf_deferred_requests[MAX_DEFERRED_REQUESTS];
-static unsigned __mf_num_deferred_requests = 0;
-
/* ------------------------------------------------------------------------ */
/* Forward function declarations */
@@ -397,6 +391,9 @@ __mf_set_options (const char *optstr)
LOCKTH ();
BEGIN_RECURSION_PROTECT ();
rc = __mfu_set_options (optstr);
+ /* XXX: It's not really that easy. A change to a bunch of parameters
+ can require updating auxiliary state or risk crashing:
+ free_queue_length, crumple_zone ... */
END_RECURSION_PROTECT ();
UNLOCKTH ();
return rc;
@@ -496,7 +493,7 @@ __mfu_set_options (const char *optstr)
/* void slot 0 */
__mf_lookup_cache[0].low = MAXPTR;
- TRACE ("mf: set options from `%s'\n", saved_optstr);
+ TRACE ("set options from `%s'\n", saved_optstr);
/* Call this unconditionally, in case -sigusr1-report was toggled. */
__mf_sigusr1_respond ();
@@ -573,10 +570,11 @@ void __mf_init ()
{
char *ov = 0;
+ /* This initial bootstrap phase requires that __mf_starting_p = 1. */
#ifdef PIC
__mf_resolve_dynamics ();
#endif
- __mf_state = active;
+ __mf_starting_p = 0;
__mf_set_default_options ();
@@ -656,7 +654,7 @@ __wrap_main (int argc, char* argv[])
extern void __mf_fini () DTOR;
void __mf_fini ()
{
- TRACE ("mf: __mf_fini\n");
+ TRACE ("__mf_fini\n");
__mfu_report ();
}
@@ -687,7 +685,7 @@ void __mfu_check (void *ptr, size_t sz,
if (UNLIKELY (__mf_opts.sigusr1_report))
__mf_sigusr1_respond ();
- TRACE ("mf: check ptr=%p b=%u size=%lu %s location=`%s'\n",
+ TRACE ("check ptr=%p b=%u size=%lu %s location=`%s'\n",
ptr, entry_idx, sz, (type == 0 ? "read" : "write"), location);
switch (__mf_opts.mudflap_mode)
@@ -988,7 +986,7 @@ __mf_register (void *ptr, size_t sz, int
void
__mfu_register (void *ptr, size_t sz, int type, const char *name)
{
- TRACE ("mf: register ptr=%p size=%lu type=%x name='%s'\n", ptr, sz,
+ TRACE ("register ptr=%p size=%lu type=%x name='%s'\n", ptr, sz,
type, name ? name : "");
if (__mf_opts.collect_stats)
@@ -1048,7 +1046,7 @@ __mfu_register (void *ptr, size_t sz, in
&& ovr_obj->data.high == high)
{
/* do nothing */
- VERBOSE_TRACE ("mf: duplicate static reg %p-%p `%s'\n",
+ VERBOSE_TRACE ("duplicate static reg %p-%p `%s'\n",
low, high,
(ovr_obj->data.name ? ovr_obj->data.name : ""));
break;
@@ -1062,7 +1060,7 @@ __mfu_register (void *ptr, size_t sz, in
ovr_obj->data.high == high)
{
/* do nothing */
- VERBOSE_TRACE ("mf: duplicate guess reg %p-%p\n", low, high);
+ VERBOSE_TRACE ("duplicate guess reg %p-%p\n", low, high);
break;
}
@@ -1088,7 +1086,7 @@ __mfu_register (void *ptr, size_t sz, in
num_overlapping_objs);
assert (num_ovr_objs == num_overlapping_objs);
- VERBOSE_TRACE ("mf: splitting guess %p-%p, # overlaps: %u\n",
+ VERBOSE_TRACE ("splitting guess %p-%p, # overlaps: %u\n",
low, high, num_ovr_objs);
/* Add GUESS regions between the holes: before each
@@ -1187,7 +1185,7 @@ __mfu_unregister (void *ptr, size_t sz)
if (UNLIKELY (__mf_opts.sigusr1_report))
__mf_sigusr1_respond ();
- TRACE ("mf: unregister ptr=%p size=%lu\n", ptr, sz);
+ TRACE ("unregister ptr=%p size=%lu\n", ptr, sz);
switch (__mf_opts.mudflap_mode)
{
@@ -1422,7 +1420,7 @@ __mf_tree_analyze (__mf_object_tree_t *o
unsigned i;
uintptr_t addr;
- VERBOSE_TRACE ("mf: analyze low=%p live=%u name=`%s'\n",
+ VERBOSE_TRACE ("analyze low=%p live=%u name=`%s'\n",
obj->data.low, obj->data.liveness, obj->data.name);
s->live_obj_count ++;
@@ -1498,7 +1496,7 @@ __mf_adapt_cache ()
new_mask |= 0x3ff; /* XXX: force a large cache. */
new_mask &= (LOOKUP_CACHE_SIZE_MAX - 1);
- VERBOSE_TRACE ("mf: adapt cache obj=%u/%u sizes=%lu/%.0f/%.0f => "
+ VERBOSE_TRACE ("adapt cache obj=%u/%u sizes=%lu/%.0f/%.0f => "
"util=%u%% m=%p s=%u\n",
s.obj_count, s.live_obj_count, s.total_size, s.total_weight, s.weighted_size,
(unsigned)(cache_utilization*100.0), new_mask, new_shift);
@@ -2042,7 +2040,7 @@ __mf_violation (void *ptr, size_t sz, ui
static unsigned violation_number;
DECLARE(void, free, void *ptr);
- TRACE ("mf: violation pc=%p location=%s type=%d ptr=%p size=%lu\n", pc,
+ TRACE ("violation pc=%p location=%s type=%d ptr=%p size=%lu\n", pc,
(location != NULL ? location : ""), type, ptr, sz);
if (__mf_opts.collect_stats)
@@ -2214,7 +2212,7 @@ __mf_watch_or_not (void *ptr, size_t sz,
uintptr_t ptr_low = (uintptr_t) ptr;
unsigned count = 0;
- TRACE ("mf: %s ptr=%p size=%lu",
+ TRACE ("%s ptr=%p size=%lu",
(flag ? "watch" : "unwatch"), ptr, sz);
switch (__mf_opts.mudflap_mode)
Index: mf-runtime.h.in
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/Attic/mf-runtime.h.in,v
retrieving revision 1.1.2.14
diff -u -p -w -s -r1.1.2.14 mf-runtime.h.in
--- mf-runtime.h.in 18 Jun 2003 17:08:32 -0000 1.1.2.14
+++ mf-runtime.h.in 4 Jul 2003 22:59:49 -0000
@@ -25,6 +25,8 @@ extern unsigned char __mf_lc_shift;
/* Multithreading support. */
#ifdef _MUDFLAPTH
/* extern pthread_mutex_t __mf_biglock; */
+#define _REENTRANT
+#define _THREAD_SAFE
#endif
/* Codes to describe the type of access to check: __mf_check arg 3 */
Index: testsuite/lib/mfdg.exp
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/testsuite/lib/Attic/mfdg.exp,v
retrieving revision 1.1.2.2
diff -u -p -w -s -r1.1.2.2 mfdg.exp
--- testsuite/lib/mfdg.exp 5 Mar 2003 19:08:05 -0000 1.1.2.2
+++ testsuite/lib/mfdg.exp 4 Jul 2003 22:59:49 -0000
@@ -39,6 +39,9 @@ proc dg-test { args } {
set keep 0
set i 0
+ set dg-repetitions 1 ;# may be overridden by { dg-repetitions N }
+ global dg-timeout
+ set dg-timeout 0 ;# likewise by { dg-timeout N }
if { [string index [lindex $args 0] 0] == "-" } {
for { set i 0 } { $i < [llength $args] } { incr i } {
@@ -254,14 +257,17 @@ proc dg-test { args } {
if ![file exists $output_file] {
warning "$name compilation failed to produce executable"
} else {
+ set testname $name
+ for {set rep 0} {$rep < ${dg-repetitions}} {incr rep} {
+ # include repetition number in test name
+ if {$rep > 0} { set name "$testname (rerun $rep)" }
+
set status -1
set result [${tool}_load $output_file]
set status [lindex $result 0];
set output [lindex $result 1];
#send_user "After exec, status: $status\n"
- # FChE: reorganized logic below
-
if { "$status" == "pass" } {
verbose "Exec succeeded." 3
} elseif { "$status" == "fail" } {
@@ -298,6 +304,7 @@ proc dg-test { args } {
}
}
}
+ }
# Are there any further tests to perform?
# Note that if the program has special run-time requirements, running
@@ -325,4 +332,46 @@ proc dg-test { args } {
if { ! ${keep} && ${dg-interpreter-batch-mode} == 0 } {
catch "exec rm -f $output_file"
}
+}
+
+
+
+#
+# Indicate that this test case is to be rerun several times. This
+# is useful if it is nondeterministic. This applies to rerunning the
+# test program only, not rebuilding it.
+# The embedded format is "{ dg-repetitions N }", where N is the number
+# of repetitions. It better be greater than zero.
+#
+proc dg-repetitions { line value } {
+ upvar dg-repetitions repetitions
+ set repetitions $value
+}
+
+
+#
+# Indicate that this test case is to be run with a short timeout.
+# The embedded format is "{ dg-timeout N }", where N is in seconds.
+#
+proc dg-timeout { line value } {
+ global dg-timeout
+ set dg-timeout $value
+}
+
+
+# dejagnu's config/unix.exp hard-codes 300 seconds as the timeout
+# for any natively run executable. That's too long for tests run
+# multiple times and that may possibly hang. So we override it here
+# to provide some degree of control.
+rename standard_wait hooked_standard_wait
+proc standard_wait { dest timeout } {
+ global dg-timeout
+ if {[info exists dg-timeout]} {
+ if {${dg-timeout} > 0} {
+ verbose -log "Overriding timeout = ${dg-timeout}"
+ set timeout ${dg-timeout}
+ }
+ }
+
+ hooked_standard_wait $dest $timeout
}
Index: testsuite/libmudflap.cth/pass37-frag.c
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/testsuite/libmudflap.cth/Attic/pass37-frag.c,v
retrieving revision 1.1.2.2
diff -u -p -w -s -r1.1.2.2 pass37-frag.c
--- testsuite/libmudflap.cth/pass37-frag.c 11 Jun 2003 18:15:56 -0000 1.1.2.2
+++ testsuite/libmudflap.cth/pass37-frag.c 4 Jul 2003 22:59:50 -0000
@@ -52,4 +52,7 @@ int main ()
return 0;
}
+
/* { dg-output "100 100 100 100 100 100 100 100 100 100" } */
+/* { dg-repetitions 20 } */
+/* { dg-timeout 3 } */
Index: testsuite/libmudflap.cth/pass39-frag.c
===================================================================
RCS file: testsuite/libmudflap.cth/pass39-frag.c
diff -N testsuite/libmudflap.cth/pass39-frag.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/libmudflap.cth/pass39-frag.c 4 Jul 2003 22:59:50 -0000
@@ -0,0 +1,57 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <sched.h>
+#include <assert.h>
+
+static void *
+func (void *p)
+{
+ int *counter = (int *) p;
+ unsigned i;
+ enum { numarrays = 100, numels = 17 };
+ char *arrays [numarrays];
+
+ for (i=0; i<numarrays; i++)
+ {
+ (*counter) ++;
+ unsigned x = i % numels;
+ arrays[i] = calloc (numels, sizeof(arrays[i][0]));
+ assert (arrays[i] != NULL);
+ arrays[i][x] = i;
+ free (arrays[i]);
+ sched_yield (); /* sleep (1); */
+ }
+
+ return (NULL);
+}
+
+
+int main ()
+{
+ int rc;
+ unsigned i;
+ enum foo { NT=10 };
+ pthread_t threads[NT];
+ int counts[NT];
+
+
+ for (i=0; i<NT; i++)
+ {
+ counts[i] = 0;
+ rc = pthread_create (& threads[i], NULL, func, (void *) & counts[i]);
+ if (rc) abort();
+ }
+
+ for (i=0; i<NT; i++)
+ {
+ rc = pthread_join (threads[i], NULL);
+ if (rc) abort();
+ printf ("%d%s", counts[i], (i==NT-1) ? "\n" : " ");
+ }
+
+ return 0;
+}
+/* { dg-output "100 100 100 100 100 100 100 100 100 100" } */
+/* { dg-repetitions 20 } */
+/* { dg-timeout 3 } */
More information about the Gcc-patches
mailing list