summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libc/envlock.c
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2002-05-14 19:02:06 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2002-05-14 19:02:06 +0000
commitbaf7133855d07a897c5337b5860b6e9c61482d2f (patch)
tree8fa971de8e3d73a4a7a88d950566354a573f48f4 /c/src/lib/libc/envlock.c
parent2002-05-03 Ralf Corsepius <corsepiu@faw.uni-ulm.de> (diff)
downloadrtems-baf7133855d07a897c5337b5860b6e9c61482d2f.tar.bz2
2001-05-14 Till Straumann <strauman@slac.stanford.edu>
* Per PR212, added envlock support for newlib. This is used by at least getenv()/putenv() to avoid race conditions. * libc/envlock.c: New file. * libc/Makefile.am: Modified to reflect above.
Diffstat (limited to '')
-rw-r--r--c/src/lib/libc/envlock.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/c/src/lib/libc/envlock.c b/c/src/lib/libc/envlock.c
new file mode 100644
index 0000000000..c9489b3e88
--- /dev/null
+++ b/c/src/lib/libc/envlock.c
@@ -0,0 +1,82 @@
+/*
+ * $Id$
+ *
+ * Author: Till Straumann <strauman@slac.stanford.edu>, 3/2002
+ */
+
+/* provide locking for the global environment 'environ' */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <sys/reent.h>
+
+#include <assert.h>
+
+/*
+ * NOTES:
+ * - although it looks like a classical multiple-readers / single writer (MRSW)
+ * locking problem, we still use a single lock for the following reasons:
+ * 1) newlib has no provision / hook for calling different locking routines
+ * from setenv/putenv and getenv, respectively.
+ * 2) MRSW involves calling several semaphore-primitives, even in the most
+ * likely case of a first-reader's access. This probably takes more CPU
+ * time than just waiting until another reader is done; environment
+ * access is fast.
+ * - the lock implementation must allow nesting (same thread may call
+ * lock-lock-unlock-unlock).
+ * - NEWLIB-1.8.2 has an ugly BUG: if environ is NULL, _findenv_r() bails
+ * out leaving the lock held :-(
+ *
+ */
+
+static rtems_id envLock=0;
+
+static void
+__rtems_envlock_init(void)
+{
+ extern char **environ;
+ rtems_status_code rc;
+
+ if (envLock) /* already initialized */
+ return;
+
+ assert(environ && "MUST have non-NULL 'environ' due to newlib bug");
+
+ rc = rtems_semaphore_create(
+ rtems_build_name('E','N','V','S'),
+ 1,
+ RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY | RTEMS_INHERIT_PRIORITY,
+ 0,
+ &envLock);
+ if (RTEMS_SUCCESSFUL!=rc)
+ rtems_fatal_error_occurred(rc);
+}
+
+void
+__env_lock(struct _reent *r)
+{
+ /* Do lazy init */
+ if (!envLock)
+ __rtems_envlock_init();
+ /*
+ * Must not use a semaphore before pre-tasking hook is called.
+ * - it will corrupt memory :-(
+ */
+
+ if (_Thread_Executing)
+ rtems_semaphore_obtain(envLock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+}
+
+void
+__env_unlock(struct _reent *r)
+{
+ /*
+ * Must not use a semaphore before pre-tasking hook is called.
+ * - it will corrupt memory :-(
+ */
+ if (_Thread_Executing)
+ rtems_semaphore_release(envLock);
+}