This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[tree-ssa libmudflap] basic pthread support [long]


Hi -

The following patch adds basic support for mudflap checking
of pthread-based multithreaded applications.  The effect is to
put a single big lock around libmudflap entry functions.  The
lookup cache is not specifically protected during the inlined
checks - I'm ambivalent about its necessity and implications.

To use this libmudflap variant, one needs to use a different
gcc flag to compile/link the program: "-fmudflapth" (th=threads).
For shared linking, one should generally *not* specify "-lpthread"
on the link command line explicitly, for it would precede
libmudflap and prevent proper interposition.

There were some interesting complications along the way:
linuxthreads likes to allocate child thread stacks in a special
manager thread, whose own stack is too small to run enter
libmudflap.  So we prefer to allocate child thread stacks from
within the caller by fidgeting with the pthread_attr_t value.

Another interesting bit again comes up with linux/glibc: when
we're done with libmudflap's interposed pthread_create call,
and want to call the real function, plain dlsym() doesn't work.
That's because glibc uses symbol versioning to provide multiple
alternate pthread_create entry points (for use by older binaries),
and dlsym() can pick the wrong one.  So a bunch of weird configury
work was necessary to teach libmudflap to find the proper symbol
version during configuration time, and use a custom dlvsym()
function to use it at run time.  Please keep your lunch down.

Getting it to just build on Solaris and IRIX adds to the mess.
There are some minor cleanups mixed in there too.

[gcc]

Index: ChangeLog.tree-ssa
+2003-05-09  Frank Ch. Eigler  <fche@redhat.com>
+
+	* toplev.c (lang_independent_options): Add "-fmudflapth".
+	* flags.h (flag_mudflap): Document meaning of >1 value.
+	* gcc.c (MFWRAP_SPEC, MFLIB_SPEC): Add -fmudflapth support.
+	(cpp_unique_options, cc1_options): Ditto.
+

Index: flags.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flags.h,v
retrieving revision 1.86.2.23
diff -u -p -r1.86.2.23 flags.h
--- flags.h	7 May 2003 13:27:56 -0000	1.86.2.23
+++ flags.h	9 May 2003 21:45:23 -0000
@@ -659,7 +659,8 @@ extern int flag_detailed_statistics;
 /* Nonzero means enable synchronous exceptions for non-call instructions.  */
 extern int flag_non_call_exceptions;
 
-/* Nonzero means enable mudflap bounds-checking transforms. */
+/* Nonzero means enable mudflap bounds-checking transforms;
+   >1 means also to include multithreading locks.  */
 extern int flag_mudflap;
 
 /* Disable tree simplification.  */
Index: gcc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcc.c,v
retrieving revision 1.324.2.28
diff -u -p -r1.324.2.28 gcc.c
--- gcc.c	7 May 2003 13:28:00 -0000	1.324.2.28
+++ gcc.c	9 May 2003 21:45:24 -0000
@@ -611,13 +611,14 @@ proper position among the other output f
 /* XXX: valid only if linking with static libmudflap.a */
 /* XXX: valid only for GNU ld */
 /* XXX: should exactly match hooks provided by libmudflap.a */
-#define MFWRAP_SPEC " %{fmudflap: %{static:\
+#define MFWRAP_SPEC " %{static: %{fmudflap|fmudflapth: \
  --wrap=malloc --wrap=free --wrap=calloc --wrap=realloc\
  --wrap=mmap --wrap=munmap --wrap=alloca\
+} %{fmudflapth: --wrap=pthread_create\
 }}"
 #endif
 #ifndef MFLIB_SPEC
