From baf7133855d07a897c5337b5860b6e9c61482d2f Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Tue, 14 May 2002 19:02:06 +0000 Subject: 2001-05-14 Till Straumann * 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. --- c/src/exec/libcsupport/src/Makefile.am | 4 +- c/src/exec/libcsupport/src/envlock.c | 82 ++++++++++++++++++++++++++++++++++ c/src/lib/ChangeLog | 7 +++ c/src/lib/libc/Makefile.am | 4 +- c/src/lib/libc/envlock.c | 82 ++++++++++++++++++++++++++++++++++ 5 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 c/src/exec/libcsupport/src/envlock.c create mode 100644 c/src/lib/libc/envlock.c (limited to 'c') diff --git a/c/src/exec/libcsupport/src/Makefile.am b/c/src/exec/libcsupport/src/Makefile.am index 630522af4c..075f97731f 100644 --- a/c/src/exec/libcsupport/src/Makefile.am +++ b/c/src/exec/libcsupport/src/Makefile.am @@ -34,6 +34,8 @@ DIRECTORY_SCAN_C_FILES = opendir.c closedir.c readdir.c rewinddir.c \ MALLOC_C_FILES = malloc.c mallocfreespace.c __brk.c __sbrk.c +ENVIRON_C_FILES = envlock.c + PASSWORD_GROUP_C_FILES = getpwent.c getgrent.c TERMINAL_IDENTIFICATION_C_FILES = ctermid.c isatty.c ttyname.c ttyname_r.c @@ -44,7 +46,7 @@ LIBC_GLUE_C_FILES = __getpid.c __gettod.c __times.c truncate.c access.c \ UNIX_LIBC_C_FILES = unixlibc.c hosterr.c COMMON_C_FILES = gxx_wrappers.c printk.c $(BASE_FS_C_FILES) \ - $(MALLOC_C_FILES) $(TERMIOS_C_FILES) $(ERROR_C_FILES) \ + $(MALLOC_C_FILES) $(ENVIRON_C_FILES) $(TERMIOS_C_FILES) $(ERROR_C_FILES) \ $(ASSOCIATION_C_FILES) UNIX_C_FILES = $(UNIX_LIBC_C_FILES) diff --git a/c/src/exec/libcsupport/src/envlock.c b/c/src/exec/libcsupport/src/envlock.c new file mode 100644 index 0000000000..c9489b3e88 --- /dev/null +++ b/c/src/exec/libcsupport/src/envlock.c @@ -0,0 +1,82 @@ +/* + * $Id$ + * + * Author: Till Straumann , 3/2002 + */ + +/* provide locking for the global environment 'environ' */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +/* + * 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); +} diff --git a/c/src/lib/ChangeLog b/c/src/lib/ChangeLog index 320ee15b04..af966603b4 100644 --- a/c/src/lib/ChangeLog +++ b/c/src/lib/ChangeLog @@ -1,3 +1,10 @@ +2001-05-14 Till Straumann + + * 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. + 2002-05-03 Ralf Corsepius * include/Makefile.am: Remove. diff --git a/c/src/lib/libc/Makefile.am b/c/src/lib/libc/Makefile.am index 630522af4c..075f97731f 100644 --- a/c/src/lib/libc/Makefile.am +++ b/c/src/lib/libc/Makefile.am @@ -34,6 +34,8 @@ DIRECTORY_SCAN_C_FILES = opendir.c closedir.c readdir.c rewinddir.c \ MALLOC_C_FILES = malloc.c mallocfreespace.c __brk.c __sbrk.c +ENVIRON_C_FILES = envlock.c + PASSWORD_GROUP_C_FILES = getpwent.c getgrent.c TERMINAL_IDENTIFICATION_C_FILES = ctermid.c isatty.c ttyname.c ttyname_r.c @@ -44,7 +46,7 @@ LIBC_GLUE_C_FILES = __getpid.c __gettod.c __times.c truncate.c access.c \ UNIX_LIBC_C_FILES = unixlibc.c hosterr.c COMMON_C_FILES = gxx_wrappers.c printk.c $(BASE_FS_C_FILES) \ - $(MALLOC_C_FILES) $(TERMIOS_C_FILES) $(ERROR_C_FILES) \ + $(MALLOC_C_FILES) $(ENVIRON_C_FILES) $(TERMIOS_C_FILES) $(ERROR_C_FILES) \ $(ASSOCIATION_C_FILES) UNIX_C_FILES = $(UNIX_LIBC_C_FILES) 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 , 3/2002 + */ + +/* provide locking for the global environment 'environ' */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +/* + * 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); +} -- cgit v1.2.3