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