tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Trivial program size inflation



> Date: Tue, 4 Jul 2023 18:30:58 +0000
> From: Taylor R Campbell <campbell+netbsd-tech-userlevel%mumble.net@localhost>
> 
> Other low-hanging fruit I see would be to split getenv out of the
> other environment variable operations, to get rid of locking and
> rbtree stuff.  But it's diminishing returns at this point -- not clear
> the attached patchset/diff is worth committing.  Gets me down to this:
> 
>    text    data     bss     dec     hex filename
>   30744    3280    3376   37400    9218 main
> 
> After that, maybe we could find a substitute for the syslog_ss stuff
> in stack-protector -- but that's probably not worth the trouble, for
> what is maybe another few kilobytes or so.

...actually attached
From 14201a18296b67e2e254566ce0c5f3106c0b3e67 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Tue, 4 Jul 2023 18:16:08 +0000
Subject: [PATCH 1/3] rbtree(3): New RB_TREE_INITIALIZER macro.

Allows static initialization of an rbtree.

XXX pullup-10
---
 sys/sys/rbtree.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/sys/sys/rbtree.h b/sys/sys/rbtree.h
index b4a8ba3f7fc1..686cf2ed299a 100644
--- a/sys/sys/rbtree.h
+++ b/sys/sys/rbtree.h
@@ -125,12 +125,17 @@ TAILQ_HEAD(rb_node_qh, rb_node);
 #define	RB_TAILQ_INSERT_HEAD(a, b, c)		TAILQ_INSERT_HEAD(a, b, c)
 #define	RB_TAILQ_INSERT_BEFORE(a, b, c)		TAILQ_INSERT_BEFORE(a, b, c)
 #define	RB_TAILQ_INSERT_AFTER(a, b, c, d)	TAILQ_INSERT_AFTER(a, b, c, d)
+
+#define	RBDEBUG_TREE_INITIALIZER(t)					      \
+	.rbt_nodes = TAILQ_INITIALIZER((t).rbt_nodes),
 #else
 #define	RB_TAILQ_REMOVE(a, b, c)		do { } while (/*CONSTCOND*/0)
 #define	RB_TAILQ_INIT(a)			do { } while (/*CONSTCOND*/0)
 #define	RB_TAILQ_INSERT_HEAD(a, b, c)		do { } while (/*CONSTCOND*/0)
 #define	RB_TAILQ_INSERT_BEFORE(a, b, c)		do { } while (/*CONSTCOND*/0)
 #define	RB_TAILQ_INSERT_AFTER(a, b, c, d)	do { } while (/*CONSTCOND*/0)
+
+#define	RBDEBUG_TREE_INITIALIZER(t)		/* nothing */
 #endif /* RBDEBUG */
 
 /*
@@ -181,6 +186,12 @@ typedef struct rb_tree {
 #define	RBSTAT_DEC(v)	do { } while (/*CONSTCOND*/0)
 #endif
 
+#define	RB_TREE_INITIALIZER(t, ops) (rb_tree_t)				      \
+{									      \
+	.rbt_ops = (ops),						      \
+	RBDEBUG_TREE_INITIALIZER(t)					      \
+}
+
 void	rb_tree_init(rb_tree_t *, const rb_tree_ops_t *);
 void *	rb_tree_insert_node(rb_tree_t *, void *);
 void *	rb_tree_find_node(rb_tree_t *, const void *);

From ef18c568cb559da7e82e7951050cf7cd54b0a350 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Tue, 4 Jul 2023 18:17:23 +0000
Subject: [PATCH 2/3] libc: Use RB_TREE_INITIALIZER to nix initfini.c/_env.c
 coupling.

XXX pullup-10
---
 lib/libc/misc/initfini.c |  3 ---
 lib/libc/stdlib/_env.c   | 10 ++--------
 2 files changed, 2 insertions(+), 11 deletions(-)

