-
Notifications
You must be signed in to change notification settings - Fork 407
/
gc_dlopen.c
107 lines (96 loc) · 3.87 KB
/
gc_dlopen.c
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
97
98
99
100
101
102
103
104
105
106
107
/*
* 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"
/* 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)
# 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
/* 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 cannot just acquire the allocator 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
static void
disable_gc_for_dlopen(void)
{
LOCK();
while (GC_incremental && GC_collection_in_progress()) {
ENTER_GC();
GC_collect_a_little_inner(1000);
EXIT_GC();
}
++GC_dont_gc;
UNLOCK();
}
# endif
/* Redefine dlopen to guarantee mutual exclusion with */
/* GC_register_dynamic_libraries. Should probably happen for */
/* other operating systems, too. */
/* This is similar to WRAP/REAL_FUNC() in pthread_support.c. */
# ifdef GC_USE_LD_WRAP
# define WRAP_DLFUNC(f) __wrap_##f
# define REAL_DLFUNC(f) __real_##f
void *REAL_DLFUNC(dlopen)(const char *, int);
# else
# define WRAP_DLFUNC(f) GC_##f
# define REAL_DLFUNC(f) f
# endif
# define GC_wrap_dlopen WRAP_DLFUNC(dlopen)
GC_API void *
GC_wrap_dlopen(const char *path, int mode)
{
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
/* This undoes disable_gc_for_dlopen(). */
GC_enable();
# endif
return result;
}
# undef GC_wrap_dlopen
# 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 */
# ifdef GC_MUST_RESTORE_REDEFINED_DLOPEN
# define dlopen GC_dlopen
# endif
#endif /* GC_PTHREADS && !GC_NO_DLOPEN */