-#define MFLIB_SPEC " %{fmudflap: -export-dynamic -lmudflap %{static:%(link_gcc_c_sequence) -lmudflap}}"
+#define MFLIB_SPEC " %{fmudflap: -export-dynamic -lmudflap %{static:%(link_gcc_c_sequence) -lmudflap}} %{fmudflapth: -export-dynamic -lmudflapth -lpthread %{static:%(link_gcc_c_sequence) -lmudflapth}} "
 #endif
 
 /* config.h can define LIBGCC_SPEC to override how and when libgcc.a is
@@ -759,6 +760,7 @@ static const char *cpp_unique_options =
  %{!undef:%{!ansi:%{!std=*:%p}%{std=gnu*:%p}} %P} %{trigraphs}\
  %{remap} %{g3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i\
  %{fmudflap:-D_MUDFLAP -include mf-runtime.h}\
+ %{fmudflapth:-D_MUDFLAP -D_MUDFLAPTH -include mf-runtime.h}\
  %{E|M|MM:%W{o*}}";
 
 /* This contains cpp options which are common with cc1_options and are passed
@@ -785,7 +787,7 @@ static const char *cc1_options =
  %{--target-help:--target-help}\
  %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
  %{fsyntax-only:-o %j} %{-param*}\
- %{fmudflap:-fmudflap -fno-builtin -fno-merge-constants}";
+ %{fmudflap|fmudflapth:-fmudflap -fno-builtin -fno-merge-constants}";
 
 static const char *asm_options =
 "%a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}";
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.654.2.50
diff -u -p -r1.654.2.50 toplev.c
--- toplev.c	7 May 2003 13:28:26 -0000	1.654.2.50
+++ toplev.c	9 May 2003 21:45:25 -0000
@@ -1255,6 +1255,8 @@ static const lang_independent_options f_
    N_("Trap for signed overflow in addition / subtraction / multiplication") },
   { "mudflap", &flag_mudflap, 1,
    N_("Add mudflap bounds-checking instrumentation") },
+  { "mudflapth", &flag_mudflap, 2,
+   N_("Add mudflap instrumentation, with multithreading support") },
   { "new-ra", &flag_new_regalloc, 1,
    N_("Use graph coloring register allocation.") },
   { "disable-simple", &flag_disable_simple, 1,

[libmudflap]
+2003-05-09  Frank Ch. Eigler  <fche@redhat.com>
+
+	* configure.in: Add pthread support, plus glibc and porting hacks.
+	* Makefile.am (LIBMUDFLAPTH): New conditional, to build -lmudflapth
+	from objects built into ./pth/.
+	* mf-runtime.c (__mfu_watch,register,...): Fork new unlocked
+	functions for internal entry points.  Update callers to pick
+	locked vs. unlocked variants.
+	(__mf_resolve_single_dynamic): Extend to support symbol versioning
+	info coming in from a static data structure.
+	(*): Reorder miscellaneous declarations to group data vs functions.
+	(__mf_set_default_options): Simplify.
+	(__mf_usage): Mention threading status of host executable.
+	* mf-impl.h: Move max/min decls here.  Reorganize __mf_dynamic
+	decls to match above.
+	(LOCKTH, UNLOCKTH): New macros for Big Libmudflap Lock management.
+	* mf-heuristics.c: Choose between locked/unlocked calls.  Add
+	some lock/unlock markers.  Remove some unused code.
+	* mf-hooks: Ditto.
+	(pthread_create): New hook function.
+	(__mf_pthread_cleanup, _spawner): New helper functions.
+	* configure. aclocal.m4, config.h.in, Makefile.in: Regenerated.
+

Index: Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/Attic/Makefile.am,v
retrieving revision 1.1.2.27
diff -u -p -r1.1.2.27 Makefile.am
--- Makefile.am	28 Apr 2003 15:17:09 -0000	1.1.2.27
+++ Makefile.am	9 May 2003 21:29:16 -0000
@@ -10,7 +10,13 @@ SUBDIRS = testsuite
 
 AM_CFLAGS = -ansi -Wall
 
-lib_LTLIBRARIES = libmudflap.la
+if LIBMUDFLAPTH
+libmudflapth = libmudflapth.la
+else
+libmudflapth =
+endif
+
+lib_LTLIBRARIES = libmudflap.la $(libmudflapth)
 include_HEADERS = mf-runtime.h
 
 libmudflap_la_SOURCES = \
@@ -57,14 +63,70 @@ HOOKOBJS = \
  gmtime-hook.lo \
  localtime-hook.lo
 
-#.NOTPARALLEL: # Otherwise the following loop will be executed in parallel!
 $(HOOKOBJS): mf-hooks.c mf-runtime.h mf-impl.h
 	hook=`basename $@ -hook.lo`; \
 	$(LTCOMPILE) -DWRAP_$$hook -c $(srcdir)/mf-hooks.c -o $@
 
-libmudflap_la_LDFLAGS = 
+# Hook objects only for libmudflapth use 
+PTHHOOKOBJS= \
+ pth/malloc-hook.lo \
+ pth/free-hook.lo \
+ pth/calloc-hook.lo \
+ pth/realloc-hook.lo \
+ pth/memcpy-hook.lo \
+ pth/memmove-hook.lo \
+ pth/memset-hook.lo \
+ pth/memcmp-hook.lo \
+ pth/memchr-hook.lo \
+ pth/memrchr-hook.lo \
+ pth/strcpy-hook.lo \
+ pth/strncpy-hook.lo \
+ pth/strcat-hook.lo \
+ pth/strncat-hook.lo \
+ pth/strcmp-hook.lo \
+ pth/strcasecmp-hook.lo \
+ pth/strncmp-hook.lo \
+ pth/strncasecmp-hook.lo \
+ pth/strdup-hook.lo \
+ pth/strndup-hook.lo \
+ pth/strchr-hook.lo \
+ pth/strrchr-hook.lo \
+ pth/strstr-hook.lo \
+ pth/memmem-hook.lo \
+ pth/strlen-hook.lo \
+ pth/strnlen-hook.lo \
+ pth/bzero-hook.lo \
+ pth/bcopy-hook.lo \
+ 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
+
+clean-local:
+	rm -f pth/*.o pth/*.lo
+
+libmudflapth_la_SOURCES =
+pth/mf-runtime.lo: mf-runtime.c mf-runtime.h mf-impl.h
+	$(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
+	hook=`basename $@ -hook.lo`; \
+	$(LTCOMPILE) -DLIBMUDFLAPTH -DWRAP_$$hook -c $(srcdir)/mf-hooks.c -o $@
+
 libmudflap_la_LIBADD = $(HOOKOBJS)
 libmudflap_la_DEPENDENCIES = $(libmudflap_la_LIBADD)
+
+libmudflapth_la_LIBADD = pth/mf-runtime.lo pth/mf-heuristics.lo $(PTHHOOKOBJS)
+libmudflapth_la_DEPENDENCIES = $(libmudflapth_la_LIBADD)
+
 
 
 # XXX hack alert
Index: configure.in
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/Attic/configure.in,v
retrieving revision 1.1.2.14
diff -u -p -r1.1.2.14 configure.in
--- configure.in	28 Apr 2003 15:17:09 -0000	1.1.2.14
+++ configure.in	9 May 2003 21:29:16 -0000
@@ -20,6 +20,34 @@ AC_SUBST(target_alias)
 
 AM_CONFIG_HEADER(config.h)
 
+AC_LANG_C
+AC_PROG_CC
+if test "x$GCC" != "xyes"; then
+  AC_MSG_ERROR([libmudflap must be built with GCC])
+fi
+AC_PROG_CPP
+
+# Some hosts don't have dlsym(RTLD_NEXT, "symbol") for use in
+# symbol interposition.  We disable shared libraries for these.
+AC_MSG_CHECKING([whether dlsym(RTLD_NEXT,...) is available])
+AC_TRY_COMPILE([
+#define _GNU_SOURCE
+#include <dlfcn.h>
+],
+[void *foo = dlsym (RTLD_NEXT, "exit");],
+[AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)
+enable_shared=no])
+
+AC_CHECK_HEADERS(stdint.h execinfo.h signal.h pthread.h dlfcn.h)
+AC_CHECK_FUNCS(backtrace backtrace_symbols gettimeofday signal)
+
+# Disable shared libraries for hosts without pthread.h
+if test "x$ac_have_pthread_h" = ""; then
+   enable_shared=no
+fi
+
+
 AC_LIBTOOL_DLOPEN
 AM_PROG_LIBTOOL
 AC_SUBST(enable_shared)
@@ -36,16 +64,53 @@ else
 fi
 AC_SUBST(MF_HAVE_UINTPTR_T)
 
-AC_CHECK_HEADERS(stdint.h execinfo.h signal.h pthread.h)
-AC_CHECK_FUNCS(backtrace backtrace_symbols gettimeofday signal)
+if test ! -d pth
+then
+  # libmudflapth objects are built in this subdirectory
+  mkdir pth
+fi
+
+pthread_create_version='""'
+AM_CONDITIONAL(LIBMUDFLAPTH, [test "x$ac_have_pthread_h" != ""])
+
 AC_CHECK_LIB(dl, dlsym)
 
-if ${CONFIG_SHELL-/bin/sh} ./libtool --tag CC --features |
-   grep "enable shared" > /dev/null; then
-  LIBMUDFLAP_PICFLAGS=-prefer-pic
-else
-  LIBMUDFLAP_PICFLAGS=
+if test "x$enable_shared" = "xyes" && test "x$ac_have_pthread_h" != ""; then
+  # NB: don't check for -lpthread here, because then it would be
+  # added to LIBS.  For the thread-unaware libmudflap.la, we don't
+  # want it there.
+
+  # glibc-related hacks.  dlsym() may pick the wrong version of
+  # interposed functions like pthread_create on modern glibc.
+  # We need to find the proper symbol version string, and use
+  # the nonstandard dlvsym().
+  AC_CHECK_FUNCS(dlvsym)
+  AC_CHECK_TOOL(NM, nm)
+  if test "x$ac_cv_have_dlvsym" != ""; then
+    # Try compiling a simple pthreads program.  Find the shared libraries it
+    # ends up with.  Then use "nm" on those libraries to extract the
+    # default symbol versioning suffix ("@@"), if any.  But that's tricky.
+    # Rather, run nm on the resulting executable.  Unfortunately, autoconf
+    # doesn't appear to have a macro that builds a test executable for
+    # subsequent analysis ... so we do it by hand here. 
+    cat >> conftest.c << EOF
+#include <pthread.h>
+int main () { void *p = (void *) & pthread_create; return (int) p; }
+EOF
+    oldLIBS="$LIBS"
+    LIBS="$LIBS -lpthread"
+    AC_MSG_CHECKING(pthread_create symbol version)
+    if eval $ac_link 2>&5 && test -s conftest${ac_exeext}; then
+      version=`$NM conftest${ac_exeect} | grep 'pthread_create@@' | sed -e 's/^.*@@//'`
+      if test "x$version" != "x"; then
+        pthread_create_version="\"$version\""
+        AC_MSG_RESULT($pthread_create_version)
+      fi
+    fi
+    LIBS="$oldLIBS"
+  fi
 fi
-AC_SUBST(LIBMUDFLAP_PICFLAGS)
+AC_DEFINE_UNQUOTED(PTHREAD_CREATE_VERSION, $pthread_create_version, [pthread_create symbol version])   
+
 
 AC_OUTPUT([Makefile testsuite/Makefile mf-runtime.h])
Index: mf-heuristics.c
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/Attic/mf-heuristics.c,v
retrieving revision 1.1.2.12
diff -u -p -r1.1.2.12 mf-heuristics.c
--- mf-heuristics.c	5 Mar 2003 19:08:04 -0000	1.1.2.12
+++ mf-heuristics.c	9 May 2003 21:29:16 -0000
@@ -1,4 +1,3 @@
-
 /* Mudflap: narrow-pointer bounds-checking by tree rewriting.
    Copyright (C) 2002, 2003 Free Software Foundation, Inc.
    Contributed by Frank Ch. Eigler <fche@redhat.com>
@@ -9,7 +8,10 @@
    XXX: libgcc license?
 */
 