diff --git a/lib/libc/misc/initfini.c b/lib/libc/misc/initfini.c
index 9f5cec1d2cce..6d17c167c71e 100644
--- a/lib/libc/misc/initfini.c
+++ b/lib/libc/misc/initfini.c
@@ -132,7 +132,4 @@ _libc_init(void)
 
 	/* Initialize the atexit mutexes */
 	__libc_atexit_init();
-
-	/* Initialize environment memory RB tree. */
-	__libc_env_init();
 }
diff --git a/lib/libc/stdlib/_env.c b/lib/libc/stdlib/_env.c
index 6608522790f8..316459356bf7 100644
--- a/lib/libc/stdlib/_env.c
+++ b/lib/libc/stdlib/_env.c
@@ -73,7 +73,8 @@ static const rb_tree_ops_t env_tree_ops = {
 };
 
 /* The single instance of above tree. */
-static rb_tree_t	env_tree;
+static rb_tree_t	env_tree =
+    RB_TREE_INITIALIZER(env_tree, &env_tree_ops);
 
 /* The allocated environment. */
 static char	**allocated_environ;
@@ -401,10 +402,3 @@ __unlockenv(void)
 }
 
 #endif
-
-/* Initialize environment memory RB tree. */
-void __section(".text.startup")
-__libc_env_init(void)
-{
-	rb_tree_init(&env_tree, &env_tree_ops);
-}

From 1d295afec1bd9645c672d8702ce6ee7ad5c32304 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Tue, 4 Jul 2023 17:26:18 +0000
Subject: [PATCH 3/3] WIP: libc: Split read-only environment logic into a
 separate unit.

The idea is to prune all the locking, rb, allocation, &c., from
statically linked programs that just call getenv.

Still WIP because I can't figure out how to make statically linked
read-only access elide the locking.

XXX pullup-10 (if we work out the issues)
---
 lib/libc/stdlib/Makefile.inc |   2 +-
 lib/libc/stdlib/_env.c       | 107 ++--------------------------------
 lib/libc/stdlib/_envlock.c   |  90 +++++++++++++++++++++++++++++
 lib/libc/stdlib/_findenv.c   | 108 +++++++++++++++++++++++++++++++++++
 lib/libc/stdlib/local.h      |   2 +
 5 files changed, 207 insertions(+), 102 deletions(-)
 create mode 100644 lib/libc/stdlib/_envlock.c
 create mode 100644 lib/libc/stdlib/_findenv.c

diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index fcc13020a7e6..6b33e66abab5 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -4,7 +4,7 @@
 # stdlib sources
 .PATH: ${ARCHDIR}/stdlib ${.CURDIR}/stdlib
 
-SRCS+=	_env.c _rand48.c \
+SRCS+=	_env.c _envlock.c _findenv.c _rand48.c \
 	a64l.c abort.c atexit.c atof.c atoi.c atol.c atoll.c \
 	bsearch.c cxa_thread_atexit.c drand48.c exit.c \
 	getenv.c getopt.c getopt_long.c getsubopt.c \
diff --git a/lib/libc/stdlib/_env.c b/lib/libc/stdlib/_env.c
index 316459356bf7..c4576a6901c6 100644
--- a/lib/libc/stdlib/_env.c
+++ b/lib/libc/stdlib/_env.c
@@ -82,11 +82,6 @@ static size_t	allocated_environ_size;
 
 #define	ENV_ARRAY_SIZE_MIN	16
 
-/* The lock protecting access to the environment. */
-#ifdef _REENTRANT
-static rwlock_t env_lock = RWLOCK_INITIALIZER;
-#endif
-
 /* Compatibility function. */
 char *__findenv(const char *name, int *offsetp);
 
@@ -121,33 +116,6 @@ env_tree_compare_key(void *ctx, const void *node, const void *key)
 	    (const uint8_t *)key - offsetof(env_node_t, data));
 }
 
