gc_dlopen.c raw

   1  /*
   2   * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
   3   * Copyright (c) 1997 by Silicon Graphics.  All rights reserved.
   4   * Copyright (c) 2000 by Hewlett-Packard Company.  All rights reserved.
   5   *
   6   * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
   7   * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
   8   *
   9   * Permission is hereby granted to use or copy this program
  10   * for any purpose, provided the above notices are retained on all copies.
  11   * Permission to modify the code and to distribute modified code is granted,
  12   * provided the above notices are retained, and a notice that the code was
  13   * modified is included with the above copyright notice.
  14   */
  15  
  16  #include "private/gc_priv.h"
  17  
  18  /*
  19   * This is located in this file (rather than in `dyn_load.c` file) to
  20   * avoid having to link against `libdl` library if the client does not
  21   * call `dlopen()`.  Of course, this is meaningless if the collector is
  22   * in a dynamic library.
  23   */
  24  #if defined(GC_PTHREADS) && !defined(GC_NO_DLOPEN)
  25  
  26  #  undef GC_MUST_RESTORE_REDEFINED_DLOPEN
  27  #  if defined(dlopen) && !defined(GC_USE_LD_WRAP)
  28  /*
  29   * To support various threads packages, `gc.h` file interposes on `dlopen`
  30   * by defining the latter to be `GC_dlopen`, which is implemented below.
  31   * However, `GC_dlopen()` itself uses the real system `dlopen()`, thus
  32   * we first remove `dlopen` definition by `gc.h` file and restore it later,
  33   * after `GC_dlopen()` definition.
  34   */
  35  #    undef dlopen
  36  #    define GC_MUST_RESTORE_REDEFINED_DLOPEN
  37  #  endif
  38  
  39  /*
  40   * Make sure we are not in the middle of a collection, and make sure we
  41   * do not start any.  This is invoked prior to a `dlopen` call to avoid
  42   * synchronization issues.  We cannot just acquire the allocator lock,
  43   * since startup code in `dlopen` may try to allocate.  This solution
  44   * risks heap growth (or, even, heap overflow) in the presence of many
  45   * `dlopen` calls in either a multi-threaded environment, or if the
  46   * library initialization code allocates substantial amounts of garbage
  47   * collected memory.
  48   */
  49  #  ifndef USE_PROC_FOR_LIBRARIES
  50  static void
  51  disable_gc_for_dlopen(void)
  52  {
  53    LOCK();
  54    while (GC_incremental && GC_collection_in_progress()) {
  55      GC_collect_a_little_inner(1000);
  56    }
  57    ++GC_dont_gc;
  58    UNLOCK();
  59  }
  60  #  endif
  61  
  62  /*
  63   * Redefine `dlopen` to guarantee mutual exclusion with
  64   * `GC_register_dynamic_libraries()`.  Should probably happen for
  65   * other operating systems, too.
  66   */
  67  
  68  /* This is similar to `WRAP_FUNC`/`REAL_FUNC` in `pthread_support.c` file. */
  69  #  ifdef GC_USE_LD_WRAP
  70  #    define WRAP_DLFUNC(f) __wrap_##f
  71  #    define REAL_DLFUNC(f) __real_##f
  72  void *REAL_DLFUNC(dlopen)(const char *, int);
  73  #  else
  74  #    define WRAP_DLFUNC(f) GC_##f
  75  #    define REAL_DLFUNC(f) f
  76  #  endif
  77  
  78  #  define GC_wrap_dlopen WRAP_DLFUNC(dlopen)
  79  GC_API void *
  80  GC_wrap_dlopen(const char *path, int mode)
  81  {
  82    void *result;
  83  
  84  #  ifndef USE_PROC_FOR_LIBRARIES
  85    /*
  86     * Disable collections.  This solution risks heap growth (or, even,
  87     * heap overflow) but there seems no better solutions.
  88     */
  89    disable_gc_for_dlopen();
  90  #  endif
  91    result = REAL_DLFUNC(dlopen)(path, mode);
  92  #  ifndef USE_PROC_FOR_LIBRARIES
  93    /* This undoes `disable_gc_for_dlopen()`. */
  94    GC_enable();
  95  #  endif
  96    return result;
  97  }
  98  #  undef GC_wrap_dlopen
  99  
 100  /*
 101   * Define `GC_` function as an alias for the plain one, which will be
 102   * intercepted.  This allows files that include `gc.h` file, and hence
 103   * generate references to the `GC_` symbol, to see the right symbol.
 104   */
 105  #  ifdef GC_USE_LD_WRAP
 106  
 107  GC_API void *
 108  GC_dlopen(const char *path, int mode)
 109  {
 110    return dlopen(path, mode);
 111  }
 112  #  endif /* GC_USE_LD_WRAP */
 113  
 114  #  ifdef GC_MUST_RESTORE_REDEFINED_DLOPEN
 115  #    define dlopen GC_dlopen
 116  #  endif
 117  
 118  #endif /* GC_PTHREADS && !GC_NO_DLOPEN */
 119