a new libgcov interface: __gcov_dump_all

Xinliang David Li davidxl@google.com
Tue Jul 22 16:29:00 GMT 2014


Please take a look the updated patch. It addresses the issue of using
dlclose before dump, and potential races (between a thread closing a
library and the dumper call).

David

On Sun, Jul 20, 2014 at 11:12 PM, Nathan Sidwell <nathan@acm.org> wrote:
> On 07/20/14 21:38, Xinliang David Li wrote:
>>
>> The gcov_info chain is not duplicated -- there is already one chain
>> (linking only modules of the library) per shared library in current
>> implementation.  My change does not affect underlying behavior at all
>> -- it merely introduces a new interface to access private dumper
>> methods associated with shared libs.
>
>
> ah, got it.  thanks for clarifying.  Can't help thinking gcov_init should be
> doing this, and wondering about dlload/dlclose.  Let me think
>
> nathan
-------------- next part --------------
Index: libgcc/libgcov.h
===================================================================
--- libgcc/libgcov.h	(revision 212682)
+++ libgcc/libgcov.h	(working copy)
@@ -218,8 +218,14 @@ extern void __gcov_flush (void) ATTRIBUT
 /* Function to reset all counters to 0.  */
 extern void __gcov_reset (void);
 
-/* Function to enable early write of profile information so far.  */
-extern void __gcov_dump (void);
+/* Function to enable early write of profile information so far.  
+   __GCOV_DUMP is also used by __GCOV_DUMP_ALL. The latter 
+   depends on __GCOV_DUMP to have hidden or protected visibility
+   so that each library has its own copy of the registered dumper.  */
+extern void __gcov_dump (void) ATTRIBUTE_HIDDEN;
+
+/* Call __gcov_dump registered from each shared library.  */
+void __gcov_dump_all (void);
 
 /* The merge function that just sums the counters.  */
 extern void __gcov_merge_add (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
Index: libgcc/ChangeLog
===================================================================
--- libgcc/ChangeLog	(revision 212682)
+++ libgcc/ChangeLog	(working copy)
@@ -1,3 +1,9 @@
+2014-07-18  Xinliang David Li  <davidxl@google.com>
+
+	* libgcov-driver.c: Force __gcov_dump to be exported
+	* libgcov-interface.c (register_dumper): New function.
+	(__gcov_dump_all): Ditto.
+
 2014-07-14  Richard Biener  <rguenther@suse.de>
 
 	* libgcov.h (struct gcov_fn_info): Make ctrs size 1.
Index: libgcc/libgcov-driver.c
===================================================================
--- libgcc/libgcov-driver.c	(revision 212682)
+++ libgcc/libgcov-driver.c	(working copy)
@@ -55,6 +55,13 @@ extern void set_gcov_dump_complete (void
 extern void reset_gcov_dump_complete (void) ATTRIBUTE_HIDDEN;
 extern int get_gcov_dump_complete (void) ATTRIBUTE_HIDDEN;
 extern void set_gcov_list (struct gcov_info *) ATTRIBUTE_HIDDEN;
+  
+#ifndef IN_GCOV_TOOL
+
+/* Creates strong reference to force _gcov_dump.o to be linked
+   in shared library for exported interfaces.  */
+void (*__gcov_dummy_ref)(void) = &__gcov_dump;
+#endif
 
 struct gcov_fn_buffer
 {
Index: libgcc/libgcov-interface.c
===================================================================
--- libgcc/libgcov-interface.c	(revision 212682)
+++ libgcc/libgcov-interface.c	(working copy)
@@ -115,6 +115,100 @@ __gcov_dump (void)
   set_gcov_dump_complete ();
 }
 
+typedef void (*gcov_dumper_type) (void);
+struct dumper_entry
+{
+  gcov_dumper_type dumper;
+  struct dumper_entry *next_dumper;
+};
+
+static struct dumper_entry this_dumper = {&__gcov_dump, 0};
+
+/* global dumper list with default visibilty. */
+struct dumper_entry *__gcov_dumper_list;
+
+#ifdef __GTHREAD_MUTEX_INIT
+__gthread_mutex_t __gcov_dump_mx = __GTHREAD_MUTEX_INIT;
+#define init_mx_once()
+#else
+__gthread_mutex_t __gcov_dump_mx;
+
+static void
+init_mx (void)
+{
+  __GTHREAD_MUTEX_INIT_FUNCTION (&__gcov_dump_mx);
+}
+static void
+init_mx_once (void)
+{
+  static __gthread_once_t once = __GTHREAD_ONCE_INIT;
+  __gthread_once (&once, init_mx);
+}
+#endif
+
+/* Register the library private __gcov_dump method
+   to the global list.  */
+
+__attribute__((constructor))
+static void
+register_dumper (void)
+{
+  init_mx_once ();
+  __gthread_mutex_lock (&__gcov_dump_mx);
+  this_dumper.next_dumper = __gcov_dumper_list;
+  __gcov_dumper_list = &this_dumper;
+  __gthread_mutex_unlock (&__gcov_dump_mx);
+}
+
+__attribute__((destructor))
+static void
+unregister_dumper (void)
+{
+  struct dumper_entry *dumper;
+  struct dumper_entry *prev_dumper = 0;
+
+  init_mx_once ();
+  __gthread_mutex_lock (&__gcov_dump_mx);
+  dumper = __gcov_dumper_list;
+
+  while (dumper)
+    {
+      if (dumper->dumper == &__gcov_dump)
+        {
+	  if (prev_dumper)
+	    prev_dumper->next_dumper = dumper->next_dumper;
+ 	  else
+	    __gcov_dumper_list = dumper->next_dumper;
+          break;
+        }
+      prev_dumper = dumper;
+      dumper = dumper->next_dumper;
+    }
+  __gthread_mutex_unlock (&__gcov_dump_mx);
+}
+
+/* Public interface to dump profile data for all shared libraries
+   via registered dumpers from the libraries. This interface
+   has default visibility (unlike gcov_dump which has hidden
+   visbility.  */
+
+void
+__gcov_dump_all (void)
+{
+  struct dumper_entry *dumper;
+
+  init_mx_once ();
+  __gthread_mutex_lock (&__gcov_dump_mx);
+
+  dumper = __gcov_dumper_list;
+  while (dumper)
+   {
+     dumper->dumper ();
+     dumper = dumper->next_dumper;
+   }
+  __gthread_mutex_unlock (&__gcov_dump_mx);
+}
+
 #endif /* L_gcov_dump */
 
 


More information about the Gcc-patches mailing list