Module Name:    src
Committed By:   joerg
Date:           Mon Mar 28 00:37:41 UTC 2011

Modified Files:
        src/libexec/ld.elf_so: rtld.c

Log Message:
Refine locking scheme around init/fini to not hold the exclusive lock.
Use a simple generation count instead and restart looking for work if it
changed (e.g. due to an dlopen call from an init function).
Leave the possible dlclose() race for now.


To generate a diff of this commit:
cvs rdiff -u -r1.146 -r1.147 src/libexec/ld.elf_so/rtld.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/libexec/ld.elf_so/rtld.c
diff -u src/libexec/ld.elf_so/rtld.c:1.146 src/libexec/ld.elf_so/rtld.c:1.147
--- src/libexec/ld.elf_so/rtld.c:1.146	Sun Mar 27 22:20:51 2011
+++ src/libexec/ld.elf_so/rtld.c	Mon Mar 28 00:37:40 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: rtld.c,v 1.146 2011/03/27 22:20:51 joerg Exp $	 */
+/*	$NetBSD: rtld.c,v 1.147 2011/03/28 00:37:40 joerg Exp $	 */
 
 /*
  * Copyright 1996 John D. Polstra.
@@ -40,7 +40,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: rtld.c,v 1.146 2011/03/27 22:20:51 joerg Exp $");
+__RCSID("$NetBSD: rtld.c,v 1.147 2011/03/28 00:37:40 joerg Exp $");
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -89,6 +89,7 @@
 Obj_Entry       _rtld_objself;	/* The dynamic linker shared object */
 u_int		_rtld_objcount;	/* Number of objects in _rtld_objlist */
 u_int		_rtld_objloads;	/* Number of objects loaded in _rtld_objlist */
+u_int		_rtld_objgen;	/* Generation count for _rtld_objlist */
 const char	_rtld_path[] = _PATH_RTLD;
 
 /* Initialize a fake symbol for resolving undefined weak references. */
@@ -139,9 +140,13 @@
 	Objlist_Entry *elm;
 	Objlist finilist;
 	Obj_Entry *obj;
+	void (*fini)(void);
+	u_int cur_objgen;
 
 	dbg(("_rtld_call_fini_functions(%d)", force));
 
+restart:
+	cur_objgen = ++_rtld_objgen;
 	SIMPLEQ_INIT(&finilist);
 	_rtld_initlist_tsort(&finilist, 1);
 
@@ -157,10 +162,20 @@
 		dbg (("calling fini function %s at %p",  obj->path,
 		    (void *)obj->fini));
 		obj->fini_called = 1;
-		/* XXXlocking: exit point */
-		_rtld_mutex_may_recurse = true;
-		(*obj->fini)();
-		_rtld_mutex_may_recurse = false;
+		/*
+		 * XXX This can race against a concurrent dlclose().
+		 * XXX In that case, the object could be unmapped before
+		 * XXX the fini() call is done.
+		 */
+		fini = obj->fini;
+		_rtld_exclusive_exit();
+		(*fini)();
+		_rtld_exclusive_enter();
+		if (_rtld_objgen != cur_objgen) {
+			dbg(("restarting fini iteration"));
+			_rtld_objlist_clear(&finilist);
+			goto restart;
+		}
 	}
 
 	/* Second pass: objects marked with DF_1_INITFIRST. */
@@ -175,10 +190,16 @@
 		dbg (("calling fini function %s at %p (DF_1_INITFIRST)",
 		    obj->path, (void *)obj->fini));
 		obj->fini_called = 1;
-		/* XXXlocking: exit point */
-		_rtld_mutex_may_recurse = true;
-		(*obj->fini)();
-		_rtld_mutex_may_recurse = false;
+		/* XXX See above for the race condition here */
+		fini = obj->fini;
+		_rtld_exclusive_exit();
+		(*fini)();
+		_rtld_exclusive_enter();
+		if (_rtld_objgen != cur_objgen) {
+			dbg(("restarting fini iteration"));
+			_rtld_objlist_clear(&finilist);
+			goto restart;
+		}
 	}
 
         _rtld_objlist_clear(&finilist);
@@ -190,8 +211,13 @@
 	Objlist_Entry *elm;
 	Objlist initlist;
 	Obj_Entry *obj;
+	void (*init)(void);
+	u_int cur_objgen;
 
 	dbg(("_rtld_call_init_functions()"));
+
+restart:
+	cur_objgen = ++_rtld_objgen;
 	SIMPLEQ_INIT(&initlist);
 	_rtld_initlist_tsort(&initlist, 0);
 
@@ -204,10 +230,15 @@
 		dbg (("calling init function %s at %p (DF_1_INITFIRST)",
 		    obj->path, (void *)obj->init));
 		obj->init_called = 1;
-		/* XXXlocking: exit point */
-		_rtld_mutex_may_recurse = true;
-		(*obj->init)();
-		_rtld_mutex_may_recurse = false;
+		init = obj->init;
+		_rtld_exclusive_exit();
+		(*init)();
+		_rtld_exclusive_enter();
+		if (_rtld_objgen != cur_objgen) {
+			dbg(("restarting init iteration"));
+			_rtld_objlist_clear(&initlist);
+			goto restart;
+		}
 	}
 
 	/* Second pass: all other objects. */
@@ -219,10 +250,15 @@
 		dbg (("calling init function %s at %p",  obj->path,
 		    (void *)obj->init));
 		obj->init_called = 1;
-		/* XXXlocking: exit point */
-		_rtld_mutex_may_recurse = true;
-		(*obj->init)();
-		_rtld_mutex_may_recurse = false;
+		init = obj->init;
+		_rtld_exclusive_exit();
+		(*init)();
+		_rtld_exclusive_enter();
+		if (_rtld_objgen != cur_objgen) {
+			dbg(("restarting init iteration"));
+			_rtld_objlist_clear(&initlist);
+			goto restart;
+		}
 	}
 
         _rtld_objlist_clear(&initlist);

Reply via email to