Commits

Anonymous committed faf48b1

new dso-callbacks (with C closures)

Comments (0)

Files changed (4)

+2010-02-15  Sebastien Binet  <binet@farnsworth>
+
+	* tagging CxxUtils-00-00-51
+	* new dso-callbacks (with C closures)
+	* A CxxUtils/AthDsoCbk.h
+	* A src/AthDsoCbk.c
+	* M cmt/requirements
+
 2010-02-12  Charles Leggett
 	* added MD5.h, MD5.cxx: RSA MD5 digest generator
 	* tag CxxUtils-00-00-50

CxxUtils/AthDsoCbk.h

+/** -*- C -*-
+ * AthDsoCbk.h  
+ * Header file for the dso callbacks api 
+ * Author: S.Binet<binet@cern.ch> 
+ */
+
+#ifndef CXXUTILS_ATHDSOCBK_H
+#define CXXUTILS_ATHDSOCBK_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif /*__cplusplus */
+
+/* forward declares */
+
+/* type of events the dso-callback framework will dispatch */
+struct ath_dso_event
+{
+  const char* fname; /* the name of the dso being loaded */
+  int step;          /* 0: before loading the dso
+                        1: after  loading the dso */
+};
+
+/* type of the callback function the dso logger will execute 
+ *  NOTE: userdata pointer may be NULL
+ */
+typedef (*ath_dso_event_cbk_t)(const struct ath_dso_event*, void *userdata);
+
+/* register a callback function with the dso-cbk framework 
+ * @return 0 on success
+ *        -1 on failure
+ */
+int ath_dso_cbk_register(ath_dso_event_cbk_t cbk, void *userdata);
+
+/* unregister a callback function with the dso-cbk framework
+ * @return 0 on success
+ *        -1 on failure
+ */
+int ath_dso_cbk_unregister(ath_dso_event_cbk_t cbk);
+
+#ifdef __cplusplus
+} /* extern C */
+#endif /*__cplusplus */
+
+#endif /* !CXXUTILS_ATHDSOCBK_H */
+
 library exctrace_collector exctrace/exctrace_collector.cxx
 
 private
+## for logging dlopen calls
+library AthDsoCbk AthDsoCbk.c
+apply_pattern named_install_library name=AthDsoCbk
+macro_append AthDsoCbk_linkopts " -lpthread "
+
 ## unit tests
 
 use TestTools	   TestTools-*         AtlasTest