-/*
- * Determine the of the name in an environment string. Return 0 if the
- * name is not valid.
- */
-size_t
-__envvarnamelen(const char *str, bool withequal)
-{
-	size_t l_name;
-
-	if (str == NULL)
-		return 0;
-
-	l_name = strcspn(str, "=");
-	if (l_name == 0)
-		return 0;
-
-	if (withequal) {
-		if (str[l_name] != '=')
-			return 0;
-	} else {
-		if (str[l_name] == '=')
-			return 0;
-	}
-
-	return l_name;
-}
-
 /*
  * Free memory occupied by environment variable if possible. This function
  * must be called with the environment write locked.
@@ -247,26 +215,19 @@ __scrubenv(void)
 
 /*
  * Get a (new) slot in the environment. This function must be called with
- * the environment write locked.
+ * the environment locked, with a write-lock if allocate=true.
  */
 ssize_t
 __getenvslot(const char *name, size_t l_name, bool allocate)
 {
-	size_t new_size, num_entries, required_size;
+	ssize_t num_entries;
+	size_t new_size, required_size;
 	char **new_environ;
 
 	/* Search for an existing environment variable of the given name. */
-	num_entries = 0;
-	if (environ != NULL) {
-		while (environ[num_entries] != NULL) {
-			if (strncmp(environ[num_entries], name, l_name) == 0 &&
-			    environ[num_entries][l_name] == '=') {
-				/* We found a match. */
-				return num_entries;
-			}
-			num_entries ++;
-		}
-	}
+	num_entries = __findenvslot(name, l_name);
+	if (num_entries < 0)
+		return -1;
 
 	/* No match found, return if we don't want to allocate a new slot. */
 	if (!allocate)
@@ -328,16 +289,6 @@ __getenvslot(const char *name, size_t l_name, bool allocate)
 	return num_entries;
 }
 
-/* Find a string in the environment. */
-char *
-__findenvvar(const char *name, size_t l_name)
-{
-	ssize_t offset;
-
-	offset = __getenvslot(name, l_name, false);
-	return (offset != -1) ? environ[offset] + l_name + 1 : NULL;
-}
-
 /* Compatibility interface, do *not* call this function. */
 char *
 __findenv(const char *name, int *offsetp)
@@ -356,49 +307,3 @@ __findenv(const char *name, int *offsetp)
 	*offsetp = (int)offset;
 	return environ[offset] + l_name + 1;
 }
