diff options
Diffstat (limited to 'libc/stdlib')
83 files changed, 1236 insertions, 1133 deletions
diff --git a/libc/stdlib/Makefile.in b/libc/stdlib/Makefile.in index dfef6d18e..ae74995bb 100644 --- a/libc/stdlib/Makefile.in +++ b/libc/stdlib/Makefile.in @@ -1,99 +1,85 @@ # Makefile for uClibc # -# Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> +# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org> # # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. # +subdirs += libc/stdlib + include $(top_srcdir)libc/stdlib/malloc/Makefile.in include $(top_srcdir)libc/stdlib/malloc-simple/Makefile.in include $(top_srcdir)libc/stdlib/malloc-standard/Makefile.in -CSRC := \ - abort.c getenv.c mkdtemp.c mktemp.c realpath.c mkstemp.c \ - rand.c random.c random_r.c setenv.c system.c div.c ldiv.c lldiv.c \ - getpt.c drand48-iter.c jrand48.c \ - jrand48_r.c lrand48.c lrand48_r.c mrand48.c mrand48_r.c nrand48.c \ +CSRC-y := \ + abort.c getenv.c mkdtemp.c realpath.c canonicalize.c mkstemp.c mkostemp.c \ + mkstemps.c mkostemps.c rand.c random.c random_r.c setenv.c div.c ldiv.c \ + lldiv.c getpt.c drand48-iter.c jrand48.c \ + jrand48_r.c lcong48.c lrand48.c lrand48_r.c mrand48.c mrand48_r.c nrand48.c \ nrand48_r.c rand_r.c srand48.c srand48_r.c seed48.c seed48_r.c \ - valloc.c a64l.c l64a.c __uc_malloc.c -ifeq ($(UCLIBC_HAS_ADVANCED_REALTIME),y) -CSRC += posix_memalign.c -endif -ifeq ($(UCLIBC_HAS_PTY),y) -CSRC += grantpt.c unlockpt.c ptsname.c -endif -ifeq ($(UCLIBC_HAS_ARC4RANDOM),y) -CSRC += arc4random.c -endif -ifeq ($(UCLIBC_HAS_LFS),y) -CSRC += mkstemp64.c -endif -ifeq ($(UCLIBC_HAS_FLOATS),y) -CSRC += drand48.c drand48_r.c erand48.c erand48_r.c -ifeq ($(UCLIBC_SUSV3_LEGACY),y) -CSRC += gcvt.c -endif + a64l.c l64a.c __uc_malloc.c +CSRC-$(UCLIBC_SUSV2_LEGACY) += valloc.c +CSRC-$(UCLIBC_HAS_ADVANCED_REALTIME) += posix_memalign.c +CSRC-$(UCLIBC_HAS_PTY) += grantpt.c unlockpt.c ptsname.c +CSRC-$(UCLIBC_HAS_ARC4RANDOM) += arc4random.c +CSRC-$(UCLIBC_HAS_LFS) += mkstemp64.c mkostemp64.c mkstemps64.c mkostemps64.c +CSRC-$(UCLIBC_HAS_FLOATS) += drand48.c drand48_r.c erand48.c erand48_r.c +CSRC-$(if $(findstring yy,$(UCLIBC_HAS_FLOATS)$(UCLIBC_SUSV3_LEGACY)),y) += \ + gcvt.c +CSRC-$(UCLIBC_SUSV3_LEGACY) += mktemp.c + +ifneq ($(UCLIBC_HAS_BACKTRACE),) +CFLAGS-abort.c = -fasynchronous-unwind-tables endif # multi source stdlib.c -CSRC += abs.c labs.c atoi.c atol.c strtol.c strtoul.c _stdlib_strto_l.c \ - qsort.c bsearch.c \ +CSRC-y += abs.c labs.c atoi.c atol.c strtol.c strtoul.c _stdlib_strto_l.c \ + qsort.c qsort_r.c bsearch.c rpmatch.c \ llabs.c atoll.c strtoll.c strtoull.c _stdlib_strto_ll.c # (aliases) strtoq.o strtouq.o -ifeq ($(UCLIBC_HAS_FLOATS),y) -CSRC += atof.c -endif -ifeq ($(UCLIBC_HAS_XLOCALE),y) -CSRC += strtol_l.c strtoul_l.c _stdlib_strto_l_l.c \ +CSRC-$(UCLIBC_HAS_FLOATS) += atof.c +CSRC-$(UCLIBC_HAS_XLOCALE) += strtol_l.c strtoul_l.c _stdlib_strto_l_l.c \ strtoll_l.c strtoull_l.c _stdlib_strto_ll_l.c -endif -ifeq ($(UCLIBC_HAS_WCHAR),y) -CSRC += mblen.c mbtowc.c wctomb.c mbstowcs.c wcstombs.c \ + +CSRC-$(UCLIBC_HAS_WCHAR) += mblen.c mbtowc.c wctomb.c mbstowcs.c wcstombs.c \ _stdlib_mb_cur_max.c _stdlib_wcsto_l.c _stdlib_wcsto_ll.c \ wcstol.c wcstoul.c wcstoll.c wcstoull.c -ifeq ($(UCLIBC_HAS_XLOCALE),y) -CSRC +=_stdlib_wcsto_l_l.c _stdlib_wcsto_ll_l.c \ +CSRC-$(if $(findstring yy,$(UCLIBC_HAS_WCHAR)$(UCLIBC_HAS_XLOCALE)),y) += \ + _stdlib_wcsto_l_l.c _stdlib_wcsto_ll_l.c \ wcstol_l.c wcstoul_l.c wcstoll_l.c wcstoull_l.c -endif -endif # multi source _strtod.c -ifeq ($(UCLIBC_HAS_FLOATS),y) -CSRC += strtod.c strtof.c strtold.c __strtofpmax.c __fp_range_check.c -ifeq ($(UCLIBC_HAS_XLOCALE),y) -CSRC += strtod_l.c strtof_l.c strtold_l.c __strtofpmax_l.c -endif -ifeq ($(UCLIBC_HAS_WCHAR),y) -CSRC += wcstod.c wcstof.c wcstold.c __wcstofpmax.c -ifeq ($(UCLIBC_HAS_XLOCALE),y) -CSRC += wcstod_l.c wcstof_l.c wcstold_l.c __wcstofpmax_l.c -endif -endif -endif +CSRC-$(UCLIBC_HAS_FLOATS) += strtod.c strtof.c strtold.c __strtofpmax.c __fp_range_check.c +CSRC-$(if $(findstring yy,$(UCLIBC_HAS_FLOATS)$(UCLIBC_HAS_XLOCALE)),y) += \ + strtod_l.c strtof_l.c strtold_l.c __strtofpmax_l.c +CSRC-$(if $(findstring yy,$(UCLIBC_HAS_FLOATS)$(UCLIBC_HAS_WCHAR)),y) += \ + wcstod.c wcstof.c wcstold.c __wcstofpmax.c +CSRC-$(if $(findstring yyy,$(UCLIBC_HAS_FLOATS)$(UCLIBC_HAS_WCHAR)$(UCLIBC_HAS_XLOCALE)),y) += \ + wcstod_l.c wcstof_l.c wcstold_l.c __wcstofpmax_l.c # (aliases) wcstoq.o wcstouq.o # wcstod wcstof wcstold # multi source _atexit.c -CSRC += __cxa_atexit.c __cxa_finalize.c __exit_handler.c exit.c on_exit.c -ifeq ($(COMPAT_ATEXIT),y) -CSRC += old_atexit.c -endif +CSRC-y += __cxa_atexit.c __cxa_finalize.c __exit_handler.c exit.c on_exit.c STDLIB_DIR := $(top_srcdir)libc/stdlib STDLIB_OUT := $(top_builddir)libc/stdlib -STDLIB_SRC := $(patsubst %.c,$(STDLIB_DIR)/%.c,$(CSRC)) -STDLIB_OBJ := $(patsubst %.c,$(STDLIB_OUT)/%.o,$(CSRC)) +STDLIB_SRC := $(patsubst %.c,$(STDLIB_DIR)/%.c,$(CSRC-y)) +STDLIB_OBJ := $(patsubst %.c,$(STDLIB_OUT)/%.o,$(CSRC-y)) libc-y += $(STDLIB_OBJ) -libc-static-y += $(STDLIB_OUT)/atexit.o +libc-static-y += $(STDLIB_OUT)/atexit.o $(STDLIB_OUT)/system.o +libc-static-$(COMPAT_ATEXIT) += $(STDLIB_OUT)/old_atexit.o +libc-shared-y += $(STDLIB_OUT)/system.oS + # this should always be the PIC version, because it could be used in shared libs libc-nonshared-y += $(STDLIB_OUT)/atexit.os - +libc-nonshared-$(COMPAT_ATEXIT) += $(STDLIB_OUT)/old_atexit.os libc-nomulti-y += $(STDLIB_OUT)/labs.o $(STDLIB_OUT)/atol.o $(STDLIB_OUT)/_stdlib_strto_l.o $(STDLIB_OUT)/_stdlib_strto_ll.o libc-nomulti-$(UCLIBC_HAS_XLOCALE) += $(STDLIB_OUT)/_stdlib_strto_l_l.o $(STDLIB_OUT)/_stdlib_strto_ll_l.o -objclean-y += stdlib_objclean +objclean-y += CLEAN_libc/stdlib -stdlib_objclean: - $(RM) $(STDLIB_OUT)/*.{o,os,oS} +CLEAN_libc/stdlib: + $(do_rm) $(addprefix $(STDLIB_OUT)/*., o os oS) diff --git a/libc/stdlib/__uc_malloc.c b/libc/stdlib/__uc_malloc.c index 81eee1343..e1b6c8407 100644 --- a/libc/stdlib/__uc_malloc.c +++ b/libc/stdlib/__uc_malloc.c @@ -13,8 +13,7 @@ Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. +not, see <http://www.gnu.org/licenses/>. */ @@ -22,9 +21,6 @@ Cambridge, MA 02139, USA. #include <unistd.h> #include <malloc.h> -libc_hidden_proto(_exit) -libc_hidden_proto(__uc_malloc) -libc_hidden_proto(__uc_malloc_failed) void (*__uc_malloc_failed)(size_t size) = NULL; /* Seemingly superfluous assigment of NULL above prevents gas error @@ -42,6 +38,7 @@ void *__uc_malloc(size_t size) return p; if (!__uc_malloc_failed) _exit(1); + free(p); __uc_malloc_failed(size); } } diff --git a/libc/stdlib/_atexit.c b/libc/stdlib/_atexit.c index e5840f471..8a3196781 100644 --- a/libc/stdlib/_atexit.c +++ b/libc/stdlib/_atexit.c @@ -40,19 +40,21 @@ #include <features.h> #include <unistd.h> #include <stdlib.h> +#include <stdio.h> #include <errno.h> #include <atomic.h> +#if defined __UCLIBC_HAS_THREADS__ && defined __UCLIBC_HAS_THREADS_NATIVE__ +# include <fork.h> +#endif #include <bits/uClibc_mutex.h> -__UCLIBC_MUTEX_EXTERN(__atexit_lock); +__UCLIBC_MUTEX_EXTERN(__atexit_lock) attribute_hidden; -libc_hidden_proto(exit) -libc_hidden_proto(_exit) -typedef void (*aefuncp) (void); /* atexit function pointer */ -typedef void (*oefuncp) (int, void *); /* on_exit function pointer */ -typedef void (*cxaefuncp) (void *); /* __cxa_atexit function pointer */ +typedef void (*aefuncp)(void); /* atexit function pointer */ +typedef void (*oefuncp)(int, void *); /* on_exit function pointer */ +typedef void (*cxaefuncp)(void *); /* __cxa_atexit function pointer */ typedef enum { ef_free, ef_in_use, @@ -61,7 +63,7 @@ typedef enum { } ef_type; /* exit function types */ /* this is in the L_exit object */ -extern void (*__exit_cleanup) (int) attribute_hidden; +extern void (*__exit_cleanup)(int) attribute_hidden; /* these are in the L___do_exit object */ extern int __exit_slots attribute_hidden; @@ -90,10 +92,10 @@ extern struct exit_function *__exit_function_table attribute_hidden; #else extern struct exit_function __exit_function_table[__UCLIBC_MAX_ATEXIT] attribute_hidden; #endif -extern struct exit_function *__new_exitfn (void) attribute_hidden; +extern struct exit_function *__new_exitfn(void) attribute_hidden; /* this is in the L___cxa_atexit object */ -extern int __cxa_atexit (cxaefuncp, void *arg, void *dso_handle); +extern int __cxa_atexit(cxaefuncp, void *arg, void *dso_handle); /* remove old_atexit after 0.9.29 */ @@ -155,7 +157,7 @@ int on_exit(oefuncp func, void *arg) #ifdef L___cxa_atexit libc_hidden_proto(__cxa_atexit) -int __cxa_atexit (cxaefuncp func, void *arg, void *dso_handle) +int __cxa_atexit(cxaefuncp func, void *arg, void *dso_handle) { struct exit_function *efp; @@ -185,8 +187,8 @@ libc_hidden_def(__cxa_atexit) * with the same dso handle. Otherwise, if D is NULL, call all of the * registered handlers. */ -void __cxa_finalize (void *dso_handle); -void __cxa_finalize (void *dso_handle) +void __cxa_finalize(void *dso_handle); +void __cxa_finalize(void *dso_handle) { struct exit_function *efp; int exit_count_snapshot = __exit_count; @@ -209,17 +211,15 @@ void __cxa_finalize (void *dso_handle) } } -#if 0 /* haven't looked into this yet... */ /* * Remove the registered fork handlers. We do not have to * unregister anything if the program is going to terminate anyway. */ #ifdef UNREGISTER_ATFORK - if (d != NULL) { - UNREGISTER_ATFORK (d); + if (dso_handle != NULL) { + UNREGISTER_ATFORK(dso_handle); } #endif -#endif } #endif @@ -242,13 +242,23 @@ struct exit_function attribute_hidden *__new_exitfn(void) __UCLIBC_MUTEX_LOCK(__atexit_lock); + /* + * Reuse free slots at the end of the list. + * This avoids eating memory when dlopen and dlclose modules multiple times. + */ + while (__exit_count > 0) { + if (__exit_function_table[__exit_count-1].type == ef_free) { + --__exit_count; + } else break; + } + #ifdef __UCLIBC_DYNAMIC_ATEXIT__ /* If we are out of function table slots, make some more */ if (__exit_slots < __exit_count+1) { - efp=realloc(__exit_function_table, + efp = realloc(__exit_function_table, (__exit_slots+20)*sizeof(struct exit_function)); if (efp == NULL) { - __set_errno(ENOMEM); + /* __set_errno(ENOMEM); */ goto DONE; } __exit_function_table = efp; @@ -281,18 +291,18 @@ void __exit_handler(int status) struct exit_function *efp; /* In reverse order */ - while ( __exit_count ) { + while (__exit_count) { efp = &__exit_function_table[--__exit_count]; switch (efp->type) { case ef_on_exit: if (efp->funcs.on_exit.func) { - (efp->funcs.on_exit.func) (status, efp->funcs.on_exit.arg); + (efp->funcs.on_exit.func)(status, efp->funcs.on_exit.arg); } break; case ef_cxa_atexit: if (efp->funcs.cxa_atexit.func) { /* glibc passes status too, but that's not in the prototype */ - (efp->funcs.cxa_atexit.func) (efp->funcs.cxa_atexit.arg); + (efp->funcs.cxa_atexit.func)(efp->funcs.cxa_atexit.arg); } break; } @@ -305,12 +315,22 @@ void __exit_handler(int status) #endif #ifdef L_exit +/* Defeat compiler optimization which assumes function addresses are never NULL */ +static __always_inline int not_null_ptr(const void *p) +{ + const void *q; + __asm__ ("" + : "=r" (q) /* output */ + : "0" (p) /* input */ + ); + return q != 0; +} + extern void weak_function _stdio_term(void) attribute_hidden; -attribute_hidden void (*__exit_cleanup) (int) = 0; +attribute_hidden void (*__exit_cleanup)(int) = 0; __UCLIBC_MUTEX_INIT(__atexit_lock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); -extern void __uClibc_fini(void); -libc_hidden_proto(__uClibc_fini) +extern void __uClibc_fini(void) attribute_hidden; /* * Normal program termination @@ -319,19 +339,19 @@ void exit(int rv) { /* Perform exit-specific cleanup (atexit and on_exit) */ __UCLIBC_MUTEX_LOCK(__atexit_lock); - if (__exit_cleanup) { + if (not_null_ptr(__exit_cleanup)) { __exit_cleanup(rv); } __UCLIBC_MUTEX_UNLOCK(__atexit_lock); __uClibc_fini(); - /* If we are using stdio, try to shut it down. At the very least, + /* If we are using stdio, try to shut it down. At the very least, * this will attempt to commit all buffered writes. It may also * unbuffer all writable files, or close them outright. * Check the stdio routines for details. */ - if (_stdio_term) - _stdio_term(); + if (not_null_ptr(_stdio_term)) + _stdio_term(); _exit(rv); } diff --git a/libc/stdlib/_strtod.c b/libc/stdlib/_strtod.c index 1b2adc986..c4c79e511 100644 --- a/libc/stdlib/_strtod.c +++ b/libc/stdlib/_strtod.c @@ -36,7 +36,7 @@ */ /**********************************************************************/ -/* OPTIONS */ +/* OPTIONS */ /**********************************************************************/ /* Defined if we want to recognize "nan", "inf", and "infinity". (C99) */ @@ -79,7 +79,7 @@ #define _STRTOD_ZERO_CHECK 1 /**********************************************************************/ -/* Don't change anything that follows. */ +/* Don't change anything that follows. */ /**********************************************************************/ #ifdef _STRTOD_ERRNO @@ -95,7 +95,6 @@ /**********************************************************************/ -#define _ISOC99_SOURCE 1 #include <stdlib.h> #include <string.h> #include <ctype.h> @@ -107,23 +106,16 @@ #include <locale.h> #ifdef __UCLIBC_HAS_WCHAR__ - -#include <wchar.h> -#include <wctype.h> -#include <bits/uClibc_uwchar.h> -libc_hidden_proto(iswspace) +# include <wchar.h> +# include <wctype.h> +# include <bits/uClibc_uwchar.h> #endif -#ifdef __UCLIBC_HAS_XLOCALE__ -#include <xlocale.h> -libc_hidden_proto(iswspace_l) -#endif /* __UCLIBC_HAS_XLOCALE__ */ - /* Handle _STRTOD_HEXADECIMAL_FLOATS via uClibc config now. */ #undef _STRTOD_HEXADECIMAL_FLOATS #ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__ -#define _STRTOD_HEXADECIMAL_FLOATS 1 -#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */ +# define _STRTOD_HEXADECIMAL_FLOATS 1 +#endif /**********************************************************************/ @@ -175,13 +167,6 @@ extern void __fp_range_check(__fpmax_t y, __fpmax_t x) attribute_hidden; /**********************************************************************/ #if defined(L___strtofpmax) || defined(L___strtofpmax_l) || defined(L___wcstofpmax) || defined(L___wcstofpmax_l) -#ifdef __UCLIBC_HAS_XLOCALE__ -libc_hidden_proto(__ctype_b_loc) -#elif defined __UCLIBC_HAS_CTYPE_TABLES__ -libc_hidden_proto(__ctype_b) -libc_hidden_proto(__ctype_tolower) -#endif - #if defined(L___wcstofpmax) || defined(L___wcstofpmax_l) #define __strtofpmax __wcstofpmax @@ -215,7 +200,6 @@ __fpmax_t attribute_hidden __strtofpmax(const Wchar *str, Wchar **endptr, int ex #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ -/* Experimentally off - libc_hidden_proto(memcmp) */ __fpmax_t attribute_hidden __XL_NPP(__strtofpmax)(const Wchar *str, Wchar **endptr, int exponent_power __LOCALE_PARAM ) @@ -348,16 +332,11 @@ __fpmax_t attribute_hidden __XL_NPP(__strtofpmax)(const Wchar *str, Wchar **endp static const char nan_inf_str[] = "\05nan\0\012infinity\0\05inf\0"; int i = 0; -#ifdef __UCLIBC_HAS_LOCALE__ - /* Avoid tolower problems for INFINITY in the tr_TR locale. (yuk)*/ -#undef _tolower -#define _tolower(C) ((C)|0x20) -#endif /* __UCLIBC_HAS_LOCALE__ */ - do { /* Unfortunately, we have no memcasecmp(). */ int j = 0; - while (_tolower(pos[j]) == nan_inf_str[i+1+j]) { + /* | 0x20 is a cheap lowercasing (valid for ASCII letters and numbers only) */ + while ((pos[j] | 0x20) == nan_inf_str[i+1+j]) { ++j; if (!nan_inf_str[i+1+j]) { number = i / 0.; @@ -525,7 +504,6 @@ void attribute_hidden __fp_range_check(__fpmax_t y, __fpmax_t x) #endif -libc_hidden_proto(__XL_NPP(strtof)) float __XL_NPP(strtof)(const Wchar *str, Wchar **endptr __LOCALE_PARAM ) { #if FPMAX_TYPE == 1 @@ -542,7 +520,6 @@ float __XL_NPP(strtof)(const Wchar *str, Wchar **endptr __LOCALE_PARAM ) return y; #endif } -libc_hidden_def(__XL_NPP(strtof)) #endif #endif @@ -560,7 +537,6 @@ libc_hidden_def(__XL_NPP(strtof)) #define Wchar char #endif -libc_hidden_proto(__XL_NPP(strtod)) double __XL_NPP(strtod)(const Wchar *__restrict str, Wchar **__restrict endptr __LOCALE_PARAM ) { @@ -578,7 +554,9 @@ double __XL_NPP(strtod)(const Wchar *__restrict str, return y; #endif } -libc_hidden_def(__XL_NPP(strtod)) +#ifdef L_strtod +libc_hidden_def(strtod) +#endif #endif #endif @@ -596,7 +574,6 @@ libc_hidden_def(__XL_NPP(strtod)) #define Wchar char #endif -libc_hidden_proto(__XL_NPP(strtold)) long double __XL_NPP(strtold) (const Wchar *str, Wchar **endptr __LOCALE_PARAM ) { #if FPMAX_TYPE == 3 @@ -613,7 +590,6 @@ long double __XL_NPP(strtold) (const Wchar *str, Wchar **endptr __LOCALE_PARAM return y; #endif } -libc_hidden_def(__XL_NPP(strtold)) #endif #endif diff --git a/libc/stdlib/a64l.c b/libc/stdlib/a64l.c index d09dbf464..05396b275 100644 --- a/libc/stdlib/a64l.c +++ b/libc/stdlib/a64l.c @@ -13,9 +13,8 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> diff --git a/libc/stdlib/abort.c b/libc/stdlib/abort.c index b71512f33..dc2747f61 100644 --- a/libc/stdlib/abort.c +++ b/libc/stdlib/abort.c @@ -13,8 +13,7 @@ Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ +not, see <http://www.gnu.org/licenses/>. */ /* Hacked up for uClibc by Erik Andersen */ @@ -26,13 +25,18 @@ Cambridge, MA 02139, USA. */ #include <signal.h> #include <errno.h> -libc_hidden_proto(abort) -/* Experimentally off - libc_hidden_proto(memset) */ -libc_hidden_proto(sigaction) -libc_hidden_proto(sigprocmask) -libc_hidden_proto(raise) -libc_hidden_proto(_exit) + +/* Defeat compiler optimization which assumes function addresses are never NULL */ +static __always_inline int not_null_ptr(const void *p) +{ + const void *q; + __asm__ ("" + : "=r" (q) /* output */ + : "0" (p) /* input */ + ); + return q != 0; +} /* Our last ditch effort to commit suicide */ #ifdef __UCLIBC_ABORT_INSTRUCTION__ @@ -42,9 +46,6 @@ libc_hidden_proto(_exit) # warning "no abort instruction defined for your arch" #endif -#ifdef __UCLIBC_HAS_STDIO_SHUTDOWN_ON_ABORT__ -extern void weak_function _stdio_term(void) attribute_hidden; -#endif static smallint been_there_done_that = 0; /* Be prepared in case multiple threads try to abort() */ @@ -60,9 +61,9 @@ void abort(void) __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE(mylock); /* Unmask SIGABRT to be sure we can get it */ - if (__sigemptyset(&sigs) == 0 && __sigaddset(&sigs, SIGABRT) == 0) { - sigprocmask(SIG_UNBLOCK, &sigs, (sigset_t *) NULL); - } + __sigemptyset(&sigs); + __sigaddset(&sigs, SIGABRT); + sigprocmask(SIG_UNBLOCK, &sigs, NULL); while (1) { /* Try to suicide with a SIGABRT */ @@ -74,7 +75,7 @@ void abort(void) * this will attempt to commit all buffered writes. It may also * unbuffer all writable files, or close them outright. * Check the stdio routines for details. */ - if (_stdio_term) { + if (not_null_ptr(_stdio_term)) { _stdio_term(); } #endif @@ -91,9 +92,9 @@ abort_it: been_there_done_that++; memset(&act, '\0', sizeof(struct sigaction)); - act.sa_handler = SIG_DFL; + if (SIG_DFL) /* if it's constant zero, already done */ + act.sa_handler = SIG_DFL; __sigfillset(&act.sa_mask); - act.sa_flags = 0; sigaction(SIGABRT, &act, NULL); goto abort_it; diff --git a/libc/stdlib/arc4random.c b/libc/stdlib/arc4random.c index bf6a4cd30..0013612e9 100644 --- a/libc/stdlib/arc4random.c +++ b/libc/stdlib/arc4random.c @@ -1,24 +1,29 @@ -/* $$$: arc4random.c 2005/02/08 robert */ -/* $NetBSD: arc4random.c,v 1.5.2.1 2004/03/26 22:52:50 jmc Exp $ */ -/* $OpenBSD: arc4random.c,v 1.6 2001/06/05 05:05:38 pvalchev Exp $ */ - /* - * Arc4 random number generator for OpenBSD. - * Copyright 1996 David Mazieres <dm@lcs.mit.edu>. + * Copyright (c) 1996, David Mazieres <dm@uun.org> * - * Modification and redistribution in source and binary forms is - * permitted provided that due credit is given to the author and the - * OpenBSD project by leaving this copyright notice intact. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* + * Arc4 random number generator for OpenBSD. + * * This code is derived from section 17.1 of Applied Cryptography, * second edition, which describes a stream cipher allegedly * compatible with RSA Labs "RC4" cipher (the actual description of * which is a trade secret). The same algorithm is used as a stream * cipher called "arcfour" in Tatu Ylonen's ssh package. * - * Here the stream cipher has been modified always to include the time + * Here the stream cipher has been modified always to include entropy * when initializing the state. That makes it impossible to * regenerate the same random sequence twice, so this can't be used * for encryption, but will generate good random numbers. @@ -26,41 +31,29 @@ * RC4 is a registered trademark of RSA Laboratories. */ +/* $OpenBSD: arc4random.c,v 1.16 2007/02/12 19:58:47 otto Exp $ */ + #include <features.h> + #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> -#include <sys/param.h> #include <sys/time.h> -#ifdef __ARC4RANDOM_USE_ERANDOM__ -#include <sys/sysctl.h> -//libc_hidden_proto(sysctl) -#endif - -libc_hidden_proto(open) -libc_hidden_proto(read) -libc_hidden_proto(close) -libc_hidden_proto(gettimeofday) struct arc4_stream { - uint8_t i; - uint8_t j; - uint8_t s[256]; + u_int8_t i; + u_int8_t j; + u_int8_t s[256]; }; -static int rs_initialized; +static smallint rs_initialized; static struct arc4_stream rs; - -static __inline__ void arc4_init(struct arc4_stream *); -static __inline__ void arc4_addrandom(struct arc4_stream *, u_char *, int); -static void arc4_stir(struct arc4_stream *); -static __inline__ uint8_t arc4_getbyte(struct arc4_stream *); -static __inline__ uint32_t arc4_getword(struct arc4_stream *); +static pid_t arc4_stir_pid; +static int arc4_count; static __inline__ void -arc4_init(as) - struct arc4_stream *as; +arc4_init(struct arc4_stream *as) { int n; @@ -70,14 +63,25 @@ arc4_init(as) as->j = 0; } +static __inline__ u_int8_t +arc4_getbyte(struct arc4_stream *as) +{ + u_int8_t si, sj; + + as->i = (as->i + 1); + si = as->s[as->i]; + as->j = (as->j + si); + sj = as->s[as->j]; + as->s[as->i] = sj; + as->s[as->j] = si; + return (as->s[(si + sj) & 0xff]); +} + static __inline__ void -arc4_addrandom(as, dat, datlen) - struct arc4_stream *as; - u_char *dat; - int datlen; +arc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen) { int n; - uint8_t si; + u_int8_t si; as->i--; for (n = 0; n < 256; n++) { @@ -91,76 +95,90 @@ arc4_addrandom(as, dat, datlen) } static void -arc4_stir(as) - struct arc4_stream *as; +arc4_stir(struct arc4_stream *as) { - int fd; - struct { - struct timeval tv; - uint rnd[(128 - sizeof(struct timeval)) / sizeof(uint)]; - } rdat; int n; + u_char rnd[128]; + struct timeval tv; + +#ifndef __ARC4RANDOM_USES_NODEV__ + int fd; - gettimeofday(&rdat.tv, NULL); fd = open("/dev/urandom", O_RDONLY); if (fd != -1) { - read(fd, rdat.rnd, sizeof(rdat.rnd)); + read(fd, rnd, sizeof(rnd)); close(fd); } -#ifdef __ARC4RANDOM_USE_ERANDOM__ + /* Did the pseudo-random device fail? Use gettimeofday(). */ + else +#endif + if (gettimeofday(&tv, NULL) != (-1)) { + + /* Initialize the first element so it's hopefully not '0', + * to help out the next loop. Tossing in some prime numbers + * probably can't hurt. */ + rnd[0] = (tv.tv_sec % 10000) * 3 + tv.tv_usec * 7 + \ + (getpid() % 1000) * 13; + + for (n = 1; n < 127 ; n++) { + + /* Take advantage of the stack space. Only initialize + * elements equal to '0'. This will make the rnd[] + * array much less vulnerable to timing attacks. Here + * we'll stir getpid() into the value of the previous + * element. Approximately 1 in 128 elements will still + * become '0'. */ + + if (rnd[n] == 0) { + rnd[n] = ((rnd[n - 1] + n) ^ \ + ((getpid() % 1000) * 17)); + } + } + } else { - int mib[3]; - uint i; - size_t len; - - /* Device could not be opened, we might be chrooted, take - * randomness from sysctl. */ - - mib[0] = CTL_KERN; - mib[1] = KERN_RANDOM; - mib[2] = RANDOM_ERANDOM; - - for (i = 0; i < sizeof(rdat.rnd) / sizeof(uint); i++) { - len = sizeof(uint); - if (sysctl(mib, 3, &rdat.rnd[i], &len, NULL, 0) == -1) - break; + /* gettimeofday() failed? Do the same thing as above, but only + * with getpid(). */ + + rnd[0] = (getpid() % 1000) * 19; + for (n = 1; n < 127 ; n++) { + if (rnd[n] == 0) { + rnd[n] = ((rnd[n - 1] + n) ^ \ + ((getpid() % 1000) * 23)); + } } } -#endif - arc4_addrandom(as, (void *) &rdat, sizeof(rdat)); + arc4_stir_pid = getpid(); + arc4_addrandom(as, rnd, sizeof(rnd)); /* - * Throw away the first N words of output, as suggested in the - * paper "Weaknesses in the Key Scheduling Algorithm of RC4" - * by Fluher, Mantin, and Shamir. + * Discard early keystream, as per recommendations in: * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps - * N = 256 in our case. */ - for (n = 0; n < 256 * 4; n++) - arc4_getbyte(as); + for (n = 0; n < 256; n++) + (void)arc4_getbyte(as); + arc4_count = 1600000; } -static __inline__ uint8_t -arc4_getbyte(as) - struct arc4_stream *as; +#if 0 +static void __arc4random_stir(void); +/* + * __arc4_getbyte() is a libc private function intended for use + * with malloc. + */ +u_int8_t +__arc4_getbyte(void) { - uint8_t si, sj; - - as->i = (as->i + 1); - si = as->s[as->i]; - as->j = (as->j + si); - sj = as->s[as->j]; - as->s[as->i] = sj; - as->s[as->j] = si; - return (as->s[(si + sj) & 0xff]); + if (--arc4_count == 0 || !rs_initialized) + __arc4random_stir(); + return arc4_getbyte(&rs); } +#endif -static __inline__ uint32_t -arc4_getword(as) - struct arc4_stream *as; +static __inline__ u_int32_t +arc4_getword(struct arc4_stream *as) { - uint32_t val; + u_int32_t val; val = arc4_getbyte(as) << 24; val |= arc4_getbyte(as) << 16; val |= arc4_getbyte(as) << 8; @@ -168,9 +186,8 @@ arc4_getword(as) return val; } -libc_hidden_proto(arc4random_stir) -void -arc4random_stir(void) +static void +__arc4random_stir(void) { if (!rs_initialized) { arc4_init(&rs); @@ -178,33 +195,21 @@ arc4random_stir(void) } arc4_stir(&rs); } -libc_hidden_def(arc4random_stir) +strong_alias(__arc4random_stir,arc4random_stir) void arc4random_addrandom(u_char *dat, int datlen) { if (!rs_initialized) - arc4random_stir(); + __arc4random_stir(); arc4_addrandom(&rs, dat, datlen); } -uint32_t +u_int32_t arc4random(void) { - if (!rs_initialized) - arc4random_stir(); + arc4_count -= 4; + if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != getpid()) + __arc4random_stir(); return arc4_getword(&rs); } - -#if 0 -/*-------- Test code --------*/ -#include <stdlib.h> -#include <stdio.h> - -int main(void) { - int random_number; - random_number = arc4random() % 65536; - printf("%d\n", random_number); - return 0; -} -#endif diff --git a/libc/stdlib/bsd_getpt.c b/libc/stdlib/bsd_getpt.c index 1afd57f47..289748617 100644 --- a/libc/stdlib/bsd_getpt.c +++ b/libc/stdlib/bsd_getpt.c @@ -13,9 +13,8 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <errno.h> #include <fcntl.h> @@ -23,8 +22,6 @@ #include <unistd.h> #if defined __USE_BSD -libc_hidden_proto(open) -/* Experimentally off - libc_hidden_proto(mempcpy) */ /* Prefix for master pseudo terminal nodes. */ #define _PATH_PTY "/dev/pty" @@ -42,7 +39,7 @@ const char __libc_ptyname1[] attribute_hidden = PTYNAME1; const char __libc_ptyname2[] attribute_hidden = PTYNAME2; /* Open a master pseudo terminal and return its file descriptor. */ -int +static __inline__ int __getpt (void) { char buf[sizeof (_PATH_PTY) + 2]; diff --git a/libc/stdlib/canonicalize.c b/libc/stdlib/canonicalize.c new file mode 100644 index 000000000..da09d5841 --- /dev/null +++ b/libc/stdlib/canonicalize.c @@ -0,0 +1,19 @@ +/* + * canonicalize.c -- Return a malloc'd string containing the canonical + * absolute name of the named file. The last file name component need + * not exist, and may be a symlink to a nonexistent file. + * Copyright (C) 2009 STMicroelectronics + * Author: Salvatore Cro <salvatore.cro@st.com> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include <stdlib.h> + +#ifdef __USE_GNU + +char * canonicalize_file_name (const char *name) +{ + return realpath (name, NULL); +} +#endif diff --git a/libc/stdlib/drand48-iter.c b/libc/stdlib/drand48-iter.c index 221cbe08f..b4b7b33b0 100644 --- a/libc/stdlib/drand48-iter.c +++ b/libc/stdlib/drand48-iter.c @@ -13,23 +13,22 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <errno.h> #include <stdlib.h> #include <limits.h> #include <stdint.h> +#include <stdlib.h> #include <sys/types.h> /* Global state for non-reentrant functions. */ -struct drand48_data __libc_drand48_data attribute_hidden; +struct drand48_data __libc_drand48_data; #ifdef __UCLIBC_MJN3_ONLY__ #warning turn int __drand48_iterate into void #endif /* __UCLIBC_MJN3_ONLY__ */ -int __drand48_iterate (unsigned short int xsubi[3], struct drand48_data *buffer) attribute_hidden; int __drand48_iterate (unsigned short int xsubi[3], struct drand48_data *buffer) { uint64_t X; diff --git a/libc/stdlib/drand48.c b/libc/stdlib/drand48.c index f96947cb2..1e3684fb5 100644 --- a/libc/stdlib/drand48.c +++ b/libc/stdlib/drand48.c @@ -13,17 +13,11 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> -libc_hidden_proto(erand48_r) - -/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ -extern struct drand48_data __libc_drand48_data attribute_hidden; - double drand48 (void) { double result; diff --git a/libc/stdlib/drand48_r.c b/libc/stdlib/drand48_r.c index 1000a3acb..6413434c9 100644 --- a/libc/stdlib/drand48_r.c +++ b/libc/stdlib/drand48_r.c @@ -13,15 +13,13 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <errno.h> #include <math.h> #include <stdlib.h> -libc_hidden_proto(erand48_r) int drand48_r (struct drand48_data *buffer, double *result) { diff --git a/libc/stdlib/erand48.c b/libc/stdlib/erand48.c index 853c2c35a..d0d313039 100644 --- a/libc/stdlib/erand48.c +++ b/libc/stdlib/erand48.c @@ -13,17 +13,11 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> -libc_hidden_proto(erand48_r) - -/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ -extern struct drand48_data __libc_drand48_data attribute_hidden; - double erand48 (unsigned short int xsubi[3]) { double result; diff --git a/libc/stdlib/erand48_r.c b/libc/stdlib/erand48_r.c index 42db6f74b..9c1ce1d3c 100644 --- a/libc/stdlib/erand48_r.c +++ b/libc/stdlib/erand48_r.c @@ -13,18 +13,13 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <ieee754.h> #include <stdlib.h> #include <limits.h> -extern int __drand48_iterate(unsigned short xsubi[3], - struct drand48_data *buffer) attribute_hidden; - -libc_hidden_proto(erand48_r) int erand48_r (unsigned short int xsubi[3], struct drand48_data *buffer, double *result) { union ieee754_double temp; diff --git a/libc/stdlib/gcvt.c b/libc/stdlib/gcvt.c index f1c1f4270..3c27b62c4 100644 --- a/libc/stdlib/gcvt.c +++ b/libc/stdlib/gcvt.c @@ -1,7 +1,6 @@ #include <stdio.h> #include <stdlib.h> -libc_hidden_proto(sprintf) #ifdef __UCLIBC_HAS_FLOATS__ #define MAX_NDIGIT 17 diff --git a/libc/stdlib/getenv.c b/libc/stdlib/getenv.c index 7b3df7e64..9b04d0fab 100644 --- a/libc/stdlib/getenv.c +++ b/libc/stdlib/getenv.c @@ -8,9 +8,6 @@ #include <unistd.h> #include <stdlib.h> -libc_hidden_proto(getenv) -/* Experimentally off - libc_hidden_proto(memcmp) */ -/* Experimentally off - libc_hidden_proto(strlen) */ /* IEEE Std 1003.1-2001 says getenv need not be thread safe, so * don't bother locking access to __environ */ @@ -30,4 +27,4 @@ char *getenv(const char *var) } return NULL; } -libc_hidden_def(getenv) +libc_hidden_weak(getenv) diff --git a/libc/stdlib/getpt.c b/libc/stdlib/getpt.c index 3033a13aa..a46e084a7 100644 --- a/libc/stdlib/getpt.c +++ b/libc/stdlib/getpt.c @@ -13,9 +13,8 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <errno.h> #include <fcntl.h> @@ -26,10 +25,7 @@ #include <sys/statfs.h> extern __typeof(statfs) __libc_statfs; -libc_hidden_proto(__libc_statfs) -libc_hidden_proto(open) -libc_hidden_proto(close) #if !defined __ASSUME_DEVPTS__ @@ -46,12 +42,12 @@ libc_hidden_proto(close) #if !defined __UNIX98PTY_ONLY__ && defined __UCLIBC_HAS_GETPT__ /* Prototype for function that opens BSD-style master pseudo-terminals. */ -extern int __bsd_getpt (void) attribute_hidden; +static __inline__ int __bsd_getpt (void); #endif /* Open a master pseudo terminal and return its file descriptor. */ -int -posix_openpt (int flags) +static int +__posix_openpt (int flags) { #define have_no_dev_ptmx (1<<0) #define devpts_mounted (1<<1) @@ -74,14 +70,19 @@ posix_openpt (int flags) /* Check that the /dev/pts filesystem is mounted or if /dev is a devfs filesystem (this implies /dev/pts). */ - if ((_state & devpts_mounted) - || (__libc_statfs (_PATH_DEVPTS, &fsbuf) == 0 + if ( +#if !defined __UNIX98PTY_ONLY__ + (_state & devpts_mounted) || +#endif + (__libc_statfs (_PATH_DEVPTS, &fsbuf) == 0 && fsbuf.f_type == DEVPTS_SUPER_MAGIC) || (__libc_statfs (_PATH_DEV, &fsbuf) == 0 && fsbuf.f_type == DEVFS_SUPER_MAGIC)) { /* Everything is ok. */ +#if !defined __UNIX98PTY_ONLY__ _state |= devpts_mounted; +#endif return fd; } @@ -103,25 +104,24 @@ posix_openpt (int flags) return -1; } } +#if !defined __UNIX98PTY_ONLY__ && defined __UCLIBC_HAS_GETPT__ + /* If we have no ptmx then ignore flags and use the fallback. */ + if (_state & have_no_dev_ptmx) + return __bsd_getpt(); +#endif return -1; } -libc_hidden_def(posix_openpt) +strong_alias(__posix_openpt,posix_openpt) #undef have_no_dev_ptmx #undef devpts_mounted #if defined __USE_GNU && defined __UCLIBC_HAS_GETPT__ -int -getpt (void) +int getpt (void) { - int fd = posix_openpt(O_RDWR); -#if !defined __UNIX98PTY_ONLY__ - if (fd == -1) - fd = __bsd_getpt(); -#endif - return fd; + return __posix_openpt(O_RDWR); } -#if !defined __UNIX98PTY_ONLY__ +#if !defined __UNIX98PTY_ONLY__ && defined __UCLIBC_HAS_GETPT__ # define PTYNAME1 "pqrstuvwxyzabcde"; # define PTYNAME2 "0123456789abcdef"; diff --git a/libc/stdlib/grantpt.c b/libc/stdlib/grantpt.c index b60ffe7dc..f80f0946c 100644 --- a/libc/stdlib/grantpt.c +++ b/libc/stdlib/grantpt.c @@ -13,8 +13,7 @@ You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + see <http://www.gnu.org/licenses/>. */ #include <limits.h> #include <stdlib.h> @@ -33,25 +32,18 @@ /* Prototype for function that changes ownership and access permission for slave pseudo terminals that do not live on a `devpts' filesystem. */ -int __unix_grantpt (int fd); +static int __unix_grantpt (int fd); /* Prototype for private function that gets the name of the slave pseudo terminal in a safe way. */ static int pts_name (int fd, char **pts, size_t buf_len); - -#endif +extern __typeof(statfs) __libc_statfs; /* Change the ownership and access permission of the slave pseudo terminal associated with the master pseudo terminal specified by FD. */ -int -#if !defined __ASSUME_DEVPTS__ -grantpt (int fd) -#else -grantpt (attribute_unused int fd) -#endif +int grantpt (int fd) { -#if !defined __ASSUME_DEVPTS__ struct statfs fsbuf; char _buf[PATH_MAX]; char *buf = _buf; @@ -59,18 +51,25 @@ grantpt (attribute_unused int fd) if (pts_name (fd, &buf, sizeof (_buf))) return -1; - if (statfs (buf, &fsbuf) < 0) + if (__libc_statfs (buf, &fsbuf) < 0) return -1; /* If the slave pseudo terminal lives on a `devpts' filesystem, the ownership and access permission are already set. */ if (fsbuf.f_type != DEVPTS_SUPER_MAGIC && fsbuf.f_type != DEVFS_SUPER_MAGIC) - return __unix_grantpt (fd); -#endif + return __unix_grantpt (fd); + return 0; } -#if !defined __ASSUME_DEVPTS__ # define grantpt __unix_grantpt # include "unix_grantpt.c" + +#else + +int grantpt (attribute_unused int fd) +{ + return 0; +} + #endif diff --git a/libc/stdlib/jrand48.c b/libc/stdlib/jrand48.c index 6f812068b..c18c28e0b 100644 --- a/libc/stdlib/jrand48.c +++ b/libc/stdlib/jrand48.c @@ -13,17 +13,11 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> -libc_hidden_proto(jrand48_r) - -/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ -extern struct drand48_data __libc_drand48_data attribute_hidden; - long int jrand48 (unsigned short int xsubi[3]) { long int result; diff --git a/libc/stdlib/jrand48_r.c b/libc/stdlib/jrand48_r.c index fe77c3c38..e6d09ca17 100644 --- a/libc/stdlib/jrand48_r.c +++ b/libc/stdlib/jrand48_r.c @@ -13,16 +13,11 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> -extern int __drand48_iterate(unsigned short xsubi[3], - struct drand48_data *buffer) attribute_hidden; - -libc_hidden_proto(jrand48_r) int jrand48_r (unsigned short int xsubi[3], struct drand48_data *buffer, long int *result) { /* Compute next state. */ diff --git a/libc/stdlib/l64a.c b/libc/stdlib/l64a.c index a8b2d551e..6f2888a6d 100644 --- a/libc/stdlib/l64a.c +++ b/libc/stdlib/l64a.c @@ -13,9 +13,8 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> @@ -36,21 +35,21 @@ char * l64a (long int n) { unsigned long int m = (unsigned long int) n; static char result[7]; - int cnt; + char *p; /* The standard says that only 32 bits are used. */ - m &= 0xffffffff; + if (sizeof(m) != 4) + m &= 0xffffffff; - if (m == 0ul) - /* The value for N == 0 is defined to be the empty string. */ - return (char *) ""; - - for (cnt = 0; m > 0ul; ++cnt) + /* The value for N == 0 is defined to be the empty string, + * this code provides that as well. */ + p = result; + while (m) { - result[cnt] = conv_table[m & 0x3f]; + *p++ = conv_table[m & 0x3f]; m >>= 6; } - result[cnt] = '\0'; + *p = '\0'; return result; } diff --git a/libc/stdlib/lcong48.c b/libc/stdlib/lcong48.c new file mode 100644 index 000000000..06cab6672 --- /dev/null +++ b/libc/stdlib/lcong48.c @@ -0,0 +1,29 @@ +/* vi: set sw=4 ts=4: */ +/* Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. */ + +#include <features.h> + +#if defined __USE_SVID || defined __USE_XOPEN +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +static int __lcong48_r (unsigned short int param[7], struct drand48_data *buffer) +{ + /* Store the given values. */ + memcpy (buffer->__x, ¶m[0], sizeof (buffer->__x)); + buffer->__a = ((uint64_t) param[5] << 32 | (uint32_t) param[4] << 16 | param[3]); + buffer->__c = param[6]; + buffer->__init = 1; + + return 0; +} +# ifdef __USE_MISC +strong_alias(__lcong48_r,lcong48_r) +# endif + +void lcong48 (unsigned short int param[7]) +{ + (void) __lcong48_r (param, &__libc_drand48_data); +} +#endif diff --git a/libc/stdlib/ldiv.c b/libc/stdlib/ldiv.c index 88a877116..34ad8a37d 100644 --- a/libc/stdlib/ldiv.c +++ b/libc/stdlib/ldiv.c @@ -13,9 +13,8 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <features.h> #include <stdlib.h> diff --git a/libc/stdlib/lldiv.c b/libc/stdlib/lldiv.c index ff670174c..166bd46e4 100644 --- a/libc/stdlib/lldiv.c +++ b/libc/stdlib/lldiv.c @@ -13,9 +13,8 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <features.h> #include <stdlib.h> diff --git a/libc/stdlib/lrand48.c b/libc/stdlib/lrand48.c index 863951f07..a88ad6cc7 100644 --- a/libc/stdlib/lrand48.c +++ b/libc/stdlib/lrand48.c @@ -13,17 +13,11 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> -libc_hidden_proto(nrand48_r) - -/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ -extern struct drand48_data __libc_drand48_data attribute_hidden; - long int lrand48 (void) { long int result; diff --git a/libc/stdlib/lrand48_r.c b/libc/stdlib/lrand48_r.c index 277fb9ae3..09a9327b5 100644 --- a/libc/stdlib/lrand48_r.c +++ b/libc/stdlib/lrand48_r.c @@ -13,15 +13,12 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> -libc_hidden_proto(nrand48_r) -libc_hidden_proto(lrand48_r) int lrand48_r (struct drand48_data *buffer, long int *result) { /* Be generous for the arguments, detect some errors. */ diff --git a/libc/stdlib/malloc-simple/Makefile.in b/libc/stdlib/malloc-simple/Makefile.in index 51488ff58..c3ef4b73f 100644 --- a/libc/stdlib/malloc-simple/Makefile.in +++ b/libc/stdlib/malloc-simple/Makefile.in @@ -1,22 +1,26 @@ # Makefile for uClibc # -# Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> +# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org> # # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. # +subdirs += libc/stdlib/malloc-simple + STDLIB_MALLOC_SIMPLE_DIR := $(top_srcdir)libc/stdlib/malloc-simple STDLIB_MALLOC_SIMPLE_OUT := $(top_builddir)libc/stdlib/malloc-simple -CSRC := $(notdir $(wildcard $(STDLIB_MALLOC_SIMPLE_DIR)/*.c)) -CSRC := $(filter-out alloc.c,$(CSRC)) +CSRC-y := $(notdir $(wildcard $(STDLIB_MALLOC_SIMPLE_DIR)/*.c)) +# multi source alloc.c +CSRC- := alloc.c +CSRC-y := $(filter-out $(CSRC-),$(CSRC-y)) -STDLIB_MALLOC_SIMPLE_SRC := $(patsubst %.c,$(STDLIB_MALLOC_SIMPLE_DIR)/%.c,$(CSRC)) -STDLIB_MALLOC_SIMPLE_OBJ := $(patsubst %.c,$(STDLIB_MALLOC_SIMPLE_OUT)/%.o,$(CSRC)) +STDLIB_MALLOC_SIMPLE_SRC := $(patsubst %.c,$(STDLIB_MALLOC_SIMPLE_DIR)/%.c,$(CSRC-y)) +STDLIB_MALLOC_SIMPLE_OBJ := $(patsubst %.c,$(STDLIB_MALLOC_SIMPLE_OUT)/%.o,$(CSRC-y)) libc-$(MALLOC_SIMPLE) += $(STDLIB_MALLOC_SIMPLE_OBJ) -objclean-y += stdlib_malloc_simple_objclean +objclean-y += CLEAN_libc/stdlib/malloc-simple -stdlib_malloc_simple_objclean: - $(RM) $(STDLIB_MALLOC_SIMPLE_OUT)/*.{o,os} +CLEAN_libc/stdlib/malloc-simple: + $(do_rm) $(addprefix $(STDLIB_MALLOC_SIMPLE_OUT)/*., o os) diff --git a/libc/stdlib/malloc-simple/alloc.c b/libc/stdlib/malloc-simple/alloc.c index 13d4166a7..a3c068a5b 100644 --- a/libc/stdlib/malloc-simple/alloc.c +++ b/libc/stdlib/malloc-simple/alloc.c @@ -15,11 +15,9 @@ #include <string.h> #include <errno.h> #include <sys/mman.h> +#include <malloc.h> -/* Experimentally off - libc_hidden_proto(memcpy) */ -/*libc_hidden_proto(memset)*/ -libc_hidden_proto(mmap) -libc_hidden_proto(munmap) +extern int weak_function __libc_free_aligned(void *ptr) attribute_hidden; #ifdef L_malloc void *malloc(size_t size) @@ -39,13 +37,15 @@ void *malloc(size_t size) #ifdef __ARCH_USE_MMU__ # define MMAP_FLAGS MAP_PRIVATE | MAP_ANONYMOUS #else -# define MMAP_FLAGS MAP_SHARED | MAP_ANONYMOUS +# define MMAP_FLAGS MAP_SHARED | MAP_ANONYMOUS | MAP_UNINITIALIZED #endif result = mmap((void *) 0, size + sizeof(size_t), PROT_READ | PROT_WRITE, MMAP_FLAGS, 0, 0); - if (result == MAP_FAILED) + if (result == MAP_FAILED) { + __set_errno(ENOMEM); return 0; + } * (size_t *) result = size; return(result + sizeof(size_t)); } @@ -63,11 +63,10 @@ void * calloc(size_t nmemb, size_t lsize) __set_errno(ENOMEM); return NULL; } - result=malloc(size); -#if 0 - /* Standard unix mmap using /dev/zero clears memory so calloc - * doesn't need to actually zero anything.... - */ + result = malloc(size); + +#ifndef __ARCH_USE_MMU__ + /* mmap'd with MAP_UNINITIALIZED, we have to blank memory ourselves */ if (result != NULL) { memset(result, 0, size); } @@ -99,7 +98,6 @@ void *realloc(void *ptr, size_t size) #endif #ifdef L_free -extern int weak_function __libc_free_aligned(void *ptr); void free(void *ptr) { if (unlikely(ptr == NULL)) @@ -116,7 +114,7 @@ void free(void *ptr) #ifdef L_memalign #include <bits/uClibc_mutex.h> -__UCLIBC_MUTEX_STATIC(__malloc_lock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); +__UCLIBC_MUTEX_INIT(__malloc_lock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); #define __MALLOC_LOCK __UCLIBC_MUTEX_LOCK(__malloc_lock) #define __MALLOC_UNLOCK __UCLIBC_MUTEX_UNLOCK(__malloc_lock) @@ -127,7 +125,7 @@ struct alignlist __ptr_t aligned; /* The address that memaligned returned. */ __ptr_t exact; /* The address that malloc returned. */ }; -struct alignlist *_aligned_blocks; +static struct alignlist *_aligned_blocks; /* Return memory to the heap. */ int __libc_free_aligned(void *ptr) @@ -186,4 +184,5 @@ DONE: return result; } +libc_hidden_def(memalign) #endif diff --git a/libc/stdlib/malloc-standard/Makefile.in b/libc/stdlib/malloc-standard/Makefile.in index 3bbe93e08..04a46b681 100644 --- a/libc/stdlib/malloc-standard/Makefile.in +++ b/libc/stdlib/malloc-standard/Makefile.in @@ -1,23 +1,23 @@ # Makefile for uClibc # -# Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> +# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org> # # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. # -# calloc.c can be found at uClibc/libc/stdlib/calloc.c -# valloc.c can be found at uClibc/libc/stdlib/valloc.c -CSRC := malloc.c calloc.c realloc.c free.c memalign.c mallopt.c mallinfo.c +subdirs += libc/stdlib/malloc-standard STDLIB_MALLOC_STANDARD_DIR := $(top_srcdir)libc/stdlib/malloc-standard STDLIB_MALLOC_STANDARD_OUT := $(top_builddir)libc/stdlib/malloc-standard -STDLIB_MALLOC_STANDARD_SRC := $(patsubst %.c,$(STDLIB_MALLOC_STANDARD_DIR)/%.c,$(CSRC)) -STDLIB_MALLOC_STANDARD_OBJ := $(patsubst %.c,$(STDLIB_MALLOC_STANDARD_OUT)/%.o,$(CSRC)) +CSRC-y := $(notdir $(wildcard $(STDLIB_MALLOC_STANDARD_DIR)/*.c)) + +STDLIB_MALLOC_STANDARD_SRC := $(patsubst %.c,$(STDLIB_MALLOC_STANDARD_DIR)/%.c,$(CSRC-y)) +STDLIB_MALLOC_STANDARD_OBJ := $(patsubst %.c,$(STDLIB_MALLOC_STANDARD_OUT)/%.o,$(CSRC-y)) libc-$(MALLOC_STANDARD) += $(STDLIB_MALLOC_STANDARD_OBJ) -objclean-y += stdlib_malloc_standard_objclean +objclean-y += CLEAN_libc/stdlib/malloc-standard -stdlib_malloc_standard_objclean: - $(RM) $(STDLIB_MALLOC_STANDARD_OUT)/*.{o,os} +CLEAN_libc/stdlib/malloc-standard: + $(do_rm) $(addprefix $(STDLIB_MALLOC_STANDARD_OUT)/*., o os) diff --git a/libc/stdlib/malloc-standard/calloc.c b/libc/stdlib/malloc-standard/calloc.c index 80ba3d04a..a70516f0e 100644 --- a/libc/stdlib/malloc-standard/calloc.c +++ b/libc/stdlib/malloc-standard/calloc.c @@ -16,7 +16,6 @@ #include "malloc.h" -/* Experimentally off - libc_hidden_proto(memset) */ /* ------------------------------ calloc ------------------------------ */ void* calloc(size_t n_elements, size_t elem_size) diff --git a/libc/stdlib/malloc-standard/free.c b/libc/stdlib/malloc-standard/free.c index 4d24697be..8b7a81fca 100644 --- a/libc/stdlib/malloc-standard/free.c +++ b/libc/stdlib/malloc-standard/free.c @@ -16,7 +16,6 @@ #include "malloc.h" -libc_hidden_proto(munmap) /* ------------------------- __malloc_trim ------------------------- __malloc_trim is an inverse of sorts to __malloc_alloc. It gives memory @@ -105,9 +104,13 @@ static int __malloc_trim(size_t pad, mstate av) */ int malloc_trim(size_t pad) { + int r; + __MALLOC_LOCK; mstate av = get_malloc_state(); __malloc_consolidate(av); - return __malloc_trim(pad, av); + r = __malloc_trim(pad, av); + __MALLOC_UNLOCK; + return r; } /* diff --git a/libc/stdlib/malloc-standard/mallinfo.c b/libc/stdlib/malloc-standard/mallinfo.c index 18331010a..dbe4d49b8 100644 --- a/libc/stdlib/malloc-standard/mallinfo.c +++ b/libc/stdlib/malloc-standard/mallinfo.c @@ -15,11 +15,10 @@ */ #include "malloc.h" +#include <stdio.h> /* fprintf */ -libc_hidden_proto(fprintf) /* ------------------------------ mallinfo ------------------------------ */ -libc_hidden_proto(mallinfo) struct mallinfo mallinfo(void) { mstate av; @@ -82,16 +81,12 @@ struct mallinfo mallinfo(void) } libc_hidden_def(mallinfo) -void malloc_stats(FILE *file) +void malloc_stats(void) { struct mallinfo mi; - if (file==NULL) { - file = stderr; - } - mi = mallinfo(); - fprintf(file, + fprintf(stderr, "total bytes allocated = %10u\n" "total bytes in use bytes = %10u\n" "total non-mmapped bytes allocated = %10d\n" diff --git a/libc/stdlib/malloc-standard/malloc.c b/libc/stdlib/malloc-standard/malloc.c index 3253ebda6..fd33b50c7 100644 --- a/libc/stdlib/malloc-standard/malloc.c +++ b/libc/stdlib/malloc-standard/malloc.c @@ -744,7 +744,7 @@ static void* __malloc_alloc(size_t nb, mstate av) } /* catch all failure paths */ - errno = ENOMEM; + __set_errno(ENOMEM); return 0; } @@ -832,8 +832,6 @@ void* malloc(size_t bytes) } #endif - __MALLOC_LOCK; - av = get_malloc_state(); /* Convert request size to internal form by adding (sizeof(size_t)) bytes overhead plus possibly more to obtain necessary alignment and/or @@ -845,6 +843,9 @@ void* malloc(size_t bytes) checked_request2size(bytes, nb); + __MALLOC_LOCK; + av = get_malloc_state(); + /* Bypass search if no frees yet */ diff --git a/libc/stdlib/malloc-standard/malloc.h b/libc/stdlib/malloc-standard/malloc.h index e0f3658b7..1a4cc5a62 100644 --- a/libc/stdlib/malloc-standard/malloc.h +++ b/libc/stdlib/malloc-standard/malloc.h @@ -24,13 +24,13 @@ #include <sys/mman.h> #include <bits/uClibc_mutex.h> -libc_hidden_proto(mmap) -libc_hidden_proto(sysconf) -libc_hidden_proto(sbrk) -libc_hidden_proto(abort) -__UCLIBC_MUTEX_EXTERN(__malloc_lock); +__UCLIBC_MUTEX_EXTERN(__malloc_lock) +#if defined __UCLIBC_HAS_THREADS__ && !defined __LINUXTHREADS_OLD__ + attribute_hidden +#endif + ; #define __MALLOC_LOCK __UCLIBC_MUTEX_LOCK(__malloc_lock) #define __MALLOC_UNLOCK __UCLIBC_MUTEX_UNLOCK(__malloc_lock) @@ -353,16 +353,13 @@ __UCLIBC_MUTEX_EXTERN(__malloc_lock); #endif #ifdef __ARCH_USE_MMU__ - -#define MMAP(addr, size, prot) \ - (mmap((addr), (size), (prot), MAP_PRIVATE|MAP_ANONYMOUS, 0, 0)) - +# define _MAP_UNINITIALIZED 0 #else +# define _MAP_UNINITIALIZED MAP_UNINITIALIZED +#endif #define MMAP(addr, size, prot) \ - (mmap((addr), (size), (prot), MAP_SHARED|MAP_ANONYMOUS, 0, 0)) - -#endif + (mmap((addr), (size), (prot), MAP_PRIVATE|MAP_ANONYMOUS|_MAP_UNINITIALIZED, 0, 0)) /* ----------------------- Chunk representations ----------------------- */ @@ -515,7 +512,7 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ #define checked_request2size(req, sz) \ if (REQUEST_OUT_OF_RANGE(req)) { \ - errno = ENOMEM; \ + __set_errno(ENOMEM); \ return 0; \ } \ (sz) = request2size(req); @@ -917,7 +914,7 @@ typedef struct malloc_state *mstate; malloc relies on the property that malloc_state is initialized to all zeroes (as is true of C statics). */ -extern struct malloc_state __malloc_state; /* never directly referenced */ +extern struct malloc_state __malloc_state attribute_hidden; /* never directly referenced */ /* All uses of av_ are via get_malloc_state(). @@ -954,12 +951,12 @@ void __malloc_consolidate(mstate) attribute_hidden; #define check_malloced_chunk(P,N) __do_check_malloced_chunk(P,N) #define check_malloc_state() __do_check_malloc_state() -extern void __do_check_chunk(mchunkptr p); -extern void __do_check_free_chunk(mchunkptr p); -extern void __do_check_inuse_chunk(mchunkptr p); -extern void __do_check_remalloced_chunk(mchunkptr p, size_t s); -extern void __do_check_malloced_chunk(mchunkptr p, size_t s); -extern void __do_check_malloc_state(void); +extern void __do_check_chunk(mchunkptr p) attribute_hidden; +extern void __do_check_free_chunk(mchunkptr p) attribute_hidden; +extern void __do_check_inuse_chunk(mchunkptr p) attribute_hidden; +extern void __do_check_remalloced_chunk(mchunkptr p, size_t s) attribute_hidden; +extern void __do_check_malloced_chunk(mchunkptr p, size_t s) attribute_hidden; +extern void __do_check_malloc_state(void) attribute_hidden; #include <assert.h> diff --git a/libc/stdlib/malloc-standard/memalign.c b/libc/stdlib/malloc-standard/memalign.c index 7e0674be5..e9ae5a7b9 100644 --- a/libc/stdlib/malloc-standard/memalign.c +++ b/libc/stdlib/malloc-standard/memalign.c @@ -52,8 +52,8 @@ void* memalign(size_t alignment, size_t bytes) alignment = a; } - __MALLOC_LOCK; checked_request2size(bytes, nb); + __MALLOC_LOCK; /* Strategy: find a spot within that chunk that meets the alignment * request, and then possibly free the leading and trailing space. */ @@ -127,4 +127,4 @@ void* memalign(size_t alignment, size_t bytes) __MALLOC_UNLOCK; return retval; } - +libc_hidden_def(memalign) diff --git a/libc/stdlib/malloc-standard/realloc.c b/libc/stdlib/malloc-standard/realloc.c index 41cae43d1..e49d11125 100644 --- a/libc/stdlib/malloc-standard/realloc.c +++ b/libc/stdlib/malloc-standard/realloc.c @@ -16,8 +16,6 @@ #include "malloc.h" -libc_hidden_proto(mremap) -/* Experimentally off - libc_hidden_proto(memcpy) */ /* ------------------------------ realloc ------------------------------ */ void* realloc(void* oldmem, size_t bytes) @@ -56,9 +54,9 @@ void* realloc(void* oldmem, size_t bytes) return NULL; } + checked_request2size(bytes, nb); __MALLOC_LOCK; av = get_malloc_state(); - checked_request2size(bytes, nb); oldp = mem2chunk(oldmem); oldsize = chunksize(oldp); diff --git a/libc/stdlib/malloc/Makefile.in b/libc/stdlib/malloc/Makefile.in index 73e0d6419..9efd34e8b 100644 --- a/libc/stdlib/malloc/Makefile.in +++ b/libc/stdlib/malloc/Makefile.in @@ -2,17 +2,19 @@ # # Copyright (C) 2002-2003 NEC Electronics Corporation # Copyright (C) 2002-2003 Miles Bader <miles@gnu.org> -# Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> +# Copyright (C) 2000-2008 Erik Andersen <andersen@uclibc.org> # # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. # -CSRC := malloc.c calloc.c free.c realloc.c memalign.c \ +subdirs += libc/stdlib/malloc + +CSRC-y := malloc.c calloc.c free.c realloc.c memalign.c \ heap_alloc.c heap_alloc_at.c heap_free.c # Turn on malloc debugging if requested +CSRC-$(UCLIBC_MALLOC_DEBUGGING) += malloc_debug.c heap_debug.c ifeq ($(UCLIBC_MALLOC_DEBUGGING),y) -CSRC += malloc_debug.c heap_debug.c CFLAGS += -DMALLOC_DEBUGGING -DHEAP_DEBUGGING ifeq ($(UCLIBC_UCLINUX_BROKEN_MUNMAP),y) CFLAGS += -DMALLOC_MMB_DEBUGGING @@ -22,15 +24,15 @@ endif STDLIB_MALLOC_DIR := $(top_srcdir)libc/stdlib/malloc STDLIB_MALLOC_OUT := $(top_builddir)libc/stdlib/malloc -STDLIB_MALLOC_SRC := $(patsubst %.c,$(STDLIB_MALLOC_DIR)/%.c,$(CSRC)) -STDLIB_MALLOC_OBJ := $(patsubst %.c,$(STDLIB_MALLOC_OUT)/%.o,$(CSRC)) +STDLIB_MALLOC_SRC := $(patsubst %.c,$(STDLIB_MALLOC_DIR)/%.c,$(CSRC-y)) +STDLIB_MALLOC_OBJ := $(patsubst %.c,$(STDLIB_MALLOC_OUT)/%.o,$(CSRC-y)) libc-$(MALLOC) += $(STDLIB_MALLOC_OBJ) -objclean-y += stdlib_malloc_objclean +objclean-y += CLEAN_libc/stdlib/malloc -stdlib_malloc_objclean: - $(RM) $(STDLIB_MALLOC_OUT)/*.{o,os} +CLEAN_libc/stdlib/malloc: + $(do_rm) $(addprefix $(STDLIB_MALLOC_OUT)/*., o os) malloc.o free.o realloc.o memalign.o: malloc.h # Depend on uClinux_config.h to cache changes in __UCLIBC_MALLOC_DEBUGGING__ diff --git a/libc/stdlib/malloc/calloc.c b/libc/stdlib/malloc/calloc.c index 79e6ec6c7..2b315dbc8 100644 --- a/libc/stdlib/malloc/calloc.c +++ b/libc/stdlib/malloc/calloc.c @@ -14,15 +14,14 @@ * for more details. * * You should have received a copy of the GNU Library General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; see the file COPYING.LIB. If not, see + * <http://www.gnu.org/licenses/>. */ #include <stdlib.h> #include <string.h> #include <errno.h> -/* Experimentally off - libc_hidden_proto(memset) */ void * calloc(size_t nmemb, size_t lsize) { diff --git a/libc/stdlib/malloc/free.c b/libc/stdlib/malloc/free.c index da395331b..14d110153 100644 --- a/libc/stdlib/malloc/free.c +++ b/libc/stdlib/malloc/free.c @@ -15,14 +15,22 @@ #include <unistd.h> #include <sys/mman.h> -libc_hidden_proto(munmap) -libc_hidden_proto(sbrk) #include "malloc.h" #include "heap.h" +#ifdef HEAP_USE_LOCKING +#define free_to_heap(mem, heap, lck) __free_to_heap(mem, heap, lck) +#else +#define free_to_heap(mem, heap, lck) __free_to_heap(mem, heap) +#endif + static void -free_to_heap (void *mem, struct heap *heap) +__free_to_heap (void *mem, struct heap_free_area **heap +#ifdef HEAP_USE_LOCKING + , __UCLIBC_MUTEX_TYPE *heap_lock +#endif + ) { size_t size; struct heap_free_area *fa; @@ -39,7 +47,7 @@ free_to_heap (void *mem, struct heap *heap) size = MALLOC_SIZE (mem); mem = MALLOC_BASE (mem); - __heap_lock (heap); + __heap_lock (heap_lock); /* Put MEM back in the heap, and get the free-area it was placed in. */ fa = __heap_free (heap, mem, size); @@ -48,7 +56,7 @@ free_to_heap (void *mem, struct heap *heap) unmapped. */ if (HEAP_FREE_AREA_SIZE (fa) < MALLOC_UNMAP_THRESHOLD) /* Nope, nothing left to do, just release the lock. */ - __heap_unlock (heap); + __heap_unlock (heap_lock); else /* Yup, try to unmap FA. */ { @@ -81,7 +89,7 @@ free_to_heap (void *mem, struct heap *heap) MALLOC_DEBUG (-1, "not unmapping: 0x%lx - 0x%lx (%ld bytes)", start, end, end - start); __malloc_unlock_sbrk (); - __heap_unlock (heap); + __heap_unlock (heap_lock); return; } #endif @@ -98,7 +106,7 @@ free_to_heap (void *mem, struct heap *heap) another free area, even if it's smaller than MALLOC_MIN_SIZE, will cause us not to reserve anything. */ { - /* Put the reserved memory back in the heap; we asssume that + /* Put the reserved memory back in the heap; we assume that MALLOC_UNMAP_THRESHOLD is greater than MALLOC_MIN_SIZE, so we use the latter unconditionally here. */ __heap_free (heap, (void *)start, MALLOC_MIN_SIZE); @@ -108,7 +116,7 @@ free_to_heap (void *mem, struct heap *heap) #ifdef MALLOC_USE_SBRK /* Release the heap lock; we're still holding the sbrk lock. */ - __heap_unlock (heap); + __heap_unlock (heap_lock); /* Lower the brk. */ sbrk (start - end); /* Release the sbrk lock too; now we hold no locks. */ @@ -169,18 +177,18 @@ free_to_heap (void *mem, struct heap *heap) /* Start searching again from the end of this block. */ start = mmb_end; + /* Release the descriptor block we used. */ + free_to_heap (mmb, &__malloc_mmb_heap, &__malloc_mmb_heap_lock); + /* We have to unlock the heap before we recurse to free the mmb descriptor, because we might be unmapping from the mmb heap. */ - __heap_unlock (heap); - - /* Release the descriptor block we used. */ - free_to_heap (mmb, &__malloc_mmb_heap); + __heap_unlock (heap_lock); /* Do the actual munmap. */ munmap ((void *)mmb_start, mmb_end - mmb_start); - __heap_lock (heap); + __heap_lock (heap_lock); # ifdef __UCLIBC_HAS_THREADS__ /* In a multi-threaded program, it's possible that PREV_MMB has @@ -213,7 +221,7 @@ free_to_heap (void *mem, struct heap *heap) } /* Finally release the lock for good. */ - __heap_unlock (heap); + __heap_unlock (heap_lock); MALLOC_MMB_DEBUG_INDENT (-1); @@ -243,7 +251,7 @@ free_to_heap (void *mem, struct heap *heap) } /* Release the heap lock before we do the system call. */ - __heap_unlock (heap); + __heap_unlock (heap_lock); if (unmap_end > unmap_start) /* Finally, actually unmap the memory. */ @@ -260,5 +268,5 @@ free_to_heap (void *mem, struct heap *heap) void free (void *mem) { - free_to_heap (mem, &__malloc_heap); + free_to_heap (mem, &__malloc_heap, &__malloc_heap_lock); } diff --git a/libc/stdlib/malloc/heap.h b/libc/stdlib/malloc/heap.h index 6505cd223..11bd49ffe 100644 --- a/libc/stdlib/malloc/heap.h +++ b/libc/stdlib/malloc/heap.h @@ -13,48 +13,27 @@ #include <features.h> - -/* On multi-threaded systems, the heap includes a lock. */ +#include <bits/uClibc_mutex.h> #ifdef __UCLIBC_HAS_THREADS__ -# include <pthread.h> -# include <bits/uClibc_pthread.h> # define HEAP_USE_LOCKING #endif +#define __heap_lock(heap_lock) __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE(*(heap_lock)) +#define __heap_unlock(heap_lock) __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE(*(heap_lock)) /* The heap allocates in multiples of, and aligned to, HEAP_GRANULARITY. HEAP_GRANULARITY must be a power of 2. Malloc depends on this being the same as MALLOC_ALIGNMENT. */ -#define HEAP_GRANULARITY_TYPE double __attribute_aligned__ (sizeof (size_t)) -#define HEAP_GRANULARITY (__alignof__ (HEAP_GRANULARITY_TYPE)) +#define HEAP_GRANULARITY_TYPE double __attribute_aligned__ (HEAP_GRANULARITY) +#define HEAP_GRANULARITY \ + (__alignof__ (double) > sizeof (size_t) ? __alignof__ (double) : sizeof (size_t)) -/* A heap is a collection of memory blocks, from which smaller blocks - of memory can be allocated. */ -struct heap -{ - /* A list of memory in the heap available for allocation. */ - struct heap_free_area *free_areas; - -#ifdef HEAP_USE_LOCKING - /* A lock that can be used by callers to control access to the heap. - The heap code _does not_ use this lock, it's merely here for the - convenience of users! */ - pthread_mutex_t lock; -#endif -}; -/* The HEAP_INIT macro can be used as a static initializer for a heap - variable. The HEAP_INIT_WITH_FA variant is used to initialize a heap +/* The HEAP_INIT_WITH_FA variant is used to initialize a heap with an initial static free-area; its argument FA should be declared using HEAP_DECLARE_STATIC_FREE_AREA. */ -#ifdef HEAP_USE_LOCKING -# define HEAP_INIT { 0, PTHREAD_MUTEX_INITIALIZER } -# define HEAP_INIT_WITH_FA(fa) { &fa._fa, PTHREAD_MUTEX_INITIALIZER } -#else -# define HEAP_INIT { 0 } -# define HEAP_INIT_WITH_FA(fa) { &fa._fa } -#endif +# define HEAP_INIT_WITH_FA(fa) &fa._fa /* A free-list area `header'. These are actually stored at the _ends_ of free areas (to make allocating from the beginning of the area simpler), @@ -106,50 +85,33 @@ struct heap_free_area #define HEAP_MIN_FREE_AREA_SIZE \ HEAP_ADJUST_SIZE (sizeof (struct heap_free_area) + 32) - -/* branch-prediction macros; they may already be defined by libc. */ -#ifndef likely -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) -#define likely(cond) __builtin_expect(!!(int)(cond), 1) -#define unlikely(cond) __builtin_expect((int)(cond), 0) -#else -#define likely(cond) (cond) -#define unlikely(cond) (cond) -#endif -#endif /* !likely */ - - /* Define HEAP_DEBUGGING to cause the heap routines to emit debugging info to stderr when the variable __heap_debug is set to true. */ #ifdef HEAP_DEBUGGING -extern int __heap_debug; +extern int __heap_debug attribute_hidden; #define HEAP_DEBUG(heap, str) (__heap_debug ? __heap_dump (heap, str) : 0) #else #define HEAP_DEBUG(heap, str) (void)0 #endif /* Output a text representation of HEAP to stderr, labelling it with STR. */ -extern void __heap_dump (struct heap *heap, const char *str); +extern void __heap_dump (struct heap_free_area *heap, const char *str) attribute_hidden; /* Do some consistency checks on HEAP. If they fail, output an error message to stderr, and exit. STR is printed with the failure message. */ -extern void __heap_check (struct heap *heap, const char *str); - - -#define __heap_lock(heap) __pthread_mutex_lock (&(heap)->lock) -#define __heap_unlock(heap) __pthread_mutex_unlock (&(heap)->lock) +extern void __heap_check (struct heap_free_area *heap, const char *str) attribute_hidden; /* Delete the free-area FA from HEAP. */ static __inline__ void -__heap_delete (struct heap *heap, struct heap_free_area *fa) +__heap_delete (struct heap_free_area **heap, struct heap_free_area *fa) { if (fa->next) fa->next->prev = fa->prev; if (fa->prev) fa->prev->next = fa->next; else - heap->free_areas = fa->next; + *heap = fa->next; } @@ -157,7 +119,7 @@ __heap_delete (struct heap *heap, struct heap_free_area *fa) HEAP. PREV and NEXT may be 0; if PREV is 0, FA is installed as the first free-area. */ static __inline__ void -__heap_link_free_area (struct heap *heap, struct heap_free_area *fa, +__heap_link_free_area (struct heap_free_area **heap, struct heap_free_area *fa, struct heap_free_area *prev, struct heap_free_area *next) { @@ -167,7 +129,7 @@ __heap_link_free_area (struct heap *heap, struct heap_free_area *fa, if (prev) prev->next = fa; else - heap->free_areas = fa; + *heap = fa; if (next) next->prev = fa; } @@ -176,14 +138,14 @@ __heap_link_free_area (struct heap *heap, struct heap_free_area *fa, PREV may be 0, in which case FA is installed as the first free-area (but FA may not be 0). */ static __inline__ void -__heap_link_free_area_after (struct heap *heap, +__heap_link_free_area_after (struct heap_free_area **heap, struct heap_free_area *fa, struct heap_free_area *prev) { if (prev) prev->next = fa; else - heap->free_areas = fa; + *heap = fa; fa->prev = prev; } @@ -192,7 +154,7 @@ __heap_link_free_area_after (struct heap *heap, PREV and NEXT may be 0; if PREV is 0, MEM is installed as the first free-area. */ static __inline__ struct heap_free_area * -__heap_add_free_area (struct heap *heap, void *mem, size_t size, +__heap_add_free_area (struct heap_free_area **heap, void *mem, size_t size, struct heap_free_area *prev, struct heap_free_area *next) { @@ -210,7 +172,7 @@ __heap_add_free_area (struct heap *heap, void *mem, size_t size, /* Allocate SIZE bytes from the front of the free-area FA in HEAP, and return the amount actually allocated (which may be more than SIZE). */ static __inline__ size_t -__heap_free_area_alloc (struct heap *heap, +__heap_free_area_alloc (struct heap_free_area **heap, struct heap_free_area *fa, size_t size) { size_t fa_size = fa->size; @@ -234,16 +196,16 @@ __heap_free_area_alloc (struct heap *heap, /* Allocate and return a block at least *SIZE bytes long from HEAP. *SIZE is adjusted to reflect the actual amount allocated (which may be greater than requested). */ -extern void *__heap_alloc (struct heap *heap, size_t *size); +extern void *__heap_alloc (struct heap_free_area **heap, size_t *size) attribute_hidden; /* Allocate SIZE bytes at address MEM in HEAP. Return the actual size allocated, or 0 if we failed. */ -extern size_t __heap_alloc_at (struct heap *heap, void *mem, size_t size); +extern size_t __heap_alloc_at (struct heap_free_area **heap, void *mem, size_t size) attribute_hidden; /* Return the memory area MEM of size SIZE to HEAP. Returns the heap free area into which the memory was placed. */ -extern struct heap_free_area *__heap_free (struct heap *heap, - void *mem, size_t size); +extern struct heap_free_area *__heap_free (struct heap_free_area **heap, + void *mem, size_t size) attribute_hidden; /* Return true if HEAP contains absolutely no memory. */ -#define __heap_is_empty(heap) (! (heap)->free_areas) +#define __heap_is_empty(heap) (! (heap)) diff --git a/libc/stdlib/malloc/heap_alloc.c b/libc/stdlib/malloc/heap_alloc.c index 9f5fd6c1a..77b7d8560 100644 --- a/libc/stdlib/malloc/heap_alloc.c +++ b/libc/stdlib/malloc/heap_alloc.c @@ -20,7 +20,7 @@ *SIZE is adjusted to reflect the actual amount allocated (which may be greater than requested). */ void * -__heap_alloc (struct heap *heap, size_t *size) +__heap_alloc (struct heap_free_area **heap, size_t *size) { struct heap_free_area *fa; size_t _size = *size; @@ -33,10 +33,10 @@ __heap_alloc (struct heap *heap, size_t *size) we must make sure that every allocated block can hold one. */ _size = HEAP_ADJUST_SIZE (sizeof (struct heap_free_area)); - HEAP_DEBUG (heap, "before __heap_alloc"); + HEAP_DEBUG (*heap, "before __heap_alloc"); /* Look for a free area that can contain _SIZE bytes. */ - for (fa = heap->free_areas; fa; fa = fa->next) + for (fa = *heap; fa; fa = fa->next) if (fa->size >= _size) { /* Found one! */ @@ -45,7 +45,7 @@ __heap_alloc (struct heap *heap, size_t *size) break; } - HEAP_DEBUG (heap, "after __heap_alloc"); + HEAP_DEBUG (*heap, "after __heap_alloc"); return mem; } diff --git a/libc/stdlib/malloc/heap_alloc_at.c b/libc/stdlib/malloc/heap_alloc_at.c index a65140fea..45d68598a 100644 --- a/libc/stdlib/malloc/heap_alloc_at.c +++ b/libc/stdlib/malloc/heap_alloc_at.c @@ -19,17 +19,17 @@ /* Allocate SIZE bytes at address MEM in HEAP. Return the actual size allocated, or 0 if we failed. */ size_t -__heap_alloc_at (struct heap *heap, void *mem, size_t size) +__heap_alloc_at (struct heap_free_area **heap, void *mem, size_t size) { struct heap_free_area *fa; size_t alloced = 0; size = HEAP_ADJUST_SIZE (size); - HEAP_DEBUG (heap, "before __heap_alloc_at"); + HEAP_DEBUG (*heap, "before __heap_alloc_at"); /* Look for a free area that can contain SIZE bytes. */ - for (fa = heap->free_areas; fa; fa = fa->next) + for (fa = *heap; fa; fa = fa->next) { void *fa_mem = HEAP_FREE_AREA_START (fa); if (fa_mem <= mem) @@ -41,7 +41,7 @@ __heap_alloc_at (struct heap *heap, void *mem, size_t size) } } - HEAP_DEBUG (heap, "after __heap_alloc_at"); + HEAP_DEBUG (*heap, "after __heap_alloc_at"); return alloced; } diff --git a/libc/stdlib/malloc/heap_debug.c b/libc/stdlib/malloc/heap_debug.c index a2a9f4ec1..5f17aae04 100644 --- a/libc/stdlib/malloc/heap_debug.c +++ b/libc/stdlib/malloc/heap_debug.c @@ -17,9 +17,6 @@ #include <string.h> #include <unistd.h> -libc_hidden_proto(vfprintf) -libc_hidden_proto(fprintf) -libc_hidden_proto(_exit) #include "malloc.h" #include "heap.h" @@ -31,10 +28,10 @@ int __heap_debug = 0; static void -__heap_dump_freelist (struct heap *heap) +__heap_dump_freelist (struct heap_free_area *heap) { struct heap_free_area *fa; - for (fa = heap->free_areas; fa; fa = fa->next) + for (fa = heap; fa; fa = fa->next) __malloc_debug_printf (0, "0x%lx: 0x%lx - 0x%lx (%d)\tP=0x%lx, N=0x%lx", (long)fa, @@ -47,7 +44,7 @@ __heap_dump_freelist (struct heap *heap) /* Output a text representation of HEAP to stderr, labelling it with STR. */ void -__heap_dump (struct heap *heap, const char *str) +__heap_dump (struct heap_free_area *heap, const char *str) { static smallint recursed; @@ -69,7 +66,7 @@ __heap_dump (struct heap *heap, const char *str) /* Output an error message to stderr, and exit. STR is printed with the failure message. */ static void attribute_noreturn -__heap_check_failure (struct heap *heap, struct heap_free_area *fa, +__heap_check_failure (struct heap_free_area *heap, struct heap_free_area *fa, const char *str, char *fmt, ...) { va_list val; @@ -95,11 +92,11 @@ __heap_check_failure (struct heap *heap, struct heap_free_area *fa, /* Do some consistency checks on HEAP. If they fail, output an error message to stderr, and exit. STR is printed with the failure message. */ void -__heap_check (struct heap *heap, const char *str) +__heap_check (struct heap_free_area *heap, const char *str) { typedef unsigned long ul_t; struct heap_free_area *fa, *prev; - struct heap_free_area *first_fa = heap->free_areas; + struct heap_free_area *first_fa = heap; if (first_fa && first_fa->prev) __heap_check_failure (heap, first_fa, str, diff --git a/libc/stdlib/malloc/heap_free.c b/libc/stdlib/malloc/heap_free.c index 1c4634c55..15343c05a 100644 --- a/libc/stdlib/malloc/heap_free.c +++ b/libc/stdlib/malloc/heap_free.c @@ -18,12 +18,12 @@ /* Return the block of memory at MEM, of size SIZE, to HEAP. */ struct heap_free_area * -__heap_free (struct heap *heap, void *mem, size_t size) +__heap_free (struct heap_free_area **heap, void *mem, size_t size) { struct heap_free_area *fa, *prev_fa; void *end = (char *)mem + size; - HEAP_DEBUG (heap, "before __heap_free"); + HEAP_DEBUG (*heap, "before __heap_free"); /* Find the right position in the free-list entry to place the new block. This is the most speed critical loop in this malloc implementation: @@ -32,7 +32,7 @@ __heap_free (struct heap *heap, void *mem, size_t size) in the free-list when it becomes fragmented and long. [A better implemention would use a balanced tree or something for the free-list, though that bloats the code-size and complexity quite a bit.] */ - for (prev_fa = 0, fa = heap->free_areas; fa; prev_fa = fa, fa = fa->next) + for (prev_fa = 0, fa = *heap; fa; prev_fa = fa, fa = fa->next) if (unlikely (HEAP_FREE_AREA_END (fa) >= mem)) break; @@ -83,7 +83,7 @@ __heap_free (struct heap *heap, void *mem, size_t size) /* Make the new block into a separate free-list entry. */ fa = __heap_add_free_area (heap, mem, size, prev_fa, fa); - HEAP_DEBUG (heap, "after __heap_free"); + HEAP_DEBUG (*heap, "after __heap_free"); return fa; } diff --git a/libc/stdlib/malloc/malloc.c b/libc/stdlib/malloc/malloc.c index ce74c5608..f6bf10a93 100644 --- a/libc/stdlib/malloc/malloc.c +++ b/libc/stdlib/malloc/malloc.c @@ -16,8 +16,6 @@ #include <errno.h> #include <sys/mman.h> -libc_hidden_proto(mmap) -libc_hidden_proto(sbrk) #include "malloc.h" #include "heap.h" @@ -26,16 +24,19 @@ libc_hidden_proto(sbrk) /* The malloc heap. We provide a bit of initial static space so that programs can do a little mallocing without mmaping in more space. */ HEAP_DECLARE_STATIC_FREE_AREA (initial_fa, 256); -struct heap __malloc_heap = HEAP_INIT_WITH_FA (initial_fa); +struct heap_free_area *__malloc_heap = HEAP_INIT_WITH_FA (initial_fa); +#ifdef HEAP_USE_LOCKING +__UCLIBC_MUTEX_INIT(__malloc_heap_lock,PTHREAD_MUTEX_INITIALIZER); +#endif #if defined(MALLOC_USE_LOCKING) && defined(MALLOC_USE_SBRK) /* A lock protecting our use of sbrk. */ -malloc_mutex_t __malloc_sbrk_lock; +__UCLIBC_MUTEX(__malloc_sbrk_lock); #endif /* MALLOC_USE_LOCKING && MALLOC_USE_SBRK */ #ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__ -/* A list of all malloc_mmb structures describing blocsk that +/* A list of all malloc_mmb structures describing blocks that malloc has mmapped, ordered by the block address. */ struct malloc_mmb *__malloc_mmapped_blocks = 0; @@ -43,12 +44,24 @@ struct malloc_mmb *__malloc_mmapped_blocks = 0; them from the main heap, but that tends to cause heap fragmentation in annoying ways. */ HEAP_DECLARE_STATIC_FREE_AREA (initial_mmb_fa, 48); /* enough for 3 mmbs */ -struct heap __malloc_mmb_heap = HEAP_INIT_WITH_FA (initial_mmb_fa); +struct heap_free_area *__malloc_mmb_heap = HEAP_INIT_WITH_FA (initial_mmb_fa); +#ifdef HEAP_USE_LOCKING +__UCLIBC_MUTEX_INIT(__malloc_mmb_heap_lock,PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); +#endif #endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */ +#ifdef HEAP_USE_LOCKING +#define malloc_from_heap(size, heap, lck) __malloc_from_heap(size, heap, lck) +#else +#define malloc_from_heap(size, heap, lck) __malloc_from_heap(size, heap) +#endif static void * -malloc_from_heap (size_t size, struct heap *heap) +__malloc_from_heap (size_t size, struct heap_free_area **heap +#ifdef HEAP_USE_LOCKING + , __UCLIBC_MUTEX_TYPE *heap_lock +#endif + ) { void *mem; @@ -57,12 +70,12 @@ malloc_from_heap (size_t size, struct heap *heap) /* Include extra space to record the size of the allocated block. */ size += MALLOC_HEADER_SIZE; - __heap_lock (heap); + __heap_lock (heap_lock); /* First try to get memory that's already in our heap. */ mem = __heap_alloc (heap, &size); - __heap_unlock (heap); + __heap_unlock (heap_lock); if (unlikely (! mem)) /* We couldn't allocate from the heap, so grab some more @@ -111,7 +124,7 @@ malloc_from_heap (size_t size, struct heap *heap) MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); #else block = mmap ((void *)0, block_size, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANONYMOUS, 0, 0); + MAP_SHARED | MAP_ANONYMOUS | MAP_UNINITIALIZED, 0, 0); #endif #endif /* MALLOC_USE_SBRK */ @@ -122,11 +135,11 @@ malloc_from_heap (size_t size, struct heap *heap) struct malloc_mmb *mmb, *prev_mmb, *new_mmb; #endif - MALLOC_DEBUG (1, "adding system memroy to heap: 0x%lx - 0x%lx (%d bytes)", + MALLOC_DEBUG (1, "adding system memory to heap: 0x%lx - 0x%lx (%d bytes)", (long)block, (long)block + block_size, block_size); /* Get back the heap lock. */ - __heap_lock (heap); + __heap_lock (heap_lock); /* Put BLOCK into the heap. */ __heap_free (heap, block, block_size); @@ -136,19 +149,19 @@ malloc_from_heap (size_t size, struct heap *heap) /* Try again to allocate. */ mem = __heap_alloc (heap, &size); - __heap_unlock (heap); #if !defined(MALLOC_USE_SBRK) && defined(__UCLIBC_UCLINUX_BROKEN_MUNMAP__) /* Insert a record of BLOCK in sorted order into the __malloc_mmapped_blocks list. */ + new_mmb = malloc_from_heap (sizeof *new_mmb, &__malloc_mmb_heap, &__malloc_mmb_heap_lock); + for (prev_mmb = 0, mmb = __malloc_mmapped_blocks; mmb; prev_mmb = mmb, mmb = mmb->next) if (block < mmb->mem) break; - new_mmb = malloc_from_heap (sizeof *new_mmb, &__malloc_mmb_heap); new_mmb->next = mmb; new_mmb->mem = block; new_mmb->size = block_size; @@ -162,6 +175,7 @@ malloc_from_heap (size_t size, struct heap *heap) (unsigned)new_mmb, (unsigned)new_mmb->mem, block_size); #endif /* !MALLOC_USE_SBRK && __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */ + __heap_unlock (heap_lock); } } @@ -191,7 +205,7 @@ malloc (size_t size) __malloc_debug_init (); } if (__malloc_check) - __heap_check (&__malloc_heap, "malloc"); + __heap_check (__malloc_heap, "malloc"); #endif #ifdef __MALLOC_GLIBC_COMPAT__ @@ -207,7 +221,7 @@ malloc (size_t size) if (unlikely(((unsigned long)size > (unsigned long)(MALLOC_HEADER_SIZE*-2)))) goto oom; - mem = malloc_from_heap (size, &__malloc_heap); + mem = malloc_from_heap (size, &__malloc_heap, &__malloc_heap_lock); if (unlikely (!mem)) { oom: diff --git a/libc/stdlib/malloc/malloc.h b/libc/stdlib/malloc/malloc.h index 7277cd2cf..aa41870b9 100644 --- a/libc/stdlib/malloc/malloc.h +++ b/libc/stdlib/malloc/malloc.h @@ -17,11 +17,10 @@ alignment can be a significant win on targets like m68k and Coldfire, where __alignof__(double) == 2. */ #define MALLOC_ALIGNMENT \ - __alignof__ (double __attribute_aligned__ (sizeof (size_t))) + (__alignof__ (double) > sizeof (size_t) ? __alignof__ (double) : sizeof (size_t)) /* The system pagesize... */ -extern size_t __pagesize; -#define MALLOC_PAGE_SIZE __pagesize +#define MALLOC_PAGE_SIZE sysconf(_SC_PAGESIZE) /* The minimum size of block we request from the the system to extend the heap for small allocations (we may request a bigger block if necessary to @@ -70,14 +69,14 @@ struct malloc_mmb struct malloc_mmb *next; }; -/* A list of all malloc_mmb structures describing blocsk that malloc has +/* A list of all malloc_mmb structures describing blocks that malloc has mmapped, ordered by the block address. */ extern struct malloc_mmb *__malloc_mmapped_blocks; /* A heap used for allocating malloc_mmb structures. We could allocate them from the main heap, but that tends to cause heap fragmentation in annoying ways. */ -extern struct heap __malloc_mmb_heap; +extern struct heap_free_area *__malloc_mmb_heap; /* Define MALLOC_MMB_DEBUGGING to cause malloc to emit debugging info about about mmap block allocation/freeing by the `uclinux broken munmap' code @@ -128,70 +127,46 @@ extern int __malloc_mmb_debug; /* Return the size of a malloc allocation, given the user address. */ #define MALLOC_SIZE(addr) (*(size_t *)MALLOC_BASE(addr)) +#include <bits/uClibc_mutex.h> -/* Locking for multithreaded apps. */ #ifdef __UCLIBC_HAS_THREADS__ - -# include <pthread.h> -# include <bits/uClibc_pthread.h> - # define MALLOC_USE_LOCKING +#endif -typedef pthread_mutex_t malloc_mutex_t; -# define MALLOC_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER - -# ifdef MALLOC_USE_SBRK +#ifdef MALLOC_USE_SBRK /* This lock is used to serialize uses of the `sbrk' function (in both malloc and free, sbrk may be used several times in succession, and things will break if these multiple calls are interleaved with another thread's use of sbrk!). */ -extern malloc_mutex_t __malloc_sbrk_lock; -# define __malloc_lock_sbrk() __pthread_mutex_lock (&__malloc_sbrk_lock) -# define __malloc_unlock_sbrk() __pthread_mutex_unlock (&__malloc_sbrk_lock) -# endif /* MALLOC_USE_SBRK */ - -#else /* !__UCLIBC_HAS_THREADS__ */ - -/* Without threads, mutex operations are a nop. */ +__UCLIBC_MUTEX_EXTERN(__malloc_sbrk_lock); +# define __malloc_lock_sbrk() __UCLIBC_MUTEX_LOCK_CANCEL_UNSAFE (__malloc_sbrk_lock) +# define __malloc_unlock_sbrk() __UCLIBC_MUTEX_UNLOCK_CANCEL_UNSAFE (__malloc_sbrk_lock) +#else # define __malloc_lock_sbrk() (void)0 # define __malloc_unlock_sbrk() (void)0 - -#endif /* __UCLIBC_HAS_THREADS__ */ - - -/* branch-prediction macros; they may already be defined by libc. */ -#ifndef likely -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) -#define likely(cond) __builtin_expect(!!(int)(cond), 1) -#define unlikely(cond) __builtin_expect((int)(cond), 0) -#else -#define likely(cond) (cond) -#define unlikely(cond) (cond) -#endif -#endif /* !likely */ - +#endif /* MALLOC_USE_SBRK */ /* Define MALLOC_DEBUGGING to cause malloc to emit debugging info to stderr when the variable __malloc_debug is set to true. */ #ifdef MALLOC_DEBUGGING -extern void __malloc_debug_init (void); +extern void __malloc_debug_init (void) attribute_hidden; /* The number of spaces in a malloc debug indent level. */ #define MALLOC_DEBUG_INDENT_SIZE 3 -extern int __malloc_debug, __malloc_check; +extern int __malloc_debug attribute_hidden, __malloc_check attribute_hidden; # define MALLOC_DEBUG(indent, fmt, args...) \ (__malloc_debug ? __malloc_debug_printf (indent, fmt , ##args) : 0) # define MALLOC_DEBUG_INDENT(indent) \ (__malloc_debug ? __malloc_debug_indent (indent) : 0) -extern int __malloc_debug_cur_indent; +extern int __malloc_debug_cur_indent attribute_hidden; /* Print FMT and args indented at the current debug print level, followed by a newline, and change the level by INDENT. */ -extern void __malloc_debug_printf (int indent, const char *fmt, ...); +extern void __malloc_debug_printf (int indent, const char *fmt, ...) attribute_hidden; /* Change the current debug print level by INDENT, and return the value. */ #define __malloc_debug_indent(indent) (__malloc_debug_cur_indent += indent) @@ -221,4 +196,18 @@ extern void __malloc_debug_printf (int indent, const char *fmt, ...); /* The malloc heap. */ -extern struct heap __malloc_heap; +extern struct heap_free_area *__malloc_heap attribute_hidden; +#ifdef __UCLIBC_HAS_THREADS__ +__UCLIBC_MUTEX_EXTERN(__malloc_heap_lock) +# ifndef __LINUXTHREADS_OLD__ + attribute_hidden +# endif + ; +# ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__ +__UCLIBC_MUTEX_EXTERN(__malloc_mmb_heap_lock) +# ifndef __LINUXTHREADS_OLD__ + attribute_hidden +# endif + ; +# endif +#endif diff --git a/libc/stdlib/malloc/malloc_debug.c b/libc/stdlib/malloc/malloc_debug.c index 39c3919c5..1a5374faa 100644 --- a/libc/stdlib/malloc/malloc_debug.c +++ b/libc/stdlib/malloc/malloc_debug.c @@ -16,10 +16,6 @@ #include <unistd.h> #include <stdarg.h> -libc_hidden_proto(atoi) -libc_hidden_proto(vfprintf) -libc_hidden_proto(putc) -libc_hidden_proto(getenv) #include "malloc.h" #include "heap.h" diff --git a/libc/stdlib/malloc/memalign.c b/libc/stdlib/malloc/memalign.c index 5b248f3e2..74d5dbd2d 100644 --- a/libc/stdlib/malloc/memalign.c +++ b/libc/stdlib/malloc/memalign.c @@ -19,8 +19,6 @@ #include "heap.h" -#define MAX(x,y) ((x) > (y) ? (x) : (y)) - /* ______________________ TOTAL _________________________ / \ @@ -31,12 +29,14 @@ */ void *memalign (size_t alignment, size_t size); +/* XXX shadow outer malloc.h */ +libc_hidden_proto(memalign) void * memalign (size_t alignment, size_t size) { void *mem, *base; unsigned long tot_addr, tot_end_addr, addr, end_addr; - struct heap *heap = &__malloc_heap; + struct heap_free_area **heap = &__malloc_heap; /* Make SIZE something we like. */ size = HEAP_ADJUST_SIZE (size); @@ -93,3 +93,4 @@ memalign (size_t alignment, size_t size) return MALLOC_SETUP (base, end_addr - (unsigned long)base); } +libc_hidden_def(memalign) diff --git a/libc/stdlib/malloc/realloc.c b/libc/stdlib/malloc/realloc.c index 948326762..bdfb52694 100644 --- a/libc/stdlib/malloc/realloc.c +++ b/libc/stdlib/malloc/realloc.c @@ -15,7 +15,6 @@ #include <string.h> #include <errno.h> -/* Experimentally off - libc_hidden_proto(memcpy) */ #include "malloc.h" #include "heap.h" @@ -27,14 +26,19 @@ realloc (void *mem, size_t new_size) size_t size; char *base_mem; + if (! mem) + return malloc (new_size); + /* Check for special cases. */ if (! new_size) { free (mem); - return malloc (new_size); + return NULL; } - if (! mem) - return malloc (new_size); + + /* This matches the check in malloc() */ + if (unlikely(((unsigned long)new_size > (unsigned long)(MALLOC_HEADER_SIZE*-2)))) + return NULL; /* Normal realloc. */ @@ -59,9 +63,9 @@ realloc (void *mem, size_t new_size) { size_t extra = new_size - size; - __heap_lock (&__malloc_heap); + __heap_lock (&__malloc_heap_lock); extra = __heap_alloc_at (&__malloc_heap, base_mem + size, extra); - __heap_unlock (&__malloc_heap); + __heap_unlock (&__malloc_heap_lock); if (extra) /* Record the changed size. */ @@ -82,9 +86,9 @@ realloc (void *mem, size_t new_size) else if (new_size + MALLOC_REALLOC_MIN_FREE_SIZE <= size) /* Shrink the block. */ { - __heap_lock (&__malloc_heap); + __heap_lock (&__malloc_heap_lock); __heap_free (&__malloc_heap, base_mem + new_size, size - new_size); - __heap_unlock (&__malloc_heap); + __heap_unlock (&__malloc_heap_lock); MALLOC_SET_SIZE (base_mem, new_size); } diff --git a/libc/stdlib/mkdtemp.c b/libc/stdlib/mkdtemp.c index fa9ae3b05..185e206a3 100644 --- a/libc/stdlib/mkdtemp.c +++ b/libc/stdlib/mkdtemp.c @@ -14,11 +14,11 @@ You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + see <http://www.gnu.org/licenses/>. */ #include <stdio.h> #include <stdlib.h> +#include <sys/stat.h> #include "../misc/internals/tempname.h" #ifdef __USE_BSD @@ -29,7 +29,7 @@ (This function comes from OpenBSD.) */ char * mkdtemp (char *template) { - if (__gen_tempname (template, __GT_DIR)) + if (__gen_tempname (template, __GT_DIR, 0, 0, S_IRUSR | S_IWUSR | S_IXUSR)) return NULL; else return template; diff --git a/libc/stdlib/mkostemp.c b/libc/stdlib/mkostemp.c new file mode 100644 index 000000000..4eab0797a --- /dev/null +++ b/libc/stdlib/mkostemp.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1998-2012 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include "../misc/internals/tempname.h" + +/* Generate a unique temporary file name from TEMPLATE. + The last six characters of TEMPLATE must be "XXXXXX"; + they are replaced with a string that makes the filename unique. + Then open the file and return a fd. */ +int +mkostemp (char *template, int flags) +{ + flags -= flags & O_ACCMODE; /* Remove O_RDONLY, O_WRONLY, and O_RDWR. */ + return __gen_tempname (template, __GT_FILE, flags, 0, S_IRUSR | S_IWUSR); +} diff --git a/libc/stdlib/mkostemp64.c b/libc/stdlib/mkostemp64.c new file mode 100644 index 000000000..25595ad96 --- /dev/null +++ b/libc/stdlib/mkostemp64.c @@ -0,0 +1,32 @@ +/* Copyright (C) 2000-2012 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include "../misc/internals/tempname.h" + +/* Generate a unique temporary file name from TEMPLATE. + The last six characters of TEMPLATE must be "XXXXXX"; + they are replaced with a string that makes the filename unique. + Then open the file and return a fd. */ +int +mkostemp64 (char *template, int flags) +{ + return __gen_tempname (template, __GT_BIGFILE, flags | O_LARGEFILE, 0, + S_IRUSR | S_IWUSR | S_IXUSR); +} diff --git a/libc/stdlib/mkostemps.c b/libc/stdlib/mkostemps.c new file mode 100644 index 000000000..13a517185 --- /dev/null +++ b/libc/stdlib/mkostemps.c @@ -0,0 +1,36 @@ +/* Copyright (C) 1998-2012 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include "../misc/internals/tempname.h" + +/* Generate a unique temporary file name from TEMPLATE. + The TEMPLATE is of the form "XXXXXXsuffix" where six characters + after the TEMPLATE must be "XXXXXX" followed by the suffix. + The suffix length must be specified with suffixlen. + "XXXXXX" are replaced with a string that makes the filename unique. + Then open the file and return a fd. */ +int mkostemps (char *template, int suffixlen, int flags) +{ + flags -= flags & O_ACCMODE; /* Remove O_RDONLY, O_WRONLY, and O_RDWR. */ + return __gen_tempname (template, __GT_FILE, flags, suffixlen, + S_IRUSR | S_IWUSR); +} + + diff --git a/libc/stdlib/mkostemps64.c b/libc/stdlib/mkostemps64.c new file mode 100644 index 000000000..0436fcf81 --- /dev/null +++ b/libc/stdlib/mkostemps64.c @@ -0,0 +1,34 @@ +/* Copyright (C) 1998-2012 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include "../misc/internals/tempname.h" + +/* Generate a unique temporary file name from TEMPLATE. + The TEMPLATE is of the form "XXXXXXsuffix" where six characters + after the TEMPLATE must be "XXXXXX" followed by the suffix. + The suffix length must be specified with suffixlen. + "XXXXXX" are replaced with a string that makes the filename unique. + Then open the file and return a fd. */ +int mkostemps64 (char *template, int suffixlen, int flags) +{ + flags -= flags & O_ACCMODE; /* Remove O_RDONLY, O_WRONLY, and O_RDWR. */ + return __gen_tempname (template, __GT_FILE, flags, suffixlen, + S_IRUSR | S_IWUSR); +} diff --git a/libc/stdlib/mkstemp.c b/libc/stdlib/mkstemp.c index c569ceaf5..abcc93e62 100644 --- a/libc/stdlib/mkstemp.c +++ b/libc/stdlib/mkstemp.c @@ -13,11 +13,11 @@ You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + see <http://www.gnu.org/licenses/>. */ #include <stdio.h> #include <stdlib.h> +#include <sys/stat.h> #include "../misc/internals/tempname.h" /* Generate a unique temporary file name from TEMPLATE. @@ -26,5 +26,5 @@ Then open the file and return a fd. */ int mkstemp (char *template) { - return __gen_tempname (template, __GT_FILE); + return __gen_tempname (template, __GT_FILE, 0, 0, S_IRUSR | S_IWUSR); } diff --git a/libc/stdlib/mkstemp64.c b/libc/stdlib/mkstemp64.c index 02a03f00e..82c6da531 100644 --- a/libc/stdlib/mkstemp64.c +++ b/libc/stdlib/mkstemp64.c @@ -13,11 +13,11 @@ You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + see <http://www.gnu.org/licenses/>. */ #include <stdio.h> #include <stdlib.h> +#include <sys/stat.h> #include "../misc/internals/tempname.h" /* Generate a unique temporary file name from TEMPLATE. @@ -26,5 +26,5 @@ Then open the file and return a fd. */ int mkstemp64 (char *template) { - return __gen_tempname (template, __GT_BIGFILE); + return __gen_tempname (template, __GT_BIGFILE, 0, 0, S_IRUSR | S_IWUSR); } diff --git a/libc/stdlib/mkstemps.c b/libc/stdlib/mkstemps.c new file mode 100644 index 000000000..22aebf4ba --- /dev/null +++ b/libc/stdlib/mkstemps.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1998-2012 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include "../misc/internals/tempname.h" + +/* Generate a unique temporary file name from TEMPLATE. + The TEMPLATE is of the form "XXXXXXsuffix" where six characters + after the TEMPLATE must be "XXXXXX" followed by the suffix. + The suffix length must be specified with suffixlen. + "XXXXXX" are replaced with a string that makes the filename unique. + Then open the file and return a fd. */ +int mkstemps (char *template, int suffixlen) +{ + return __gen_tempname (template, __GT_FILE, 0, suffixlen, + S_IRUSR | S_IWUSR); +} diff --git a/libc/stdlib/mkstemps64.c b/libc/stdlib/mkstemps64.c new file mode 100644 index 000000000..19fb4c861 --- /dev/null +++ b/libc/stdlib/mkstemps64.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1998-2012 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include "../misc/internals/tempname.h" + +/* Generate a unique temporary file name from TEMPLATE. + The TEMPLATE is of the form "XXXXXXsuffix" where six characters + after the TEMPLATE must be "XXXXXX" followed by the suffix. + The suffix length must be specified with suffixlen. + "XXXXXX" are replaced with a string that makes the filename unique. + Then open the file and return a fd. */ +int mkstemps64 (char *template, int suffixlen) +{ + return __gen_tempname (template, __GT_BIGFILE, 0, suffixlen, + S_IRUSR | S_IWUSR); +} diff --git a/libc/stdlib/mktemp.c b/libc/stdlib/mktemp.c index f3af1c15c..be8815358 100644 --- a/libc/stdlib/mktemp.c +++ b/libc/stdlib/mktemp.c @@ -13,8 +13,7 @@ You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + see <http://www.gnu.org/licenses/>. */ #include <stdio.h> #include <stdlib.h> @@ -25,11 +24,9 @@ * they are replaced with a string that makes the filename unique. */ char *mktemp(char *template) { - if (__gen_tempname (template, __GT_NOCREATE) < 0) + if (__gen_tempname (template, __GT_NOCREATE, 0,0, 0) < 0) /* We return the null string if we can't find a unique file name. */ template[0] = '\0'; return template; } - -link_warning(mktemp, "the use of `mktemp' is dangerous, better use `mkstemp'") diff --git a/libc/stdlib/mrand48.c b/libc/stdlib/mrand48.c index 6905545bd..d86f7ba5c 100644 --- a/libc/stdlib/mrand48.c +++ b/libc/stdlib/mrand48.c @@ -13,17 +13,11 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> -libc_hidden_proto(jrand48_r) - -/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ -extern struct drand48_data __libc_drand48_data attribute_hidden; - long int mrand48 (void) { long int result; diff --git a/libc/stdlib/mrand48_r.c b/libc/stdlib/mrand48_r.c index ca2bd7bbb..0c4df4aa5 100644 --- a/libc/stdlib/mrand48_r.c +++ b/libc/stdlib/mrand48_r.c @@ -13,13 +13,11 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> -libc_hidden_proto(jrand48_r) int mrand48_r (struct drand48_data *buffer, long int *result) { diff --git a/libc/stdlib/nrand48.c b/libc/stdlib/nrand48.c index 0199a30a5..3eda3ec09 100644 --- a/libc/stdlib/nrand48.c +++ b/libc/stdlib/nrand48.c @@ -13,17 +13,11 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> -libc_hidden_proto(nrand48_r) - -/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ -extern struct drand48_data __libc_drand48_data attribute_hidden; - long int nrand48 (unsigned short int xsubi[3]) { long int result; diff --git a/libc/stdlib/nrand48_r.c b/libc/stdlib/nrand48_r.c index 63b0ac8ef..ff7ab52d1 100644 --- a/libc/stdlib/nrand48_r.c +++ b/libc/stdlib/nrand48_r.c @@ -13,16 +13,11 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> -extern int __drand48_iterate(unsigned short xsubi[3], - struct drand48_data *buffer) attribute_hidden; - -libc_hidden_proto(nrand48_r) int nrand48_r (unsigned short int xsubi[3], struct drand48_data *buffer, long int *result) { /* Compute next state. */ diff --git a/libc/stdlib/posix_memalign.c b/libc/stdlib/posix_memalign.c index 115fb8999..523bc2cbd 100644 --- a/libc/stdlib/posix_memalign.c +++ b/libc/stdlib/posix_memalign.c @@ -15,9 +15,8 @@ * for more details. * * You should have received a copy of the GNU Library General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * along with this program; see the file COPYING.LIB. If not, see + * <http://www.gnu.org/licenses/>. */ #include <stdlib.h> diff --git a/libc/stdlib/ptsname.c b/libc/stdlib/ptsname.c index bd9c3cab2..2d3b31731 100644 --- a/libc/stdlib/ptsname.c +++ b/libc/stdlib/ptsname.c @@ -13,9 +13,8 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdio.h> #include <errno.h> @@ -29,13 +28,6 @@ #include <unistd.h> #include <bits/uClibc_uintmaxtostr.h> -/* Experimentally off - libc_hidden_proto(strcat) */ -/* Experimentally off - libc_hidden_proto(strcpy) */ -/* Experimentally off - libc_hidden_proto(strlen) */ -libc_hidden_proto(isatty) -libc_hidden_proto(ioctl) -libc_hidden_proto(fstat) -libc_hidden_proto(stat) #if !defined __UNIX98PTY_ONLY__ @@ -68,7 +60,6 @@ extern const char __libc_ptyname2[] attribute_hidden; /* Store at most BUFLEN characters of the pathname of the slave pseudo terminal associated with the master FD is open on in BUF. Return 0 on success, otherwise an error number. */ -libc_hidden_proto(ptsname_r) int ptsname_r (int fd, char *buf, size_t buflen) { int save_errno = errno; diff --git a/libc/stdlib/pty-private.h b/libc/stdlib/pty-private.h index 621dbfd6f..ef628a112 100644 --- a/libc/stdlib/pty-private.h +++ b/libc/stdlib/pty-private.h @@ -15,8 +15,7 @@ You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + see <http://www.gnu.org/licenses/>. */ #ifndef _PTY_PRIVATE_H #define _PTY_PRIVATE_H 1 diff --git a/libc/stdlib/qsort_r.c b/libc/stdlib/qsort_r.c new file mode 100644 index 000000000..1db270e62 --- /dev/null +++ b/libc/stdlib/qsort_r.c @@ -0,0 +1,7 @@ +/* Copyright (C) 2004-2006 Manuel Novoa III <mjn3@uclibc.org> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#define L_qsort_r +#include "stdlib.c" diff --git a/libc/stdlib/rand.c b/libc/stdlib/rand.c index 03323f501..4b899c0fc 100644 --- a/libc/stdlib/rand.c +++ b/libc/stdlib/rand.c @@ -7,10 +7,8 @@ #include <stdlib.h> -libc_hidden_proto(random) -int rand (void) +int rand(void) { - return((int)random()); + return (int)random(); } - diff --git a/libc/stdlib/rand_r.c b/libc/stdlib/rand_r.c index 610044083..722ba4949 100644 --- a/libc/stdlib/rand_r.c +++ b/libc/stdlib/rand_r.c @@ -14,9 +14,8 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> diff --git a/libc/stdlib/random.c b/libc/stdlib/random.c index 3eb8aed8a..b009c4310 100644 --- a/libc/stdlib/random.c +++ b/libc/stdlib/random.c @@ -27,10 +27,6 @@ #include <stddef.h> #include <stdlib.h> -libc_hidden_proto(random_r) -libc_hidden_proto(srandom_r) -libc_hidden_proto(setstate_r) -libc_hidden_proto(initstate_r) /* POSIX.1c requires that there is mutual exclusion for the `rand' and `srand' functions to prevent concurrent calls from modifying common @@ -74,11 +70,7 @@ __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); -/* For each of the currently supported random number generators, we have a - break value on the amount of state information (you need at least this many - bytes of state info to support this random number generator), a degree for - the polynomial (actually a trinomial) that the R.N.G. is based on, and - separation between the two lower order coefficients of the trinomial. */ +/* Keep constants in sync with random_r.c */ /* Linear congruential. */ #define TYPE_0 0 @@ -110,13 +102,8 @@ __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); #define DEG_4 63 #define SEP_4 1 - -/* Array versions of the above information to make code run faster. - Relies on fact that TYPE_i == i. */ - #define MAX_TYPES 5 /* Max number of types above. */ - /* Initially, everything is set up as if from: initstate(1, randtbl, 128); Note that this initialization takes advantage of the fact that srandom @@ -244,7 +231,6 @@ char * setstate (char *arg_state) rear pointers can't wrap on the same call by not testing the rear pointer if the front one has wrapped. Returns a 31-bit random number. */ -libc_hidden_proto(random) long int random (void) { int32_t retval; diff --git a/libc/stdlib/random_r.c b/libc/stdlib/random_r.c index ca80a7808..4b2b3f85d 100644 --- a/libc/stdlib/random_r.c +++ b/libc/stdlib/random_r.c @@ -27,8 +27,7 @@ #include <limits.h> #include <stddef.h> #include <stdlib.h> - - +#include <unistd.h> /* An improved random number generation package. In addition to the standard rand()/srand() like interface, this package also has a special state info @@ -109,8 +108,8 @@ struct random_poly_info { - int seps[MAX_TYPES]; - int degrees[MAX_TYPES]; + smallint seps[MAX_TYPES]; + smallint degrees[MAX_TYPES]; }; static const struct random_poly_info random_poly_info = @@ -121,7 +120,6 @@ static const struct random_poly_info random_poly_info = - /* If we are using the trivial TYPE_0 R.N.G., just do the old linear congruential bit. Otherwise, we do our fancy trinomial stuff, which is the same in all the other cases due to all the global variables that have been @@ -133,7 +131,6 @@ static const struct random_poly_info random_poly_info = rear pointers can't wrap on the same call by not testing the rear pointer if the front one has wrapped. Returns a 31-bit random number. */ -libc_hidden_proto(random_r) int random_r(struct random_data *buf, int32_t *result) { int32_t *state; @@ -191,7 +188,6 @@ libc_hidden_def(random_r) information a given number of times to get rid of any initial dependencies introduced by the L.C.R.N.G. Note that the initialization of randtbl[] for default usage relies on values produced by this routine. */ -libc_hidden_proto(srandom_r) int srandom_r (unsigned int seed, struct random_data *buf) { int type; @@ -259,7 +255,6 @@ libc_hidden_def(srandom_r) Note: The first thing we do is save the current state, if any, just like setstate so that it doesn't matter when initstate is called. Returns a pointer to the old state. */ -libc_hidden_proto(initstate_r) int initstate_r (unsigned int seed, char *arg_state, size_t n, struct random_data *buf) { int type; @@ -318,7 +313,6 @@ libc_hidden_def(initstate_r) to the order in which things are done, it is OK to call setstate with the same state as the current state Returns a pointer to the old state information. */ -libc_hidden_proto(setstate_r) int setstate_r (char *arg_state, struct random_data *buf) { int32_t *new_state = 1 + (int32_t *) arg_state; diff --git a/libc/stdlib/realpath.c b/libc/stdlib/realpath.c index e9eabdfaa..cf9d45fa2 100644 --- a/libc/stdlib/realpath.c +++ b/libc/stdlib/realpath.c @@ -21,11 +21,6 @@ #include <sys/stat.h> /* for S_IFLNK */ -/* Experimentally off - libc_hidden_proto(strcat) */ -/* Experimentally off - libc_hidden_proto(strcpy) */ -/* Experimentally off - libc_hidden_proto(strlen) */ -libc_hidden_proto(readlink) -libc_hidden_proto(getcwd) #ifndef PATH_MAX #ifdef _POSIX_VERSION @@ -41,19 +36,10 @@ libc_hidden_proto(getcwd) #define MAX_READLINKS 32 -#ifdef __STDC__ char *realpath(const char *path, char got_path[]) -#else -char *realpath(path, got_path) -const char *path; -char got_path[]; -#endif { char copy_path[PATH_MAX]; - /* use user supplied buffer directly - reduces stack usage */ - /* char got_path[PATH_MAX]; */ - char *max_path; - char *new_path; + char *max_path, *new_path, *allocated_path; size_t path_len; int readlinks = 0; #ifdef S_IFLNK @@ -77,12 +63,13 @@ char got_path[]; /* Copy so that path is at the end of copy_path[] */ strcpy(copy_path + (PATH_MAX-1) - path_len, path); path = copy_path + (PATH_MAX-1) - path_len; + allocated_path = got_path ? NULL : (got_path = malloc(PATH_MAX)); max_path = got_path + PATH_MAX - 2; /* points to last non-NUL char */ new_path = got_path; if (*path != '/') { /* If it's a relative pathname use getcwd for starters. */ if (!getcwd(new_path, PATH_MAX - 1)) - return NULL; + goto err; new_path += strlen(new_path); if (new_path[-1] != '/') *new_path++ = '/'; @@ -119,6 +106,8 @@ char got_path[]; while (*path != '\0' && *path != '/') { if (new_path > max_path) { __set_errno(ENAMETOOLONG); + err: + free(allocated_path); return NULL; } *new_path++ = *path++; @@ -127,7 +116,7 @@ char got_path[]; /* Protect against infinite loops. */ if (readlinks++ > MAX_READLINKS) { __set_errno(ELOOP); - return NULL; + goto err; } path_len = strlen(path); /* See if last (so far) pathname component is a symlink. */ @@ -138,13 +127,13 @@ char got_path[]; if (link_len < 0) { /* EINVAL means the file exists but isn't a symlink. */ if (errno != EINVAL) { - return NULL; + goto err; } } else { /* Safe sex check. */ if (path_len + link_len >= PATH_MAX - 2) { __set_errno(ENAMETOOLONG); - return NULL; + goto err; } /* Note: readlink doesn't add the null byte. */ /* copy_path[link_len] = '\0'; - we don't need it too */ @@ -170,3 +159,4 @@ char got_path[]; *new_path = '\0'; return got_path; } +libc_hidden_def(realpath) diff --git a/libc/stdlib/rpmatch.c b/libc/stdlib/rpmatch.c new file mode 100644 index 000000000..dce06b641 --- /dev/null +++ b/libc/stdlib/rpmatch.c @@ -0,0 +1,7 @@ +/* Copyright (C) 2012 Bernhard Reutner-Fischer <uclibc@uclibc.org> + * + * Licensed under the LGPL v2.1+, see the file COPYING.LIB in this tarball. + */ + +#define L_rpmatch +#include "stdlib.c" diff --git a/libc/stdlib/seed48.c b/libc/stdlib/seed48.c index f068b980d..285b5c220 100644 --- a/libc/stdlib/seed48.c +++ b/libc/stdlib/seed48.c @@ -13,17 +13,11 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> -libc_hidden_proto(seed48_r) - -/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ -extern struct drand48_data __libc_drand48_data attribute_hidden; - unsigned short int * seed48 (unsigned short int seed16v[3]) { diff --git a/libc/stdlib/seed48_r.c b/libc/stdlib/seed48_r.c index 3769e0fa7..7444370d6 100644 --- a/libc/stdlib/seed48_r.c +++ b/libc/stdlib/seed48_r.c @@ -13,17 +13,14 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> #include <string.h> #include <limits.h> -/* Experimentally off - libc_hidden_proto(memcpy) */ -libc_hidden_proto(seed48_r) int seed48_r (unsigned short int seed16v[3], struct drand48_data *buffer) { /* Save old value at a private place to be used as return value. */ diff --git a/libc/stdlib/setenv.c b/libc/stdlib/setenv.c index 833bd8fcd..ecc302536 100644 --- a/libc/stdlib/setenv.c +++ b/libc/stdlib/setenv.c @@ -12,9 +12,8 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. + License along with the GNU C Library; see the file COPYING.LIB. If + not, see <http://www.gnu.org/licenses/>. modified for uClibc by Erik Andersen <andersen@codepoet.org> */ @@ -25,12 +24,6 @@ #include <string.h> #include <unistd.h> -/* Experimentally off - libc_hidden_proto(memcpy) */ -/* Experimentally off - libc_hidden_proto(strchr) */ -/* Experimentally off - libc_hidden_proto(strlen) */ -/* Experimentally off - libc_hidden_proto(strncmp) */ -/* Experimentally off - libc_hidden_proto(strndup) */ -libc_hidden_proto(unsetenv) #include <bits/uClibc_mutex.h> __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER); @@ -46,116 +39,112 @@ static char **last_environ; is then placed in the environment, while the argument of `putenv' must be used directly. This is all complicated by the fact that we try to reuse values once generated for a `setenv' call since we can never - free the strings. */ -int __add_to_environ (const char *name, const char *value, - const char *combined, int replace) attribute_hidden; -int __add_to_environ (const char *name, const char *value, - const char *combined, int replace) + free the strings. [in uclibc, we do not] */ +static int __add_to_environ(const char *name, const char *value, + int replace) { - register char **ep; - register size_t size; - const size_t namelen = strlen (name); - const size_t vallen = value != NULL ? strlen (value) + 1 : 0; - int rv = -1; - - __UCLIBC_MUTEX_LOCK(mylock); - - /* We have to get the pointer now that we have the lock and not earlier - since another thread might have created a new environment. */ - ep = __environ; - - size = 0; - if (ep != NULL) { - for (; *ep != NULL; ++ep) { - if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') - break; - else - ++size; - } - } - - if (ep == NULL || *ep == NULL) { - char **new_environ; - - /* We allocated this space; we can extend it. */ - new_environ = (char **) realloc (last_environ, (size + 2) * sizeof (char *)); - if (new_environ == NULL) { - goto DONE; - } - - /* If the whole entry is given add it. */ - if (combined != NULL) { - /* We must not add the string to the search tree since it belongs - to the user. */ - new_environ[size] = (char *) combined; - } else { - /* See whether the value is already known. */ - new_environ[size] = (char *) malloc (namelen + 1 + vallen); - if (new_environ[size] == NULL) { - __set_errno (ENOMEM); - goto DONE; + register char **ep; + register size_t size; + char *var_val; + char **new_environ; + /* name may come from putenv() and thus may contain "=VAL" part */ + const size_t namelen = strchrnul(name, '=') - name; + int rv = -1; + + __UCLIBC_MUTEX_LOCK(mylock); + + /* We have to get the pointer now that we have the lock and not earlier + since another thread might have created a new environment. */ + ep = __environ; + + size = 0; + if (ep != NULL) { + while (*ep != NULL) { + if (!strncmp(*ep, name, namelen) && (*ep)[namelen] == '=') { + /* Found */ + if (!replace) + goto DONE_OK; + goto REPLACE; } - - memcpy (new_environ[size], name, namelen); - new_environ[size][namelen] = '='; - memcpy (&new_environ[size][namelen + 1], value, vallen); - } - - if (__environ != last_environ) { - memcpy ((char *) new_environ, (char *) __environ, - size * sizeof (char *)); + ++size; + ++ep; } - - new_environ[size + 1] = NULL; - last_environ = __environ = new_environ; - } else if (replace) { - char *np; - - /* Use the user string if given. */ - if (combined != NULL) { - np = (char *) combined; - } else { - np = malloc (namelen + 1 + vallen); - if (np == NULL) { - goto DONE; - } - memcpy (np, name, namelen); - np[namelen] = '='; - memcpy (&np[namelen + 1], value, vallen); + } + + /* Not found, add at the end */ + + /* We allocated this space; we can extend it. */ + new_environ = realloc(last_environ, (size + 2) * sizeof(char *)); + if (new_environ == NULL) { + /* __set_errno(ENOMEM); */ + goto DONE; + } + if (__environ != last_environ) { + memcpy(new_environ, __environ, size * sizeof(char *)); + } + last_environ = __environ = new_environ; + + ep = &new_environ[size]; + /* Ensure env is NULL terminated in case malloc below fails */ + ep[0] = NULL; + ep[1] = NULL; + + REPLACE: + var_val = (char*) name; + /* Build VAR=VAL if we called by setenv, not putenv. */ + if (value != NULL) { + const size_t vallen = strlen(value) + 1; + + var_val = malloc(namelen + 1 + vallen); + if (var_val == NULL) { + /* __set_errno(ENOMEM); */ + goto DONE; } - *ep = np; - } + memcpy(var_val, name, namelen); + var_val[namelen] = '='; + memcpy(&var_val[namelen + 1], value, vallen); + } + *ep = var_val; - rv = 0; + DONE_OK: + rv = 0; DONE: - __UCLIBC_MUTEX_UNLOCK(mylock); - return rv; + __UCLIBC_MUTEX_UNLOCK(mylock); + return rv; } -libc_hidden_proto(setenv) -int setenv (const char *name, const char *value, int replace) +int setenv(const char *name, const char *value, int replace) { - return __add_to_environ (name, value, NULL, replace); + if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) { + __set_errno(EINVAL); + return -1; + } + + /* NB: setenv("VAR", NULL, 1) inserts "VAR=" string */ + return __add_to_environ(name, value ? value : "", replace); } libc_hidden_def(setenv) -libc_hidden_proto(unsetenv) -int unsetenv (const char *name) +int unsetenv(const char *name) { - size_t len; - char **ep; - - if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) { - __set_errno (EINVAL); + const char *eq; + size_t len; + char **ep; + + if (name == NULL || *name == '\0' + || *(eq = strchrnul(name, '=')) == '=' + ) { + __set_errno(EINVAL); return -1; - } - - len = strlen (name); - __UCLIBC_MUTEX_LOCK(mylock); - ep = __environ; - while (*ep != NULL) { - if (!strncmp (*ep, name, len) && (*ep)[len] == '=') { + } + len = eq - name; /* avoiding strlen this way */ + + __UCLIBC_MUTEX_LOCK(mylock); + ep = __environ; + /* NB: clearenv(); unsetenv("foo"); should not segfault */ + if (ep) while (*ep != NULL) { + if (!strncmp(*ep, name, len) && (*ep)[len] == '=') { /* Found it. Remove this pointer by moving later ones back. */ char **dp = ep; do { @@ -165,42 +154,34 @@ int unsetenv (const char *name) } else { ++ep; } - } - __UCLIBC_MUTEX_UNLOCK(mylock); - return 0; + } + __UCLIBC_MUTEX_UNLOCK(mylock); + return 0; } libc_hidden_def(unsetenv) /* The `clearenv' was planned to be added to POSIX.1 but probably never made it. Nevertheless the POSIX.9 standard (POSIX bindings for Fortran 77) requires this function. */ -int clearenv (void) +int clearenv(void) { - __UCLIBC_MUTEX_LOCK(mylock); - if (__environ == last_environ && __environ != NULL) { - /* We allocated this environment so we can free it. */ - free (__environ); - last_environ = NULL; - } - /* Clear the environment pointer removes the whole environment. */ - __environ = NULL; - __UCLIBC_MUTEX_UNLOCK(mylock); - return 0; + __UCLIBC_MUTEX_LOCK(mylock); + /* If we allocated this environment we can free it. + * If we did not allocate this environment, it's NULL already + * and is safe to free(). */ + free(last_environ); + last_environ = NULL; + /* Clearing environ removes the whole environment. */ + __environ = NULL; + __UCLIBC_MUTEX_UNLOCK(mylock); + return 0; } /* Put STRING, which is of the form "NAME=VALUE", in the environment. */ -int putenv (char *string) +int putenv(char *string) { - int result; - const char *const name_end = strchr (string, '='); - - if (name_end != NULL) { - char *name = strndup(string, name_end - string); - result = __add_to_environ (name, NULL, string, 1); - free(name); - return(result); - } - unsetenv (string); - return 0; + if (strchr(string, '=') != NULL) { + return __add_to_environ(string, NULL, 1); + } + return unsetenv(string); } - diff --git a/libc/stdlib/srand48.c b/libc/stdlib/srand48.c index 42e90c9f9..ef526c172 100644 --- a/libc/stdlib/srand48.c +++ b/libc/stdlib/srand48.c @@ -13,17 +13,11 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> -libc_hidden_proto(srand48_r) - -/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ -extern struct drand48_data __libc_drand48_data attribute_hidden; - void srand48 (long seedval) { srand48_r (seedval, &__libc_drand48_data); diff --git a/libc/stdlib/srand48_r.c b/libc/stdlib/srand48_r.c index 45bb75f11..d65825c4b 100644 --- a/libc/stdlib/srand48_r.c +++ b/libc/stdlib/srand48_r.c @@ -13,14 +13,12 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ #include <stdlib.h> #include <limits.h> -libc_hidden_proto(srand48_r) int srand48_r (long int seedval, struct drand48_data *buffer) { /* The standards say we only have 32 bits. */ diff --git a/libc/stdlib/stdlib.c b/libc/stdlib/stdlib.c index 68796656a..6c887eabc 100644 --- a/libc/stdlib/stdlib.c +++ b/libc/stdlib/stdlib.c @@ -12,8 +12,8 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * License along with this library; if not, see + * <http://www.gnu.org/licenses/>. */ /* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! @@ -32,58 +32,8 @@ * Add wscto{inttype} functions. */ -#define _ISOC99_SOURCE /* for ULLONG primarily... */ #include <limits.h> #include <stdint.h> -/* Work around gcc's refusal to create aliases. - * TODO: Add in a define to disable the aliases? */ - -#if UINT_MAX == ULONG_MAX -#ifdef L_labs -#define abs __ignore_abs -#endif -#ifdef L_atol -#define atoi __ignore_atoi -#endif -#endif -#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) -#ifdef L_labs -#define llabs __ignore_llabs -#endif -#ifdef L_atol -#define atoll __ignore_atoll -#endif -#ifdef L_strtol -#define strtoll __ignore_strtoll -#endif -#ifdef L_strtoul -#define strtoull __ignore_strtoull -#endif -#ifdef L_wcstol -#define wcstoll __ignore_wcstoll -#endif -#ifdef L_wcstoul -#define wcstoull __ignore_wcstoull -#endif -#ifdef strtol_l -#define strtoll_l __ignore_strtoll_l -#endif -#ifdef L_strtoul_l -#define strtoull_l __ignore_strtoull_l -#endif -#ifdef L_wcstol_l -#define wcstoll_l __ignore_wcstoll_l -#endif -#ifdef L_wcstoul_l -#define wcstoull_l __ignore_wcstoull_l -#endif -#endif -#if defined(ULLONG_MAX) && (ULLONG_MAX == UINTMAX_MAX) -#if defined L_labs || defined L_llabs -#define imaxabs __ignore_imaxabs -#endif -#endif - #include <stdint.h> #include <inttypes.h> #include <ctype.h> @@ -100,10 +50,6 @@ #include <wctype.h> #include <bits/uClibc_uwchar.h> -#ifdef __UCLIBC_HAS_XLOCALE__ -#include <xlocale.h> -#endif /* __UCLIBC_HAS_XLOCALE__ */ - /* TODO: clean up the following... */ #if WCHAR_MAX > 0xffffUL @@ -114,7 +60,7 @@ #ifdef __UCLIBC_HAS_LOCALE__ -#define ENCODING ((__UCLIBC_CURLOCALE_DATA).encoding) +#define ENCODING (__UCLIBC_CURLOCALE->encoding) #ifndef __CTYPE_HAS_UTF_8_LOCALES #ifdef L_mblen /* emit only once */ @@ -197,7 +143,6 @@ _stdlib_wcsto_ll(register const wchar_t * __restrict str, /**********************************************************************/ #ifdef L_atof -libc_hidden_proto(strtod) double atof(const char *nptr) { @@ -227,21 +172,15 @@ long int labs(long int j) } #if UINT_MAX == ULONG_MAX -#undef abs -extern __typeof(labs) abs; -strong_alias(labs,abs) +strong_alias_untyped(labs,abs) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) -#undef llabs -extern __typeof(labs) llabs; -strong_alias(labs,llabs) +strong_alias_untyped(labs,llabs) #endif #if ULONG_MAX == UINTMAX_MAX -#undef imaxabs -extern __typeof(labs) imaxabs; -strong_alias(labs,imaxabs) +strong_alias_untyped(labs,imaxabs) #endif #endif @@ -256,9 +195,7 @@ long long int llabs(long long int j) } #if (ULLONG_MAX == UINTMAX_MAX) -#undef imaxabs -extern __typeof(llabs) imaxabs; -strong_alias(llabs,imaxabs) +strong_alias_untyped(llabs,imaxabs) #endif #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ @@ -269,9 +206,7 @@ strong_alias(llabs,imaxabs) #if INT_MAX < LONG_MAX -libc_hidden_proto(strtol) -libc_hidden_proto(atoi) int atoi(const char *nptr) { return (int) strtol(nptr, (char **) NULL, 10); @@ -284,27 +219,19 @@ libc_hidden_def(atoi) /**********************************************************************/ #ifdef L_atol -libc_hidden_proto(strtol) -libc_hidden_proto(atol) long atol(const char *nptr) { return strtol(nptr, (char **) NULL, 10); } -libc_hidden_def(atol) #if UINT_MAX == ULONG_MAX -#undef atoi -extern __typeof(atol) atoi; -libc_hidden_proto(atoi) -strong_alias(atol,atoi) +strong_alias_untyped(atol,atoi) libc_hidden_def(atoi) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) -#undef atoll -extern __typeof(atol) atoll; -strong_alias(atol,atoll) +strong_alias_untyped(atol,atoll) #endif #endif @@ -313,7 +240,6 @@ strong_alias(atol,atoll) #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) -libc_hidden_proto(strtoll) long long atoll(const char *nptr) { @@ -324,9 +250,16 @@ long long atoll(const char *nptr) #endif /**********************************************************************/ +#ifdef L_rpmatch +int rpmatch (const char *__response) +{ + return (__response[0] == 'y' || __response[0] == 'Y') ? 1 : + (__response[0] == 'n' || __response[0] == 'N') ? 0 : -1; +} +#endif +/**********************************************************************/ #if defined(L_strtol) || defined(L_strtol_l) -libc_hidden_proto(__XL_NPP(strtol)) long __XL_NPP(strtol)(const char * __restrict str, char ** __restrict endptr, int base __LOCALE_PARAM) { @@ -339,15 +272,11 @@ strong_alias(strtol,strtoimax) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) -#ifdef L_strtol_l -#undef strtoll_l -#else -#undef strtoll -#endif -extern __typeof(strtol) __XL_NPP(strtoll); -libc_hidden_proto(__XL_NPP(strtoll)) -strong_alias(__XL_NPP(strtol),__XL_NPP(strtoll)) +strong_alias_untyped(__XL_NPP(strtol),__XL_NPP(strtoll)) +#ifdef L_strtol libc_hidden_def(__XL_NPP(strtoll)) +strong_alias(strtol,strtoq) +#endif #endif #endif @@ -356,16 +285,14 @@ libc_hidden_def(__XL_NPP(strtoll)) #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) -libc_hidden_proto(__XL_NPP(strtoll)) long long __XL_NPP(strtoll)(const char * __restrict str, char ** __restrict endptr, int base __LOCALE_PARAM) { return (long long) __XL_NPP(_stdlib_strto_ll)(str, endptr, base, 1 __LOCALE_ARG); } +#ifdef L_strtoll libc_hidden_def(__XL_NPP(strtoll)) - -#if !defined(L_strtoll_l) #if (ULLONG_MAX == UINTMAX_MAX) strong_alias(strtoll,strtoimax) #endif @@ -378,7 +305,6 @@ strong_alias(strtoll,strtoq) /**********************************************************************/ #if defined(L_strtoul) || defined(L_strtoul_l) -libc_hidden_proto(__XL_NPP(strtoul)) unsigned long __XL_NPP(strtoul)(const char * __restrict str, char ** __restrict endptr, int base __LOCALE_PARAM) @@ -392,15 +318,10 @@ strong_alias(strtoul,strtoumax) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) -#ifdef L_strtoul_l -#undef strtoull_l -#else -#undef strtoull +strong_alias_untyped(__XL_NPP(strtoul),__XL_NPP(strtoull)) +#if !defined(L_strtoul_l) +strong_alias(strtoul,strtouq) #endif -extern __typeof(strtoul) __XL_NPP(strtoull); -libc_hidden_proto(__XL_NPP(strtoull)) -strong_alias(__XL_NPP(strtoul),__XL_NPP(strtoull)) -libc_hidden_def(__XL_NPP(strtoull)) #endif @@ -410,14 +331,12 @@ libc_hidden_def(__XL_NPP(strtoull)) #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) -libc_hidden_proto(__XL_NPP(strtoull)) unsigned long long __XL_NPP(strtoull)(const char * __restrict str, char ** __restrict endptr, int base __LOCALE_PARAM) { return __XL_NPP(_stdlib_strto_ll)(str, endptr, base, 0 __LOCALE_ARG); } -libc_hidden_def(__XL_NPP(strtoull)) #if !defined(L_strtoull_l) #if (ULLONG_MAX == UINTMAX_MAX) @@ -465,10 +384,8 @@ strong_alias(strtoull,strtouq) #define Wuchar __uwchar_t #ifdef __UCLIBC_DO_XLOCALE #define ISSPACE(C) iswspace_l((C), locale_arg) -libc_hidden_proto(iswspace_l) #else #define ISSPACE(C) iswspace((C)) -libc_hidden_proto(iswspace) #endif #else /* defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) */ @@ -477,10 +394,8 @@ libc_hidden_proto(iswspace) #define Wuchar unsigned char #ifdef __UCLIBC_DO_XLOCALE #define ISSPACE(C) isspace_l((C), locale_arg) -libc_hidden_proto(isspace_l) #else #define ISSPACE(C) isspace((C)) -libc_hidden_proto(isspace) #endif #endif /* defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) */ @@ -500,12 +415,6 @@ unsigned long attribute_hidden _stdlib_strto_l(register const Wchar * __restrict /* This is the main work fuction which handles both strtol (sflag = 1) and * strtoul (sflag = 0). */ -#ifdef __UCLIBC_HAS_XLOCALE__ -libc_hidden_proto(__ctype_b_loc) -#elif defined __UCLIBC_HAS_CTYPE_TABLES__ -libc_hidden_proto(__ctype_b) -#endif - unsigned long attribute_hidden __XL_NPP(_stdlib_strto_l)(register const Wchar * __restrict str, Wchar ** __restrict endptr, int base, int sflag __LOCALE_PARAM) @@ -620,10 +529,8 @@ unsigned long attribute_hidden __XL_NPP(_stdlib_strto_l)(register const Wchar * #define Wuchar __uwchar_t #ifdef __UCLIBC_DO_XLOCALE #define ISSPACE(C) iswspace_l((C), locale_arg) -libc_hidden_proto(iswspace_l) #else #define ISSPACE(C) iswspace((C)) -libc_hidden_proto(iswspace) #endif #else /* defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) */ @@ -632,10 +539,8 @@ libc_hidden_proto(iswspace) #define Wuchar unsigned char #ifdef __UCLIBC_DO_XLOCALE #define ISSPACE(C) isspace_l((C), locale_arg) -libc_hidden_proto(isspace_l) #else #define ISSPACE(C) isspace((C)) -libc_hidden_proto(isspace) #endif #endif /* defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) */ @@ -652,9 +557,6 @@ unsigned long long attribute_hidden _stdlib_strto_ll(register const Wchar * __re #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ -#if !defined __UCLIBC_HAS_XLOCALE__ && defined __UCLIBC_HAS_CTYPE_TABLES__ -libc_hidden_proto(__ctype_b) -#endif /* This is the main work fuction which handles both strtoll (sflag = 1) and * strtoull (sflag = 0). */ @@ -765,17 +667,7 @@ unsigned long long attribute_hidden __XL_NPP(_stdlib_strto_ll)(register const Wc #endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ #endif -/**********************************************************************/ -/* Made _Exit() an alias for _exit(), as per C99. */ -/* #ifdef L__Exit */ -/* libc_hidden_proto(_exit) */ -/* void _Exit(int status) */ -/* { */ -/* _exit(status); */ -/* } */ - -/* #endif */ -/**********************************************************************/ + #ifdef L_bsearch void *bsearch(const void *key, const void *base, size_t /* nmemb */ high, @@ -806,7 +698,7 @@ void *bsearch(const void *key, const void *base, size_t /* nmemb */ high, #endif /**********************************************************************/ -#ifdef L_qsort +#ifdef L_qsort_r /* This code is derived from a public domain shell sort routine by * Ray Gardner and found in Bob Stout's snippets collection. The @@ -816,11 +708,11 @@ void *bsearch(const void *key, const void *base, size_t /* nmemb */ high, * calculation, as well as to reduce the generated code size with * bcc and gcc. */ -libc_hidden_proto(qsort) -void qsort(void *base, +void qsort_r(void *base, size_t nel, size_t width, - int (*comp)(const void *, const void *)) + __compar_d_fn_t comp, + void *arg) { size_t wgap, i, j, k; char tmp; @@ -846,7 +738,7 @@ void qsort(void *base, j -= wgap; a = j + ((char *)base); b = a + wgap; - if ((*comp)(a, b) <= 0) { + if ((*comp)(a, b, arg) <= 0) { break; } k = width; @@ -862,7 +754,7 @@ void qsort(void *base, } while (wgap); } } -libc_hidden_def(qsort) +libc_hidden_def(qsort_r) /* ---------- original snippets version below ---------- */ @@ -909,14 +801,25 @@ void ssort(void *base, #endif #endif + +#ifdef L_qsort +void qsort(void *base, + size_t nel, + size_t width, + __compar_fn_t comp) +{ + return qsort_r (base, nel, width, (__compar_d_fn_t) comp, NULL); +} +libc_hidden_def(qsort) +#endif + /**********************************************************************/ #ifdef L__stdlib_mb_cur_max -libc_hidden_proto(_stdlib_mb_cur_max) size_t _stdlib_mb_cur_max(void) { #ifdef __CTYPE_HAS_UTF_8_LOCALES - return __UCLIBC_CURLOCALE_DATA.mb_cur_max; + return __UCLIBC_CURLOCALE->mb_cur_max; #else #ifdef __CTYPE_HAS_8_BIT_LOCALES #ifdef __UCLIBC_MJN3_ONLY__ @@ -936,7 +839,7 @@ libc_hidden_def(_stdlib_mb_cur_max) * To note, until now all the supported encoding are stateless. */ -static inline int is_stateful(unsigned char encoding) +static __always_inline int is_stateful(unsigned char encoding) { switch (encoding) { @@ -956,7 +859,6 @@ static inline int is_stateful(unsigned char encoding) /**********************************************************************/ #ifdef L_mblen -libc_hidden_proto(mbrlen) int mblen(register const char *s, size_t n) { @@ -988,7 +890,6 @@ int mblen(register const char *s, size_t n) /**********************************************************************/ #ifdef L_mbtowc -libc_hidden_proto(mbrtowc) int mbtowc(wchar_t *__restrict pwc, register const char *__restrict s, size_t n) { @@ -1023,7 +924,6 @@ int mbtowc(wchar_t *__restrict pwc, register const char *__restrict s, size_t n) /* Note: We completely ignore state in all currently supported conversions. */ -libc_hidden_proto(wcrtomb) int wctomb(register char *__restrict s, wchar_t swc) { @@ -1042,7 +942,6 @@ int wctomb(register char *__restrict s, wchar_t swc) /**********************************************************************/ #ifdef L_mbstowcs -libc_hidden_proto(mbsrtowcs) size_t mbstowcs(wchar_t * __restrict pwcs, const char * __restrict s, size_t n) { @@ -1059,7 +958,6 @@ size_t mbstowcs(wchar_t * __restrict pwcs, const char * __restrict s, size_t n) /* Note: We completely ignore state in all currently supported conversions. */ -libc_hidden_proto(wcsrtombs) size_t wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n) { @@ -1072,28 +970,18 @@ size_t wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n) /**********************************************************************/ #if defined(L_wcstol) || defined(L_wcstol_l) -libc_hidden_proto(__XL_NPP(wcstol)) long __XL_NPP(wcstol)(const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base __LOCALE_PARAM) { return __XL_NPP(_stdlib_wcsto_l)(str, endptr, base, 1 __LOCALE_ARG); } -libc_hidden_def(__XL_NPP(wcstol)) #if (ULONG_MAX == UINTMAX_MAX) && !defined(L_wcstol_l) strong_alias(wcstol,wcstoimax) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) -#ifdef L_wcstol_l -#undef wcstoll_l -#else -#undef wcstoll -#endif -extern __typeof(wcstol) __XL_NPP(wcstoll); -libc_hidden_proto(__XL_NPP(wcstoll)) -strong_alias(__XL_NPP(wcstol),__XL_NPP(wcstoll)) -libc_hidden_def(__XL_NPP(wcstoll)) +strong_alias_untyped(__XL_NPP(wcstol),__XL_NPP(wcstoll)) #endif #endif @@ -1102,14 +990,12 @@ libc_hidden_def(__XL_NPP(wcstoll)) #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) -libc_hidden_proto(__XL_NPP(wcstoll)) long long __XL_NPP(wcstoll)(const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base __LOCALE_PARAM) { return (long long) __XL_NPP(_stdlib_wcsto_ll)(str, endptr, base, 1 __LOCALE_ARG); } -libc_hidden_def(__XL_NPP(wcstoll)) #if !defined(L_wcstoll_l) #if (ULLONG_MAX == UINTMAX_MAX) @@ -1124,29 +1010,19 @@ strong_alias(wcstoll,wcstoq) /**********************************************************************/ #if defined(L_wcstoul) || defined(L_wcstoul_l) -libc_hidden_proto(__XL_NPP(wcstoul)) unsigned long __XL_NPP(wcstoul)(const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base __LOCALE_PARAM) { return __XL_NPP(_stdlib_wcsto_l)(str, endptr, base, 0 __LOCALE_ARG); } -libc_hidden_def(__XL_NPP(wcstoul)) #if (ULONG_MAX == UINTMAX_MAX) && !defined(L_wcstoul_l) strong_alias(wcstoul,wcstoumax) #endif #if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) -#ifdef L_wcstoul_l -#undef wcstoull_l -#else -#undef wcstoull -#endif -extern __typeof(wcstoul) __XL_NPP(wcstoull); -libc_hidden_proto(__XL_NPP(wcstoull)) -strong_alias(__XL_NPP(wcstoul),__XL_NPP(wcstoull)) -libc_hidden_def(__XL_NPP(wcstoull)) +strong_alias_untyped(__XL_NPP(wcstoul),__XL_NPP(wcstoull)) #endif #endif @@ -1155,14 +1031,12 @@ libc_hidden_def(__XL_NPP(wcstoull)) #if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) -libc_hidden_proto(__XL_NPP(wcstoull)) unsigned long long __XL_NPP(wcstoull)(const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base __LOCALE_PARAM) { return __XL_NPP(_stdlib_wcsto_ll)(str, endptr, base, 0 __LOCALE_ARG); } -libc_hidden_def(__XL_NPP(wcstoull)) #if !defined(L_wcstoull_l) #if (ULLONG_MAX == UINTMAX_MAX) diff --git a/libc/stdlib/system.c b/libc/stdlib/system.c index 4d75a4077..771c30e3f 100644 --- a/libc/stdlib/system.c +++ b/libc/stdlib/system.c @@ -5,66 +5,259 @@ */ #include <stdio.h> +#include <string.h> #include <stddef.h> #include <signal.h> #include <unistd.h> #include <sys/wait.h> #include <stdlib.h> - -libc_hidden_proto(_exit) -libc_hidden_proto(wait4) -libc_hidden_proto(execl) -libc_hidden_proto(signal) -libc_hidden_proto(vfork) - -/* uClinux-2.0 has vfork, but Linux 2.0 doesn't */ -#include <sys/syscall.h> -#ifndef __NR_vfork -# define vfork fork -libc_hidden_proto(fork) +#include <paths.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sched.h> +#include <errno.h> +#include <bits/libc-lock.h> +#include <sysdep-cancel.h> #endif extern __typeof(system) __libc_system; +#if !defined __UCLIBC_HAS_THREADS_NATIVE__ +#include <sys/syscall.h> + int __libc_system(const char *command) { int wait_val, pid; - __sighandler_t save_quit, save_int, save_chld; + struct sigaction sa, save_quit, save_int; + sigset_t save_mask; if (command == 0) return 1; - save_quit = signal(SIGQUIT, SIG_IGN); - save_int = signal(SIGINT, SIG_IGN); - save_chld = signal(SIGCHLD, SIG_DFL); + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_IGN; + /* __sigemptyset(&sa.sa_mask); - done by memset() */ + /* sa.sa_flags = 0; - done by memset() */ + + sigaction(SIGQUIT, &sa, &save_quit); + sigaction(SIGINT, &sa, &save_int); + __sigaddset(&sa.sa_mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &sa.sa_mask, &save_mask); if ((pid = vfork()) < 0) { - signal(SIGQUIT, save_quit); - signal(SIGINT, save_int); - signal(SIGCHLD, save_chld); - return -1; + wait_val = -1; + goto out; } if (pid == 0) { - signal(SIGQUIT, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGCHLD, SIG_DFL); + sigaction(SIGQUIT, &save_quit, NULL); + sigaction(SIGINT, &save_int, NULL); + sigprocmask(SIG_SETMASK, &save_mask, NULL); - execl("/bin/sh", "sh", "-c", command, (char *) 0); + execl(_PATH_BSHELL, "sh", "-c", command, (char *) 0); _exit(127); } - /* Signals are not absolutly guarenteed with vfork */ - signal(SIGQUIT, SIG_IGN); - signal(SIGINT, SIG_IGN); #if 0 __printf("Waiting for child %d\n", pid); #endif - if (wait4(pid, &wait_val, 0, 0) == -1) + if (__wait4_nocancel(pid, &wait_val, 0, 0) == -1) wait_val = -1; - signal(SIGQUIT, save_quit); - signal(SIGINT, save_int); - signal(SIGCHLD, save_chld); +out: + sigaction(SIGQUIT, &save_quit, NULL); + sigaction(SIGINT, &save_int, NULL); + sigprocmask(SIG_SETMASK, &save_mask, NULL); return wait_val; } +#else +/* We have to and actually can handle cancelable system(). The big + problem: we have to kill the child process if necessary. To do + this a cleanup handler has to be registered and is has to be able + to find the PID of the child. The main problem is to reliable have + the PID when needed. It is not necessary for the parent thread to + return. It might still be in the kernel when the cancellation + request comes. Therefore we have to use the clone() calls ability + to have the kernel write the PID into the user-level variable. */ + +libc_hidden_proto(sigaction) +libc_hidden_proto(waitpid) + +#if defined __ia64__ +# define FORK() \ + INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \ + &pid, NULL, NULL) +#elif defined __sparc__ +# define FORK() \ + INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL) +#else +# define FORK() \ + INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid) +#endif + +static void cancel_handler (void *arg); + +# define CLEANUP_HANDLER \ + __libc_cleanup_region_start (1, cancel_handler, &pid) + +# define CLEANUP_RESET \ + __libc_cleanup_region_end (0) + +static struct sigaction intr, quit; +static int sa_refcntr; +__libc_lock_define_initialized (static, lock); + +# define DO_LOCK() __libc_lock_lock (lock) +# define DO_UNLOCK() __libc_lock_unlock (lock) +# define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; }) +# define ADD_REF() sa_refcntr++ +# define SUB_REF() --sa_refcntr + +/* Execute LINE as a shell command, returning its status. */ +static int +do_system (const char *line) +{ + int status, save; + pid_t pid; + struct sigaction sa; + sigset_t omask; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_IGN; + /*sa.sa_flags = 0; - done by memset */ + /*__sigemptyset (&sa.sa_mask); - done by memset */ + + DO_LOCK (); + if (ADD_REF () == 0) + { + if (sigaction (SIGINT, &sa, &intr) < 0) + { + SUB_REF (); + goto out; + } + if (sigaction (SIGQUIT, &sa, &quit) < 0) + { + save = errno; + SUB_REF (); + goto out_restore_sigint; + } + } + DO_UNLOCK (); + + /* We reuse the bitmap in the 'sa' structure. */ + __sigaddset (&sa.sa_mask, SIGCHLD); + save = errno; + if (sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0) + { + { + DO_LOCK (); + if (SUB_REF () == 0) + { + save = errno; + (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); + out_restore_sigint: + (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL); + __set_errno (save); + } + out: + DO_UNLOCK (); + return -1; + } + } + + CLEANUP_HANDLER; + + pid = FORK (); + if (pid == (pid_t) 0) + { + /* Child side. */ + const char *new_argv[4]; + new_argv[0] = _PATH_BSHELL; + new_argv[1] = "-c"; + new_argv[2] = line; + new_argv[3] = NULL; + + /* Restore the signals. */ + (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL); + (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); + (void) sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL); + INIT_LOCK (); + + /* Exec the shell. */ + (void) execve (_PATH_BSHELL, (char *const *) new_argv, __environ); + _exit (127); + } + else if (pid < (pid_t) 0) + /* The fork failed. */ + status = -1; + else + /* Parent side. */ + { + /* Note the system() is a cancellation point. But since we call + waitpid() which itself is a cancellation point we do not + have to do anything here. */ + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + status = -1; + } + + CLEANUP_RESET; + + save = errno; + DO_LOCK (); + if ((SUB_REF () == 0 + && (sigaction (SIGINT, &intr, (struct sigaction *) NULL) + | sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0) + || sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0) + { + status = -1; + } + DO_UNLOCK (); + + return status; +} + + +int +__libc_system (const char *line) +{ + if (line == NULL) + /* Check that we have a command processor available. It might + not be available after a chroot(), for example. */ + return do_system ("exit 0") == 0; + + if (SINGLE_THREAD_P) + return do_system (line); + + int oldtype = LIBC_CANCEL_ASYNC (); + + int result = do_system (line); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} + + +/* The cancellation handler. */ +static void +cancel_handler (void *arg) +{ + pid_t child = *(pid_t *) arg; + + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL); + + TEMP_FAILURE_RETRY (waitpid (child, NULL, 0)); + + DO_LOCK (); + + if (SUB_REF () == 0) + { + (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); + (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL); + } + + DO_UNLOCK (); +} +#endif +#ifdef IS_IN_libc weak_alias(__libc_system,system) +#endif diff --git a/libc/stdlib/unix_grantpt.c b/libc/stdlib/unix_grantpt.c index d1eef9efd..66c18c0ed 100644 --- a/libc/stdlib/unix_grantpt.c +++ b/libc/stdlib/unix_grantpt.c @@ -14,8 +14,7 @@ You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + see <http://www.gnu.org/licenses/>. */ #include <assert.h> #include <errno.h> @@ -30,26 +29,6 @@ #include <unistd.h> #include "pty-private.h" -/* Experimentally off - libc_hidden_proto(memchr) */ -libc_hidden_proto(getgid) -libc_hidden_proto(getuid) -libc_hidden_proto(setrlimit) -libc_hidden_proto(waitpid) -libc_hidden_proto(dup2) -libc_hidden_proto(chmod) -libc_hidden_proto(chown) -libc_hidden_proto(vfork) -libc_hidden_proto(fork) -libc_hidden_proto(stat) -libc_hidden_proto(ptsname_r) -libc_hidden_proto(execle) -libc_hidden_proto(_exit) - -/* uClinux-2.0 has vfork, but Linux 2.0 doesn't */ -#include <sys/syscall.h> -#if ! defined __NR_vfork -#define vfork fork -#endif /* Return the result of ptsname_r in the buffer pointed to by PTS, which should be of length BUF_LEN. If it is too long to fit in @@ -89,7 +68,7 @@ pts_name (int fd, char **pts, size_t buf_len) if (! new_buf) { rv = -1; - errno = ENOMEM; + /* __set_errno(ENOMEM); */ break; } buf = new_buf; diff --git a/libc/stdlib/unlockpt.c b/libc/stdlib/unlockpt.c index 8c426553c..a4476e147 100644 --- a/libc/stdlib/unlockpt.c +++ b/libc/stdlib/unlockpt.c @@ -14,15 +14,13 @@ You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + see <http://www.gnu.org/licenses/>. */ #include <errno.h> #include <stdlib.h> #include <sys/ioctl.h> #include <termios.h> -libc_hidden_proto(ioctl) /* Unlock the slave pseudo terminal associated with the master pseudo terminal specified by FD. */ diff --git a/libc/stdlib/valloc.c b/libc/stdlib/valloc.c index 13dbe0f67..0351387c7 100644 --- a/libc/stdlib/valloc.c +++ b/libc/stdlib/valloc.c @@ -14,8 +14,7 @@ Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. +not, see <http://www.gnu.org/licenses/>. The author may be reached (Email) at the address mike@@ai.mit.edu, or (US mail) as Mike Haertel c/o Free Software Foundation. */ @@ -24,7 +23,6 @@ Cambridge, MA 02139, USA. #include <unistd.h> #include <malloc.h> -libc_hidden_proto(getpagesize) static size_t pagesize; |
