@@ -533,6 +533,23 @@ call_dl_init (void *closure)
_dl_init (args->new, args->argc, args->argv, args->env);
}
+/* Return true if the object does not need any processing beyond the
+ l_direct_opencount update. Needs to be kept in sync with the logic
+ in dl_o-en_worker_begin after the l->l_searchlist.r_list != NULL check.
+ MODE is the dlopen mode argument. */
+static bool
+is_already_fully_open (struct link_map_private *map, int mode)
+{
+ return (map != NULL /* An existing map was found. */
+ /* dlopen completed initialization of this map. Maps with
+ l_type == lt_library start out as partially initialized. */
+ && map->l_searchlist.r_list != NULL
+ /* The object is already in the global scope if requested. */
+ && (!(mode & RTLD_GLOBAL) || map->l_global)
+ /* The object is already NODELETE if requested. */
+ && (!(mode & RTLD_NODELETE) || map->l_rw->l_nodelete_active));
+}
+
static void
dl_open_worker_begin (void *a)
{
@@ -559,9 +576,10 @@ dl_open_worker_begin (void *a)
_dl_debug_initialize (0, args->nsid);
/* Load the named object. */
- struct link_map_private *new;
- args->map = new = _dl_map_object (args->caller_map, file, lt_loaded, 0,
- mode | __RTLD_CALLMAP, args->nsid);
+ struct link_map_private *new = args->map;
+ if (new == NULL)
+ args->map = new = _dl_map_new_object (args->caller_map, file, lt_loaded, 0,
+ mode | __RTLD_CALLMAP, args->nsid);
/* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
set and the object is not already loaded. */
@@ -578,7 +596,7 @@ dl_open_worker_begin (void *a)
/* This object is directly loaded. */
++new->l_rw->l_direct_opencount;
- /* It was already open. */
+ /* It was already open. See is_already_fully_open above. */
if (__glibc_unlikely (new->l_searchlist.r_list != NULL))
{
/* Let the user know about the opencount. */
@@ -881,7 +899,6 @@ no more namespaces available for dlmopen()"));
struct dl_open_args args;
args.file = file;
args.mode = mode;
- args.map = NULL;
args.nsid = nsid;
/* args.libc_already_loaded is always assigned by dl_open_worker
(before any explicit/non-local returns). */
@@ -906,6 +923,15 @@ no more namespaces available for dlmopen()"));
else
args.caller_map = NULL;
+ args.map = _dl_lookup_map (args.nsid, file);
+ if (is_already_fully_open (args.map, mode))
+ {
+ /* We can use the fast path. */
+ ++args.map->l_rw->l_direct_opencount;
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ return args.map;
+ }
+
struct dl_exception exception;
int errcode = _dl_catch_exception (&exception, dl_open_worker, &args);