svn commit: trunk/uClibc/libc/unistd

vapier at uclibc.org vapier at uclibc.org
Wed Jan 23 16:56:55 UTC 2008


Author: vapier
Date: 2008-01-23 08:56:52 -0800 (Wed, 23 Jan 2008)
New Revision: 20888

Log:
give execlp() its own cache on no-mmu to avoid recursive cache fighting

Modified:
   trunk/uClibc/libc/unistd/exec.c


Changeset:
Modified: trunk/uClibc/libc/unistd/exec.c
===================================================================
--- trunk/uClibc/libc/unistd/exec.c	2008-01-23 13:02:20 UTC (rev 20887)
+++ trunk/uClibc/libc/unistd/exec.c	2008-01-23 16:56:52 UTC (rev 20888)
@@ -42,47 +42,66 @@
 libc_hidden_proto(getenv)
 
 /**********************************************************************/
-#if defined(__ARCH_USE_MMU__) || defined(__UCLIBC_UCLINUX_BROKEN_MUNMAP__)
+#define EXEC_FUNC_COMMON 0
+#define EXEC_FUNC_EXECVP 1
+#if defined(__ARCH_USE_MMU__)
 
-/* We have an MMU, so use alloca() to grab space for buffers and
- * arg lists.  Also fall back to alloca() if munmap() is broken. */
+/* We have an MMU, so use alloca() to grab space for buffers and arg lists. */
 
-# define EXEC_ALLOC_SIZE(VAR)	/* nothing to do */
-# define EXEC_ALLOC(SIZE,VAR)	alloca((SIZE))
-# define EXEC_FREE(PTR,VAR)		((void)0)
+# define EXEC_ALLOC_SIZE(VAR)      /* nothing to do */
+# define EXEC_ALLOC(SIZE,VAR,FUNC) alloca((SIZE))
+# define EXEC_FREE(PTR,VAR)        ((void)0)
 
 #else
 
-/* We do not have an MMU, so using alloca() is not an option.
- * Less obviously, using malloc() is not an option either since
- * malloc()ed memory can leak in a vfork() and exec*() situation.
- * Therefore, we must use mmap() and unmap() directly, caching
- * the result as we go.  This way we minimize the leak to 1
- * allocation.
+/* We do not have an MMU, so using alloca() is not an option (as this will
+ * easily overflow the stack in most setups).  Less obviously, using malloc()
+ * is not an option either since malloc()ed memory can leak in from a vfork()ed
+ * child into the parent as no one is around after the child calls exec*() to
+ * free() the memory.  Therefore, we must use mmap() and unmap() directly,
+ * caching the result as we go.  This way we minimize the leak by reusing the
+ * memory with every call to an exec*().
+ *
+ * To prevent recursive use of the same cached memory, we have to give execvp()
+ * its own cache.  Here are the nested exec calls (a/-: alloc/no-alloc):
+ *  execve(-) -> calls straight to kernel
+ *  execl(a)  -> execve(-)
+ *  execlp(a) -> execvp(a)	!! recursive usage !!
+ *  execle(a) -> execve(-)
+ *  execv(-)  -> execve(-)
+ *  execvp(a) -> execve(-)
  */
 
-# define EXEC_ALLOC_SIZE(VAR)	size_t VAR;	/* Semicolon included! */
-# define EXEC_ALLOC(SIZE,VAR)	__exec_alloc((VAR = (SIZE)))
-# define EXEC_FREE(PTR,VAR)		((void)0)
+# define EXEC_ALLOC_SIZE(VAR)      /* nothing to do */
+# define EXEC_ALLOC(SIZE,VAR,FUNC) __exec_alloc((SIZE), FUNC)
+# define EXEC_FREE(PTR,VAR)        ((void)0)
 
-extern void *__exec_alloc(size_t size) attribute_hidden;
+extern void *__exec_alloc(size_t size, int func) attribute_hidden;
 
 # ifdef L___exec_alloc
 