+#include "config.h"
+
 #include <stdio.h>
+
 #include "mf-runtime.h"
 #include "mf-impl.h"
 
@@ -17,23 +19,15 @@
 #error "Do not compile this file with -fmudflap!"
 #endif
 
-/* XXX */
+
 extern char _end;
 extern char _start;
+/* XXX: linux-x86 specific */
 static const uintptr_t stack_segment_base = 0xC0000000;
 static const uintptr_t stack_segment_top  = 0xBF800000;
 
 
-static int
-is_stack_address (uintptr_t addr)
-{
-  return 
-    (addr <= stack_segment_base) &&
-    (addr >= stack_segment_top);
-}
-
-
-#if 0
+#if 0 /* if only glibc exported these */
 /* These are used by heur_argv_envp below.  */
 static int system_argc;
 static char **system_argv;
@@ -147,9 +141,9 @@ __mf_heuristic_check (uintptr_t ptr, uin
 			  
 			  /* XXX: bad hack; permit __mf_register to do its job.  */
 			  __mf_state = active;
-			  __mf_register ((uintptr_t) low, (uintptr_t) (high-low),
-					 __MF_TYPE_GUESS, 
-					 "/proc/self/maps segment");
+			  __mfu_register ((uintptr_t) low, (uintptr_t) (high-low),
+					  __MF_TYPE_GUESS, 
+					  "/proc/self/maps segment");
 			  __mf_state = reentrant;
 			  
 			  return 0; /* undecided (tending to cachable) */
@@ -185,7 +179,7 @@ __mf_heuristic_check (uintptr_t ptr, uin
 	      int i;
 	      while (system_envp[envp_length]) envp_length ++;
 	      if (envp_length)
-		__mf_register ((uintptr_t) system_envp,
+		__mfu_register ((uintptr_t) system_envp,
 			       (uintptr_t) (sizeof (char*) * (envp_length + 1)),
 			       __MF_TYPE_GUESS, "environ[]");
 
@@ -195,7 +189,7 @@ __mf_heuristic_check (uintptr_t ptr, uin
 		  if (env)
 		    {
 		      unsigned len = strlen (env);
-		      __mf_register ((uintptr_t) env,
+		      __mfu_register ((uintptr_t) env,
 				     (uintptr_t) len+1,
 				     __MF_TYPE_GUESS,
 				     "envp[i]");
@@ -208,7 +202,7 @@ __mf_heuristic_check (uintptr_t ptr, uin
 	    {
 	      int i;
 
-	      __mf_register ((uintptr_t) system_argv,
+	      __mfu_register ((uintptr_t) system_argv,
 			     (uintptr_t) (sizeof (char *) * (system_argc + 1)),
 			     __MF_TYPE_GUESS,
 			     "argv");
@@ -219,7 +213,7 @@ __mf_heuristic_check (uintptr_t ptr, uin
 		  if (arg)
 		    {
 		      unsigned len = strlen (arg);
-		      __mf_register ((uintptr_t) arg,
+		      __mfu_register ((uintptr_t) arg,
 				     (uintptr_t) (len + 1),
 				     __MF_TYPE_GUESS,
 				     "argv[i]");
Index: mf-hooks.c
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/Attic/mf-hooks.c,v
retrieving revision 1.1.2.31
diff -u -p -r1.1.2.31 mf-hooks.c
--- mf-hooks.c	28 Apr 2003 15:17:09 -0000	1.1.2.31
+++ mf-hooks.c	9 May 2003 21:29:17 -0000
@@ -7,6 +7,11 @@ This file is part of GCC.
 XXX: libgcc license?
 */
 
+#include "config.h"
+
+#define _POSIX_SOURCE
+#define _GNU_SOURCE
+
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -14,6 +19,8 @@ XXX: libgcc license?
 #include <sys/types.h>
 #include <unistd.h>
 #include <assert.h>
+#include <errno.h>
+#include <limits.h>
 #include <time.h>
 
 #include "mf-runtime.h"
@@ -176,21 +183,23 @@ WRAPPER(void *, realloc, void *buf, size
 
   /* Ensure heap wiping doesn't occur during this peculiar
      unregister/reregister pair.  */
+  LOCKTH ();
   saved_wipe_heap = __mf_opts.wipe_heap;
   __mf_opts.wipe_heap = 0;
 
   if (LIKELY(buf))
-    __mf_unregister (buf, 0);
+    __mfu_unregister (buf, 0);
   
   if (LIKELY(result))
     {
       result += __mf_opts.crumple_zone;
-      __mf_register (result, c, __MF_TYPE_HEAP_I, "realloc region");
+      __mfu_register (result, c, __MF_TYPE_HEAP_I, "realloc region");
       /* XXX: register __MF_TYPE_NOACCESS for crumple zones.  */
     }
 
   /* Restore previous setting.  */
   __mf_opts.wipe_heap = saved_wipe_heap;
+  UNLOCKTH ();
 
   return result;
 }
@@ -887,3 +896,220 @@ WRAPPER2(struct tm*, gmtime, const time_
 
 
 /* ------------------------------------------------------------------------ */
+
+#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;
+};
+
+
+/* To avoid dynamic memory allocation, use static array.
+   This should be defined in <limits.h>.  */
+#ifndef PTHREAD_THREADS_MAX
+#define PTHREAD_THREADS_MAX 1000
+#endif
+
+static struct pthread_info __mf_pthread_info[PTHREAD_THREADS_MAX];
+/* XXX: needs a lock */
+
+
+static void 
+__mf_pthread_cleanup (void *arg)
+{
+  struct pthread_info *pi = arg;
+  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;
+
+  /* XXX: register thread errno */
+  pthread_cleanup_push (& __mf_pthread_cleanup, arg);
+
+  pi->self = pthread_self ();
+
+  /* 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_signal test below. */
+  /* XXX: Consider using pthread_key_t objects instead of cleanup
+     stacks. */
+
+  return result;
+}
+
+
+#if PIC
+/* A special bootstrap variant. */
+static 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 ("mf: pthread_create\n");
+
+  LOCKTH();
+
+  /* Garbage collect dead thread stacks.  */
+  for (i = 0; i < PTHREAD_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.  */
+  for (i = 0; i < PTHREAD_THREADS_MAX; i++)
+    {
+      pi = & __mf_pthread_info [i];
+      if (! pi->used_p)
+	{
+	  pi->used_p = 1;
+	  break;
+	}
+    }
+  UNLOCKTH();
+
+  if (i == PTHREAD_THREADS_MAX) /* no slots free - simulated out-of-memory.  */
+    {
+      errno = EAGAIN;
+      pi->used_p = 0;
+      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.  Give up on error.  */
+  if (pthread_attr_getstackaddr (& override_attr, & override_stack) != 0 ||
+      pthread_attr_getstacksize (& override_attr, & override_stacksize) != 0)
+    {
+      errno = EAGAIN;
+      pi->used_p = 0;
+      return -1;
+    }
+
+  /* Do we need to allocate the new thread's stack?  */
+  if (override_stack == NULL)
+    {
+      uintptr_t alignment = 256; /* Must be a power of 2.  */
+
+      /* 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)
+	 & (~(uintptr_t)(alignment-1)));
+      
+      if (pthread_attr_setstackaddr (& override_attr, override_stack) != 0 ||
+	  pthread_attr_setstacksize (& override_attr, override_stacksize) != 0)
+	{
+	  /* Er, what now?  */
+	  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;
+
+  /* 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.18
diff -u -p -r1.1.2.18 mf-impl.h
--- mf-impl.h	28 Apr 2003 15:17:09 -0000	1.1.2.18
+++ mf-impl.h	9 May 2003 21:29:17 -0000
@@ -19,6 +19,8 @@
 
 #if HAVE_PTHREAD_H
 #include <pthread.h>
+#elif LIBMUDFLAPTH
+#error "Cannot build libmudflapth without pthread.h."
 #endif
 
 
@@ -28,11 +30,15 @@
 #define __MF_TYPE_MAX __MF_TYPE_GUESS
 
 
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
 
-/* Address calculation macros.  */
-
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
 
-/* XXX: these macros should be in an __MF*-like namespace. */
+/* Address calculation macros.  */
 
 #define MINPTR ((uintptr_t) 0)
 #define MAXPTR (~ (uintptr_t) 0)
@@ -57,10 +63,8 @@ extern void __mf_violation (void *ptr, s
 			    uintptr_t pc, const char *location, 
 			    int type);
 extern size_t __mf_backtrace (char ***, void *, unsigned);
-extern void __mf_resolve_dynamics ();
 extern int __mf_heuristic_check (uintptr_t, uintptr_t);
 
-
 /* ------------------------------------------------------------------------ */
 /* Type definitions. */
 /* ------------------------------------------------------------------------ */
@@ -169,14 +173,23 @@ struct __mf_options
 
 /* This is a table of dynamically resolved function pointers. */
 
-struct __mf_dynamic 
+struct __mf_dynamic_entry
 {
-  void * dyn_calloc;
-  void * dyn_free;
-  void * dyn_malloc;
-  void * dyn_mmap;
-  void * dyn_munmap;
-  void * dyn_realloc;
+  void *pointer;
+  char *name;
+  char *version;
+};
+
+/* The definition of the array (mf-runtime.c) must match the enums!  */
+extern struct __mf_dynamic_entry __mf_dynamic[];
+enum __mf_dynamic_index
+{ 
+  dyn_calloc, dyn_free, dyn_malloc, dyn_mmap,
+  dyn_munmap, dyn_realloc, 
+  dyn_INITRESOLVE,  /* Marker for last init-time resolution. */
+#ifdef LIBMUDFLAPTH 
+  dyn_pthread_create
+#endif
 };
 
 #endif /* PIC */
@@ -185,14 +198,19 @@ struct __mf_dynamic 
 /* Private global variables. */
 /* ------------------------------------------------------------------------ */
 
-#ifdef HAVE_PTHREAD_H
+#ifdef LIBMUDFLAPTH
 extern pthread_mutex_t __mf_biglock;
+#define LOCKTH() do { int rc = pthread_mutex_lock (& __mf_biglock); \
+                      assert (rc==0); } while (0)
+#define UNLOCKTH() do { int rc = pthread_mutex_unlock (& __mf_biglock); \
+                        assert (rc==0); } while (0)
+#else
+#define LOCKTH() do {} while (0)
+#define UNLOCKTH() do {} while (0)
 #endif
+
 extern enum __mf_state __mf_state;
 extern struct __mf_options __mf_opts;
-#ifdef PIC
-extern struct __mf_dynamic __mf_dynamic;
-#endif 
 
 /* ------------------------------------------------------------------------ */
 /* Utility macros. */
@@ -252,7 +270,10 @@ extern struct __mf_dynamic __mf_dynamic;
 
 
 #ifdef PIC
-#define __USE_GNU
+
+extern void __mf_resolve_single_dynamic (struct __mf_dynamic_entry *);
+
+#define _GNU_SOURCE
 #include <dlfcn.h>
 
 #define WRAPPER(ret, fname, ...)                      \
@@ -264,9 +285,9 @@ ret fname (__VA_ARGS__)
 #define DECLARE(ty, fname, ...)                       \
  typedef ty (*__mf_fn_ ## fname) (__VA_ARGS__)
 #define CALL_REAL(fname, ...)                         \
-  ({ if (UNLIKELY(!__mf_dynamic.dyn_ ## fname))       \
-     __mf_resolve_dynamics ();                        \
-  ((__mf_fn_ ## fname)(__mf_dynamic.dyn_ ## fname))   \
+  ({ if (UNLIKELY(!__mf_dynamic[dyn_ ## fname].pointer))  \
+     __mf_resolve_single_dynamic (& __mf_dynamic[dyn_ ## fname]);  \
+  ((__mf_fn_ ## fname)(__mf_dynamic[dyn_ ## fname].pointer)) \
                       (__VA_ARGS__);})
 #define CALL_BACKUP(fname, ...)                       \
   __mf_0fn_ ## fname(__VA_ARGS__)
@@ -291,6 +312,14 @@ ret __wrap_ ## fname (__VA_ARGS__)
 /* WRAPPER2 is for functions intercepted via macros at compile time. */
 #define WRAPPER2(ret, fname, ...)                     \
 ret __mfwrap_ ## fname (__VA_ARGS__)
+
+
+/* Unlocked variants of main entry points from mf-runtime.h.  */
+extern void __mfu_check (void *ptr, size_t sz, int type, const char *location);
+extern void __mfu_register (void *ptr, size_t sz, int type, const char *name);
+extern void __mfu_unregister (void *ptr, size_t sz);
+extern void __mfu_report ();
+extern int __mfu_set_options (const char *opts);
 
 
 #endif /* __MF_IMPL_H */
Index: mf-runtime.c
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/Attic/mf-runtime.c,v
retrieving revision 1.1.2.34
diff -u -p -r1.1.2.34 mf-runtime.c
--- mf-runtime.c	28 Apr 2003 15:17:09 -0000	1.1.2.34
+++ mf-runtime.c	9 May 2003 21:29:17 -0000
@@ -9,9 +9,19 @@ 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 <stdio.h>
 #include <stdlib.h>
+#include <sys/types.h>
 #include <sys/time.h>
+#include <time.h>
 #include <unistd.h>
 #ifdef HAVE_EXECINFO_H
 #include <execinfo.h>
@@ -32,22 +42,13 @@ XXX: libgcc license?
 
 
 /* ------------------------------------------------------------------------ */
-
-#ifndef max
-#define max(a,b) ((a) > (b) ? (a) : (b))
-#endif
-
-#ifndef min
-#define min(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-
-/* ------------------------------------------------------------------------ */
 /* Utility macros */
 
+#define CTOR  __attribute__ ((constructor))
+#define DTOR  __attribute__ ((destructor))
+
 
 /* Codes to describe the context in which a violation occurs. */
-
 #define __MF_VIOL_UNKNOWN 0
 #define __MF_VIOL_READ 1
 #define __MF_VIOL_WRITE 2
@@ -55,7 +56,6 @@ XXX: libgcc license?
 #define __MF_VIOL_UNREGISTER 4
 #define __MF_VIOL_WATCH 5
 
-
 /* Protect against recursive calls. */
 #define BEGIN_RECURSION_PROTECT           \
   enum __mf_state old_state;              \
@@ -68,6 +68,7 @@ XXX: libgcc license?
   __mf_state = old_state;
 
 
+
 /* ------------------------------------------------------------------------ */
 /* Required globals.  */
 
@@ -80,23 +81,112 @@ uintptr_t __mf_lc_mask = LOOKUP_CACHE_MA
 unsigned char __mf_lc_shift = LOOKUP_CACHE_SHIFT_DFL;
 #define LOOKUP_CACHE_SIZE (__mf_lc_mask + 1)
 
-
 struct __mf_options __mf_opts;
 enum __mf_state __mf_state = inactive;
-#ifdef HAVE_PTHREAD_H
-pthread_mutex_t __mf_biglock = PTHREAD_MUTEX_INITIALIZER;
+
+#ifdef LIBMUDFLAPTH
+pthread_mutex_t __mf_biglock =
+#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
+       PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
+#else
+       PTHREAD_MUTEX_INITIALIZER;
 #endif
-#ifdef PIC
-struct __mf_dynamic __mf_dynamic;
 #endif
 
+/* Use HAVE_PTHREAD_H here instead of LIBMUDFLAPTH, so that even
+   the libmudflap.la (no threading support) can diagnose whether
+   the application is linked with -lpthread.  See __mf_usage() below.  */
 #if HAVE_PTHREAD_H
-#pragma weak pthread_create
-const void *threads_active_p = (void *) pthread_create;
+#pragma weak pthread_join
+const void *threads_active_p = (void *) pthread_join;
 #endif
 
 
+/* ------------------------------------------------------------------------ */
+/* stats-related globals.  */
+
+static unsigned long __mf_count_check;
+static unsigned long __mf_lookup_cache_reusecount [LOOKUP_CACHE_SIZE_MAX];
+static unsigned long __mf_treerot_left, __mf_treerot_right;
+static unsigned long __mf_count_register;
+static unsigned long __mf_total_register_size [__MF_TYPE_MAX+1];
+static unsigned long __mf_count_unregister;
+static unsigned long __mf_total_unregister_size;
+static unsigned long __mf_count_violation [__MF_VIOL_WATCH+1];
+static unsigned long __mf_sigusr1_received;
+static unsigned long __mf_sigusr1_handled;
+
+
+/* ------------------------------------------------------------------------ */
+/* mode-check-related globals.  */
+
+typedef struct __mf_object
+{
+  uintptr_t low, high; /* __mf_register parameters */
+  const char *name;
+  char type; /* __MF_TYPE_something */
+  char watching_p; /* Trigger a VIOL_WATCH on access? */
+  unsigned read_count; /* Number of times __mf_check/read was called on this object.  */
+  unsigned write_count; /* Likewise for __mf_check/write.  */
+  unsigned liveness; /* A measure of recent checking activity.  */
+  unsigned description_epoch; /* Last epoch __mf_describe_object printed this.  */
+
+  uintptr_t alloc_pc;
+  struct timeval alloc_time;
+  char **alloc_backtrace;
+  size_t alloc_backtrace_size;
+
+  int deallocated_p;
+  uintptr_t dealloc_pc;
+  struct timeval dealloc_time;
+  char **dealloc_backtrace;
+  size_t dealloc_backtrace_size;
+} __mf_object_t;
+
+
+typedef struct __mf_object_tree
+{
+  __mf_object_t data;
+  struct __mf_object_tree *left;
+  struct __mf_object_tree *right;
+} __mf_object_tree_t;
+
+/* Live objects: binary tree on __mf_object_t.low */
+static __mf_object_tree_t *__mf_object_root;
+
+/* Dead objects: circular arrays; _MIN_CEM .. _MAX_CEM only */
+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 */
+
+static void __mf_init () CTOR;
 static void __mf_sigusr1_respond ();
+static unsigned __mf_find_objects (uintptr_t ptr_low, uintptr_t ptr_high, 
+				   __mf_object_tree_t **objs, unsigned max_objs);
+static unsigned __mf_find_dead_objects (uintptr_t ptr_low, uintptr_t ptr_high, 
+					__mf_object_tree_t **objs, unsigned max_objs);
+static void __mf_link_object (__mf_object_tree_t *obj);
+static void __mf_age_tree (__mf_object_tree_t *obj);
+static void __mf_adapt_cache ();
+static void __mf_unlink_object (__mf_object_tree_t *obj);
+static void __mf_describe_object (__mf_object_t *obj);
+static unsigned __mf_watch_or_not (void *ptr, size_t sz, char flag);
 
 
 
@@ -108,26 +198,16 @@ __mf_set_default_options ()
 {
   memset (& __mf_opts, 0, sizeof (__mf_opts));
 
-  __mf_opts.trace_mf_calls = 0;
-  __mf_opts.verbose_trace = 0;
-  __mf_opts.collect_stats = 0;
-  __mf_opts.internal_checking = 0;
   __mf_opts.tree_aging =    13037;
   __mf_opts.adapt_cache = 1000003;
-  __mf_opts.print_leaks = 0;
   __mf_opts.abbreviate = 1;
-  __mf_opts.check_initialization = 0;
   __mf_opts.verbose_violations = 1;
-  /* __mf_opts.multi_threaded = 0; */
   __mf_opts.free_queue_length = 4;
   __mf_opts.persistent_count = 100;
   __mf_opts.crumple_zone = 32;
   __mf_opts.backtrace = 4;
   __mf_opts.mudflap_mode = mode_check;
   __mf_opts.violation_mode = viol_nop;
-  __mf_opts.heur_proc_map = 0;
-  __mf_opts.heur_stack_bound = 0;
-  __mf_opts.heur_start_end = 0;
   __mf_opts.heur_argv_environ = 1;
 }
 
@@ -202,12 +282,6 @@ options [] =
     {"abbreviate", 
      "abbreviate repetitive listings",
      set_option, 1, &__mf_opts.abbreviate},
-    /* XXX: this should be sensitive to gcc --enable-threading= setting */
-    /*
-    {"multi-threaded", 
-     "support multiple threads",
-     set_option, 1, &__mf_opts.multi_threaded},
-    */
     {"wipe-stack",
      "wipe stack objects at unwind",
      set_option, 1, &__mf_opts.wipe_stack},
@@ -226,7 +300,6 @@ options [] =
     {"heur-argv-environ", 
      "support argv/environ heuristics",
      set_option, 1, &__mf_opts.heur_argv_environ},
-     
     {"free-queue-length", 
      "queue N deferred free() calls before performing them",
      read_integer_option, 0, &__mf_opts.free_queue_length},
@@ -258,7 +331,7 @@ __mf_usage ()
   struct option *opt;
 
   fprintf (stderr, 
-	   "This is a %sGCC \"mudflap\" memory-checked binary.\n"
+	   "This is a %s%sGCC \"mudflap\" memory-checked binary.\n"
 	   "Mudflap is Copyright (C) 2002-2003 Free Software Foundation, Inc.\n"
 	   "\n"
 	   "The mudflap code can be controlled by an environment variable:\n"
@@ -270,11 +343,17 @@ __mf_usage ()
 	   "any of the following options.  Use `-no-OPTION' to disable options.\n"
 	   "\n",
 #if HAVE_PTHREAD_H
-	   (threads_active_p ? "multi-threaded " : "single-threaded ")
+	   (threads_active_p ? "multi-threaded " : "single-threaded "),
 #else
-	    ""
+	   "",
+#endif
+#if LIBMUDFLAPTH
+	   "thread-aware "
+#else
+	   "thread-unaware "
 #endif
 	    );
+  /* XXX: The multi-threaded thread-unaware combination is bad.  */
 
   for (opt = options; opt->name; opt++)
     {
@@ -307,6 +386,17 @@ __mf_usage ()
 int 
 __mf_set_options (const char *optstr)
 {
+  int rc;
+  LOCKTH ();
+  rc = __mfu_set_options (optstr);
+  UNLOCKTH ();
+  return rc;
+}
+
+
+int 
+__mfu_set_options (const char *optstr)
+{
   struct option *opts = 0;
   char *nxt = 0;
   long tmp = 0;
@@ -404,120 +494,70 @@ __mf_set_options (const char *optstr)
   return rc;
 }
 
-#define CTOR  __attribute__ ((constructor))
-#define DTOR  __attribute__ ((destructor))
 
 #ifdef PIC
 
-static void 
-resolve_single_dynamic (void **target, const char *name)
+void 
+__mf_resolve_single_dynamic (struct __mf_dynamic_entry *e)
 {
   char *err;
-  assert (target);
-  *target = NULL;
-  *target = dlsym (RTLD_NEXT, name);
+
+  assert (e);
+  e->pointer = NULL;
+
+#if HAVE_DLVSYM
+  if (e->version != NULL && e->version[0] != '\0') /* non-null/empty */
+    e->pointer = dlvsym (RTLD_NEXT, e->name, e->version);
+  else
+#endif
+    e->pointer = dlsym (RTLD_NEXT, e->name);
+  
   err = dlerror ();
+
   if (err)
     {
       fprintf (stderr, "mf: error in dlsym(\"%s\"): %s\n",
-	       name, err);
+	       e->name, err);
       abort ();
     }  
-  if (! *target)
+  if (! e->pointer)
     {
-      fprintf (stderr, "mf: dlsym(\"%s\") = NULL\n", name);
+      fprintf (stderr, "mf: dlsym(\"%s\") = NULL\n", e->name);
       abort ();
     }
 }
 
-void 
+
+static void 
 __mf_resolve_dynamics () 
 {
-#define RESOLVE(fname) \
-resolve_single_dynamic (&__mf_dynamic.dyn_ ## fname, #fname)
-  RESOLVE(calloc);
-  RESOLVE(free);
-  RESOLVE(malloc);
-  RESOLVE(mmap);
-  RESOLVE(munmap);
-  RESOLVE(realloc);
-#undef RESOLVE
+  int i;
+  for (i = 0; i < dyn_INITRESOLVE; i++)
+    __mf_resolve_single_dynamic (& __mf_dynamic[i]);
 }
 
-#endif /* PIC */
-
-
-
-/* ------------------------------------------------------------------------ */
-/* stats-related globals.  */
-
-static unsigned long __mf_count_check;
-static unsigned long __mf_lookup_cache_reusecount [LOOKUP_CACHE_SIZE_MAX];
-static unsigned long __mf_treerot_left, __mf_treerot_right;
-static unsigned long __mf_count_register;
-static unsigned long __mf_total_register_size [__MF_TYPE_MAX+1];
-static unsigned long __mf_count_unregister;
-static unsigned long __mf_total_unregister_size;
-static unsigned long __mf_count_violation [__MF_VIOL_WATCH+1];
-static unsigned long __mf_sigusr1_received;
-static unsigned long __mf_sigusr1_handled;
-
-
-/* ------------------------------------------------------------------------ */
-/* mode-check-related globals.  */
-
-typedef struct __mf_object
-{
-  uintptr_t low, high; /* __mf_register parameters */
-  const char *name;
-  char type; /* __MF_TYPE_something */
-  char watching_p; /* Trigger a VIOL_WATCH on access? */
-  unsigned read_count; /* Number of times __mf_check/read was called on this object.  */
-  unsigned write_count; /* Likewise for __mf_check/write.  */
-  unsigned liveness; /* A measure of recent checking activity.  */
-  unsigned description_epoch; /* Last epoch __mf_describe_object printed this.  */
-
-  uintptr_t alloc_pc;
-  struct timeval alloc_time;
-  char **alloc_backtrace;
-  size_t alloc_backtrace_size;
-
-  int deallocated_p;
-  uintptr_t dealloc_pc;
-  struct timeval dealloc_time;
-  char **dealloc_backtrace;
-  size_t dealloc_backtrace_size;
-} __mf_object_t;
-
 
-typedef struct __mf_object_tree
-{
-  __mf_object_t data;
-  struct __mf_object_tree *left;
-  struct __mf_object_tree *right;
-} __mf_object_tree_t;
+/* NB: order must match enums in mf-impl.h */
+struct __mf_dynamic_entry __mf_dynamic [] =
+{
+  {NULL, "calloc", NULL},
+  {NULL, "free", NULL},
+  {NULL, "malloc", NULL},
+  {NULL, "mmap", NULL},
+  {NULL, "munmap", NULL},
+  {NULL, "realloc", NULL},
+  {NULL, "DUMMY", NULL}, /* dyn_INITRESOLVE */
+#ifdef LIBMUDFLAPTH
+  {NULL, "pthread_create", PTHREAD_CREATE_VERSION}
+#endif
+};
 
-/* Live objects: binary tree on __mf_object_t.low */
-__mf_object_tree_t *__mf_object_root;
-/* Dead objects: circular arrays; _MIN_CEM .. _MAX_CEM only */
-unsigned __mf_object_dead_head[__MF_TYPE_MAX_CEM+1]; /* next empty spot */
-__mf_object_tree_t *__mf_object_cemetary[__MF_TYPE_MAX_CEM+1][__MF_PERSIST_MAX];
+#endif /* PIC */
 
-static unsigned __mf_find_objects (uintptr_t ptr_low, uintptr_t ptr_high, 
-				   __mf_object_tree_t **objs, unsigned max_objs);
-static unsigned __mf_find_dead_objects (uintptr_t ptr_low, uintptr_t ptr_high, 
-					__mf_object_tree_t **objs, unsigned max_objs);
-static void __mf_link_object (__mf_object_tree_t *obj);
-static void __mf_age_tree (__mf_object_tree_t *obj);
-static void __mf_adapt_cache ();
-static void __mf_unlink_object (__mf_object_tree_t *obj);
-static void __mf_describe_object (__mf_object_t *obj);
-static unsigned __mf_watch_or_not (void *ptr, size_t sz, char flag);
 
 
 /* ------------------------------------------------------------------------ */
 
-extern void __mf_init () CTOR;
 void __mf_init ()
 {
   char *ov = 0;
@@ -533,7 +573,7 @@ void __mf_init ()
   ov = getenv ("MUDFLAP_OPTIONS");
   if (ov)
     {
-      int rc = __mf_set_options (ov);
+      int rc = __mfu_set_options (ov);
       if (rc < 0)
 	{
 	  __mf_usage ();
@@ -545,7 +585,7 @@ void __mf_init ()
   __mf_describe_object (NULL);
 
 #define REG_RESERVED(obj) \
-  __mf_register (& obj, sizeof(obj), __MF_TYPE_NOACCESS, # obj)
+  __mfu_register (& obj, sizeof(obj), __MF_TYPE_NOACCESS, # obj)
 
   REG_RESERVED (__mf_lookup_cache);
   REG_RESERVED (__mf_lc_mask);
@@ -553,21 +593,21 @@ void __mf_init ()
   /* XXX: others of our statics?  */
 
   /* Prevent access to *NULL. */
-  __mf_register (MINPTR, 1, __MF_TYPE_NOACCESS, "NULL");
+  __mfu_register (MINPTR, 1, __MF_TYPE_NOACCESS, "NULL");
   __mf_lookup_cache[0].low = (uintptr_t) -1;
 
   /* XXX: bad hack: assumes Linux process layout */
   if (__mf_opts.heur_argv_environ)
     {
       int foo = 0;
-      __mf_register (& foo,
-		     (size_t) 0xC0000000 - (size_t) (& foo),
-		     __MF_TYPE_GUESS,
-		     "argv/environ area");
+      __mfu_register (& foo,
+		      (size_t) 0xC0000000 - (size_t) (& foo),
+		      __MF_TYPE_GUESS,
+		      "argv/environ area");
       /* XXX: separate heuristic? */
-      __mf_register (& errno, sizeof (errno),
-		     __MF_TYPE_GUESS,
-		     "errno area");
+      __mfu_register (& errno, sizeof (errno),
+		      __MF_TYPE_GUESS,
+		      "errno area");
     }
 }
 
@@ -576,7 +616,7 @@ extern void __mf_fini () DTOR;
 void __mf_fini ()
 {
   TRACE ("mf: __mf_fini\n");
-  __mf_report ();
+  __mfu_report ();
 }
 
 
@@ -586,6 +626,14 @@ void __mf_fini ()
 
 void __mf_check (void *ptr, size_t sz, int type, const char *location)
 {
+  LOCKTH ();
+  __mfu_check (ptr, sz, type, location);
+  UNLOCKTH ();
+}
+
+
+void __mfu_check (void *ptr, size_t sz, int type, const char *location)
+{
   unsigned entry_idx = __MF_CACHE_INDEX (ptr);
   struct __mf_cache *entry = & __mf_lookup_cache [entry_idx];
   int judgement = 0; /* 0=undecided; <0=violation; >0=okay */
@@ -890,6 +938,15 @@ __mf_uncache_object (__mf_object_t *old_
 void
 __mf_register (void *ptr, size_t sz, int type, const char *name)
 {
+  LOCKTH ();
+  __mfu_register (ptr, sz, type, name);
+  UNLOCKTH ();
+}
+
+
+void
+__mfu_register (void *ptr, size_t sz, int type, const char *name)
+{
   /* if (UNLIKELY (!(__mf_state == active || __mf_state == starting))) return; */
 
   TRACE ("mf: register ptr=%08lx size=%lu type=%x name='%s'\n", ptr, sz, 
@@ -905,7 +962,7 @@ __mf_register (void *ptr, size_t sz, int
 
 
   if (UNLIKELY (__mf_opts.sigusr1_report))
-  __mf_sigusr1_respond ();
+    __mf_sigusr1_respond ();
 
   switch (__mf_opts.mudflap_mode)
     {
@@ -1010,15 +1067,15 @@ __mf_register (void *ptr, size_t sz, int
 		    if (all_ovr_objs[n]->data.low > next_low) /* Gap? */
 		      {
 			uintptr_t next_high = CLAMPSUB (all_ovr_objs[n]->data.low, 1);
-			__mf_register ((void *) next_low, next_high-next_low+1,
-				       __MF_TYPE_GUESS, name);
+			__mfu_register ((void *) next_low, next_high-next_low+1,
+					__MF_TYPE_GUESS, name);
 		      }
 		    next_low = CLAMPADD (all_ovr_objs[n]->data.high, 1);
 		  }
 		/* Add in any leftover room at the top.  */
 		if (next_low <= high)
-		  __mf_register ((void *) next_low, high-next_low+1,
-				 __MF_TYPE_GUESS, name);
+		  __mfu_register ((void *) next_low, high-next_low+1,
+				  __MF_TYPE_GUESS, name);
 
 		/* XXX: future optimization: allow consecutive GUESS regions to
 		   be glued together.  */
@@ -1045,10 +1102,10 @@ __mf_register (void *ptr, size_t sz, int
   		   located GUESS region should end up being split up
   		   in any case.  */
 		END_RECURSION_PROTECT;
-		__mf_unregister ((void *) old_low, old_high-old_low+1);
-		__mf_register ((void *) low, sz, type, name);
-		__mf_register ((void *) old_low, old_high-old_low+1,
-			       __MF_TYPE_GUESS, old_name);
+		__mfu_unregister ((void *) old_low, old_high-old_low+1);
+		__mfu_register ((void *) low, sz, type, name);
+		__mfu_register ((void *) old_low, old_high-old_low+1,
+				__MF_TYPE_GUESS, old_name);
 		return;
 	      }
 
@@ -1078,10 +1135,18 @@ __mf_register (void *ptr, size_t sz, int
 }
 
 
-
 void
 __mf_unregister (void *ptr, size_t sz)
 {
+  LOCKTH ();
+  __mfu_unregister (ptr, sz);
+  UNLOCKTH ();
+}
+
+
+void
+__mfu_unregister (void *ptr, size_t sz)
+{
   DECLARE (void, free, void *ptr);
 
   BEGIN_RECURSION_PROTECT;
@@ -1761,6 +1826,14 @@ __mf_report_leaks (__mf_object_tree_t *n
 void
 __mf_report ()
 {
+  LOCKTH ();
+  __mfu_report ();
+  UNLOCKTH ();
+}
+
+void
+__mfu_report ()
+{
   /* if (UNLIKELY (__mf_state == active)) return; */
 
   if (__mf_opts.collect_stats)
@@ -2080,17 +2153,22 @@ __mf_violation (void *ptr, size_t sz, ui
 /* ------------------------------------------------------------------------ */
 
 
-/* ------------------------------------------------------------------------ */
-/* __mf_check */
-
 unsigned __mf_watch (void *ptr, size_t sz)
 {
-  return __mf_watch_or_not (ptr, sz, 1);
+  unsigned rc;
+  LOCKTH ();
+  rc = __mf_watch_or_not (ptr, sz, 1);
+  UNLOCKTH ();
+  return rc;
 }
 
 unsigned __mf_unwatch (void *ptr, size_t sz)
 {
-  return __mf_watch_or_not (ptr, sz, 0);
+  unsigned rc;
+  LOCKTH ();
+  rc = __mf_watch_or_not (ptr, sz, 0);
+  UNLOCKTH ();
+  return rc;
 }
 
 
Index: mf-runtime.h.in
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/Attic/mf-runtime.h.in,v
retrieving revision 1.1.2.12
diff -u -p -r1.1.2.12 mf-runtime.h.in
--- mf-runtime.h.in	28 Apr 2003 15:17:09 -0000	1.1.2.12
+++ mf-runtime.h.in	9 May 2003 21:29:17 -0000
@@ -22,6 +22,10 @@ extern struct __mf_cache __mf_lookup_cac
 extern uintptr_t __mf_lc_mask;
 extern unsigned char __mf_lc_shift;
 
+/* Multithreading support.  */
+#ifdef _MUDFLAPTH
+/* extern pthread_mutex_t __mf_biglock; */
+#endif
 
 /* Codes to describe the type of access to check: __mf_check arg 3 */
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]