-
-#ifdef _REENTRANT
-
-/* Lock the environment for read. */
-bool
-__readlockenv(void)
-{
-	int error;
-
-	error = rwlock_rdlock(&env_lock);
-	if (error == 0)
-		return true;
-
-	errno = error;
-	return false;
-}
-
-/* Lock the environment for write. */
-bool
-__writelockenv(void)
-{
-	int error;
-
-	error = rwlock_wrlock(&env_lock);
-	if (error == 0)
-		return true;
-
-	errno = error;
-	return false;
-}
-
-/* Unlock the environment for write. */
-bool
-__unlockenv(void)
-{
-	int error;
-
-	error = rwlock_unlock(&env_lock);
-	if (error == 0)
-		return true;
-
-	errno = error;
-	return false;
-}
-
-#endif
diff --git a/lib/libc/stdlib/_envlock.c b/lib/libc/stdlib/_envlock.c
new file mode 100644
index 000000000000..27c596fbabd5
--- /dev/null
+++ b/lib/libc/stdlib/_envlock.c
@@ -0,0 +1,90 @@
+/*	$NetBSD: _env.c,v 1.13 2022/03/12 17:31:39 christos Exp $ */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matthias Scheler.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: _env.c,v 1.13 2022/03/12 17:31:39 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include "env.h"
+#include "local.h"
+#include "namespace.h"
+
+#include <errno.h>
+
+#ifdef _REENTRANT
+
+/* The lock protecting access to the environment. */
+static rwlock_t env_lock = RWLOCK_INITIALIZER;
+
+/* Lock the environment for read. */
+bool
+__readlockenv(void)
+{
+	int error;
+
+	error = rwlock_rdlock(&env_lock);
+	if (error == 0)
+		return true;
+
+	errno = error;
+	return false;
+}
+
+/* Lock the environment for write. */
+bool
+__writelockenv(void)
+{
+	int error;
+
+	error = rwlock_wrlock(&env_lock);
+	if (error == 0)
+		return true;
+
+	errno = error;
+	return false;
+}
+
+/* Unlock the environment for write. */
+bool
+__unlockenv(void)
+{
+	int error;
+
+	error = rwlock_unlock(&env_lock);
+	if (error == 0)
+		return true;
+
+	errno = error;
+	return false;
+}
+
+#endif
diff --git a/lib/libc/stdlib/_findenv.c b/lib/libc/stdlib/_findenv.c
new file mode 100644
index 000000000000..fa2cc89cec12
--- /dev/null
+++ b/lib/libc/stdlib/_findenv.c
@@ -0,0 +1,108 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matthias Scheler.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * _findenv.c -- subroutines for read-only access to the environment
+ *
+ * Kept in a separate compilation unit from _env.c so that statically
+ * linked programs using only getenv(3) can omit code for the write
+ * access paths and skip the runtime overhead of locking.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD$");
+
+#include "env.h"
+#include "local.h"
+#include "namespace.h"
+
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+/*
+ * Determine the of the name in an environment string. Return 0 if the
+ * name is not valid.
+ */
+size_t
+__envvarnamelen(const char *str, bool withequal)
+{
+	size_t l_name;
+
+	if (str == NULL)
+		return 0;
+
+	l_name = strcspn(str, "=");
+	if (l_name == 0)
+		return 0;
+
+	if (withequal) {
+		if (str[l_name] != '=')
+			return 0;
+	} else {
+		if (str[l_name] == '=')
+			return 0;
+	}
+
+	return l_name;
+}
+
+/*
+ * Get an existing slot in the environment. This function must be
+ * called with the environment locked.
+ */
+ssize_t
+__findenvslot(const char *name, size_t l_name)
+{
+	ssize_t num_entries;
+
+	for (num_entries = 0; environ[num_entries] != NULL; num_entries++) {
+		if (strncmp(environ[num_entries], name, l_name) == 0 &&
+		    environ[num_entries][l_name] == '=') {
+			return num_entries;
+		}
+		if (num_entries == SSIZE_MAX) /* paranoia */
+			return -1;
+	}
+	return -1;
+}
+
+/* Find a string in the environment. */
+char *
+__findenvvar(const char *name, size_t l_name)
+{
+	ssize_t offset;
+
+	offset = __findenvslot(name, l_name);
+	return (offset != -1) ? environ[offset] + l_name + 1 : NULL;
+}
diff --git a/lib/libc/stdlib/local.h b/lib/libc/stdlib/local.h
index 285a9b448614..c18f80245f6e 100644
--- a/lib/libc/stdlib/local.h
+++ b/lib/libc/stdlib/local.h
@@ -29,6 +29,8 @@
 #include <sys/types.h>
 #include <stdbool.h>
 
+extern ssize_t __findenvslot(const char *, size_t);
+
 extern size_t __envvarnamelen(const char *str, bool withequal);
 
 extern void __freeenvvar(char *envvar);
diff --git a/lib/libc/misc/initfini.c b/lib/libc/misc/initfini.c
index 9f5cec1d2cce..6d17c167c71e 100644
--- a/lib/libc/misc/initfini.c
+++ b/lib/libc/misc/initfini.c
@@ -132,7 +132,4 @@ _libc_init(void)
 
 	/* Initialize the atexit mutexes */
 	__libc_atexit_init();
