gc_dlopen.c 3.79 KB
Newer Older
eg's avatar
eg committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
 * Copyright (c) 1997 by Silicon Graphics.  All rights reserved.
 * Copyright (c) 2000 by Hewlett-Packard Company.  All rights reserved.
 *
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 *
 * Permission is hereby granted to use or copy this program
 * for any purpose,  provided the above notices are retained on all copies.
 * Permission to modify the code and to distribute modified code is granted,
 * provided the above notices are retained, and a notice that the code was
 * modified is included with the above copyright notice.
 */

#include "private/gc_priv.h"

18 19 20 21 22
/* This used to be in dyn_load.c.  It was extracted into a separate     */
/* file to avoid having to link against libdl.{a,so} if the client      */
/* doesn't call dlopen.  Of course this fails if the collector is in    */
/* a dynamic library. -HB                                               */
#if defined(GC_PTHREADS) && !defined(GC_NO_DLOPEN)
eg's avatar
eg committed
23

24 25 26 27 28 29 30 31 32 33
#undef GC_MUST_RESTORE_REDEFINED_DLOPEN
#if defined(dlopen) && !defined(GC_USE_LD_WRAP)
  /* To support various threads pkgs, gc.h interposes on dlopen by      */
  /* defining "dlopen" to be "GC_dlopen", which is implemented below.   */
  /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the    */
  /* real system dlopen() in their implementation. We first remove      */
  /* gc.h's dlopen definition and restore it later, after GC_dlopen().  */
# undef dlopen
# define GC_MUST_RESTORE_REDEFINED_DLOPEN
#endif
34

35 36 37 38 39 40 41 42 43
/* Make sure we're not in the middle of a collection, and make sure we  */
/* don't start any.  This is invoked prior to a dlopen call to avoid    */
/* synchronization issues.  We can't just acquire the allocation lock,  */
/* since startup code in dlopen may try to allocate.  This solution     */
/* risks heap growth (or, even, heap overflow) in the presence of many  */
/* dlopen calls in either a multi-threaded environment, or if the       */
/* library initialization code allocates substantial amounts of GC'ed   */
/* memory.                                                              */
#ifndef USE_PROC_FOR_LIBRARIES
44
  static void disable_gc_for_dlopen(void)
eg's avatar
eg committed
45
  {
46
    DCL_LOCK_STATE;
eg's avatar
eg committed
47 48
    LOCK();
    while (GC_incremental && GC_collection_in_progress()) {
49
      GC_collect_a_little_inner(1000);
eg's avatar
eg committed
50
    }
eg's avatar
eg committed
51
    ++GC_dont_gc;
eg's avatar
eg committed
52 53
    UNLOCK();
  }
54
#endif
eg's avatar
eg committed
55

56 57 58
/* Redefine dlopen to guarantee mutual exclusion with           */
/* GC_register_dynamic_libraries.  Should probably happen for   */
/* other operating systems, too.                                */
eg's avatar
eg committed
59

60
/* This is similar to WRAP/REAL_FUNC() in pthread_support.c.    */
eg's avatar
eg committed
61
#ifdef GC_USE_LD_WRAP
62 63 64
# define WRAP_DLFUNC(f) __wrap_##f
# define REAL_DLFUNC(f) __real_##f
  void * REAL_DLFUNC(dlopen)(const char *, int);
eg's avatar
eg committed
65
#else
66 67
# define WRAP_DLFUNC(f) GC_##f
# define REAL_DLFUNC(f) f
eg's avatar
eg committed
68
#endif
69 70

GC_API void * WRAP_DLFUNC(dlopen)(const char *path, int mode)
eg's avatar
eg committed
71
{
72 73 74 75 76 77 78 79 80 81 82 83
  void * result;

# ifndef USE_PROC_FOR_LIBRARIES
    /* Disable collections.  This solution risks heap growth (or,       */
    /* even, heap overflow) but there seems no better solutions.        */
    disable_gc_for_dlopen();
# endif
  result = REAL_DLFUNC(dlopen)(path, mode);
# ifndef USE_PROC_FOR_LIBRARIES
    GC_enable(); /* undoes disable_gc_for_dlopen */
# endif
  return(result);
eg's avatar
eg committed
84
}
85

86 87 88 89 90 91 92 93 94
#ifdef GC_USE_LD_WRAP
  /* Define GC_ function as an alias for the plain one, which will be   */
  /* intercepted.  This allows files which include gc.h, and hence      */
  /* generate references to the GC_ symbol, to see the right symbol.    */
  GC_API void *GC_dlopen(const char *path, int mode)
  {
    return dlopen(path, mode);
  }
#endif /* GC_USE_LD_WRAP */
95

96 97 98
#ifdef GC_MUST_RESTORE_REDEFINED_DLOPEN
# define dlopen GC_dlopen
#endif
99

100
#endif  /* GC_PTHREADS && !GC_NO_DLOPEN */