-void attribute_hidden *__exec_alloc(size_t size)
+void attribute_hidden *__exec_alloc(size_t size, int func)
 {
-	static void *p;
-	static size_t old_size;
+	static void *common_cache, *execvp_cache;
+	static size_t common_size, execvp_size;
 
-	if (old_size >= size)
-		return p;
-	else if (p)
-		munmap(p, old_size);
+	void **cache = (func ? &execvp_cache : &common_cache);
+	size_t *cache_size = (func ? &execvp_size : &common_size);
 
-	old_size = size;
-	p = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
+	if (*cache_size >= size)
+		return *cache;
+	else if (*cache)
+		munmap(*cache, *cache_size);
 
-	return (p != MAP_FAILED) ? p : NULL;
+	*cache_size = size;
+	return *cache = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
+
+	/* We don't actually handle OOM in the exec funcs ...
+	if (*cache != MAP_FAILED)
+		return *cache;
+	else
+		return (*cache = NULL);
+	*/
 }
 
 # endif
@@ -98,7 +117,7 @@
 	char **argv;
 	char **p;
 	va_list args;
-	
+
 	n = 0;
 	va_start(args, arg);
 	do {
@@ -106,7 +125,7 @@
 	} while (va_arg(args, char *));
 	va_end(args);
 
-	p = argv = (char **) EXEC_ALLOC((n+1) * sizeof(char *), size);
+	p = argv = (char **) EXEC_ALLOC((n+1) * sizeof(char *), size, EXEC_FUNC_COMMON);
 
 	p[0] = (char *)arg;
 
@@ -146,7 +165,7 @@
 	char **p;
 	char *const *envp;
 	va_list args;
-	
+
 	n = 0;
 	va_start(args, arg);
 	do {
@@ -155,7 +174,7 @@
 	envp = va_arg(args, char *const *);	/* Varies from execl and execlp. */
 	va_end(args);
 
-	p = argv = (char **) EXEC_ALLOC((n+1) * sizeof(char *), size);
+	p = argv = (char **) EXEC_ALLOC((n+1) * sizeof(char *), size, EXEC_FUNC_COMMON);
 
 	p[0] = (char *)arg;
 
@@ -184,7 +203,7 @@
 	char **argv;
 	char **p;
 	va_list args;
-	
+
 	n = 0;
 	va_start(args, arg);
 	do {
@@ -192,7 +211,7 @@
 	} while (va_arg(args, char *));
 	va_end(args);
 
-	p = argv = (char **) EXEC_ALLOC((n+1) * sizeof(char *), size);
+	p = argv = (char **) EXEC_ALLOC((n+1) * sizeof(char *), size, EXEC_FUNC_COMMON);
 
 	p[0] = (char *)arg;
 
@@ -248,7 +267,7 @@
 			/* Need the dimension - 1.  We omit counting the trailing
 			 * NULL but we actually omit the first entry. */
 			for (n=0 ; argv[n] ; n++) {}
-			nargv = (char **) EXEC_ALLOC((n+2) * sizeof(char *), size2);
+			nargv = (char **) EXEC_ALLOC((n+2) * sizeof(char *), size2, EXEC_FUNC_EXECVP);
 			nargv[0] = argv[0];
 			nargv[1] = (char *)path;
 			memcpy(nargv+2, argv+1, n*sizeof(char *));
@@ -272,7 +291,8 @@
 		}
 		len = (FILENAME_MAX - 1) - plen;
 
-		if ((buf = EXEC_ALLOC(FILENAME_MAX, size)) != NULL) {
+		buf = EXEC_ALLOC(FILENAME_MAX, size, EXEC_FUNC_EXECVP);
+		{
 			int seen_small = 0;
 			s0 = buf + len;
 			memcpy(s0, path, plen+1);




More information about the uClibc-cvs mailing list