-
-	/* Initialize environment memory RB tree. */
-	__libc_env_init();
 }
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index fcc13020a7e6..6b33e66abab5 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -4,7 +4,7 @@
 # stdlib sources
 .PATH: ${ARCHDIR}/stdlib ${.CURDIR}/stdlib
 
-SRCS+=	_env.c _rand48.c \
+SRCS+=	_env.c _envlock.c _findenv.c _rand48.c \
 	a64l.c abort.c atexit.c atof.c atoi.c atol.c atoll.c \
 	bsearch.c cxa_thread_atexit.c drand48.c exit.c \
 	getenv.c getopt.c getopt_long.c getsubopt.c \
diff --git a/lib/libc/stdlib/_env.c b/lib/libc/stdlib/_env.c
index 6608522790f8..c4576a6901c6 100644
--- a/lib/libc/stdlib/_env.c
+++ b/lib/libc/stdlib/_env.c
@@ -73,7 +73,8 @@ static const rb_tree_ops_t env_tree_ops = {
 };
 
 /* The single instance of above tree. */
-static rb_tree_t	env_tree;
+static rb_tree_t	env_tree =
+    RB_TREE_INITIALIZER(env_tree, &env_tree_ops);
 
 /* The allocated environment. */
 static char	**allocated_environ;
@@ -81,11 +82,6 @@ static size_t	allocated_environ_size;
 
 #define	ENV_ARRAY_SIZE_MIN	16
 
-/* The lock protecting access to the environment. */
-#ifdef _REENTRANT
-static rwlock_t env_lock = RWLOCK_INITIALIZER;
-#endif
-
 /* Compatibility function. */
 char *__findenv(const char *name, int *offsetp);
 
@@ -120,33 +116,6 @@ env_tree_compare_key(void *ctx, const void *node, const void *key)
 	    (const uint8_t *)key - offsetof(env_node_t, data));
 }
 
-/*
- * Determine the of the name in an environment string. Return 0 if the
- * name is not valid.
- */
-size_t
-__envvarnamelen(const char *str, bool withequal)
-{
-	size_t l_name;
-
-	if (str == NULL)
-		return 0;
-
-	l_name = strcspn(str, "=");
-	if (l_name == 0)
-		return 0;
-
-	if (withequal) {
-		if (str[l_name] != '=')
-			return 0;
-	} else {
-		if (str[l_name] == '=')
-			return 0;
-	}
-
-	return l_name;
-}
-
 /*
  * Free memory occupied by environment variable if possible. This function
  * must be called with the environment write locked.
@@ -246,26 +215,19 @@ __scrubenv(void)
 
 /*
  * Get a (new) slot in the environment. This function must be called with
- * the environment write locked.
+ * the environment locked, with a write-lock if allocate=true.
  */
 ssize_t
 __getenvslot(const char *name, size_t l_name, bool allocate)
 {
-	size_t new_size, num_entries, required_size;
+	ssize_t num_entries;
+	size_t new_size, required_size;
 	char **new_environ;
 
 	/* Search for an existing environment variable of the given name. */
-	num_entries = 0;
-	if (environ != NULL) {
-		while (environ[num_entries] != NULL) {
-			if (strncmp(environ[num_entries], name, l_name) == 0 &&
-			    environ[num_entries][l_name] == '=') {
-				/* We found a match. */
-				return num_entries;
-			}
-			num_entries ++;
-		}
-	}
+	num_entries = __findenvslot(name, l_name);
+	if (num_entries < 0)
+		return -1;
 
 	/* No match found, return if we don't want to allocate a new slot. */
 	if (!allocate)
@@ -327,16 +289,6 @@ __getenvslot(const char *name, size_t l_name, bool allocate)
 	return num_entries;
 }
 
-/* Find a string in the environment. */
-char *
-__findenvvar(const char *name, size_t l_name)
-{
-	ssize_t offset;
-
-	offset = __getenvslot(name, l_name, false);
-	return (offset != -1) ? environ[offset] + l_name + 1 : NULL;
-}
-
 /* Compatibility interface, do *not* call this function. */
 char *
 __findenv(const char *name, int *offsetp)
