/* * 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 is located in this file (rather than in `dyn_load.c` file) to * avoid having to link against `libdl` library if the client does not * call `dlopen()`. Of course, this is meaningless if the collector is * in a dynamic library. */ #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 packages, `gc.h` file interposes on `dlopen` * by defining the latter to be `GC_dlopen`, which is implemented below. * However, `GC_dlopen()` itself uses the real system `dlopen()`, thus * we first remove `dlopen` definition by `gc.h` file and restore it later, * after `GC_dlopen()` definition. */ # undef dlopen # define GC_MUST_RESTORE_REDEFINED_DLOPEN # endif /* * Make sure we are not in the middle of a collection, and make sure we * do not 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 garbage * collected memory. */ # ifndef USE_PROC_FOR_LIBRARIES static void disable_gc_for_dlopen(void) { LOCK(); while (GC_incremental && GC_collection_in_progress()) { GC_collect_a_little_inner(1000); } ++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_FUNC`/`REAL_FUNC` in `pthread_support.c` file. */ # 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 /* * Define `GC_` function as an alias for the plain one, which will be * intercepted. This allows files that include `gc.h` file, and hence * generate references to the `GC_` symbol, to see the right symbol. */ # ifdef GC_USE_LD_WRAP 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 */