aboutsummaryrefslogtreecommitdiffstats
path: root/gc/gc_dlopen.c
blob: 943c4b0c3eb9afa0741e4ed931b55b591cb9e629 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/*
 * 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.
 *
 * Original author: Bill Janssen
 * Heavily modified by Hans Boehm and others
 */

/*
 * 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.  -HB
 */

#include "private/gc_priv.h"

# if defined(LINUX_THREADS) || defined(SOLARIS_THREADS) \
     || defined(HPUX_THREADS) || defined(IRIX_THREADS)

# 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
# endif

  /* Make sure we're not in the middle of a collection, and make	*/
  /* sure we don't start any.	Returns previous value of GC_dont_gc.	*/
  /* 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 in the presence of many dlopen	*/
  /* calls in either a multithreaded environment, or if the library	*/
  /* initialization code allocates substantial amounts of GC'ed memory.	*/
  /* But I don't know of a better solution.				*/
  /* This can still deadlock if the client explicitly starts a GC 	*/
  /* during the dlopen.  He shouldn't do that.				*/
  static GC_bool disable_gc_for_dlopen()
  {
    GC_bool result;
    LOCK();
    result = GC_dont_gc;
    while (GC_incremental && GC_collection_in_progress()) {
	GC_collect_a_little_inner(1000);
    }
    GC_dont_gc = TRUE;
    UNLOCK();
    return(result);
  }

  /* Redefine dlopen to guarantee mutual exclusion with	*/
  /* GC_register_dynamic_libraries.			*/
  /* Should probably happen for other operating	systems, too. */

#include <dlfcn.h>

#ifdef GC_USE_LD_WRAP
  void * __wrap_dlopen(const char *path, int mode)
#else
  void * GC_dlopen(path, mode)
  GC_CONST char * path;
  int mode;
#endif
{
    void * result;
    GC_bool dont_gc_save;
    
#   ifndef USE_PROC_FOR_LIBRARIES
      dont_gc_save = disable_gc_for_dlopen();
#   endif
#   ifdef GC_USE_LD_WRAP
      result = (void *)__real_dlopen(path, mode);
#   else
      result = dlopen(path, mode);
#   endif
#   ifndef USE_PROC_FOR_LIBRARIES
      GC_dont_gc = dont_gc_save;
#   endif
    return(result);
}
# endif  /* LINUX_THREADS || SOLARIS_THREADS || ... */