@@ -355,56 +307,3 @@ __findenv(const char *name, int *offsetp)
 	*offsetp = (int)offset;
 	return environ[offset] + l_name + 1;
 }
-
-#ifdef _REENTRANT
-
-/* Lock the environment for read. */
-bool
-__readlockenv(void)
-{
-	int error;
-
-	error = rwlock_rdlock(&env_lock);
-	if (error == 0)
-		return true;
-
-	errno = error;
-	return false;
-}
-
-/* Lock the environment for write. */
-bool
-__writelockenv(void)
-{
-	int error;
-
-	error = rwlock_wrlock(&env_lock);
-	if (error == 0)
-		return true;
-
-	errno = error;
-	return false;
-}
-
-/* Unlock the environment for write. */
-bool
-__unlockenv(void)
-{
-	int error;
-
-	error = rwlock_unlock(&env_lock);
-	if (error == 0)
-		return true;
-
-	errno = error;
-	return false;
-}
-
-#endif
-
-/* Initialize environment memory RB tree. */
-void __section(".text.startup")
-__libc_env_init(void)
-{
-	rb_tree_init(&env_tree, &env_tree_ops);
-}
diff --git a/lib/libc/stdlib/_envlock.c b/lib/libc/stdlib/_envlock.c
new file mode 100644
index 000000000000..27c596fbabd5
--- /dev/null
+++ b/lib/libc/stdlib/_envlock.c
@@ -0,0 +1,90 @@
+/*	$NetBSD: _env.c,v 1.13 2022/03/12 17:31:39 christos Exp $ */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matthias Scheler.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: _env.c,v 1.13 2022/03/12 17:31:39 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include "env.h"
+#include "local.h"
+#include "namespace.h"
+
+#include <errno.h>
+
+#ifdef _REENTRANT
+
+/* The lock protecting access to the environment. */
+static rwlock_t env_lock = RWLOCK_INITIALIZER;
+
+/* Lock the environment for read. */
+bool
+__readlockenv(void)
+{
+	int error;
+
+	error = rwlock_rdlock(&env_lock);
+	if (error == 0)
+		return true;
+
+	errno = error;
+	return false;
+}
+
+/* Lock the environment for write. */
+bool
+__writelockenv(void)
+{
+	int error;
+
+	error = rwlock_wrlock(&env_lock);
+	if (error == 0)
+		return true;
+
+	errno = error;
+	return false;
+}
+
+/* Unlock the environment for write. */
+bool
+__unlockenv(void)
+{
+	int error;
+
+	error = rwlock_unlock(&env_lock);
+	if (error == 0)
+		return true;
+
+	errno = error;
+	return false;
+}
+
+#endif
diff --git a/lib/libc/stdlib/_findenv.c b/lib/libc/stdlib/_findenv.c
new file mode 100644
index 000000000000..fa2cc89cec12
--- /dev/null
+++ b/lib/libc/stdlib/_findenv.c
@@ -0,0 +1,108 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matthias Scheler.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * _findenv.c -- subroutines for read-only access to the environment
+ *
+ * Kept in a separate compilation unit from _env.c so that statically
+ * linked programs using only getenv(3) can omit code for the write
+ * access paths and skip the runtime overhead of locking.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD$");
+
+#include "env.h"
+#include "local.h"
+#include "namespace.h"
+
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+/*
+ * Determine the of the name in an environment string. Return 0 if the
+ * name is not valid.
+ */
+size_t
+__envvarnamelen(const char *str, bool withequal)
+{
+	size_t l_name;
+
+	if (str == NULL)
+		return 0;
+
+	l_name = strcspn(str, "=");
+	if (l_name == 0)
+		return 0;
+
+	if (withequal) {
+		if (str[l_name] != '=')
+			return 0;
+	} else {
+		if (str[l_name] == '=')
+			return 0;
+	}
+
+	return l_name;
+}
+
+/*
+ * Get an existing slot in the environment. This function must be
+ * called with the environment locked.
+ */
+ssize_t
+__findenvslot(const char *name, size_t l_name)
+{
+	ssize_t num_entries;
+
+	for (num_entries = 0; environ[num_entries] != NULL; num_entries++) {
+		if (strncmp(environ[num_entries], name, l_name) == 0 &&
+		    environ[num_entries][l_name] == '=') {
+			return num_entries;
+		}
+		if (num_entries == SSIZE_MAX) /* paranoia */
+			return -1;
+	}
+	return -1;
+}
+
+/* Find a string in the environment. */
+char *
+__findenvvar(const char *name, size_t l_name)
+{
+	ssize_t offset;
+
+	offset = __findenvslot(name, l_name);
+	return (offset != -1) ? environ[offset] + l_name + 1 : NULL;
+}
diff --git a/lib/libc/stdlib/local.h b/lib/libc/stdlib/local.h
index 285a9b448614..c18f80245f6e 100644
--- a/lib/libc/stdlib/local.h
+++ b/lib/libc/stdlib/local.h
@@ -29,6 +29,8 @@
 #include <sys/types.h>
 #include <stdbool.h>
 