+/* implementation for AthDsoCbk */
+
+/* CxxUtils includes */
+#include "CxxUtils/AthDsoCbk.h"
+
+#ifndef linux
+
+/* stubs for macosx */
+int
+ath_dso_cbk_register(ath_dso_event_cbk_t /*cbk*/, void */*userdata*/)
+{
+  return 0;
+}
+
+/* unregister a callback function with the dso-cbk framework */
+int
+ath_dso_cbk_unregister(ath_dso_event_cbk_t /*cbk*/)
+{
+  return 0;
+}
+
+#else /*linux*/
+
+#define _GNU_SOURCE 1
+
+/* stl includes */
+#include <stdlib.h>
+
+#include <stdio.h>
+#include <pthread.h>
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <unistd.h> /*for sysconf and page size*/
+
+/* return the VMem in kilo-bytes */
+static
+float fetch_vmem (void);
+
+/* internal structure to hold a callback and its associated userdata (if any)
+ */
+struct ath_dso_event_cbk_impl
+{
+  ath_dso_event_cbk_t cbk;
+  void *data;
+};
+typedef struct ath_dso_event_cbk_impl ath_dso_event_cbk;
+
+/* current registered callback */
+static ath_dso_event_cbk *g_dso_callback = NULL;
+
+/* default callback function */
+static
+int
+ath_dso_event_cbk_default(const struct ath_dso_event* event, void *userdata);
+
+struct dlfcn_hook
+{
+  void *(*dlopen) (const char *file, int mode, void *dl_caller);
+  int (*dlclose) (void *handle);
+  void *(*dlsym) (void *handle, const char *name, void *dl_caller);
+  void *(*dlvsym) (void *handle, const char *name, const char *version,
+                   void *dl_caller);
+  char *(*dlerror) (void);
+  int (*dladdr) (const void *address, Dl_info *info);
+  int (*dladdr1) (const void *address, Dl_info *info,
+                  void **extra_info, int flags);
+  int (*dlinfo) (void *handle, int request, void *arg, void *dl_caller);
+  void *(*dlmopen) (Lmid_t nsid, const char *file, int mode, void *dl_caller);
+  void *pad[4];
+};
+
+extern struct dlfcn_hook *_dlfcn_hook __attribute__ ((nocommon));
+
+void *ath_dlopen( const char *fname, int mode, void *dl_caller );
+int ath_dlclose( void *handle );
+void *ath_dlsym( void *handle, const char *name, void *dl_caller );
+void *ath_dlvsym( void *handle, const char *name, const char *version, void *dl_caller );
+char *ath_dlerror( void );
+int ath_dladdr( const void *address, Dl_info *info );
+int ath_dladdr1( const void *address, Dl_info *info, void **extra_info, int flags );
+int ath_dlinfo( void *handle, int request, void *arg, void *dl_caller );
+void *ath_dlmopen( Lmid_t nsid, const char *file, int mode, void *dl_caller );
+
+static struct dlfcn_hook ath_dl_hook = {
+  ath_dlopen, ath_dlclose, ath_dlsym, ath_dlvsym, ath_dlerror,
+  ath_dladdr, ath_dladdr1, ath_dlinfo, ath_dlmopen, { 0, 0, 0, 0 }
+};
+static pthread_mutex_t ath_dl_hook_lock = PTHREAD_MUTEX_INITIALIZER; 
+
+void* 
+ath_dlopen( const char *fname, int mode, void *dl_caller ) 
+{
+  struct ath_dso_event dso_evt;
+  void *result;
+
+  result = NULL;
+  pthread_mutex_lock(&ath_dl_hook_lock);
+
+  _dlfcn_hook = 0;
+  dso_evt.fname = fname;
+  
+  if (g_dso_callback) {
+    dso_evt.step = 0;
+    (*g_dso_callback->cbk)(&dso_evt, g_dso_callback->data);
+  }
+
+  result = dlopen( fname, mode );
+
+  if (g_dso_callback) {
+    dso_evt.step = 1;
+    (*g_dso_callback->cbk)(&dso_evt, g_dso_callback->data);
+  }
+
+  _dlfcn_hook = &ath_dl_hook;
+  pthread_mutex_unlock(&ath_dl_hook_lock);
+
+  return result;
+}
+
+int
+ath_dlclose( void *handle ) 
+{
+  int result = 0;
+  pthread_mutex_lock(&ath_dl_hook_lock);
+  _dlfcn_hook = 0;
+  result = dlclose( handle );
+  _dlfcn_hook = &ath_dl_hook;
+  pthread_mutex_unlock(&ath_dl_hook_lock);
+  return result;
+}
+
+void*
+ath_dlsym( void *handle, const char *name, void *dl_caller ) 
+{
+  void *result = 0;
+  pthread_mutex_lock(&ath_dl_hook_lock);
+  _dlfcn_hook = 0;
+  result = dlsym( handle, name );
+  _dlfcn_hook = &ath_dl_hook;
+  pthread_mutex_unlock(&ath_dl_hook_lock);
+  return result;
+}
+
+void*
+ath_dlvsym( void *handle, const char *name, const char *version, void *dl_caller ) 
+{
+  void *result = 0;
+  pthread_mutex_lock(&ath_dl_hook_lock);
+  _dlfcn_hook = 0;
+  result = dlvsym( handle, name, version );
+  _dlfcn_hook = &ath_dl_hook;
+  pthread_mutex_unlock(&ath_dl_hook_lock);
+  return result;
+}
+
+char*
+ath_dlerror( void ) 
+{
+  char *result = 0;
+  pthread_mutex_lock(&ath_dl_hook_lock);
+  _dlfcn_hook = 0;
+  result = dlerror();
+  _dlfcn_hook = &ath_dl_hook;
+  pthread_mutex_unlock(&ath_dl_hook_lock);
+  return result;
+}
+
+int
+ath_dladdr( const void *address, Dl_info *info ) 
+{
+  int result = 0;
+  pthread_mutex_lock(&ath_dl_hook_lock);
+  _dlfcn_hook = 0;
+  result = dladdr( address, info );
+  _dlfcn_hook = &ath_dl_hook;
+  pthread_mutex_unlock(&ath_dl_hook_lock);
+  return result;
+}
+
+int
+ath_dladdr1( const void *address, Dl_info *info, void **extra_info, int flags ) 
+{
+  int result = 0;
+  pthread_mutex_lock(&ath_dl_hook_lock);
+  _dlfcn_hook = 0;
+  result = dladdr1( address, info, extra_info, flags );
+  _dlfcn_hook = &ath_dl_hook;
+  pthread_mutex_unlock(&ath_dl_hook_lock);
+  return result;
+}
+
+int
+ath_dlinfo( void *handle, int request, void *arg, void *dl_caller ) 
+{
+  int result = 0;
+  pthread_mutex_lock(&ath_dl_hook_lock);
+  _dlfcn_hook = 0;
+  result = dlinfo( handle, request, arg );
+  _dlfcn_hook = &ath_dl_hook;
+  pthread_mutex_unlock(&ath_dl_hook_lock);
+  return result;
+}
+
+void*
+ath_dlmopen( Lmid_t nsid, const char *file, int mode, void *dl_caller ) 
+{
+  void *result = 0;
+  pthread_mutex_lock(&ath_dl_hook_lock);
+  _dlfcn_hook = 0;
+  result = dlmopen( nsid, file, mode );
+  _dlfcn_hook = &ath_dl_hook;
+  pthread_mutex_unlock(&ath_dl_hook_lock);
+  return result;
+}
+
+void
+ath_dl_hook_install() 
+{
+  pthread_mutex_init(&ath_dl_hook_lock, NULL);
+  printf("AthDsoCbk: installing mutex in tid [%d]\n", pthread_self());
+  /*   printf ("AthDsoCbk: setting dlopen hooks\n" ); */
+  _dlfcn_hook = &ath_dl_hook;
+}
+
+void ath_dl_hook_release ()
+{
+  _dlfcn_hook = 0;
+  printf ("AthDsoCbk: releasing library\n");
+  pthread_mutex_destroy(&ath_dl_hook_lock);
+}
+
+float
+fetch_vmem (void)
+{
+  unsigned siz, rss, shd;
+  FILE *fp = fopen ("/proc/self/statm", "r");
+  if (fp == NULL) {
+    return -999;
+  }
+  
+  /* FIXME: error handling... */
+  fscanf(fp, "%u%u%u", &siz, &rss, &shd);
+  fclose (fp);
+
+  double pg_sz = sysconf(_SC_PAGESIZE);
+  return (pg_sz * siz)/ (float)1024;
+}
+
+/* default callback function */
+int
+ath_dso_event_cbk_default(const struct ath_dso_event* evt, void *userdata)
+{
+  int pid = getpid();
+  float vmem = fetch_vmem();
+  if (userdata) {}
+  printf ("AthLdPreload: [%d] loading [%s] vmem = [%8.3f] (%d)",
+	  pid, evt->fname, vmem, evt->step);
+
+  return 0;
+}
+
+/* register a callback function with the dso-cbk framework 
+ * @return 0 on success
+ *        -1 on failure
+ */
+int
+ath_dso_cbk_register(ath_dso_event_cbk_t cbk, void *userdata)
+{
+  if (g_dso_callback != NULL) {
+    free(g_dso_callback);
+    g_dso_callback = NULL;
+  }
+  g_dso_callback = (ath_dso_event_cbk*)malloc(sizeof(ath_dso_event_cbk));
+  g_dso_callback->cbk = cbk != NULL
+    ? cbk
+    : ath_dso_event_cbk_default;
+
+  if (cbk != NULL) {
+    g_dso_callback->cbk = cbk;
+  } else {
+    g_dso_callback->cbk = ath_dso_event_cbk_default;
+  }
+  g_dso_callback->data = userdata;
+
+  return 0;
+}
+
+/* unregister a callback function with the dso-cbk framework */
+int
+ath_dso_cbk_unregister(ath_dso_event_cbk_t cbk)
+{
+  if (g_dso_callback == NULL) {
+    /* no callback previously registered ! */
+    return -1;
+  }
+  if (g_dso_callback->cbk != cbk) {
+    /* trying to unregister the wrong callback ! */
+    return -2;
+  }
+  free(g_dso_callback);
+  g_dso_callback = NULL;
+  return 0;
+}
+
+/* constructors and destructors */
+
+static void setup() __attribute__ ((constructor));
+static void cleanup() __attribute__ ((destructor));
+
+void 
+setup()
+{
+  static int initialized = 0;
+  if (!initialized) {
+    initialized = 1;
+    ath_dl_hook_install();
+  }
+}
+
+void
+cleanup()
+{
+  static int finalized = 0;
+  if (!finalized) {
+    finalized = 1;
+    ath_dl_hook_release();
+  }
+}
+
+#endif
+