+extern ssize_t __findenvslot(const char *, size_t);
+
 extern size_t __envvarnamelen(const char *str, bool withequal);
 
 extern void __freeenvvar(char *envvar);
diff --git a/sys/sys/rbtree.h b/sys/sys/rbtree.h
index b4a8ba3f7fc1..686cf2ed299a 100644
--- a/sys/sys/rbtree.h
+++ b/sys/sys/rbtree.h
@@ -125,12 +125,17 @@ TAILQ_HEAD(rb_node_qh, rb_node);
 #define	RB_TAILQ_INSERT_HEAD(a, b, c)		TAILQ_INSERT_HEAD(a, b, c)
 #define	RB_TAILQ_INSERT_BEFORE(a, b, c)		TAILQ_INSERT_BEFORE(a, b, c)
 #define	RB_TAILQ_INSERT_AFTER(a, b, c, d)	TAILQ_INSERT_AFTER(a, b, c, d)
+
+#define	RBDEBUG_TREE_INITIALIZER(t)					      \
+	.rbt_nodes = TAILQ_INITIALIZER((t).rbt_nodes),
 #else
 #define	RB_TAILQ_REMOVE(a, b, c)		do { } while (/*CONSTCOND*/0)
 #define	RB_TAILQ_INIT(a)			do { } while (/*CONSTCOND*/0)
 #define	RB_TAILQ_INSERT_HEAD(a, b, c)		do { } while (/*CONSTCOND*/0)
 #define	RB_TAILQ_INSERT_BEFORE(a, b, c)		do { } while (/*CONSTCOND*/0)
 #define	RB_TAILQ_INSERT_AFTER(a, b, c, d)	do { } while (/*CONSTCOND*/0)
+
+#define	RBDEBUG_TREE_INITIALIZER(t)		/* nothing */
 #endif /* RBDEBUG */
 
 /*
@@ -181,6 +186,12 @@ typedef struct rb_tree {
 #define	RBSTAT_DEC(v)	do { } while (/*CONSTCOND*/0)
 #endif
 
+#define	RB_TREE_INITIALIZER(t, ops) (rb_tree_t)				      \
+{									      \
+	.rbt_ops = (ops),						      \
+	RBDEBUG_TREE_INITIALIZER(t)					      \
+}
+
 void	rb_tree_init(rb_tree_t *, const rb_tree_ops_t *);
 void *	rb_tree_insert_node(rb_tree_t *, void *);
 void *	rb_tree_find_node(rb_tree_t *, const void *);


Home | Main Index | Thread Index | Old Index