URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
Compare Revisions
- This comparison shows the changes necessary to convert path
/or1k/trunk/linux/uClibc/libc/stdlib
- from Rev 1325 to Rev 1765
- ↔ Reverse comparison
Rev 1325 → Rev 1765
/mrand48_r.c
0,0 → 1,29
/* Copyright (C) 1995, 1997, 1998, 2001 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu <mailto:drepper@gnu.ai.mit.edu>>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <stdlib.h> |
|
int mrand48_r (struct drand48_data *buffer, long int *result) |
{ |
/* Be generous for the arguments, detect some errors. */ |
if (buffer == NULL) |
return -1; |
|
return jrand48_r (buffer->__x, buffer, result); |
} |
/atexit.c
0,0 → 1,251
/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> |
* This file is part of the Linux-8086 C library and is distributed |
* under the GNU Library General Public License. |
*/ |
|
/* |
* Dec 2000 Manuel Novoa III |
* |
* Made atexit handling conform to standards... i.e. no args. |
* Removed on_exit since it did not match gnu libc definition. |
* Combined atexit and __do_exit into one object file. |
* |
* Feb 2001 Manuel Novoa III |
* |
* Reworked file after addition of __uClibc_main. |
* Changed name of __do_exit to atexit_handler. |
* Changed name of __cleanup to __uClibc_cleanup. |
* Moved declaration of __uClibc_cleanup to __uClibc_main |
* where it is initialized with (possibly weak alias) |
* _stdio_term. |
* |
* Jul 2001 Steve Thayer |
* |
* Added an on_exit implementation (that now matches gnu libc definition.) |
* Pulled atexit_handler out of the atexit object since it is now required by |
* on_exit as well. Renamed it to __exit_handler. |
* Fixed a problem where exit functions stop getting called if one of |
* them calls exit(). |
* As a side effect of these changes, abort() no longer calls the exit |
* functions (it now matches the gnu libc definition). |
* |
* August 2002 Erik Andersen |
* Added locking so atexit and friends can be thread safe |
* |
*/ |
|
#define _GNU_SOURCE |
#include <features.h> |
#include <unistd.h> |
#include <stdlib.h> |
#include <errno.h> |
|
|
#ifdef __UCLIBC_HAS_THREADS__ |
#include <pthread.h> |
extern pthread_mutex_t mylock; |
# define LOCK __pthread_mutex_lock(&mylock) |
# define UNLOCK __pthread_mutex_unlock(&mylock); |
#else |
# define LOCK |
# define UNLOCK |
#endif |
|
|
typedef void (*aefuncp) (void); /* atexit function pointer */ |
typedef void (*oefuncp) (int, void *); /* on_exit function pointer */ |
typedef enum { |
ef_atexit, |
ef_on_exit |
} ef_type; /* exit function types */ |
|
/* this is in the L_exit object */ |
extern void (*__exit_cleanup) (int); |
|
/* these are in the L___do_exit object */ |
extern int __exit_slots; |
extern int __exit_count; |
extern void __exit_handler(int); |
struct exit_function { |
ef_type type; /* ef_atexit or ef_on_exit */ |
union { |
aefuncp atexit; |
struct { |
oefuncp func; |
void *arg; |
} on_exit; |
} funcs; |
}; |
#ifdef __UCLIBC_DYNAMIC_ATEXIT__ |
extern struct exit_function *__exit_function_table; |
#else |
extern struct exit_function __exit_function_table[__UCLIBC_MAX_ATEXIT]; |
#endif |
|
#ifdef L_atexit |
/* |
* register a function to be called at normal program termination |
* (the registered function takes no arguments) |
*/ |
int atexit(aefuncp func) |
{ |
struct exit_function *efp; |
|
LOCK; |
if (func) { |
#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, |
(__exit_slots+20)*sizeof(struct exit_function)); |
if (efp==NULL) { |
UNLOCK; |
__set_errno(ENOMEM); |
return -1; |
} |
__exit_function_table = efp; |
__exit_slots+=20; |
} |
#else |
if (__exit_count >= __UCLIBC_MAX_ATEXIT) { |
UNLOCK; |
__set_errno(ENOMEM); |
return -1; |
} |
#endif |
__exit_cleanup = __exit_handler; /* enable cleanup */ |
efp = &__exit_function_table[__exit_count++]; |
efp->type = ef_atexit; |
efp->funcs.atexit = func; |
} |
UNLOCK; |
return 0; |
} |
#endif |
|
#ifdef L_on_exit |
/* |
* register a function to be called at normal program termination |
* the registered function takes two arguments: |
* status - the exit status that was passed to the exit() function |
* arg - generic argument |
*/ |
int on_exit(oefuncp func, void *arg) |
{ |
struct exit_function *efp; |
|
LOCK; |
if (func) { |
#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, |
(__exit_slots+20)*sizeof(struct exit_function)); |
if (efp==NULL) { |
UNLOCK; |
__set_errno(ENOMEM); |
return -1; |
} |
__exit_function_table=efp; |
__exit_slots+=20; |
} |
#else |
if (__exit_count >= __UCLIBC_MAX_ATEXIT) { |
UNLOCK; |
__set_errno(ENOMEM); |
return -1; |
} |
#endif |
|
__exit_cleanup = __exit_handler; /* enable cleanup */ |
efp = &__exit_function_table[__exit_count++]; |
efp->type = ef_on_exit; |
efp->funcs.on_exit.func = func; |
efp->funcs.on_exit.arg = arg; |
} |
UNLOCK; |
return 0; |
} |
#endif |
|
#ifdef L___exit_handler |
int __exit_count = 0; /* Number of registered exit functions */ |
#ifdef __UCLIBC_DYNAMIC_ATEXIT__ |
struct exit_function *__exit_function_table = NULL; |
int __exit_slots = 0; /* Size of __exit_function_table */ |
#else |
struct exit_function __exit_function_table[__UCLIBC_MAX_ATEXIT]; |
#endif |
|
|
/* |
* Handle the work of executing the registered exit functions |
* This is called while we are locked, so no additional locking |
* is needed... |
*/ |
void __exit_handler(int status) |
{ |
struct exit_function *efp; |
|
/* In reverse order */ |
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); |
} |
break; |
case ef_atexit: |
if (efp->funcs.atexit) { |
(efp->funcs.atexit) (); |
} |
break; |
} |
} |
#ifdef __UCLIBC_DYNAMIC_ATEXIT__ |
/* Free up memory used by the __exit_function_table structure */ |
if (__exit_function_table) |
free(__exit_function_table); |
#endif |
} |
#endif |
|
#ifdef L_exit |
extern void weak_function _stdio_term(void); |
void (*__exit_cleanup) (int) = 0; |
#ifdef __UCLIBC_HAS_THREADS__ |
pthread_mutex_t mylock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; |
#endif |
|
#ifdef __UCLIBC_CTOR_DTOR__ |
extern void (*__app_fini)(void); |
#endif |
|
/* |
* Normal program termination |
*/ |
void exit(int rv) |
{ |
/* Perform exit-specific cleanup (atexit and on_exit) */ |
LOCK; |
if (__exit_cleanup) { |
__exit_cleanup(rv); |
} |
UNLOCK; |
|
#ifdef __UCLIBC_CTOR_DTOR__ |
if (__app_fini != NULL) |
(__app_fini)(); |
#endif |
|
/* 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(); |
|
_exit(rv); |
} |
#endif |
/unlockpt.c
0,0 → 1,49
/* Copyright (C) 1998 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998. |
|
The GNU C Library is free software; you can redistribute it and/or |
modify it under the terms of the GNU Library General Public License as |
published by the Free Software Foundation; either version 2 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 |
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., 59 Temple Place - Suite 330, |
Boston, MA 02111-1307, USA. */ |
|
#include <errno.h> |
#include <stdlib.h> |
#include <sys/ioctl.h> |
#include <termios.h> |
|
|
/* Unlock the slave pseudo terminal associated with the master pseudo |
terminal specified by FD. */ |
int |
unlockpt (int fd) |
{ |
#ifdef TIOCSPTLCK |
int save_errno = errno; |
int unlock = 0; |
|
if (ioctl (fd, TIOCSPTLCK, &unlock)) |
{ |
if (errno == EINVAL) |
{ |
errno = save_errno; |
return 0; |
} |
else |
return -1; |
} |
#endif |
/* If we have no TIOCSPTLCK ioctl, all slave pseudo terminals are |
unlocked by default. */ |
return 0; |
} |
/nrand48_r.c
0,0 → 1,41
/* Copyright (C) 1995, 1997 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu <mailto:drepper@gnu.ai.mit.edu>>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <stdlib.h> |
|
extern int __drand48_iterate(unsigned short xsubi[3], |
struct drand48_data *buffer); |
|
int nrand48_r (xsubi, buffer, result) |
unsigned short int xsubi[3]; |
struct drand48_data *buffer; |
long int *result; |
{ |
/* Compute next state. */ |
if (__drand48_iterate (xsubi, buffer) < 0) |
return -1; |
|
/* Store the result. */ |
if (sizeof (unsigned short int) == 2) |
*result = xsubi[2] << 15 | xsubi[1] >> 1; |
else |
*result = xsubi[2] >> 1; |
|
return 0; |
} |
/realpath.c
0,0 → 1,164
/* |
* realpath.c -- canonicalize pathname by removing symlinks |
* Copyright (C) 1993 Rick Sladkey <jrs@world.std.com> |
* |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU Library Public License as published by |
* the Free Software Foundation; either version 2, or (at your option) |
* any later version. |
* |
* This program 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 Library Public License for more details. |
*/ |
|
#ifdef HAVE_CONFIG_H |
#include <config.h> |
#endif |
|
#include <sys/types.h> |
#include <unistd.h> |
#include <stdio.h> |
#include <string.h> |
#include <strings.h> |
#include <limits.h> /* for PATH_MAX */ |
#include <sys/param.h> /* for MAXPATHLEN */ |
#include <errno.h> |
|
#include <sys/stat.h> /* for S_IFLNK */ |
|
#ifndef PATH_MAX |
#ifdef _POSIX_VERSION |
#define PATH_MAX _POSIX_PATH_MAX |
#else |
#ifdef MAXPATHLEN |
#define PATH_MAX MAXPATHLEN |
#else |
#define PATH_MAX 1024 |
#endif |
#endif |
#endif |
|
#define MAX_READLINKS 32 |
|
#ifdef __STDC__ |
char *realpath(const char *path, char resolved_path[]) |
#else |
char *realpath(path, resolved_path) |
const char *path; |
char resolved_path[]; |
#endif |
{ |
char copy_path[PATH_MAX]; |
char link_path[PATH_MAX]; |
char got_path[PATH_MAX]; |
char *new_path = got_path; |
char *max_path; |
int readlinks = 0; |
int n; |
|
/* Make a copy of the source path since we may need to modify it. */ |
if (strlen(path) >= PATH_MAX - 2) { |
__set_errno(ENAMETOOLONG); |
return NULL; |
} |
strcpy(copy_path, path); |
path = copy_path; |
max_path = copy_path + PATH_MAX - 2; |
/* If it's a relative pathname use getwd for starters. */ |
if (*path != '/') { |
/* Ohoo... */ |
#define HAVE_GETCWD |
#ifdef HAVE_GETCWD |
getcwd(new_path, PATH_MAX - 1); |
#else |
getwd(new_path); |
#endif |
new_path += strlen(new_path); |
if (new_path[-1] != '/') |
*new_path++ = '/'; |
} else { |
*new_path++ = '/'; |
path++; |
} |
/* Expand each slash-separated pathname component. */ |
while (*path != '\0') { |
/* Ignore stray "/". */ |
if (*path == '/') { |
path++; |
continue; |
} |
if (*path == '.') { |
/* Ignore ".". */ |
if (path[1] == '\0' || path[1] == '/') { |
path++; |
continue; |
} |
if (path[1] == '.') { |
if (path[2] == '\0' || path[2] == '/') { |
path += 2; |
/* Ignore ".." at root. */ |
if (new_path == got_path + 1) |
continue; |
/* Handle ".." by backing up. */ |
while ((--new_path)[-1] != '/'); |
continue; |
} |
} |
} |
/* Safely copy the next pathname component. */ |
while (*path != '\0' && *path != '/') { |
if (path > max_path) { |
__set_errno(ENAMETOOLONG); |
return NULL; |
} |
*new_path++ = *path++; |
} |
#ifdef S_IFLNK |
/* Protect against infinite loops. */ |
if (readlinks++ > MAX_READLINKS) { |
__set_errno(ELOOP); |
return NULL; |
} |
/* See if latest pathname component is a symlink. */ |
*new_path = '\0'; |
n = readlink(got_path, link_path, PATH_MAX - 1); |
if (n < 0) { |
/* EINVAL means the file exists but isn't a symlink. */ |
if (errno != EINVAL) { |
/* Make sure it's null terminated. */ |
*new_path = '\0'; |
strcpy(resolved_path, got_path); |
return NULL; |
} |
} else { |
/* Note: readlink doesn't add the null byte. */ |
link_path[n] = '\0'; |
if (*link_path == '/') |
/* Start over for an absolute symlink. */ |
new_path = got_path; |
else |
/* Otherwise back up over this component. */ |
while (*(--new_path) != '/'); |
/* Safe sex check. */ |
if (strlen(path) + n >= PATH_MAX - 2) { |
__set_errno(ENAMETOOLONG); |
return NULL; |
} |
/* Insert symlink contents into path. */ |
strcat(link_path, path); |
strcpy(copy_path, link_path); |
path = copy_path; |
} |
#endif /* S_IFLNK */ |
*new_path++ = '/'; |
} |
/* Delete trailing slash but don't whomp a lone slash. */ |
if (new_path != got_path + 1 && new_path[-1] == '/') |
new_path--; |
/* Make sure it's null terminated. */ |
*new_path = '\0'; |
strcpy(resolved_path, got_path); |
return resolved_path; |
} |
/mkdtemp.c
0,0 → 1,36
/* vi: set sw=4 ts=4: */ |
/* Copyright (C) 1998 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 Library General Public License as |
published by the Free Software Foundation; either version 2 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 |
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., 59 Temple Place - Suite 330, |
Boston, MA 02111-1307, USA. */ |
|
#include <stdio.h> |
#include <stdlib.h> |
#include "../misc/internals/tempname.h" |
|
/* Generate a unique temporary directory name from TEMPLATE. |
The last six characters of TEMPLATE must be "XXXXXX"; |
they are replaced with a string that makes the filename unique. |
The directory is created, mode 700, and its name is returned. |
(This function comes from OpenBSD.) */ |
char * mkdtemp (char *template) |
{ |
if (__gen_tempname (template, __GT_DIR)) |
/* We return the null string if we can't find a unique file name. */ |
template[0] = '\0'; |
|
return template; |
} |
/srand48_r.c
0,0 → 1,40
/* Copyright (C) 1995, 1996, 1997, 1998, 2001 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu <mailto:drepper@gnu.ai.mit.edu>>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <stdlib.h> |
#include <limits.h> |
|
int srand48_r (seedval, buffer) |
long int seedval; |
struct drand48_data *buffer; |
{ |
/* The standards say we only have 32 bits. */ |
if (sizeof (long int) > 4) |
seedval &= 0xffffffffl; |
|
buffer->__x[2] = seedval >> 16; |
buffer->__x[1] = seedval & 0xffffl; |
buffer->__x[0] = 0x330e; |
|
buffer->__a = 0x5deece66dull; |
buffer->__c = 0xb; |
buffer->__init = 1; |
|
return 0; |
} |
/setenv.c
0,0 → 1,201
/* Copyright (C) 1992,95,96,97,98,99,2000,2001 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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. |
|
modified for uClibc by Erik Andersen <andersen@codepoet.org> |
*/ |
|
#define _GNU_SOURCE |
#include <features.h> |
#include <errno.h> |
#include <stdlib.h> |
#include <string.h> |
#include <unistd.h> |
|
#ifdef __UCLIBC_HAS_THREADS__ |
#include <pthread.h> |
static pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER; |
# define LOCK __pthread_mutex_lock(&mylock) |
# define UNLOCK __pthread_mutex_unlock(&mylock); |
#else |
# define LOCK |
# define UNLOCK |
#endif |
|
|
/* If this variable is not a null pointer we allocated the current |
environment. */ |
static char **last_environ; |
|
|
/* This function is used by `setenv' and `putenv'. The difference between |
the two functions is that for the former must create a new string which |
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) |
{ |
register char **ep; |
register size_t size; |
const size_t namelen = strlen (name); |
const size_t vallen = value != NULL ? strlen (value) + 1 : 0; |
|
LOCK; |
|
/* 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) { |
UNLOCK; |
return -1; |
} |
|
/* 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); |
UNLOCK; |
return -1; |
} |
|
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 *)); |
} |
|
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) { |
UNLOCK; |
return -1; |
} |
memcpy (np, name, namelen); |
np[namelen] = '='; |
memcpy (&np[namelen + 1], value, vallen); |
} |
*ep = np; |
} |
|
UNLOCK; |
return 0; |
} |
|
int setenv (const char *name, const char *value, int replace) |
{ |
return __add_to_environ (name, value, NULL, replace); |
} |
|
int unsetenv (const char *name) |
{ |
size_t len; |
char **ep; |
|
if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) { |
__set_errno (EINVAL); |
return -1; |
} |
|
len = strlen (name); |
LOCK; |
ep = __environ; |
while (*ep != NULL) { |
if (!strncmp (*ep, name, len) && (*ep)[len] == '=') { |
/* Found it. Remove this pointer by moving later ones back. */ |
char **dp = ep; |
do { |
dp[0] = dp[1]; |
} while (*dp++); |
/* Continue the loop in case NAME appears again. */ |
} else { |
++ep; |
} |
} |
UNLOCK; |
return 0; |
} |
|
/* 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) |
{ |
LOCK; |
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; |
UNLOCK; |
return 0; |
} |
|
/* Put STRING, which is of the form "NAME=VALUE", in the environment. */ |
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; |
} |
|
/drand48.c
0,0 → 1,32
/* Copyright (C) 1995, 1996, 1997, 1998, 2001 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu <mailto:drepper@gnu.ai.mit.edu>>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <stdlib.h> |
|
/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ |
extern struct drand48_data __libc_drand48_data; |
|
double drand48 (void) |
{ |
double result; |
|
erand48_r (__libc_drand48_data.__x, &__libc_drand48_data, &result); |
|
return result; |
} |
/drand48-iter.c
0,0 → 1,58
/* Copyright (C) 1995, 1996, 2001 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu <mailto:drepper@gnu.ai.mit.edu>>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <errno.h> |
#include <stdlib.h> |
#include <limits.h> |
#include <stdint.h> |
#include <sys/types.h> |
|
/* Global state for non-reentrant functions. */ |
struct drand48_data __libc_drand48_data; |
|
|
int |
__drand48_iterate (unsigned short int xsubi[3], struct drand48_data *buffer) |
{ |
uint64_t X; |
uint64_t result; |
|
/* Initialize buffer, if not yet done. */ |
if (unlikely(!buffer->__init)) |
{ |
buffer->__a = 0x5deece66dull; |
buffer->__c = 0xb; |
buffer->__init = 1; |
} |
|
/* Do the real work. We choose a data type which contains at least |
48 bits. Because we compute the modulus it does not care how |
many bits really are computed. */ |
|
X = (uint64_t) xsubi[2] << 32 | (uint32_t) xsubi[1] << 16 | xsubi[0]; |
|
result = X * buffer->__a + buffer->__c; |
|
xsubi[0] = result & 0xffff; |
xsubi[1] = (result >> 16) & 0xffff; |
xsubi[2] = (result >> 32) & 0xffff; |
|
return 0; |
} |
|
/erand48.c
0,0 → 1,32
/* Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu <mailto:drepper@gnu.ai.mit.edu>>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <stdlib.h> |
|
/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ |
extern struct drand48_data __libc_drand48_data; |
|
double erand48 (unsigned short int xsubi[3]) |
{ |
double result; |
|
(void) erand48_r (xsubi, &__libc_drand48_data, &result); |
|
return result; |
} |
/jrand48.c
0,0 → 1,32
/* Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu <mailto:drepper@gnu.ai.mit.edu>>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <stdlib.h> |
|
/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ |
extern struct drand48_data __libc_drand48_data; |
|
long int jrand48 (unsigned short int xsubi[3]) |
{ |
long int result; |
|
(void) jrand48_r (xsubi, &__libc_drand48_data, &result); |
|
return result; |
} |
/lrand48.c
0,0 → 1,32
/* Copyright (C) 1995, 1996, 1997, 1998, 2001 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu <mailto:drepper@gnu.ai.mit.edu>>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <stdlib.h> |
|
/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ |
extern struct drand48_data __libc_drand48_data; |
|
long int lrand48 (void) |
{ |
long int result; |
|
nrand48_r (__libc_drand48_data.__x, &__libc_drand48_data, &result); |
|
return result; |
} |
/seed48_r.c
0,0 → 1,38
/* Copyright (C) 1995, 1997, 1998, 2001 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <stdlib.h> |
#include <string.h> |
#include <limits.h> |
|
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. */ |
memcpy (buffer->__old_x, buffer->__x, sizeof (buffer->__x)); |
|
/* Install new state. */ |
buffer->__x[2] = seed16v[2]; |
buffer->__x[1] = seed16v[1]; |
buffer->__x[0] = seed16v[0]; |
buffer->__a = 0x5deece66dull; |
buffer->__c = 0xb; |
buffer->__init = 1; |
|
return 0; |
} |
/mrand48.c
0,0 → 1,32
/* Copyright (C) 1995, 1996, 1997, 1998, 2001 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu <mailto:drepper@gnu.ai.mit.edu>>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <stdlib.h> |
|
/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ |
extern struct drand48_data __libc_drand48_data; |
|
long int mrand48 (void) |
{ |
long int result; |
|
jrand48_r (__libc_drand48_data.__x, &__libc_drand48_data, &result); |
|
return result; |
} |
/.indent.pro
0,0 → 1,33
--blank-lines-after-declarations |
--blank-lines-after-procedures |
--break-before-boolean-operator |
--no-blank-lines-after-commas |
--braces-on-if-line |
--braces-on-struct-decl-line |
--comment-indentation25 |
--declaration-comment-column25 |
--no-comment-delimiters-on-blank-lines |
--cuddle-else |
--continuation-indentation4 |
--case-indentation0 |
--else-endif-column33 |
--space-after-cast |
--line-comments-indentation0 |
--declaration-indentation1 |
--dont-format-first-column-comments |
--dont-format-comments |
--honour-newlines |
--indent-level4 |
/* changed from 0 to 4 */ |
--parameter-indentation4 |
--line-length78 /* changed from 75 */ |
--continue-at-parentheses |
--no-space-after-function-call-names |
--dont-break-procedure-type |
--dont-star-comments |
--leave-optional-blank-lines |
--dont-space-special-semicolon |
--tab-size4 |
/* additions by Mark */ |
--case-brace-indentation0 |
--leave-preprocessor-space |
/nrand48.c
0,0 → 1,32
/* Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu <mailto:drepper@gnu.ai.mit.edu>>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <stdlib.h> |
|
/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ |
extern struct drand48_data __libc_drand48_data; |
|
long int nrand48 (unsigned short int xsubi[3]) |
{ |
long int result; |
|
nrand48_r (xsubi, &__libc_drand48_data, &result); |
|
return result; |
} |
/grantpt.c
0,0 → 1,76
/* Copyright (C) 1998, 1999 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 Library General Public License as |
published by the Free Software Foundation; either version 2 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 |
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., 59 Temple Place - Suite 330, |
Boston, MA 02111-1307, USA. */ |
|
#include <limits.h> |
#include <stdlib.h> |
|
/* If __ASSUME_DEVPTS__ is defined, grantpt() reduces to a stub since we |
assume that the devfs/devpts filesystem automatically manages the |
permissions. */ |
#if !defined __ASSUME_DEVPTS__ |
#include <sys/statfs.h> |
|
/* Constant that identifies the `devpts' filesystem. */ |
#define DEVPTS_SUPER_MAGIC 0x1cd1 |
/* Constant that identifies the `devfs' filesystem. */ |
#define DEVFS_SUPER_MAGIC 0x1373 |
|
/* 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); |
|
/* 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 |
|
/* Change the ownership and access permission of the slave pseudo |
terminal associated with the master pseudo terminal specified |
by FD. */ |
int |
grantpt (int fd) |
{ |
#if !defined __ASSUME_DEVPTS__ |
struct statfs fsbuf; |
# ifdef PATH_MAX |
char _buf[PATH_MAX]; |
# else |
char _buf[512]; |
# endif |
char *buf = _buf; |
|
if (pts_name (fd, &buf, sizeof (_buf))) |
return -1; |
|
if (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 0; |
} |
|
#if !defined __ASSUME_DEVPTS__ |
# define grantpt __unix_grantpt |
# include "unix_grantpt.c" |
#endif |
/mkstemp.c
0,0 → 1,30
/* Copyright (C) 1998 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 Library General Public License as |
published by the Free Software Foundation; either version 2 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 |
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., 59 Temple Place - Suite 330, |
Boston, MA 02111-1307, USA. */ |
|
#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 mkstemp (char *template) |
{ |
return __gen_tempname (template, __GT_FILE); |
} |
/stdlib.c
0,0 → 1,1044
/* Copyright (C) 2002 Manuel Novoa III |
* From my (incomplete) stdlib library for linux and (soon) elks. |
* |
* This library is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Library General Public |
* License as published by the Free Software Foundation; either |
* version 2 of the License, or (at your option) any later version. |
* |
* This 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 |
* 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. |
*/ |
|
/* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! |
* |
* This code is currently under development. Also, I plan to port |
* it to elks which is a 16-bit environment with a fairly limited |
* compiler. Therefore, please refrain from modifying this code |
* and, instead, pass any bug-fixes, etc. to me. Thanks. Manuel |
* |
* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */ |
|
/* Oct 29, 2002 |
* Fix a couple of 'restrict' bugs in mbstowcs and wcstombs. |
* |
* Nov 21, 2002 |
* Add wscto{inttype} functions. |
*/ |
|
#define _ISOC99_SOURCE /* for ULLONG primarily... */ |
#define _GNU_SOURCE |
#include <limits.h> |
#include <stdint.h> |
#include <inttypes.h> |
#include <ctype.h> |
#include <errno.h> |
#include <assert.h> |
#include <unistd.h> |
|
/* Work around gcc's refusal to create aliases. |
* TODO: Add in a define to disable the aliases? */ |
|
#if UINT_MAX == ULONG_MAX |
#define atoi __ignore_atoi |
#define abs __ignore_abs |
#endif |
#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) |
#define llabs __ignore_llabs |
#define atoll __ignore_atoll |
#define strtoll __ignore_strtoll |
#define strtoull __ignore_strtoull |
#define wcstoll __ignore_wcstoll |
#define wcstoull __ignore_wcstoull |
#define strtoll_l __ignore_strtoll_l |
#define strtoull_l __ignore_strtoull_l |
#define wcstoll_l __ignore_wcstoll_l |
#define wcstoull_l __ignore_wcstoull_l |
#endif |
|
#include <stdlib.h> |
#include <locale.h> |
|
#ifdef __UCLIBC_HAS_WCHAR__ |
|
#include <wchar.h> |
#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 |
#define UTF_8_MAX_LEN 6 |
#else |
#define UTF_8_MAX_LEN 3 |
#endif |
|
#ifdef __UCLIBC_HAS_LOCALE__ |
|
#define ENCODING ((__UCLIBC_CURLOCALE_DATA).encoding) |
#ifndef __CTYPE_HAS_UTF_8_LOCALES |
#ifdef L_mblen |
/* emit only once */ |
#warning __CTYPE_HAS_UTF_8_LOCALES not set! |
#endif |
#endif |
|
#else /* __UCLIBC_HAS_LOCALE__ */ |
|
#ifdef __UCLIBC_MJN3_ONLY__ |
#ifdef L_mblen |
/* emit only once */ |
#warning devel checks |
#endif |
#endif |
#ifdef __CTYPE_HAS_8_BIT_LOCALES |
#error __CTYPE_HAS_8_BIT_LOCALES is defined! |
#endif |
#ifdef __CTYPE_HAS_UTF_8_LOCALES |
#error __CTYPE_HAS_UTF_8_LOCALES is defined! |
#endif |
#endif |
|
#endif /* __UCLIBC_HAS_LOCALE__ */ |
|
#if UINT_MAX == ULONG_MAX |
#undef atoi |
#undef abs |
#endif |
#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) |
#undef llabs |
#undef atoll |
#undef strtoll |
#undef strtoull |
#undef wcstoll |
#undef wcstoull |
#undef strtoll_l |
#undef strtoull_l |
#undef wcstoll_l |
#undef wcstoull_l |
#endif /* __UCLIBC_HAS_WCHAR__ */ |
|
/**********************************************************************/ |
#ifdef __UCLIBC_HAS_XLOCALE__ |
|
extern unsigned long |
_stdlib_strto_l_l(register const char * __restrict str, |
char ** __restrict endptr, int base, int sflag, |
__locale_t locale_arg); |
|
#if defined(ULLONG_MAX) |
extern unsigned long long |
_stdlib_strto_ll_l(register const char * __restrict str, |
char ** __restrict endptr, int base, int sflag, |
__locale_t locale_arg); |
#endif |
|
#ifdef __UCLIBC_HAS_WCHAR__ |
extern unsigned long |
_stdlib_wcsto_l_l(register const wchar_t * __restrict str, |
wchar_t ** __restrict endptr, int base, int sflag, |
__locale_t locale_arg); |
|
#if defined(ULLONG_MAX) |
extern unsigned long long |
_stdlib_wcsto_ll_l(register const wchar_t * __restrict str, |
wchar_t ** __restrict endptr, int base, int sflag, |
__locale_t locale_arg); |
#endif |
#endif /* __UCLIBC_HAS_WCHAR__ */ |
|
#endif /* __UCLIBC_HAS_XLOCALE__ */ |
|
|
|
extern unsigned long |
_stdlib_strto_l(register const char * __restrict str, |
char ** __restrict endptr, int base, int sflag); |
|
#if defined(ULLONG_MAX) |
extern unsigned long long |
_stdlib_strto_ll(register const char * __restrict str, |
char ** __restrict endptr, int base, int sflag); |
#endif |
|
#ifdef __UCLIBC_HAS_WCHAR__ |
extern unsigned long |
_stdlib_wcsto_l(register const wchar_t * __restrict str, |
wchar_t ** __restrict endptr, int base, int sflag); |
|
#if defined(ULLONG_MAX) |
extern unsigned long long |
_stdlib_wcsto_ll(register const wchar_t * __restrict str, |
wchar_t ** __restrict endptr, int base, int sflag); |
#endif |
#endif /* __UCLIBC_HAS_WCHAR__ */ |
/**********************************************************************/ |
#ifdef L_atof |
|
double atof(const char *nptr) |
{ |
return strtod(nptr, (char **) NULL); |
} |
|
#endif |
/**********************************************************************/ |
#ifdef L_abs |
|
#if INT_MAX < LONG_MAX |
|
int abs(int j) |
{ |
return (j >= 0) ? j : -j; |
} |
|
#endif /* INT_MAX < LONG_MAX */ |
|
#endif |
/**********************************************************************/ |
#ifdef L_labs |
|
#if UINT_MAX == ULONG_MAX |
strong_alias(labs,abs) |
#endif |
|
#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) |
strong_alias(labs,llabs) |
#endif |
|
#if ULONG_MAX == UINTMAX_MAX |
strong_alias(labs,imaxabs) |
#endif |
|
long int labs(long int j) |
{ |
return (j >= 0) ? j : -j; |
} |
|
#endif |
/**********************************************************************/ |
#ifdef L_llabs |
|
#if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) |
|
#if (ULLONG_MAX == UINTMAX_MAX) |
strong_alias(llabs,imaxabs) |
#endif |
|
long long int llabs(long long int j) |
{ |
return (j >= 0) ? j : -j; |
} |
|
#endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ |
|
#endif |
/**********************************************************************/ |
#ifdef L_atoi |
|
#if INT_MAX < LONG_MAX |
|
int atoi(const char *nptr) |
{ |
return (int) strtol(nptr, (char **) NULL, 10); |
} |
|
#endif /* INT_MAX < LONG_MAX */ |
|
#endif |
/**********************************************************************/ |
#ifdef L_atol |
|
#if UINT_MAX == ULONG_MAX |
strong_alias(atol,atoi) |
#endif |
|
#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) |
strong_alias(atol,atoll) |
#endif |
|
long atol(const char *nptr) |
{ |
return strtol(nptr, (char **) NULL, 10); |
} |
|
#endif |
/**********************************************************************/ |
#ifdef L_atoll |
|
#if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) |
|
long long atoll(const char *nptr) |
{ |
return strtoll(nptr, (char **) NULL, 10); |
} |
|
#endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ |
|
#endif |
/**********************************************************************/ |
#if defined(L_strtol) || defined(L_strtol_l) |
|
#if (ULONG_MAX == UINTMAX_MAX) && !defined(L_strtol_l) |
strong_alias(strtol,strtoimax) |
#endif |
|
#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) |
strong_alias(__XL(strtol),__XL(strtoll)) |
#endif |
|
long __XL(strtol)(const char * __restrict str, char ** __restrict endptr, |
int base __LOCALE_PARAM ) |
{ |
return __XL_NPP(_stdlib_strto_l)(str, endptr, base, 1 __LOCALE_ARG ); |
} |
|
__XL_ALIAS(strtol) |
|
#endif |
/**********************************************************************/ |
#if defined(L_strtoll) || defined(L_strtoll_l) |
|
#if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) |
|
#if !defined(L_strtoll_l) |
#if (ULLONG_MAX == UINTMAX_MAX) |
strong_alias(strtoll,strtoimax) |
#endif |
strong_alias(strtoll,strtoq) |
#endif |
|
long long __XL(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 ); |
} |
|
__XL_ALIAS(strtoll) |
|
#endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ |
|
#endif |
/**********************************************************************/ |
#if defined(L_strtoul) || defined(L_strtoul_l) |
|
#if (ULONG_MAX == UINTMAX_MAX) && !defined(L_strtoul_l) |
strong_alias(strtoul,strtoumax) |
#endif |
|
#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) |
strong_alias(__XL(strtoul),__XL(strtoull)) |
#endif |
|
unsigned long __XL(strtoul)(const char * __restrict str, |
char ** __restrict endptr, int base |
__LOCALE_PARAM ) |
{ |
return __XL_NPP(_stdlib_strto_l)(str, endptr, base, 0 __LOCALE_ARG ); |
} |
|
__XL_ALIAS(strtoul) |
|
#endif |
/**********************************************************************/ |
#if defined(L_strtoull) || defined(L_strtoull_l) |
|
#if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) |
|
#if !defined(L_strtoull_l) |
#if (ULLONG_MAX == UINTMAX_MAX) |
strong_alias(strtoull,strtoumax) |
#endif |
strong_alias(strtoull,strtouq) |
#endif |
|
unsigned long long __XL(strtoull)(const char * __restrict str, |
char ** __restrict endptr, int base |
__LOCALE_PARAM ) |
{ |
return __XL_NPP(_stdlib_strto_ll)(str, endptr, base, 0 __LOCALE_ARG ); |
} |
|
__XL_ALIAS(strtoull) |
|
#endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ |
|
#endif |
/**********************************************************************/ |
/* Support routines follow */ |
/**********************************************************************/ |
/* Set if we want errno set appropriately. */ |
/* NOTE: Implies _STRTO_ENDPTR below */ |
#define _STRTO_ERRNO 1 |
|
/* Set if we want support for the endptr arg. */ |
/* Implied by _STRTO_ERRNO. */ |
#define _STRTO_ENDPTR 1 |
|
#if _STRTO_ERRNO |
#undef _STRTO_ENDPTR |
#define _STRTO_ENDPTR 1 |
#define SET_ERRNO(X) __set_errno(X) |
#else |
#define SET_ERRNO(X) ((void)(X)) /* keep side effects */ |
#endif |
|
/**********************************************************************/ |
#if defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) |
#define L__stdlib_strto_l |
#endif |
|
#if defined(L__stdlib_strto_l) || defined(L__stdlib_strto_l_l) |
|
#if defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) |
|
#define _stdlib_strto_l _stdlib_wcsto_l |
#define _stdlib_strto_l_l _stdlib_wcsto_l_l |
#define Wchar wchar_t |
#define Wuchar __uwchar_t |
#ifdef __UCLIBC_DO_XLOCALE |
#define ISSPACE(C) iswspace_l((C), locale_arg) |
#else |
#define ISSPACE(C) iswspace((C)) |
#endif |
|
#else /* defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) */ |
|
#define Wchar char |
#define Wuchar unsigned char |
#ifdef __UCLIBC_DO_XLOCALE |
#define ISSPACE(C) isspace_l((C), locale_arg) |
#else |
#define ISSPACE(C) isspace((C)) |
#endif |
|
#endif /* defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) */ |
|
#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) |
|
unsigned long _stdlib_strto_l(register const Wchar * __restrict str, |
Wchar ** __restrict endptr, int base, |
int sflag) |
{ |
return _stdlib_strto_l_l(str, endptr, base, sflag, __UCLIBC_CURLOCALE); |
} |
|
|
#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ |
|
/* This is the main work fuction which handles both strtol (sflag = 1) and |
* strtoul (sflag = 0). */ |
|
unsigned long __XL_NPP(_stdlib_strto_l)(register const Wchar * __restrict str, |
Wchar ** __restrict endptr, int base, |
int sflag __LOCALE_PARAM ) |
{ |
unsigned long number, cutoff; |
#if _STRTO_ENDPTR |
const Wchar *fail_char; |
#define SET_FAIL(X) fail_char = (X) |
#else |
#define SET_FAIL(X) ((void)(X)) /* Keep side effects. */ |
#endif |
unsigned char negative, digit, cutoff_digit; |
|
assert(((unsigned int)sflag) <= 1); |
|
SET_FAIL(str); |
|
while (ISSPACE(*str)) { /* Skip leading whitespace. */ |
++str; |
} |
|
/* Handle optional sign. */ |
negative = 0; |
switch(*str) { |
case '-': negative = 1; /* Fall through to increment str. */ |
case '+': ++str; |
} |
|
if (!(base & ~0x10)) { /* Either dynamic (base = 0) or base 16. */ |
base += 10; /* Default is 10 (26). */ |
if (*str == '0') { |
SET_FAIL(++str); |
base -= 2; /* Now base is 8 or 16 (24). */ |
if ((0x20|(*str)) == 'x') { /* WARNING: assumes ascii. */ |
++str; |
base += base; /* Base is 16 (16 or 48). */ |
} |
} |
|
if (base > 16) { /* Adjust in case base wasn't dynamic. */ |
base = 16; |
} |
} |
|
number = 0; |
|
if (((unsigned)(base - 2)) < 35) { /* Legal base. */ |
cutoff_digit = ULONG_MAX % base; |
cutoff = ULONG_MAX / base; |
do { |
digit = (((Wuchar)(*str - '0')) <= 9) |
? (*str - '0') |
: ((*str >= 'A') |
? (((0x20|(*str)) - 'a' + 10)) /* WARNING: assumes ascii. */ |
: 40); |
|
if (digit >= base) { |
break; |
} |
|
SET_FAIL(++str); |
|
if ((number > cutoff) |
|| ((number == cutoff) && (digit > cutoff_digit))) { |
number = ULONG_MAX; |
negative &= sflag; |
SET_ERRNO(ERANGE); |
} else { |
number = number * base + digit; |
} |
} while (1); |
} |
|
#if _STRTO_ENDPTR |
if (endptr) { |
*endptr = (Wchar *) fail_char; |
} |
#endif |
|
{ |
unsigned long tmp = ((negative) |
? ((unsigned long)(-(1+LONG_MIN)))+1 |
: LONG_MAX); |
if (sflag && (number > tmp)) { |
number = tmp; |
SET_ERRNO(ERANGE); |
} |
} |
|
return negative ? (unsigned long)(-((long)number)) : number; |
} |
|
#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ |
|
|
#endif |
/**********************************************************************/ |
#if defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) |
#define L__stdlib_strto_ll |
#endif |
|
#if defined(L__stdlib_strto_ll) || defined(L__stdlib_strto_ll_l) |
|
#if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) |
|
#if defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) |
#define _stdlib_strto_ll _stdlib_wcsto_ll |
#define _stdlib_strto_ll_l _stdlib_wcsto_ll_l |
#define Wchar wchar_t |
#define Wuchar __uwchar_t |
#ifdef __UCLIBC_DO_XLOCALE |
#define ISSPACE(C) iswspace_l((C), locale_arg) |
#else |
#define ISSPACE(C) iswspace((C)) |
#endif |
|
#else /* defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) */ |
|
#define Wchar char |
#define Wuchar unsigned char |
#ifdef __UCLIBC_DO_XLOCALE |
#define ISSPACE(C) isspace_l((C), locale_arg) |
#else |
#define ISSPACE(C) isspace((C)) |
#endif |
|
#endif /* defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) */ |
|
#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) |
|
unsigned long long _stdlib_strto_ll(register const Wchar * __restrict str, |
Wchar ** __restrict endptr, int base, |
int sflag) |
{ |
return _stdlib_strto_ll_l(str, endptr, base, sflag, __UCLIBC_CURLOCALE); |
} |
|
|
#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ |
|
/* This is the main work fuction which handles both strtoll (sflag = 1) and |
* strtoull (sflag = 0). */ |
|
unsigned long long __XL_NPP(_stdlib_strto_ll)(register const Wchar * __restrict str, |
Wchar ** __restrict endptr, int base, |
int sflag __LOCALE_PARAM ) |
{ |
unsigned long long number; |
#if _STRTO_ENDPTR |
const Wchar *fail_char; |
#define SET_FAIL(X) fail_char = (X) |
#else |
#define SET_FAIL(X) ((void)(X)) /* Keep side effects. */ |
#endif |
unsigned int n1; |
unsigned char negative, digit; |
|
assert(((unsigned int)sflag) <= 1); |
|
SET_FAIL(str); |
|
while (ISSPACE(*str)) { /* Skip leading whitespace. */ |
++str; |
} |
|
/* Handle optional sign. */ |
negative = 0; |
switch(*str) { |
case '-': negative = 1; /* Fall through to increment str. */ |
case '+': ++str; |
} |
|
if (!(base & ~0x10)) { /* Either dynamic (base = 0) or base 16. */ |
base += 10; /* Default is 10 (26). */ |
if (*str == '0') { |
SET_FAIL(++str); |
base -= 2; /* Now base is 8 or 16 (24). */ |
if ((0x20|(*str)) == 'x') { /* WARNING: assumes ascii. */ |
++str; |
base += base; /* Base is 16 (16 or 48). */ |
} |
} |
|
if (base > 16) { /* Adjust in case base wasn't dynamic. */ |
base = 16; |
} |
} |
|
number = 0; |
|
if (((unsigned)(base - 2)) < 35) { /* Legal base. */ |
do { |
digit = (((Wuchar)(*str - '0')) <= 9) |
? (*str - '0') |
: ((*str >= 'A') |
? (((0x20|(*str)) - 'a' + 10)) /* WARNING: assumes ascii. */ |
: 40); |
|
if (digit >= base) { |
break; |
} |
|
SET_FAIL(++str); |
|
#if 1 |
/* Optional, but speeds things up in the usual case. */ |
if (number <= (ULLONG_MAX >> 6)) { |
number = number * base + digit; |
} else |
#endif |
{ |
n1 = ((unsigned char) number) * base + digit; |
number = (number >> CHAR_BIT) * base; |
|
if (number + (n1 >> CHAR_BIT) <= (ULLONG_MAX >> CHAR_BIT)) { |
number = (number << CHAR_BIT) + n1; |
} else { /* Overflow. */ |
number = ULLONG_MAX; |
negative &= sflag; |
SET_ERRNO(ERANGE); |
} |
} |
|
} while (1); |
} |
|
#if _STRTO_ENDPTR |
if (endptr) { |
*endptr = (Wchar *) fail_char; |
} |
#endif |
|
{ |
unsigned long long tmp = ((negative) |
? ((unsigned long long)(-(1+LLONG_MIN)))+1 |
: LLONG_MAX); |
if (sflag && (number > tmp)) { |
number = tmp; |
SET_ERRNO(ERANGE); |
} |
} |
|
return negative ? (unsigned long long)(-((long long)number)) : number; |
} |
|
#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ |
|
#endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ |
|
#endif |
/**********************************************************************/ |
/* Made _Exit() an alias for _exit(), as per C99. */ |
/* #ifdef L__Exit */ |
|
/* void _Exit(int status) */ |
/* { */ |
/* _exit(status); */ |
/* } */ |
|
/* #endif */ |
/**********************************************************************/ |
#ifdef L_bsearch |
|
void *bsearch(const void *key, const void *base, size_t /* nmemb */ high, |
size_t size, int (*compar)(const void *, const void *)) |
{ |
register char *p; |
size_t low; |
size_t mid; |
int r; |
|
if (size > 0) { /* TODO: change this to an assert?? */ |
low = 0; |
while (low < high) { |
mid = low + ((high - low) >> 1); /* Avoid possible overflow here. */ |
p = ((char *)base) + mid * size; /* Could overflow here... */ |
r = (*compar)(key, p); /* but that's an application problem! */ |
if (r > 0) { |
low = mid + 1; |
} else if (r < 0) { |
high = mid; |
} else { |
return p; |
} |
} |
} |
return NULL; |
} |
|
#endif |
/**********************************************************************/ |
#ifdef L_qsort |
|
/* This code is derived from a public domain shell sort routine by |
* Ray Gardner and found in Bob Stout's snippets collection. The |
* original code is included below in an #if 0/#endif block. |
* |
* I modified it to avoid the possibility of overflow in the wgap |
* calculation, as well as to reduce the generated code size with |
* bcc and gcc. */ |
|
void qsort (void *base, |
size_t nel, |
size_t width, |
int (*comp)(const void *, const void *)) |
{ |
size_t wgap, i, j, k; |
char tmp; |
|
if ((nel > 1) && (width > 0)) { |
assert( nel <= ((size_t)(-1)) / width ); /* check for overflow */ |
wgap = 0; |
do { |
wgap = 3 * wgap + 1; |
} while (wgap < (nel-1)/3); |
/* From the above, we know that either wgap == 1 < nel or */ |
/* ((wgap-1)/3 < (int) ((nel-1)/3) <= (nel-1)/3 ==> wgap < nel. */ |
wgap *= width; /* So this can not overflow if wnel doesn't. */ |
nel *= width; /* Convert nel to 'wnel' */ |
do { |
i = wgap; |
do { |
j = i; |
do { |
register char *a; |
register char *b; |
|
j -= wgap; |
a = j + ((char *)base); |
b = a + wgap; |
if ( (*comp)(a, b) <= 0 ) { |
break; |
} |
k = width; |
do { |
tmp = *a; |
*a++ = *b; |
*b++ = tmp; |
} while ( --k ); |
} while (j >= wgap); |
i += width; |
} while (i < nel); |
wgap = (wgap - width)/3; |
} while (wgap); |
} |
} |
|
/* ---------- original snippets version below ---------- */ |
|
#if 0 |
/* |
** ssort() -- Fast, small, qsort()-compatible Shell sort |
** |
** by Ray Gardner, public domain 5/90 |
*/ |
|
#include <stddef.h> |
|
void ssort (void *base, |
size_t nel, |
size_t width, |
int (*comp)(const void *, const void *)) |
{ |
size_t wnel, gap, wgap, i, j, k; |
char *a, *b, tmp; |
|
wnel = width * nel; |
for (gap = 0; ++gap < nel;) |
gap *= 3; |
while ( gap /= 3 ) |
{ |
wgap = width * gap; |
for (i = wgap; i < wnel; i += width) |
{ |
for (j = i - wgap; ;j -= wgap) |
{ |
a = j + (char *)base; |
b = a + wgap; |
if ( (*comp)(a, b) <= 0 ) |
break; |
k = width; |
do |
{ |
tmp = *a; |
*a++ = *b; |
*b++ = tmp; |
} while ( --k ); |
if (j < wgap) |
break; |
} |
} |
} |
} |
#endif |
|
#endif |
/**********************************************************************/ |
#ifdef L__stdlib_mb_cur_max |
|
size_t _stdlib_mb_cur_max(void) |
{ |
#ifdef __CTYPE_HAS_UTF_8_LOCALES |
return __UCLIBC_CURLOCALE_DATA.mb_cur_max; |
#else |
#ifdef __CTYPE_HAS_8_BIT_LOCALES |
#ifdef __UCLIBC_MJN3_ONLY__ |
#warning need to change this when/if transliteration is implemented |
#endif |
#endif |
return 1; |
#endif |
} |
|
#endif |
/**********************************************************************/ |
#ifdef L_mblen |
|
int mblen(register const char *s, size_t n) |
{ |
static mbstate_t state; |
size_t r; |
|
if (!s) { |
state.mask = 0; |
#ifdef __CTYPE_HAS_UTF_8_LOCALES |
return ENCODING == __ctype_encoding_utf8; |
#else |
return 0; |
#endif |
} |
|
if ((r = mbrlen(s, n, &state)) == (size_t) -2) { |
/* TODO: Should we set an error state? */ |
state.wc = 0xffffU; /* Make sure we're in an error state. */ |
return (size_t) -1; /* TODO: Change error code above? */ |
} |
return r; |
} |
|
#endif |
/**********************************************************************/ |
#ifdef L_mbtowc |
|
int mbtowc(wchar_t *__restrict pwc, register const char *__restrict s, size_t n) |
{ |
static mbstate_t state; |
size_t r; |
|
if (!s) { |
state.mask = 0; |
#ifdef __CTYPE_HAS_UTF_8_LOCALES |
return ENCODING == __ctype_encoding_utf8; |
#else |
return 0; |
#endif |
} |
|
if ((r = mbrtowc(pwc, s, n, &state)) == (size_t) -2) { |
/* TODO: Should we set an error state? */ |
state.wc = 0xffffU; /* Make sure we're in an error state. */ |
return (size_t) -1; /* TODO: Change error code above? */ |
} |
return r; |
} |
|
#endif |
/**********************************************************************/ |
#ifdef L_wctomb |
|
/* Note: We completely ignore state in all currently supported conversions. */ |
|
int wctomb(register char *__restrict s, wchar_t swc) |
{ |
return (!s) |
? |
#ifdef __CTYPE_HAS_UTF_8_LOCALES |
(ENCODING == __ctype_encoding_utf8) |
#else |
0 /* Encoding is stateless. */ |
#endif |
: ((ssize_t) wcrtomb(s, swc, NULL)); |
} |
|
#endif |
/**********************************************************************/ |
#ifdef L_mbstowcs |
|
size_t mbstowcs(wchar_t * __restrict pwcs, const char * __restrict s, size_t n) |
{ |
mbstate_t state; |
const char *e = s; /* Needed because of restrict. */ |
|
state.mask = 0; /* Always start in initial shift state. */ |
return mbsrtowcs(pwcs, &e, n, &state); |
} |
|
#endif |
/**********************************************************************/ |
#ifdef L_wcstombs |
|
/* Note: We completely ignore state in all currently supported conversions. */ |
|
size_t wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n) |
{ |
const wchar_t *e = pwcs; /* Needed because of restrict. */ |
|
return wcsrtombs(s, &e, n, NULL); |
} |
|
#endif |
/**********************************************************************/ |
#if defined(L_wcstol) || defined(L_wcstol_l) |
|
#if (ULONG_MAX == UINTMAX_MAX) && !defined(L_wcstol_l) |
strong_alias(wcstol,wcstoimax) |
#endif |
|
#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) |
strong_alias(__XL(wcstol),__XL(wcstoll)) |
#endif |
|
long __XL(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 ); |
} |
|
__XL_ALIAS(wcstol) |
|
#endif |
/**********************************************************************/ |
#if defined(L_wcstoll) || defined(L_wcstoll_l) |
|
#if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) |
|
#if !defined(L_wcstoll_l) |
#if (ULLONG_MAX == UINTMAX_MAX) |
strong_alias(wcstoll,wcstoimax) |
#endif |
strong_alias(wcstoll,wcstoq) |
#endif |
|
long long __XL(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 ); |
} |
|
__XL_ALIAS(wcstoll) |
|
#endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ |
|
#endif |
/**********************************************************************/ |
#if defined(L_wcstoul) || defined(L_wcstoul_l) |
|
#if (ULONG_MAX == UINTMAX_MAX) && !defined(L_wcstoul_l) |
strong_alias(wcstoul,wcstoumax) |
#endif |
|
#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX) |
strong_alias(__XL(wcstoul),__XL(wcstoull)) |
#endif |
|
unsigned long __XL(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 ); |
} |
|
__XL_ALIAS(wcstoul) |
|
#endif |
/**********************************************************************/ |
#if defined(L_wcstoull) || defined(L_wcstoull_l) |
|
#if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) |
|
#if !defined(L_wcstoull_l) |
#if (ULLONG_MAX == UINTMAX_MAX) |
strong_alias(wcstoull,wcstoumax) |
#endif |
strong_alias(wcstoull,wcstouq) |
#endif |
|
unsigned long long __XL(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 ); |
} |
|
__XL_ALIAS(wcstoull) |
|
#endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */ |
|
#endif |
/**********************************************************************/ |
|
/unix_grantpt.c
0,0 → 1,203
/* Copyright (C) 1998 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998. |
|
The GNU C Library is free software; you can redistribute it and/or |
modify it under the terms of the GNU Library General Public License as |
published by the Free Software Foundation; either version 2 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 |
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., 59 Temple Place - Suite 330, |
Boston, MA 02111-1307, USA. */ |
|
#include <assert.h> |
#include <errno.h> |
#include <grp.h> |
#include <limits.h> |
#include <stdlib.h> |
#include <string.h> |
#include <sys/resource.h> |
#include <sys/stat.h> |
#include <sys/types.h> |
#include <sys/wait.h> |
#include <unistd.h> |
#include "pty-private.h" |
|
|
/* uClinux-2.0 has vfork, but Linux 2.0 doesn't */ |
#include <sys/syscall.h> |
#if ! defined __NR_vfork |
#define vfork fork |
#endif |
|
extern int ptsname_r (int fd, char *buf, size_t buflen); |
|
/* 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 |
this buffer, a sufficiently long buffer is allocated using malloc, |
and returned in PTS. 0 is returned upon success, -1 otherwise. */ |
static int |
pts_name (int fd, char **pts, size_t buf_len) |
{ |
int rv; |
char *buf = *pts; |
|
for (;;) |
{ |
char *new_buf; |
|
if (buf_len) |
{ |
rv = ptsname_r (fd, buf, buf_len); |
|
if (rv != 0 || memchr (buf, '\0', buf_len)) |
/* We either got an error, or we succeeded and the |
returned name fit in the buffer. */ |
break; |
|
/* Try again with a longer buffer. */ |
buf_len += buf_len; /* Double it */ |
} |
else |
/* No initial buffer; start out by mallocing one. */ |
buf_len = 128; /* First time guess. */ |
|
if (buf != *pts) |
/* We've already malloced another buffer at least once. */ |
new_buf = realloc (buf, buf_len); |
else |
new_buf = malloc (buf_len); |
if (! new_buf) |
{ |
rv = -1; |
errno = ENOMEM; |
break; |
} |
buf = new_buf; |
} |
|
if (rv == 0) |
*pts = buf; /* Return buffer to the user. */ |
else if (buf != *pts) |
free (buf); /* Free what we malloced when returning an error. */ |
|
return rv; |
} |
|
/* Change the ownership and access permission of the slave pseudo |
terminal associated with the master pseudo terminal specified |
by FD. */ |
int |
grantpt (int fd) |
{ |
int retval = -1; |
#ifdef PATH_MAX |
char _buf[PATH_MAX]; |
#else |
char _buf[512]; |
#endif |
char *buf = _buf; |
struct stat st; |
uid_t uid; |
gid_t gid; |
pid_t pid; |
|
if (pts_name (fd, &buf, sizeof (_buf))) |
return -1; |
|
if (stat(buf, &st) < 0) |
goto cleanup; |
|
/* Make sure that we own the device. */ |
uid = getuid (); |
if (st.st_uid != uid) |
{ |
if (chown (buf, uid, st.st_gid) < 0) |
goto helper; |
} |
|
gid = getgid (); |
|
/* Make sure the group of the device is that special group. */ |
if (st.st_gid != gid) |
{ |
if (chown (buf, uid, gid) < 0) |
goto helper; |
} |
|
/* Make sure the permission mode is set to readable and writable by |
the owner, and writable by the group. */ |
if ((st.st_mode & ACCESSPERMS) != (S_IRUSR|S_IWUSR|S_IWGRP)) |
{ |
if (chmod (buf, S_IRUSR|S_IWUSR|S_IWGRP) < 0) |
goto helper; |
} |
|
retval = 0; |
goto cleanup; |
|
/* We have to use the helper program. */ |
helper: |
|
pid = vfork (); |
if (pid == -1) |
goto cleanup; |
else if (pid == 0) |
{ |
/* Disable core dumps. */ |
struct rlimit rl = { 0, 0 }; |
setrlimit (RLIMIT_CORE, &rl); |
|
/* We pase the master pseudo terminal as file descriptor PTY_FILENO. */ |
if (fd != PTY_FILENO) |
if (dup2 (fd, PTY_FILENO) < 0) |
_exit (FAIL_EBADF); |
|
execle (_PATH_PT_CHOWN, _PATH_PT_CHOWN, NULL, NULL); |
_exit (FAIL_EXEC); |
} |
else |
{ |
int w; |
|
if (waitpid (pid, &w, 0) == -1) |
goto cleanup; |
if (!WIFEXITED (w)) |
errno = ENOEXEC; |
else |
switch (WEXITSTATUS(w)) |
{ |
case 0: |
retval = 0; |
break; |
case FAIL_EBADF: |
errno = EBADF; |
break; |
case FAIL_EINVAL: |
errno = EINVAL; |
break; |
case FAIL_EACCES: |
errno = EACCES; |
break; |
case FAIL_EXEC: |
errno = ENOEXEC; |
break; |
|
default: |
assert(! "getpt: internal error: invalid exit code from pt_chown"); |
} |
} |
|
cleanup: |
if (buf != _buf) |
free (buf); |
|
return retval; |
} |
/srand48.c
0,0 → 1,28
/* Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu <mailto:drepper@gnu.ai.mit.edu>>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <stdlib.h> |
|
/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ |
extern struct drand48_data __libc_drand48_data; |
|
void srand48 (long seedval) |
{ |
srand48_r (seedval, &__libc_drand48_data); |
} |
/getpt.c
0,0 → 1,110
/* Copyright (C) 1998, 1999 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998. |
|
The GNU C Library is free software; you can redistribute it and/or |
modify it under the terms of the GNU Library General Public License as |
published by the Free Software Foundation; either version 2 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 |
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., 59 Temple Place - Suite 330, |
Boston, MA 02111-1307, USA. */ |
|
#include <errno.h> |
#include <fcntl.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <paths.h> |
|
#if !defined __ASSUME_DEVPTS__ |
# include <sys/statfs.h> |
|
/* Constant that identifies the `devpts' filesystem. */ |
# define DEVPTS_SUPER_MAGIC 0x1cd1 |
/* Constant that identifies the `devfs' filesystem. */ |
# define DEVFS_SUPER_MAGIC 0x1373 |
#endif |
|
/* Path to the master pseudo terminal cloning device. */ |
#define _PATH_DEVPTMX _PATH_DEV "ptmx" |
/* Directory containing the UNIX98 pseudo terminals. */ |
#define _PATH_DEVPTS _PATH_DEV "pts" |
|
#if !defined __UNIX98PTY_ONLY__ |
/* Prototype for function that opens BSD-style master pseudo-terminals. */ |
int __bsd_getpt (void); |
#endif |
|
/* Open a master pseudo terminal and return its file descriptor. */ |
int |
getpt (void) |
{ |
#if !defined __UNIX98PTY_ONLY__ |
static int have_no_dev_ptmx; |
#endif |
int fd; |
|
#if !defined __UNIX98PTY_ONLY__ |
if (!have_no_dev_ptmx) |
#endif |
{ |
fd = open (_PATH_DEVPTMX, O_RDWR); |
if (fd != -1) |
{ |
#if defined __ASSUME_DEVPTS__ |
return fd; |
#else |
struct statfs fsbuf; |
static int devpts_mounted; |
|
/* Check that the /dev/pts filesystem is mounted |
or if /dev is a devfs filesystem (this implies /dev/pts). */ |
if (devpts_mounted |
|| (statfs (_PATH_DEVPTS, &fsbuf) == 0 |
&& fsbuf.f_type == DEVPTS_SUPER_MAGIC) |
|| (statfs (_PATH_DEV, &fsbuf) == 0 |
&& fsbuf.f_type == DEVFS_SUPER_MAGIC)) |
{ |
/* Everything is ok. */ |
devpts_mounted = 1; |
return fd; |
} |
|
/* If /dev/pts is not mounted then the UNIX98 pseudo terminals |
are not usable. */ |
close (fd); |
#if !defined __UNIX98PTY_ONLY__ |
have_no_dev_ptmx = 1; |
#endif |
#endif |
} |
else |
{ |
#if !defined __UNIX98PTY_ONLY__ |
if (errno == ENOENT || errno == ENODEV) |
have_no_dev_ptmx = 1; |
else |
#endif |
return -1; |
} |
} |
|
#if !defined __UNIX98PTY_ONLY__ |
return __bsd_getpt (); |
#endif |
} |
|
#if !defined __UNIX98PTY_ONLY__ |
# define PTYNAME1 "pqrstuvwxyzabcde"; |
# define PTYNAME2 "0123456789abcdef"; |
|
# define __getpt __bsd_getpt |
# include "bsd_getpt.c" |
#endif |
/system.c
0,0 → 1,55
#include <stdio.h> |
#include <stddef.h> |
#include <signal.h> |
#include <unistd.h> |
#include <sys/wait.h> |
|
/* uClinux-2.0 has vfork, but Linux 2.0 doesn't */ |
#include <sys/syscall.h> |
#if ! defined __NR_vfork |
#define vfork fork |
#endif |
|
int __libc_system(char *command) |
{ |
int wait_val, pid; |
__sighandler_t save_quit, save_int, save_chld; |
|
if (command == 0) |
return 1; |
|
save_quit = signal(SIGQUIT, SIG_IGN); |
save_int = signal(SIGINT, SIG_IGN); |
save_chld = signal(SIGCHLD, SIG_DFL); |
|
if ((pid = vfork()) < 0) { |
signal(SIGQUIT, save_quit); |
signal(SIGINT, save_int); |
signal(SIGCHLD, save_chld); |
return -1; |
} |
if (pid == 0) { |
signal(SIGQUIT, SIG_DFL); |
signal(SIGINT, SIG_DFL); |
signal(SIGCHLD, SIG_DFL); |
|
execl("/bin/sh", "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) |
wait_val = -1; |
|
signal(SIGQUIT, save_quit); |
signal(SIGINT, save_int); |
signal(SIGCHLD, save_chld); |
return wait_val; |
} |
weak_alias(__libc_system, system) |
/strtold.c
0,0 → 1,32
/* vi: set sw=4 ts=4: */ |
/* strtold for uClibc |
* |
* Copyright (C) 2002 by Erik Andersen <andersen@uclibc.org> |
* |
* This program is free software; you can redistribute it and/or modify it |
* under the terms of the GNU Library General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or (at your |
* option) any later version. |
* |
* This program 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 Library General Public License |
* 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 |
* |
*/ |
|
/* This implementation is a bit lame, since we are actually making the compiler |
* to an internal conversion from a double to a long double, thereby losing |
* tons of precision. But this is small, and works for now... */ |
|
#include <stdlib.h> |
|
long double strtold (const char *str, char **endptr) |
{ |
return(strtod(str,endptr)); |
} |
|
/seed48.c
0,0 → 1,30
/* Copyright (C) 1995,1996,1997,1998,2001,2002 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <stdlib.h> |
|
/* Global state for non-reentrant functions. Defined in drand48-iter.c. */ |
extern struct drand48_data __libc_drand48_data; |
|
unsigned short int * |
seed48 (unsigned short int seed16v[3]) |
{ |
(void) seed48_r (seed16v, &__libc_drand48_data); |
return __libc_drand48_data.__old_x; |
} |
/Makefile
0,0 → 1,144
# Makefile for uClibc |
# |
# Copyright (C) 2000 by Lineo, inc. |
# Copyright (C) 2000,2001 Erik Andersen <andersen@uclibc.org> |
# |
# This program is free software; you can redistribute it and/or modify it under |
# the terms of the GNU Library General Public License as published by the Free |
# Software Foundation; either version 2 of the License, or (at your option) any |
# later version. |
# |
# This program 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 Library General Public License 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 |
# |
# Derived in part from the Linux-8086 C library, the GNU C Library, and several |
# other sundry sources. Files within this library are copyright by their |
# respective copyright holders. |
|
TOPDIR=../../ |
include $(TOPDIR)Rules.mak |
|
DIRS:= |
ifeq ($(MALLOC),y) |
DIRS+=malloc |
endif |
ifeq ($(MALLOC_SIMPLE),y) |
DIRS+=malloc-simple |
endif |
ifeq ($(MALLOC_STANDARD),y) |
DIRS+=malloc-standard |
endif |
|
|
MSRC = stdlib.c |
MOBJ = abs.o labs.o atoi.o atol.o strtol.o strtoul.o _stdlib_strto_l.o \ |
qsort.o bsearch.o \ |
llabs.o atoll.o strtoll.o strtoull.o _stdlib_strto_ll.o |
# (aliases) strtoq.o strtouq.o |
ifeq ($(UCLIBC_HAS_XLOCALE),y) |
|
MOBJx = |
MOBJx += strtol_l.o strtoul_l.o _stdlib_strto_l_l.o \ |
strtoll_l.o strtoull_l.o _stdlib_strto_ll_l.o |
endif |
|
MSRC1 = strtod.c |
MOBJ1 = |
MOBJ1x = |
|
ifeq ($(UCLIBC_HAS_FLOATS),y) |
MOBJ += atof.o |
MOBJ1 += strtod.o strtof.o strtold.o __strtofpmax.o __fp_range_check.o |
ifeq ($(UCLIBC_HAS_XLOCALE),y) |
MOBJ1x += strtod_l.o strtof_l.o strtold_l.o __strtofpmax_l.o |
endif |
ifeq ($(UCLIBC_HAS_WCHAR),y) |
MOBJ1 += wcstod.o wcstof.o wcstold.o __wcstofpmax.o |
ifeq ($(UCLIBC_HAS_XLOCALE),y) |
MOBJ1x += wcstod_l.o wcstof_l.o wcstold_l.o __wcstofpmax_l.o |
endif |
endif |
endif |
|
ifeq ($(UCLIBC_HAS_WCHAR),y) |
MOBJ += mblen.o mbtowc.o wctomb.o mbstowcs.o wcstombs.o \ |
_stdlib_mb_cur_max.o _stdlib_wcsto_l.o _stdlib_wcsto_ll.o \ |
wcstol.o wcstoul.o wcstoll.o wcstoull.o |
ifeq ($(UCLIBC_HAS_XLOCALE),y) |
MOBJx += _stdlib_wcsto_l_l.o _stdlib_wcsto_ll_l.o \ |
wcstol_l.o wcstoul_l.o wcstoll_l.o wcstoull_l.o |
endif |
endif |
# (aliases) wcstoq.o wcstouq.o |
# wcstod wcstof wcstold |
|
MSRC2 = atexit.c |
MOBJ2 = atexit.o on_exit.o __exit_handler.o exit.o |
|
CSRC = abort.c getenv.c mkdtemp.c mktemp.c realpath.c mkstemp.c mkstemp64.c \ |
rand.c random.c random_r.c setenv.c system.c div.c ldiv.c getpt.c \ |
ptsname.c grantpt.c unlockpt.c gcvt.c drand48-iter.c jrand48.c \ |
jrand48_r.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 |
ifeq ($(UCLIBC_HAS_FLOATS),y) |
CSRC += drand48.c drand48_r.c erand48.c erand48_r.c |
endif |
COBJS=$(patsubst %.c,%.o, $(CSRC)) |
|
OBJS=$(MOBJ) $(MOBJx) $(MOBJ1) $(MOBJ1x) $(MOBJ2) $(COBJS) |
|
all: $(OBJS) $(LIBC) |
|
$(LIBC): ar-target subdirs |
|
ar-target: $(OBJS) |
$(AR) $(ARFLAGS) $(LIBC) $(OBJS) |
|
$(MOBJ): $(MSRC) |
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o |
$(STRIPTOOL) -x -R .note -R .comment $*.o |
|
$(MOBJx): $(MSRC) |
$(CC) $(CFLAGS) -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o |
$(STRIPTOOL) -x -R .note -R .comment $*.o |
|
$(MOBJ1): $(MSRC1) |
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o |
$(STRIPTOOL) -x -R .note -R .comment $*.o |
|
$(MOBJ1x): $(MSRC1) |
$(CC) $(CFLAGS) -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o |
$(STRIPTOOL) -x -R .note -R .comment $*.o |
|
$(MOBJ2): $(MSRC2) |
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o |
$(STRIPTOOL) -x -R .note -R .comment $*.o |
|
$(COBJS): %.o : %.c |
$(CC) $(CFLAGS) -c $< -o $@ |
$(STRIPTOOL) -x -R .note -R .comment $*.o |
|
$(OBJ): Makefile |
|
subdirs: $(patsubst %, _dir_%, $(DIRS)) |
subdirs_clean: $(patsubst %, _dirclean_%, $(ALL_SUBDIRS)) |
|
$(patsubst %, _dir_%, $(DIRS)) : dummy |
$(MAKE) -C $(patsubst _dir_%, %, $@) |
|
$(patsubst %, _dirclean_%, $(ALL_SUBDIRS)) : dummy |
$(MAKE) -C $(patsubst _dirclean_%, %, $@) clean |
|
clean: subdirs_clean |
$(RM) *.[oa] *~ core |
|
.PHONY: dummy |
|
|
/mktemp.c
0,0 → 1,33
/* Copyright (C) 1998 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 Library General Public License as |
published by the Free Software Foundation; either version 2 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 |
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., 59 Temple Place - Suite 330, |
Boston, MA 02111-1307, USA. */ |
|
#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. */ |
char * mktemp (char *template) |
{ |
if (__gen_tempname (template, __GT_NOCREATE) < 0) |
/* We return the null string if we can't find a unique file name. */ |
template[0] = '\0'; |
|
return template; |
} |
/ldiv.c
0,0 → 1,32
/* vi: set sw=4 ts=4: */ |
/* ldiv for uClibc |
* |
* Copyright (C) 2000 by Lineo, inc. and Erik Andersen |
* Copyright (C) 2000,2001 by Erik Andersen <andersen@uclibc.org> |
* Written by Erik Andersen <andersen@uclibc.org> |
* |
* This program is free software; you can redistribute it and/or modify it |
* under the terms of the GNU Library General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or (at your |
* option) any later version. |
* |
* This program 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 Library General Public License |
* 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 |
*/ |
|
#include <stdlib.h> |
|
ldiv_t ldiv(long numer, long denom) |
{ |
ldiv_t result; |
result.quot = numer / denom; |
result.rem = numer - (result.quot * denom); |
return(result); |
} |
|
/random_r.c
0,0 → 1,365
/* |
* Copyright (c) 1983 Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms are permitted |
* provided that the above copyright notice and this paragraph are |
* duplicated in all such forms and that any documentation, |
* advertising materials, and other materials related to such |
* distribution and use acknowledge that the software was developed |
* by the University of California, Berkeley. The name of the |
* University may not be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
*/ |
|
/* |
* This is derived from the Berkeley source: |
* @(#)random.c 5.5 (Berkeley) 7/6/88 |
* It was reworked for the GNU C Library by Roland McGrath. |
* Rewritten to be reentrant by Ulrich Drepper, 1995 |
*/ |
|
#define _GNU_SOURCE |
#include <features.h> |
#include <errno.h> |
#include <limits.h> |
#include <stddef.h> |
#include <stdlib.h> |
|
|
|
/* An improved random number generation package. In addition to the standard |
rand()/srand() like interface, this package also has a special state info |
interface. The initstate() routine is called with a seed, an array of |
bytes, and a count of how many bytes are being passed in; this array is |
then initialized to contain information for random number generation with |
that much state information. Good sizes for the amount of state |
information are 32, 64, 128, and 256 bytes. The state can be switched by |
calling the setstate() function with the same array as was initialized |
with initstate(). By default, the package runs with 128 bytes of state |
information and generates far better random numbers than a linear |
congruential generator. If the amount of state information is less than |
32 bytes, a simple linear congruential R.N.G. is used. Internally, the |
state information is treated as an array of longs; the zeroth element of |
the array is the type of R.N.G. being used (small integer); the remainder |
of the array is the state information for the R.N.G. Thus, 32 bytes of |
state information will give 7 longs worth of state information, which will |
allow a degree seven polynomial. (Note: The zeroth word of state |
information also has some other information stored in it; see setstate |
for details). The random number generation technique is a linear feedback |
shift register approach, employing trinomials (since there are fewer terms |
to sum up that way). In this approach, the least significant bit of all |
the numbers in the state table will act as a linear feedback shift register, |
and will have period 2^deg - 1 (where deg is the degree of the polynomial |
being used, assuming that the polynomial is irreducible and primitive). |
The higher order bits will have longer periods, since their values are |
also influenced by pseudo-random carries out of the lower bits. The |
total period of the generator is approximately deg*(2**deg - 1); thus |
doubling the amount of state information has a vast influence on the |
period of the generator. Note: The deg*(2**deg - 1) is an approximation |
only good for large deg, when the period of the shift register is the |
dominant factor. With deg equal to seven, the period is actually much |
longer than the 7*(2**7 - 1) predicted by this formula. */ |
|
|
|
/* 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. */ |
|
/* Linear congruential. */ |
#define TYPE_0 0 |
#define BREAK_0 8 |
#define DEG_0 0 |
#define SEP_0 0 |
|
/* x**7 + x**3 + 1. */ |
#define TYPE_1 1 |
#define BREAK_1 32 |
#define DEG_1 7 |
#define SEP_1 3 |
|
/* x**15 + x + 1. */ |
#define TYPE_2 2 |
#define BREAK_2 64 |
#define DEG_2 15 |
#define SEP_2 1 |
|
/* x**31 + x**3 + 1. */ |
#define TYPE_3 3 |
#define BREAK_3 128 |
#define DEG_3 31 |
#define SEP_3 3 |
|
/* x**63 + x + 1. */ |
#define TYPE_4 4 |
#define BREAK_4 256 |
#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. */ |
|
struct random_poly_info |
{ |
int seps[MAX_TYPES]; |
int degrees[MAX_TYPES]; |
}; |
|
static const struct random_poly_info random_poly_info = |
{ |
{ SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }, |
{ DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 } |
}; |
|
|
|
|
/* Initialize the random number generator based on the given seed. If the |
type is the trivial no-state-information type, just remember the seed. |
Otherwise, initializes state[] based on the given "seed" via a linear |
congruential generator. Then, the pointers are set to known locations |
that are exactly rand_sep places apart. Lastly, it cycles the state |
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. */ |
int srandom_r (unsigned int seed, struct random_data *buf) |
{ |
int type; |
int32_t *state; |
long int i; |
long int word; |
int32_t *dst; |
int kc; |
|
if (buf == NULL) |
goto fail; |
type = buf->rand_type; |
if ((unsigned int) type >= MAX_TYPES) |
goto fail; |
|
state = buf->state; |
/* We must make sure the seed is not 0. Take arbitrarily 1 in this case. */ |
if (seed == 0) |
seed = 1; |
state[0] = seed; |
if (type == TYPE_0) |
goto done; |
|
dst = state; |
word = seed; |
kc = buf->rand_deg; |
for (i = 1; i < kc; ++i) |
{ |
/* This does: |
state[i] = (16807 * state[i - 1]) % 2147483647; |
but avoids overflowing 31 bits. */ |
long int hi = word / 127773; |
long int lo = word % 127773; |
word = 16807 * lo - 2836 * hi; |
if (word < 0) |
word += 2147483647; |
*++dst = word; |
} |
|
buf->fptr = &state[buf->rand_sep]; |
buf->rptr = &state[0]; |
kc *= 10; |
while (--kc >= 0) |
{ |
int32_t discard; |
(void) random_r (buf, &discard); |
} |
|
done: |
return 0; |
|
fail: |
return -1; |
} |
|
/* Initialize the state information in the given array of N bytes for |
future random number generation. Based on the number of bytes we |
are given, and the break values for the different R.N.G.'s, we choose |
the best (largest) one we can and set things up for it. srandom is |
then called to initialize the state information. Note that on return |
from srandom, we set state[-1] to be the type multiplexed with the current |
value of the rear pointer; this is so successive calls to initstate won't |
lose this information and will be able to restart with setstate. |
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. */ |
int initstate_r (seed, arg_state, n, buf) |
unsigned int seed; |
char *arg_state; |
size_t n; |
struct random_data *buf; |
{ |
int type; |
int degree; |
int separation; |
int32_t *state; |
|
if (buf == NULL) |
goto fail; |
|
if (n >= BREAK_3) |
type = n < BREAK_4 ? TYPE_3 : TYPE_4; |
else if (n < BREAK_1) |
{ |
if (n < BREAK_0) |
{ |
__set_errno (EINVAL); |
goto fail; |
} |
type = TYPE_0; |
} |
else |
type = n < BREAK_2 ? TYPE_1 : TYPE_2; |
|
degree = random_poly_info.degrees[type]; |
separation = random_poly_info.seps[type]; |
|
buf->rand_type = type; |
buf->rand_sep = separation; |
buf->rand_deg = degree; |
state = &((int32_t *) arg_state)[1]; /* First location. */ |
/* Must set END_PTR before srandom. */ |
buf->end_ptr = &state[degree]; |
|
buf->state = state; |
|
srandom_r (seed, buf); |
|
state[-1] = TYPE_0; |
if (type != TYPE_0) |
state[-1] = (buf->rptr - state) * MAX_TYPES + type; |
|
return 0; |
|
fail: |
__set_errno (EINVAL); |
return -1; |
} |
|
/* Restore the state from the given state array. |
Note: It is important that we also remember the locations of the pointers |
in the current state information, and restore the locations of the pointers |
from the old state information. This is done by multiplexing the pointer |
location into the zeroth word of the state information. Note that due |
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. */ |
int setstate_r (char *arg_state, struct random_data *buf) |
{ |
int32_t *new_state = 1 + (int32_t *) arg_state; |
int type; |
int old_type; |
int32_t *old_state; |
int degree; |
int separation; |
|
if (arg_state == NULL || buf == NULL) |
goto fail; |
|
old_type = buf->rand_type; |
old_state = buf->state; |
if (old_type == TYPE_0) |
old_state[-1] = TYPE_0; |
else |
old_state[-1] = (MAX_TYPES * (buf->rptr - old_state)) + old_type; |
|
type = new_state[-1] % MAX_TYPES; |
if (type < TYPE_0 || type > TYPE_4) |
goto fail; |
|
buf->rand_deg = degree = random_poly_info.degrees[type]; |
buf->rand_sep = separation = random_poly_info.seps[type]; |
buf->rand_type = type; |
|
if (type != TYPE_0) |
{ |
int rear = new_state[-1] / MAX_TYPES; |
buf->rptr = &new_state[rear]; |
buf->fptr = &new_state[(rear + separation) % degree]; |
} |
buf->state = new_state; |
/* Set end_ptr too. */ |
buf->end_ptr = &new_state[degree]; |
|
return 0; |
|
fail: |
__set_errno (EINVAL); |
return -1; |
} |
|
/* 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 |
set up. The basic operation is to add the number at the rear pointer into |
the one at the front pointer. Then both pointers are advanced to the next |
location cyclically in the table. The value returned is the sum generated, |
reduced to 31 bits by throwing away the "least random" low bit. |
Note: The code takes advantage of the fact that both the front and |
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. */ |
|
int random_r (buf, result) |
struct random_data *buf; |
int32_t *result; |
{ |
int32_t *state; |
|
if (buf == NULL || result == NULL) |
goto fail; |
|
state = buf->state; |
|
if (buf->rand_type == TYPE_0) |
{ |
int32_t val = state[0]; |
val = ((state[0] * 1103515245) + 12345) & 0x7fffffff; |
state[0] = val; |
*result = val; |
} |
else |
{ |
int32_t *fptr = buf->fptr; |
int32_t *rptr = buf->rptr; |
int32_t *end_ptr = buf->end_ptr; |
int32_t val; |
|
val = *fptr += *rptr; |
/* Chucking least random bit. */ |
*result = (val >> 1) & 0x7fffffff; |
++fptr; |
if (fptr >= end_ptr) |
{ |
fptr = state; |
++rptr; |
} |
else |
{ |
++rptr; |
if (rptr >= end_ptr) |
rptr = state; |
} |
buf->fptr = fptr; |
buf->rptr = rptr; |
} |
return 0; |
|
fail: |
__set_errno (EINVAL); |
return -1; |
} |
|
/gcvt.c
0,0 → 1,11
#include <stdio.h> |
#include <stdlib.h> |
|
#ifdef __UCLIBC_HAS_FLOATS__ |
#define MAX_NDIGIT 17 |
char *gcvt (double number, int ndigit, char *buf) |
{ |
sprintf(buf, "%.*g", (ndigit > MAX_NDIGIT)? MAX_NDIGIT : ndigit, number); |
return buf; |
} |
#endif |
/rand_r.c
0,0 → 1,48
/* Reentrant random function frm POSIX.1c. |
Copyright (C) 1996, 1999 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@cygnus.com <mailto:drepper@cygnus.com>>, 1996. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <stdlib.h> |
|
|
/* This algorithm is mentioned in the ISO C standard, here extended |
for 32 bits. */ |
int rand_r (unsigned int *seed) |
{ |
unsigned int next = *seed; |
int result; |
|
next *= 1103515245; |
next += 12345; |
result = (unsigned int) (next / 65536) % 2048; |
|
next *= 1103515245; |
next += 12345; |
result <<= 10; |
result ^= (unsigned int) (next / 65536) % 1024; |
|
next *= 1103515245; |
next += 12345; |
result <<= 10; |
result ^= (unsigned int) (next / 65536) % 1024; |
|
*seed = next; |
|
return result; |
} |
/ptsname.c
0,0 → 1,191
/* Copyright (C) 1998 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998. |
|
The GNU C Library is free software; you can redistribute it and/or |
modify it under the terms of the GNU Library General Public License as |
published by the Free Software Foundation; either version 2 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 |
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., 59 Temple Place - Suite 330, |
Boston, MA 02111-1307, USA. */ |
|
#define _STDIO_UTILITY /* For _int10tostr. */ |
#include <stdio.h> |
#include <errno.h> |
#include <paths.h> |
#include <stdlib.h> |
#include <string.h> |
#include <sys/ioctl.h> |
#include <sys/stat.h> |
#include <sys/sysmacros.h> |
#include <termios.h> |
#include <unistd.h> |
|
|
#if !defined __UNIX98PTY_ONLY__ |
|
/* Check if DEV corresponds to a master pseudo terminal device. */ |
#define MASTER_P(Dev) \ |
(major ((Dev)) == 2 \ |
|| (major ((Dev)) == 4 && minor ((Dev)) >= 128 && minor ((Dev)) < 192) \ |
|| (major ((Dev)) >= 128 && major ((Dev)) < 136)) |
|
/* Check if DEV corresponds to a master pseudo terminal device. */ |
#define SLAVE_P(Dev) \ |
(major ((Dev)) == 3 \ |
|| (major ((Dev)) == 4 && minor ((Dev)) >= 192 && minor ((Dev)) < 256) \ |
|| (major ((Dev)) >= 136 && major ((Dev)) < 144)) |
|
/* Note that major number 4 corresponds to the old BSD style pseudo |
terminal devices. As of Linux 2.1.115 these are no longer |
supported. They have been replaced by major numbers 2 (masters) |
and 3 (slaves). */ |
|
/* The are declared in getpt.c. */ |
extern const char _ptyname1[]; |
extern const char _ptyname2[]; |
|
#endif |
|
/* Directory where we can find the slave pty nodes. */ |
#define _PATH_DEVPTS "/dev/pts/" |
|
/* 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. */ |
int ptsname_r (int fd, char *buf, size_t buflen) |
{ |
int save_errno = errno; |
#if !defined __UNIX98PTY_ONLY__ |
struct stat st; |
#endif |
int ptyno; |
|
if (buf == NULL) |
{ |
errno = EINVAL; |
return EINVAL; |
} |
|
#if !defined __UNIX98PTY_ONLY__ |
if (!isatty (fd)) |
{ |
errno = ENOTTY; |
return ENOTTY; |
} |
#elif !defined TIOCGPTN |
# error "__UNIX98PTY_ONLY__ enabled but TIOCGPTN ioctl not supported by your kernel." |
#endif |
#ifdef TIOCGPTN |
if (ioctl (fd, TIOCGPTN, &ptyno) == 0) |
{ |
/* Buffer we use to print the number in. */ |
char numbuf[__BUFLEN_INT10TOSTR]; |
static const char devpts[] = _PATH_DEVPTS; |
char *p; |
|
p = _int10tostr(&numbuf[sizeof numbuf - 1], ptyno); |
|
if (buflen < sizeof devpts + &numbuf[sizeof numbuf - 1] - p) |
{ |
errno = ERANGE; |
return ERANGE; |
} |
|
strcpy (buf, devpts); |
strcat (buf, p); |
/* Note: Don't bother with stat on the slave name and checking the |
driver's major device number - the ioctl above succeeded so |
we know the fd was a Unix'98 master and the /dev/pts/ prefix |
is set by definition. If the name isn't really a slave PTY, |
the system is misconfigured anyway - something else will fail |
later. |
*/ |
errno = save_errno; |
return 0; |
} |
#endif |
#if defined __UNIX98PTY_ONLY__ |
else |
{ |
/* If the ioctl fails it wasn't a Unix 98 master PTY */ |
errno = ENOTTY; |
return ENOTTY; |
} |
#else |
# if !defined TIOCGPTN |
else if (errno == EINVAL) |
# endif |
{ |
char *p; |
|
if (buflen < strlen (_PATH_TTY) + 3) |
{ |
errno = ERANGE; |
return ERANGE; |
} |
|
if (fstat (fd, &st) < 0) |
return errno; |
|
/* Check if FD really is a master pseudo terminal. */ |
if (! MASTER_P (st.st_rdev)) |
{ |
errno = ENOTTY; |
return ENOTTY; |
} |
|
ptyno = minor (st.st_rdev); |
/* This is for the old BSD pseudo terminals. As of Linux |
2.1.115 these are no longer supported. */ |
if (major (st.st_rdev) == 4) |
ptyno -= 128; |
|
if (ptyno / 16 >= strlen (_ptyname1)) |
{ |
errno = ENOTTY; |
return ENOTTY; |
} |
|
strcpy (buf, _PATH_TTY); |
p = buf + strlen (buf); |
p[0] = _ptyname1[ptyno / 16]; |
p[1] = _ptyname2[ptyno % 16]; |
p[2] = '\0'; |
} |
|
if (stat(buf, &st) < 0) |
return errno; |
|
/* Check if the name we're about to return really corresponds to a |
slave pseudo terminal. */ |
if (! S_ISCHR (st.st_mode) || ! SLAVE_P (st.st_rdev)) |
{ |
/* This really is a configuration problem. */ |
errno = ENOTTY; |
return ENOTTY; |
} |
#endif |
|
errno = save_errno; |
return 0; |
} |
|
/* Return the pathname of the pseudo terminal slave assoicated with |
the master FD is open on, or NULL on errors. |
The returned storage is good until the next call to this function. */ |
char * |
ptsname (int fd) |
{ |
static char buffer[sizeof (_PATH_DEVPTS) + 20]; |
|
return ptsname_r (fd, buffer, sizeof (buffer)) != 0 ? NULL : buffer; |
} |
/abort.c
0,0 → 1,126
/* Copyright (C) 1991 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 Library General Public License as |
published by the Free Software Foundation; either version 2 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 |
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. */ |
|
/* Hacked up for uClibc by Erik Andersen */ |
|
#define _GNU_SOURCE |
#include <features.h> |
#include <signal.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <unistd.h> |
#include <signal.h> |
#include <errno.h> |
|
|
/* Our last ditch effort to commit suicide */ |
#if defined(__i386__) |
#define ABORT_INSTRUCTION asm ("hlt") |
#elif defined(__ia64__) |
#define ABORT_INSTRUCTION asm ("break 0") |
#elif defined(__mc68000__) |
#define ABORT_INSTRUCTION asm (".long 0xffffffff") |
#elif defined(__mips__) |
#define ABORT_INSTRUCTION asm ("break 255") |
#elif defined(__s390__) |
#define ABORT_INSTRUCTION asm (".word 0") |
#elif defined(__sparc__) |
#define ABORT_INSTRUCTION asm ("unimp 0xf00") |
#elif defined(__x86_64__) |
#define ABORT_INSTRUCTION asm ("hlt") |
#else |
#define ABORT_INSTRUCTION |
#endif |
|
extern void weak_function _stdio_term(void); |
extern void _exit __P((int __status)) __attribute__ ((__noreturn__)); |
static int been_there_done_that = 0; |
|
/* Be prepared in case multiple threads try to abort(). */ |
#ifdef __UCLIBC_HAS_THREADS__ |
#include <pthread.h> |
static pthread_mutex_t mylock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; |
# define LOCK __pthread_mutex_lock(&mylock) |
# define UNLOCK __pthread_mutex_unlock(&mylock); |
#else |
# define LOCK |
# define UNLOCK |
#endif |
|
|
/* Cause an abnormal program termination with core-dump. */ |
void abort(void) |
{ |
sigset_t sigset; |
|
/* Make sure we acquire the lock before proceeding. */ |
LOCK; |
|
/* Unmask SIGABRT to be sure we can get it */ |
if (__sigemptyset(&sigset) == 0 && __sigaddset(&sigset, SIGABRT) == 0) { |
sigprocmask(SIG_UNBLOCK, &sigset, (sigset_t *) NULL); |
} |
|
/* 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(); |
|
while (1) { |
/* Try to suicide with a SIGABRT. */ |
if (been_there_done_that == 0) { |
been_there_done_that++; |
UNLOCK; |
raise(SIGABRT); |
LOCK; |
} |
|
/* Still here? Try to remove any signal handlers. */ |
if (been_there_done_that == 1) { |
struct sigaction act; |
|
been_there_done_that++; |
memset (&act, '\0', sizeof (struct sigaction)); |
act.sa_handler = SIG_DFL; |
__sigfillset (&act.sa_mask); |
act.sa_flags = 0; |
sigaction (SIGABRT, &act, NULL); |
} |
|
/* Still here? Try to suicide with an illegal instruction */ |
if (been_there_done_that == 2) { |
been_there_done_that++; |
ABORT_INSTRUCTION; |
} |
|
/* Still here? Try to at least exit */ |
if (been_there_done_that == 3) { |
been_there_done_that++; |
_exit (127); |
} |
|
/* Still here? We're screwed. Sleepy time. Good night */ |
while (1) |
/* Try for ever and ever. */ |
ABORT_INSTRUCTION; |
} |
} |
|
/bsd_getpt.c
0,0 → 1,78
/* Copyright (C) 1998, 1999 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998. |
|
The GNU C Library is free software; you can redistribute it and/or |
modify it under the terms of the GNU Library General Public License as |
published by the Free Software Foundation; either version 2 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 |
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., 59 Temple Place - Suite 330, |
Boston, MA 02111-1307, USA. */ |
|
#include <errno.h> |
#include <fcntl.h> |
#include <string.h> |
#include <unistd.h> |
|
|
/* Prefix for master pseudo terminal nodes. */ |
#define _PATH_PTY "/dev/pty" |
|
|
/* Letters indicating a series of pseudo terminals. */ |
#ifndef PTYNAME1 |
#define PTYNAME1 "pqrsPQRS" |
#endif |
const char _ptyname1[] = PTYNAME1; |
|
/* Letters indicating the position within a series. */ |
#ifndef PTYNAME2 |
#define PTYNAME2 "0123456789abcdefghijklmnopqrstuv"; |
#endif |
const char _ptyname2[] = PTYNAME2; |
|
|
/* Open a master pseudo terminal and return its file descriptor. */ |
int |
__getpt (void) |
{ |
char buf[sizeof (_PATH_PTY) + 2]; |
const char *p, *q; |
char *s; |
|
memcpy (buf, _PATH_PTY, sizeof (_PATH_PTY)); |
s = buf + strlen (buf); |
|
/* s[0] and s[1] will be filled in the loop. */ |
s[2] = '\0'; |
|
for (p = _ptyname1; *p != '\0'; ++p) |
{ |
s[0] = *p; |
|
for (q = _ptyname2; *q != '\0'; ++q) |
{ |
int fd; |
|
s[1] = *q; |
|
fd = open (buf, O_RDWR); |
if (fd != -1) |
return fd; |
|
if (errno == ENOENT) |
return -1; |
} |
} |
|
errno = ENOENT; |
return -1; |
} |
/malloc-simple/alloc.c
0,0 → 1,204
/* alloc.c |
* |
* Written by Erik Andersen <andersee@debian.org> |
* LGPLv2 |
* |
* Parts of the memalign code were stolen from malloc-930716. |
*/ |
|
#include <features.h> |
#include <unistd.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <unistd.h> |
#include <sys/mman.h> |
|
|
#ifdef L_malloc |
void *malloc(size_t size) |
{ |
void *result; |
|
if (unlikely(size == 0)) { |
#if defined(__MALLOC_GLIBC_COMPAT__) |
size++; |
#else |
/* Some programs will call malloc (0). Lets be strict and return NULL */ |
return 0; |
#endif |
} |
|
#ifdef __UCLIBC_HAS_MMU__ |
result = mmap((void *) 0, size + sizeof(size_t), PROT_READ | PROT_WRITE, |
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
if (result == MAP_FAILED) |
return 0; |
* (size_t *) result = size; |
return(result + sizeof(size_t)); |
#else |
result = mmap((void *) 0, size, PROT_READ | PROT_WRITE, |
MAP_SHARED | MAP_ANONYMOUS, -1, 0); |
if (result == MAP_FAILED) |
return 0; |
return(result); |
#endif |
} |
#endif |
|
#ifdef L_calloc |
void * calloc(size_t nmemb, size_t lsize) |
{ |
void *result; |
size_t size=lsize * nmemb; |
|
/* guard vs integer overflow, but allow nmemb |
* to fall through and call malloc(0) */ |
if (nmemb && lsize != (size / nmemb)) { |
__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.... |
*/ |
if (result != NULL) { |
memset(result, 0, size); |
} |
#endif |
return result; |
} |
#endif |
|
#ifdef L_realloc |
void *realloc(void *ptr, size_t size) |
{ |
void *newptr = NULL; |
|
if (!ptr) |
return malloc(size); |
if (!size) { |
free(ptr); |
return malloc(0); |
} |
|
newptr = malloc(size); |
if (newptr) { |
memcpy(newptr, ptr, |
#ifdef __UCLIBC_HAS_MMU__ |
*((size_t *) (ptr - sizeof(size_t))) |
#else |
size |
#endif |
); |
free(ptr); |
} |
return newptr; |
} |
#endif |
|
#ifdef L_free |
extern int weak_function __libc_free_aligned(void *ptr); |
void free(void *ptr) |
{ |
if (ptr == NULL) |
return; |
if (unlikely(__libc_free_aligned!=NULL)) { |
if (__libc_free_aligned(ptr)) { |
return; |
} |
} |
#ifdef __UCLIBC_HAS_MMU__ |
ptr -= sizeof(size_t); |
munmap(ptr, * (size_t *) ptr + sizeof(size_t)); |
#else |
munmap(ptr, 0); |
#endif |
} |
#endif |
|
#ifdef L_memalign |
#ifdef __UCLIBC_HAS_THREADS__ |
#include <pthread.h> |
extern pthread_mutex_t __malloclock; |
# define LOCK __pthread_mutex_lock(&__malloclock) |
# define UNLOCK __pthread_mutex_unlock(&__malloclock); |
#else |
# define LOCK |
# define UNLOCK |
#endif |
|
/* List of blocks allocated with memalign or valloc */ |
struct alignlist |
{ |
struct alignlist *next; |
__ptr_t aligned; /* The address that memaligned returned. */ |
__ptr_t exact; /* The address that malloc returned. */ |
}; |
struct alignlist *_aligned_blocks; |
|
/* Return memory to the heap. */ |
int __libc_free_aligned(void *ptr) |
{ |
struct alignlist *l; |
|
if (ptr == NULL) |
return 0; |
|
LOCK; |
for (l = _aligned_blocks; l != NULL; l = l->next) { |
if (l->aligned == ptr) { |
/* Mark the block as free */ |
l->aligned = NULL; |
ptr = l->exact; |
#ifdef __UCLIBC_HAS_MMU__ |
ptr -= sizeof(size_t); |
munmap(ptr, * (size_t *) ptr + sizeof(size_t)); |
#else |
munmap(ptr, 0); |
#endif |
return 1; |
} |
} |
UNLOCK; |
return 0; |
} |
void * memalign (size_t alignment, size_t size) |
{ |
void * result; |
unsigned long int adj; |
|
result = malloc (size + alignment - 1); |
if (result == NULL) |
return NULL; |
adj = (unsigned long int) ((unsigned long int) ((char *) result - |
(char *) NULL)) % alignment; |
if (adj != 0) |
{ |
struct alignlist *l; |
LOCK; |
for (l = _aligned_blocks; l != NULL; l = l->next) |
if (l->aligned == NULL) |
/* This slot is free. Use it. */ |
break; |
if (l == NULL) |
{ |
l = (struct alignlist *) malloc (sizeof (struct alignlist)); |
if (l == NULL) { |
free(result); |
UNLOCK; |
return NULL; |
} |
l->next = _aligned_blocks; |
_aligned_blocks = l; |
} |
l->exact = result; |
result = l->aligned = (char *) result + alignment - adj; |
UNLOCK; |
} |
|
return result; |
} |
#endif |
|
/malloc-simple/Makefile
0,0 → 1,44
# Makefile for uClibc |
# |
# Copyright (C) 2000-2003 Erik Andersen <andersen@uclibc.org> |
# |
# This program is free software; you can redistribute it and/or modify it under |
# the terms of the GNU Library General Public License as published by the Free |
# Software Foundation; either version 2 of the License, or (at your option) any |
# later version. |
# |
# This program 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 Library General Public License 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 |
# |
# Derived in part from the Linux-8086 C library, the GNU C Library, and several |
# other sundry sources. Files within this library are copyright by their |
# respective copyright holders. |
|
TOPDIR=../../../ |
include $(TOPDIR)Rules.mak |
|
MSRC=alloc.c |
MOBJ=malloc.o realloc.o free.o calloc.o memalign.o |
OBJS=$(MOBJ) |
|
|
all: $(OBJS) $(LIBC) |
|
$(LIBC): ar-target |
|
ar-target: $(OBJS) |
$(AR) $(ARFLAGS) $(LIBC) $(OBJS) |
|
$(MOBJ): $(MSRC) |
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o |
$(STRIPTOOL) -x -R .note -R .comment $*.o |
|
clean: |
rm -f *.[oa] *~ core |
|
/strtod.c
0,0 → 1,631
/* Copyright (C) 2000, 2003 Manuel Novoa III |
* |
* This library is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Library General Public |
* License as published by the Free Software Foundation; either |
* version 2 of the License, or (at your option) any later version. |
* |
* This 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 |
* 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. |
*/ |
|
|
/* Notes: |
* |
* The primary objective of this implementation was minimal size and |
* portablility, while providing robustness and resonable accuracy. |
* |
* This implementation depends on IEEE floating point behavior and expects |
* to be able to generate +/- infinity as a result. |
* |
* There are a number of compile-time options below. |
*/ |
|
/* July 27, 2003 |
* |
* General cleanup and some minor size optimizations. |
* Change implementation to support __strtofpmax() rather than strtod(). |
* Now all the strto{floating pt}() funcs are implemented in terms of |
* of the internal __strtofpmax() function. |
* Support "nan", "inf", and "infinity" strings (case-insensitive). |
* Support hexadecimal floating point notation. |
* Support wchar variants. |
* Support xlocale variants. |
* |
* TODO: |
* |
* Consider accumulating blocks of digits in longs to save floating pt mults. |
* This would likely be much better on anything that only supported floats |
* where DECIMAL_DIG == 9. Actually, if floats have FLT_MAX_10_EXP == 38, |
* we could calculate almost all the exponent multipliers (p_base) in |
* long arithmetic as well. |
*/ |
|
/**********************************************************************/ |
/* OPTIONS */ |
/**********************************************************************/ |
|
/* Defined if we want to recognize "nan", "inf", and "infinity". (C99) */ |
#define _STRTOD_NAN_INF_STRINGS 1 |
|
/* Defined if we want support hexadecimal floating point notation. (C99) */ |
/* Note! Now controlled by uClibc configuration. See below. */ |
#define _STRTOD_HEXADECIMAL_FLOATS 1 |
|
/* Defined if we want to scale with a O(log2(exp)) multiplications. |
* This is generally a good thing to do unless you are really tight |
* on space and do not expect to convert values of large magnitude. */ |
|
#define _STRTOD_LOG_SCALING 1 |
|
/* WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! |
* |
* Clearing any of the options below this point is not advised (or tested). |
* |
* WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! */ |
|
/* Defined if we want strtod to set errno appropriately. */ |
/* NOTE: Implies all options below. */ |
#define _STRTOD_ERRNO 1 |
|
/* Defined if we want support for the endptr arg. */ |
/* Implied by _STRTOD_ERRNO. */ |
#define _STRTOD_ENDPTR 1 |
|
/* Defined if we want to prevent overflow in accumulating the exponent. */ |
/* Implied by _STRTOD_ERRNO. */ |
#define _STRTOD_RESTRICT_EXP 1 |
|
/* Defined if we want to process mantissa digits more intelligently. */ |
/* Implied by _STRTOD_ERRNO. */ |
#define _STRTOD_RESTRICT_DIGITS 1 |
|
/* Defined if we want to skip scaling 0 for the exponent. */ |
/* Implied by _STRTOD_ERRNO. */ |
#define _STRTOD_ZERO_CHECK 1 |
|
/**********************************************************************/ |
/* Don't change anything that follows. */ |
/**********************************************************************/ |
|
#ifdef _STRTOD_ERRNO |
#undef _STRTOD_ENDPTR |
#undef _STRTOD_RESTRICT_EXP |
#undef _STRTOD_RESTRICT_DIGITS |
#undef _STRTOD_ZERO_CHECK |
#define _STRTOD_ENDPTR 1 |
#define _STRTOD_RESTRICT_EXP 1 |
#define _STRTOD_RESTRICT_DIGITS 1 |
#define _STRTOD_ZERO_CHECK 1 |
#endif |
|
/**********************************************************************/ |
|
#define _ISOC99_SOURCE 1 |
#define _GNU_SOURCE |
#include <stdlib.h> |
#include <string.h> |
#include <ctype.h> |
#include <errno.h> |
#include <limits.h> |
#include <float.h> |
#include <bits/uClibc_fpmax.h> |
|
#include <locale.h> |
|
#ifdef __UCLIBC_HAS_WCHAR__ |
|
#include <wchar.h> |
#include <wctype.h> |
#include <bits/uClibc_uwchar.h> |
|
#endif |
|
#ifdef __UCLIBC_HAS_XLOCALE__ |
#include <xlocale.h> |
#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__ */ |
|
/**********************************************************************/ |
|
#undef _STRTOD_FPMAX |
|
#if FPMAX_TYPE == 3 |
|
#define NEED_STRTOLD_WRAPPER |
#define NEED_STRTOD_WRAPPER |
#define NEED_STRTOF_WRAPPER |
|
#elif FPMAX_TYPE == 2 |
|
#define NEED_STRTOD_WRAPPER |
#define NEED_STRTOF_WRAPPER |
|
#elif FPMAX_TYPE == 1 |
|
#define NEED_STRTOF_WRAPPER |
|
#else |
|
#error unknown FPMAX_TYPE! |
|
#endif |
|
extern void __fp_range_check(__fpmax_t y, __fpmax_t x); |
|
/**********************************************************************/ |
|
#ifdef _STRTOD_RESTRICT_DIGITS |
#define EXP_DENORM_ADJUST DECIMAL_DIG |
#define MAX_ALLOWED_EXP (DECIMAL_DIG + EXP_DENORM_ADJUST - FPMAX_MIN_10_EXP) |
|
#if MAX_ALLOWED_EXP > INT_MAX |
#error size assumption violated for MAX_ALLOWED_EXP |
#endif |
#else |
/* We want some excess if we're not restricting mantissa digits. */ |
#define MAX_ALLOWED_EXP ((20 - FPMAX_MIN_10_EXP) * 2) |
#endif |
|
|
#if defined(_STRTOD_RESTRICT_DIGITS) || defined(_STRTOD_ENDPTR) || defined(_STRTOD_HEXADECIMAL_FLOATS) |
#undef _STRTOD_NEED_NUM_DIGITS |
#define _STRTOD_NEED_NUM_DIGITS 1 |
#endif |
|
/**********************************************************************/ |
#if defined(L___strtofpmax) || defined(L___strtofpmax_l) || defined(L___wcstofpmax) || defined(L___wcstofpmax_l) |
|
#if defined(L___wcstofpmax) || defined(L___wcstofpmax_l) |
|
#define __strtofpmax __wcstofpmax |
#define __strtofpmax_l __wcstofpmax_l |
|
#define Wchar wchar_t |
#ifdef __UCLIBC_DO_XLOCALE |
#define ISSPACE(C) iswspace_l((C), locale_arg) |
#else |
#define ISSPACE(C) iswspace((C)) |
#endif |
|
#else /* defined(L___wcstofpmax) || defined(L___wcstofpmax) */ |
|
#define Wchar char |
#ifdef __UCLIBC_DO_XLOCALE |
#define ISSPACE(C) isspace_l((C), locale_arg) |
#else |
#define ISSPACE(C) isspace((C)) |
#endif |
|
#endif /* defined(L___wcstofpmax) || defined(L___wcstofpmax) */ |
|
|
#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) |
|
__fpmax_t __strtofpmax(const Wchar *str, Wchar **endptr, int exponent_power) |
{ |
return __strtofpmax_l(str, endptr, exponent_power, __UCLIBC_CURLOCALE); |
} |
|
#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ |
|
__fpmax_t __XL_NPP(__strtofpmax)(const Wchar *str, Wchar **endptr, int exponent_power |
__LOCALE_PARAM ) |
{ |
__fpmax_t number; |
__fpmax_t p_base = 10; /* Adjusted to 16 in the hex case. */ |
Wchar *pos0; |
#ifdef _STRTOD_ENDPTR |
Wchar *pos1; |
#endif |
Wchar *pos = (Wchar *) str; |
int exponent_temp; |
int negative; /* A flag for the number, a multiplier for the exponent. */ |
#ifdef _STRTOD_NEED_NUM_DIGITS |
int num_digits; |
#endif |
#ifdef __UCLIBC_HAS_LOCALE__ |
const char *decpt = __LOCALE_PTR->decimal_point; |
#if defined(L___wcstofpmax) || defined(L___wcstofpmax) |
wchar_t decpt_wc = __LOCALE_PTR->decimal_point; |
#else |
int decpt_len = __LOCALE_PTR->decimal_point_len; |
#endif |
#endif |
|
#ifdef _STRTOD_HEXADECIMAL_FLOATS |
Wchar expchar = 'e'; |
Wchar *poshex = NULL; |
__uint16_t is_mask = _ISdigit; |
#define EXPCHAR expchar |
#define IS_X_DIGIT(C) __isctype((C), is_mask) |
#else /* _STRTOD_HEXADECIMAL_FLOATS */ |
#define EXPCHAR 'e' |
#define IS_X_DIGIT(C) isdigit((C)) |
#endif /* _STRTOD_HEXADECIMAL_FLOATS */ |
|
while (ISSPACE(*pos)) { /* Skip leading whitespace. */ |
++pos; |
} |
|
negative = 0; |
switch(*pos) { /* Handle optional sign. */ |
case '-': negative = 1; /* Fall through to increment position. */ |
case '+': ++pos; |
} |
|
#ifdef _STRTOD_HEXADECIMAL_FLOATS |
if ((*pos == '0') && (((pos[1])|0x20) == 'x')) { |
poshex = ++pos; /* Save position of 'x' in case no digits */ |
++pos; /* and advance past it. */ |
is_mask = _ISxdigit; /* Used by IS_X_DIGIT. */ |
expchar = 'p'; /* Adjust exponent char. */ |
p_base = 16; /* Adjust base multiplier. */ |
} |
#endif |
|
number = 0.; |
#ifdef _STRTOD_NEED_NUM_DIGITS |
num_digits = -1; |
#endif |
/* exponent_power = 0; */ |
pos0 = NULL; |
|
LOOP: |
while (IS_X_DIGIT(*pos)) { /* Process string of (hex) digits. */ |
#ifdef _STRTOD_RESTRICT_DIGITS |
if (num_digits < 0) { /* First time through? */ |
++num_digits; /* We've now seen a digit. */ |
} |
if (num_digits || (*pos != '0')) { /* Had/have nonzero. */ |
++num_digits; |
if (num_digits <= DECIMAL_DIG) { /* Is digit significant? */ |
#ifdef _STRTOD_HEXADECIMAL_FLOATS |
number = number * p_base |
+ (isdigit(*pos) |
? (*pos - '0') |
: (((*pos)|0x20) - ('a' - 10))); |
#else /* _STRTOD_HEXADECIMAL_FLOATS */ |
number = number * p_base + (*pos - '0'); |
#endif /* _STRTOD_HEXADECIMAL_FLOATS */ |
} |
} |
#else /* _STRTOD_RESTRICT_DIGITS */ |
#ifdef _STRTOD_NEED_NUM_DIGITS |
++num_digits; |
#endif |
#ifdef _STRTOD_HEXADECIMAL_FLOATS |
number = number * p_base |
+ (isdigit(*pos) |
? (*pos - '0') |
: (((*pos)|0x20) - ('a' - 10))); |
#else /* _STRTOD_HEXADECIMAL_FLOATS */ |
number = number * p_base + (*pos - '0'); |
#endif /* _STRTOD_HEXADECIMAL_FLOATS */ |
#endif /* _STRTOD_RESTRICT_DIGITS */ |
++pos; |
} |
|
#ifdef __UCLIBC_HAS_LOCALE__ |
#if defined(L___wcstofpmax) || defined(L___wcstofpmax) |
if (!pos0 && (*pos == decpt_wc)) { /* First decimal point? */ |
pos0 = ++pos; |
goto LOOP; |
} |
#else |
if (!pos0 && !memcmp(pos, decpt, decpt_len)) { /* First decimal point? */ |
pos0 = (pos += decpt_len); |
goto LOOP; |
} |
#endif |
#else /* __UCLIBC_HAS_LOCALE__ */ |
if ((*pos == '.') && !pos0) { /* First decimal point? */ |
pos0 = ++pos; /* Save position of decimal point */ |
goto LOOP; /* and process rest of digits. */ |
} |
#endif /* __UCLIBC_HAS_LOCALE__ */ |
|
#ifdef _STRTOD_NEED_NUM_DIGITS |
if (num_digits<0) { /* Must have at least one digit. */ |
#ifdef _STRTOD_HEXADECIMAL_FLOATS |
if (poshex) { /* Back up to '0' in '0x' prefix. */ |
pos = poshex; |
goto DONE; |
} |
#endif /* _STRTOD_HEXADECIMAL_FLOATS */ |
|
#ifdef _STRTOD_NAN_INF_STRINGS |
if (!pos0) { /* No decimal point, so check for inf/nan. */ |
/* Note: nan is the first string so 'number = i/0.;' works. */ |
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]) { |
++j; |
if (!nan_inf_str[i+1+j]) { |
number = i / 0.; |
if (negative) { /* Correct for sign. */ |
number = -number; |
} |
pos += nan_inf_str[i] - 2; |
goto DONE; |
} |
} |
i += nan_inf_str[i]; |
} while (nan_inf_str[i]); |
} |
|
#endif /* STRTOD_NAN_INF_STRINGS */ |
#ifdef _STRTOD_ENDPTR |
pos = (Wchar *) str; |
#endif |
goto DONE; |
} |
#endif /* _STRTOD_NEED_NUM_DIGITS */ |
|
#ifdef _STRTOD_RESTRICT_DIGITS |
if (num_digits > DECIMAL_DIG) { /* Adjust exponent for skipped digits. */ |
exponent_power += num_digits - DECIMAL_DIG; |
} |
#endif |
|
if (pos0) { |
exponent_power += pos0 - pos; /* Adjust exponent for decimal point. */ |
} |
|
#ifdef _STRTOD_HEXADECIMAL_FLOATS |
if (poshex) { |
exponent_power *= 4; /* Above is 2**4, but below is 2. */ |
p_base = 2; |
} |
#endif /* _STRTOD_HEXADECIMAL_FLOATS */ |
|
if (negative) { /* Correct for sign. */ |
number = -number; |
} |
|
/* process an exponent string */ |
if (((*pos)|0x20) == EXPCHAR) { |
#ifdef _STRTOD_ENDPTR |
pos1 = pos; |
#endif |
negative = 1; |
switch(*++pos) { /* Handle optional sign. */ |
case '-': negative = -1; /* Fall through to increment pos. */ |
case '+': ++pos; |
} |
|
pos0 = pos; |
exponent_temp = 0; |
while (isdigit(*pos)) { /* Process string of digits. */ |
#ifdef _STRTOD_RESTRICT_EXP |
if (exponent_temp < MAX_ALLOWED_EXP) { /* Avoid overflow. */ |
exponent_temp = exponent_temp * 10 + (*pos - '0'); |
} |
#else |
exponent_temp = exponent_temp * 10 + (*pos - '0'); |
#endif |
++pos; |
} |
|
#ifdef _STRTOD_ENDPTR |
if (pos == pos0) { /* No digits? */ |
pos = pos1; /* Back up to {e|E}/{p|P}. */ |
} /* else */ |
#endif |
|
exponent_power += negative * exponent_temp; |
} |
|
#ifdef _STRTOD_ZERO_CHECK |
if (number == 0.) { |
goto DONE; |
} |
#endif |
|
/* scale the result */ |
#ifdef _STRTOD_LOG_SCALING |
exponent_temp = exponent_power; |
|
if (exponent_temp < 0) { |
exponent_temp = -exponent_temp; |
} |
|
while (exponent_temp) { |
if (exponent_temp & 1) { |
if (exponent_power < 0) { |
/* Warning... caluclating a factor for the exponent and |
* then dividing could easily be faster. But doing so |
* might cause problems when dealing with denormals. */ |
number /= p_base; |
} else { |
number *= p_base; |
} |
} |
exponent_temp >>= 1; |
p_base *= p_base; |
} |
|
#else /* _STRTOD_LOG_SCALING */ |
while (exponent_power) { |
if (exponent_power < 0) { |
number /= p_base; |
exponent_power++; |
} else { |
number *= p_base; |
exponent_power--; |
} |
} |
#endif /* _STRTOD_LOG_SCALING */ |
|
#ifdef _STRTOD_ERRNO |
if (__FPMAX_ZERO_OR_INF_CHECK(number)) { |
__set_errno(ERANGE); |
} |
#endif |
|
DONE: |
#ifdef _STRTOD_ENDPTR |
if (endptr) { |
*endptr = pos; |
} |
#endif |
|
return number; |
} |
|
#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */ |
|
#endif |
/**********************************************************************/ |
#ifdef L___fp_range_check |
#if defined(NEED_STRTOF_WRAPPER) || defined(NEED_STRTOD_WRAPPER) |
|
extern void __fp_range_check(__fpmax_t y, __fpmax_t x) |
{ |
if (__FPMAX_ZERO_OR_INF_CHECK(y) /* y is 0 or +/- infinity */ |
&& (y != 0) /* y is not 0 (could have x>0, y==0 if underflow) */ |
&& !__FPMAX_ZERO_OR_INF_CHECK(x) /* x is not 0 or +/- infinity */ |
) { |
__set_errno(ERANGE); /* Then x is not in y's range. */ |
} |
} |
|
#endif |
#endif |
/**********************************************************************/ |
#if defined(L_strtof) || defined(L_strtof_l) || defined(L_wcstof) || defined(L_wcstof_l) |
#if defined(NEED_STRTOF_WRAPPER) |
|
#if defined(L_wcstof) || defined(L_wcstof_l) |
#define strtof wcstof |
#define strtof_l wcstof_l |
#define __strtof __wcstof |
#define __strtof_l __wcstof_l |
#define __strtofpmax __wcstofpmax |
#define __strtofpmax_l __wcstofpmax_l |
#define Wchar wchar_t |
#else |
#define Wchar char |
#endif |
|
|
float __XL(strtof)(const Wchar *str, Wchar **endptr __LOCALE_PARAM ) |
{ |
#if FPMAX_TYPE == 1 |
return __XL_NPP(__strtofpmax)(str, endptr, 0 __LOCALE_ARG ); |
#else |
__fpmax_t x; |
float y; |
|
x = __XL_NPP(__strtofpmax)(str, endptr, 0 __LOCALE_ARG ); |
y = (float) x; |
|
__fp_range_check(y, x); |
|
return y; |
#endif |
} |
|
__XL_ALIAS(strtof) |
|
#endif |
#endif |
/**********************************************************************/ |
#if defined(L_strtod) || defined(L_strtod_l) || defined(L_wcstod) || defined(L_wcstod_l) |
#if defined(NEED_STRTOD_WRAPPER) |
|
#if defined(L_wcstod) || defined(L_wcstod_l) |
#define strtod wcstod |
#define strtod_l wcstod_l |
#define __strtod __wcstod |
#define __strtod_l __wcstod_l |
#define __strtofpmax __wcstofpmax |
#define __strtofpmax_l __wcstofpmax_l |
#define Wchar wchar_t |
#else |
#define Wchar char |
#endif |
|
double __XL(strtod)(const Wchar *__restrict str, |
Wchar **__restrict endptr __LOCALE_PARAM ) |
{ |
#if FPMAX_TYPE == 2 |
return __XL_NPP(__strtofpmax)(str, endptr, 0 __LOCALE_ARG ); |
#else |
__fpmax_t x; |
double y; |
|
x = __XL_NPP(__strtofpmax)(str, endptr, 0 __LOCALE_ARG ); |
y = (double) x; |
|
__fp_range_check(y, x); |
|
return y; |
#endif |
} |
|
__XL_ALIAS(strtod) |
|
#endif |
#endif |
/**********************************************************************/ |
#if defined(L_strtold) || defined(L_strtold_l) || defined(L_wcstold) || defined(L_wcstold_l) |
#if defined(NEED_STRTOLD_WRAPPER) |
|
#if defined(L_wcstold) || defined(L_wcstold_l) |
#define strtold wcstold |
#define strtold_l wcstold_l |
#define __strtold __wcstold |
#define __strtold_l __wcstold_l |
#define __strtofpmax __wcstofpmax |
#define __strtofpmax_l __wcstofpmax_l |
#define Wchar wchar_t |
#else |
#define Wchar char |
#endif |
|
long double __XL(strtold)(const Wchar *str, Wchar **endptr __LOCALE_PARAM ) |
{ |
#if FPMAX_TYPE == 3 |
return __XL_NPP(__strtofpmax)(str, endptr, 0 __LOCALE_ARG ); |
#else |
__fpmax_t x; |
long double y; |
|
x = __XL_NPP(__strtofpmax)(str, endptr, 0 __LOCALE_ARG ); |
y = (long double) x; |
|
__fp_range_check(y, x); |
|
return y; |
#endif |
} |
|
__XL_ALIAS(strtold) |
|
#endif |
#endif |
/**********************************************************************/ |
/random.c
0,0 → 1,255
/* |
* Copyright (c) 1983 Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms are permitted |
* provided that the above copyright notice and this paragraph are |
* duplicated in all such forms and that any documentation, |
* advertising materials, and other materials related to such |
* distribution and use acknowledge that the software was developed |
* by the University of California, Berkeley. The name of the |
* University may not be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
*/ |
|
/* |
* This is derived from the Berkeley source: |
* @(#)random.c 5.5 (Berkeley) 7/6/88 |
* It was reworked for the GNU C Library by Roland McGrath. |
* Rewritten to use reentrant functions by Ulrich Drepper, 1995. |
*/ |
|
#define _GNU_SOURCE |
#include <features.h> |
#include <limits.h> |
#include <stddef.h> |
#include <stdlib.h> |
#ifdef __UCLIBC_HAS_THREADS__ |
#include <pthread.h> |
/* POSIX.1c requires that there is mutual exclusion for the `rand' and |
`srand' functions to prevent concurrent calls from modifying common |
data. */ |
static pthread_mutex_t lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; |
#else |
#define __pthread_mutex_lock(x) |
#define __pthread_mutex_unlock(x) |
#endif |
|
/* An improved random number generation package. In addition to the standard |
rand()/srand() like interface, this package also has a special state info |
interface. The initstate() routine is called with a seed, an array of |
bytes, and a count of how many bytes are being passed in; this array is |
then initialized to contain information for random number generation with |
that much state information. Good sizes for the amount of state |
information are 32, 64, 128, and 256 bytes. The state can be switched by |
calling the setstate() function with the same array as was initialized |
with initstate(). By default, the package runs with 128 bytes of state |
information and generates far better random numbers than a linear |
congruential generator. If the amount of state information is less than |
32 bytes, a simple linear congruential R.N.G. is used. Internally, the |
state information is treated as an array of longs; the zeroth element of |
the array is the type of R.N.G. being used (small integer); the remainder |
of the array is the state information for the R.N.G. Thus, 32 bytes of |
state information will give 7 longs worth of state information, which will |
allow a degree seven polynomial. (Note: The zeroth word of state |
information also has some other information stored in it; see setstate |
for details). The random number generation technique is a linear feedback |
shift register approach, employing trinomials (since there are fewer terms |
to sum up that way). In this approach, the least significant bit of all |
the numbers in the state table will act as a linear feedback shift register, |
and will have period 2^deg - 1 (where deg is the degree of the polynomial |
being used, assuming that the polynomial is irreducible and primitive). |
The higher order bits will have longer periods, since their values are |
also influenced by pseudo-random carries out of the lower bits. The |
total period of the generator is approximately deg*(2**deg - 1); thus |
doubling the amount of state information has a vast influence on the |
period of the generator. Note: The deg*(2**deg - 1) is an approximation |
only good for large deg, when the period of the shift register is the |
dominant factor. With deg equal to seven, the period is actually much |
longer than the 7*(2**7 - 1) predicted by this formula. */ |
|
|
|
/* 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. */ |
|
/* Linear congruential. */ |
#define TYPE_0 0 |
#define BREAK_0 8 |
#define DEG_0 0 |
#define SEP_0 0 |
|
/* x**7 + x**3 + 1. */ |
#define TYPE_1 1 |
#define BREAK_1 32 |
#define DEG_1 7 |
#define SEP_1 3 |
|
/* x**15 + x + 1. */ |
#define TYPE_2 2 |
#define BREAK_2 64 |
#define DEG_2 15 |
#define SEP_2 1 |
|
/* x**31 + x**3 + 1. */ |
#define TYPE_3 3 |
#define BREAK_3 128 |
#define DEG_3 31 |
#define SEP_3 3 |
|
/* x**63 + x + 1. */ |
#define TYPE_4 4 |
#define BREAK_4 256 |
#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 |
advances the front and rear pointers 10*rand_deg times, and hence the |
rear pointer which starts at 0 will also end up at zero; thus the zeroth |
element of the state information, which contains info about the current |
position of the rear pointer is just |
(MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3. */ |
|
static int32_t randtbl[DEG_3 + 1] = |
{ |
TYPE_3, |
|
-1726662223, 379960547, 1735697613, 1040273694, 1313901226, |
1627687941, -179304937, -2073333483, 1780058412, -1989503057, |
-615974602, 344556628, 939512070, -1249116260, 1507946756, |
-812545463, 154635395, 1388815473, -1926676823, 525320961, |
-1009028674, 968117788, -123449607, 1284210865, 435012392, |
-2017506339, -911064859, -370259173, 1132637927, 1398500161, |
-205601318, |
}; |
|
|
static struct random_data unsafe_state = |
{ |
/* FPTR and RPTR are two pointers into the state info, a front and a rear |
pointer. These two pointers are always rand_sep places aparts, as they |
cycle through the state information. (Yes, this does mean we could get |
away with just one pointer, but the code for random is more efficient |
this way). The pointers are left positioned as they would be from the call: |
initstate(1, randtbl, 128); |
(The position of the rear pointer, rptr, is really 0 (as explained above |
in the initialization of randtbl) because the state table pointer is set |
to point to randtbl[1] (as explained below).) */ |
|
fptr : &randtbl[SEP_3 + 1], |
rptr : &randtbl[1], |
|
/* The following things are the pointer to the state information table, |
the type of the current generator, the degree of the current polynomial |
being used, and the separation between the two pointers. |
Note that for efficiency of random, we remember the first location of |
the state information, not the zeroth. Hence it is valid to access |
state[-1], which is used to store the type of the R.N.G. |
Also, we remember the last location, since this is more efficient than |
indexing every time to find the address of the last element to see if |
the front and rear pointers have wrapped. */ |
|
state : &randtbl[1], |
|
rand_type : TYPE_3, |
rand_deg : DEG_3, |
rand_sep : SEP_3, |
|
end_ptr : &randtbl[sizeof (randtbl) / sizeof (randtbl[0])] |
}; |
|
|
/* Initialize the random number generator based on the given seed. If the |
type is the trivial no-state-information type, just remember the seed. |
Otherwise, initializes state[] based on the given "seed" via a linear |
congruential generator. Then, the pointers are set to known locations |
that are exactly rand_sep places apart. Lastly, it cycles the state |
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. */ |
void srandom (unsigned int x) |
{ |
__pthread_mutex_lock(&lock); |
srandom_r (x, &unsafe_state); |
__pthread_mutex_unlock(&lock); |
} |
weak_alias (srandom, srand) |
|
/* Initialize the state information in the given array of N bytes for |
future random number generation. Based on the number of bytes we |
are given, and the break values for the different R.N.G.'s, we choose |
the best (largest) one we can and set things up for it. srandom is |
then called to initialize the state information. Note that on return |
from srandom, we set state[-1] to be the type multiplexed with the current |
value of the rear pointer; this is so successive calls to initstate won't |
lose this information and will be able to restart with setstate. |
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. */ |
char * initstate (unsigned int seed, char *arg_state, size_t n) |
{ |
int32_t *ostate; |
|
__pthread_mutex_lock(&lock); |
ostate = &unsafe_state.state[-1]; |
initstate_r (seed, arg_state, n, &unsafe_state); |
__pthread_mutex_unlock(&lock); |
return (char *) ostate; |
} |
|
/* Restore the state from the given state array. |
Note: It is important that we also remember the locations of the pointers |
in the current state information, and restore the locations of the pointers |
from the old state information. This is done by multiplexing the pointer |
location into the zeroth word of the state information. Note that due |
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. */ |
char * setstate (char *arg_state) |
{ |
int32_t *ostate; |
|
__pthread_mutex_lock(&lock); |
ostate = &unsafe_state.state[-1]; |
if (setstate_r (arg_state, &unsafe_state) < 0) |
ostate = NULL; |
__pthread_mutex_unlock(&lock); |
return (char *) ostate; |
} |
|
/* 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 |
set up. The basic operation is to add the number at the rear pointer into |
the one at the front pointer. Then both pointers are advanced to the next |
location cyclically in the table. The value returned is the sum generated, |
reduced to 31 bits by throwing away the "least random" low bit. |
Note: The code takes advantage of the fact that both the front and |
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. */ |
|
long int random () |
{ |
int32_t retval; |
|
__pthread_mutex_lock(&lock); |
random_r (&unsafe_state, &retval); |
__pthread_mutex_unlock(&lock); |
return retval; |
} |
|
/valloc.c
0,0 → 1,35
/* vi: set sw=4 ts=4: */ |
/* Allocate memory on a page boundary. |
Copyright (C) 1991, 1992 Free Software Foundation, Inc. |
|
This library is free software; you can redistribute it and/or |
modify it under the terms of the GNU Library General Public License as |
published by the Free Software Foundation; either version 2 of the |
License, or (at your option) any later version. |
|
This 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 |
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. |
|
The author may be reached (Email) at the address mike@@ai.mit.edu, |
or (US mail) as Mike Haertel c/o Free Software Foundation. */ |
|
#include <stdlib.h> |
#include <unistd.h> |
#include <malloc.h> |
|
static size_t pagesize; |
|
__ptr_t valloc (size_t size) |
{ |
if (pagesize == 0) |
pagesize = getpagesize (); |
|
return memalign(pagesize, size); |
} |
/strtof.c
0,0 → 1,32
/* vi: set sw=4 ts=4: */ |
/* strtof for uClibc |
* |
* Copyright (C) 2002 by Erik Andersen <andersen@uclibc.org> |
* |
* This program is free software; you can redistribute it and/or modify it |
* under the terms of the GNU Library General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or (at your |
* option) any later version. |
* |
* This program 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 Library General Public License |
* 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 |
* |
*/ |
|
/* This implementation is a bit lame, since we are actually making the compiler |
* to an internal conversion from a double to a float, thereby wasting a bunch |
* of precision. But this is small, and works for now... */ |
|
#include <stdlib.h> |
|
float strtof (const char *str, char **endptr) |
{ |
return(strtod(str,endptr)); |
} |
|
/div.c
0,0 → 1,33
/* vi: set sw=4 ts=4: */ |
/* div for uClibc |
* |
* Copyright (C) 2000 by Lineo, inc. and Erik Andersen |
* Copyright (C) 2000,2001 by Erik Andersen <andersen@uclibc.org> |
* Written by Erik Andersen <andersen@uclibc.org> |
* |
* This program is free software; you can redistribute it and/or modify it |
* under the terms of the GNU Library General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or (at your |
* option) any later version. |
* |
* This program 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 Library General Public License |
* 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 |
* |
*/ |
|
#include <stdlib.h> |
|
div_t div(int numer, int denom) |
{ |
div_t result; |
result.quot = numer / denom; |
result.rem = numer - (result.quot * denom); |
return(result); |
} |
|
/rand.c
0,0 → 1,26
/* rand.c |
* |
* Written by Erik Andersen <andersee@debian.org> |
* |
* This library is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Library General Public License as |
* published by the Free Software Foundation; either version 2 of the |
* License, or (at your option) any later version. |
* |
* This 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 |
* 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. */ |
|
#include <stdlib.h> |
|
int rand (void) |
{ |
return((int)random()); |
} |
|
/malloc-standard/free.c
0,0 → 1,382
/* |
This is a version (aka dlmalloc) of malloc/free/realloc written by |
Doug Lea and released to the public domain. Use, modify, and |
redistribute this code without permission or acknowledgement in any |
way you wish. Send questions, comments, complaints, performance |
data, etc to dl@cs.oswego.edu |
|
VERSION 2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) |
|
Note: There may be an updated version of this malloc obtainable at |
ftp://gee.cs.oswego.edu/pub/misc/malloc.c |
Check before installing! |
|
Hacked up for uClibc by Erik Andersen <andersen@codepoet.org> |
*/ |
|
#include "malloc.h" |
|
|
/* ------------------------- __malloc_trim ------------------------- |
__malloc_trim is an inverse of sorts to __malloc_alloc. It gives memory |
back to the system (via negative arguments to sbrk) if there is unused |
memory at the `high' end of the malloc pool. It is called automatically by |
free() when top space exceeds the trim threshold. It is also called by the |
public malloc_trim routine. It returns 1 if it actually released any |
memory, else 0. |
*/ |
static int __malloc_trim(size_t pad, mstate av) |
{ |
long top_size; /* Amount of top-most memory */ |
long extra; /* Amount to release */ |
long released; /* Amount actually released */ |
char* current_brk; /* address returned by pre-check sbrk call */ |
char* new_brk; /* address returned by post-check sbrk call */ |
size_t pagesz; |
|
pagesz = av->pagesize; |
top_size = chunksize(av->top); |
|
/* Release in pagesize units, keeping at least one page */ |
extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz; |
|
if (extra > 0) { |
|
/* |
Only proceed if end of memory is where we last set it. |
This avoids problems if there were foreign sbrk calls. |
*/ |
current_brk = (char*)(MORECORE(0)); |
if (current_brk == (char*)(av->top) + top_size) { |
|
/* |
Attempt to release memory. We ignore MORECORE return value, |
and instead call again to find out where new end of memory is. |
This avoids problems if first call releases less than we asked, |
of if failure somehow altered brk value. (We could still |
encounter problems if it altered brk in some very bad way, |
but the only thing we can do is adjust anyway, which will cause |
some downstream failure.) |
*/ |
|
MORECORE(-extra); |
new_brk = (char*)(MORECORE(0)); |
|
if (new_brk != (char*)MORECORE_FAILURE) { |
released = (long)(current_brk - new_brk); |
|
if (released != 0) { |
/* Success. Adjust top. */ |
av->sbrked_mem -= released; |
set_head(av->top, (top_size - released) | PREV_INUSE); |
check_malloc_state(); |
return 1; |
} |
} |
} |
} |
return 0; |
} |
|
/* |
Initialize a malloc_state struct. |
|
This is called only from within __malloc_consolidate, which needs |
be called in the same contexts anyway. It is never called directly |
outside of __malloc_consolidate because some optimizing compilers try |
to inline it at all call points, which turns out not to be an |
optimization at all. (Inlining it in __malloc_consolidate is fine though.) |
*/ |
static void malloc_init_state(mstate av) |
{ |
int i; |
mbinptr bin; |
|
/* Establish circular links for normal bins */ |
for (i = 1; i < NBINS; ++i) { |
bin = bin_at(av,i); |
bin->fd = bin->bk = bin; |
} |
|
av->top_pad = DEFAULT_TOP_PAD; |
av->n_mmaps_max = DEFAULT_MMAP_MAX; |
av->mmap_threshold = DEFAULT_MMAP_THRESHOLD; |
av->trim_threshold = DEFAULT_TRIM_THRESHOLD; |
|
#if MORECORE_CONTIGUOUS |
set_contiguous(av); |
#else |
set_noncontiguous(av); |
#endif |
|
|
set_max_fast(av, DEFAULT_MXFAST); |
|
av->top = initial_top(av); |
av->pagesize = malloc_getpagesize; |
} |
|
|
/* ---------------------------------------------------------------------- |
* |
* PUBLIC STUFF |
* |
* ----------------------------------------------------------------------*/ |
|
|
/* ------------------------- __malloc_consolidate ------------------------- |
|
__malloc_consolidate is a specialized version of free() that tears |
down chunks held in fastbins. Free itself cannot be used for this |
purpose since, among other things, it might place chunks back onto |
fastbins. So, instead, we need to use a minor variant of the same |
code. |
|
Also, because this routine needs to be called the first time through |
malloc anyway, it turns out to be the perfect place to trigger |
initialization code. |
*/ |
void __malloc_consolidate(mstate av) |
{ |
mfastbinptr* fb; /* current fastbin being consolidated */ |
mfastbinptr* maxfb; /* last fastbin (for loop control) */ |
mchunkptr p; /* current chunk being consolidated */ |
mchunkptr nextp; /* next chunk to consolidate */ |
mchunkptr unsorted_bin; /* bin header */ |
mchunkptr first_unsorted; /* chunk to link to */ |
|
/* These have same use as in free() */ |
mchunkptr nextchunk; |
size_t size; |
size_t nextsize; |
size_t prevsize; |
int nextinuse; |
mchunkptr bck; |
mchunkptr fwd; |
|
/* |
If max_fast is 0, we know that av hasn't |
yet been initialized, in which case do so below |
*/ |
|
if (av->max_fast != 0) { |
clear_fastchunks(av); |
|
unsorted_bin = unsorted_chunks(av); |
|
/* |
Remove each chunk from fast bin and consolidate it, placing it |
then in unsorted bin. Among other reasons for doing this, |
placing in unsorted bin avoids needing to calculate actual bins |
until malloc is sure that chunks aren't immediately going to be |
reused anyway. |
*/ |
|
maxfb = &(av->fastbins[fastbin_index(av->max_fast)]); |
fb = &(av->fastbins[0]); |
do { |
if ( (p = *fb) != 0) { |
*fb = 0; |
|
do { |
check_inuse_chunk(p); |
nextp = p->fd; |
|
/* Slightly streamlined version of consolidation code in free() */ |
size = p->size & ~PREV_INUSE; |
nextchunk = chunk_at_offset(p, size); |
nextsize = chunksize(nextchunk); |
|
if (!prev_inuse(p)) { |
prevsize = p->prev_size; |
size += prevsize; |
p = chunk_at_offset(p, -((long) prevsize)); |
unlink(p, bck, fwd); |
} |
|
if (nextchunk != av->top) { |
nextinuse = inuse_bit_at_offset(nextchunk, nextsize); |
set_head(nextchunk, nextsize); |
|
if (!nextinuse) { |
size += nextsize; |
unlink(nextchunk, bck, fwd); |
} |
|
first_unsorted = unsorted_bin->fd; |
unsorted_bin->fd = p; |
first_unsorted->bk = p; |
|
set_head(p, size | PREV_INUSE); |
p->bk = unsorted_bin; |
p->fd = first_unsorted; |
set_foot(p, size); |
} |
|
else { |
size += nextsize; |
set_head(p, size | PREV_INUSE); |
av->top = p; |
} |
|
} while ( (p = nextp) != 0); |
|
} |
} while (fb++ != maxfb); |
} |
else { |
malloc_init_state(av); |
check_malloc_state(); |
} |
} |
|
|
/* ------------------------------ free ------------------------------ */ |
void free(void* mem) |
{ |
mstate av; |
|
mchunkptr p; /* chunk corresponding to mem */ |
size_t size; /* its size */ |
mfastbinptr* fb; /* associated fastbin */ |
mchunkptr nextchunk; /* next contiguous chunk */ |
size_t nextsize; /* its size */ |
int nextinuse; /* true if nextchunk is used */ |
size_t prevsize; /* size of previous contiguous chunk */ |
mchunkptr bck; /* misc temp for linking */ |
mchunkptr fwd; /* misc temp for linking */ |
|
/* free(0) has no effect */ |
if (mem == NULL) |
return; |
|
LOCK; |
av = get_malloc_state(); |
p = mem2chunk(mem); |
size = chunksize(p); |
|
check_inuse_chunk(p); |
|
/* |
If eligible, place chunk on a fastbin so it can be found |
and used quickly in malloc. |
*/ |
|
if ((unsigned long)(size) <= (unsigned long)(av->max_fast) |
|
#if TRIM_FASTBINS |
/* If TRIM_FASTBINS set, don't place chunks |
bordering top into fastbins */ |
&& (chunk_at_offset(p, size) != av->top) |
#endif |
) { |
|
set_fastchunks(av); |
fb = &(av->fastbins[fastbin_index(size)]); |
p->fd = *fb; |
*fb = p; |
} |
|
/* |
Consolidate other non-mmapped chunks as they arrive. |
*/ |
|
else if (!chunk_is_mmapped(p)) { |
set_anychunks(av); |
|
nextchunk = chunk_at_offset(p, size); |
nextsize = chunksize(nextchunk); |
|
/* consolidate backward */ |
if (!prev_inuse(p)) { |
prevsize = p->prev_size; |
size += prevsize; |
p = chunk_at_offset(p, -((long) prevsize)); |
unlink(p, bck, fwd); |
} |
|
if (nextchunk != av->top) { |
/* get and clear inuse bit */ |
nextinuse = inuse_bit_at_offset(nextchunk, nextsize); |
set_head(nextchunk, nextsize); |
|
/* consolidate forward */ |
if (!nextinuse) { |
unlink(nextchunk, bck, fwd); |
size += nextsize; |
} |
|
/* |
Place the chunk in unsorted chunk list. Chunks are |
not placed into regular bins until after they have |
been given one chance to be used in malloc. |
*/ |
|
bck = unsorted_chunks(av); |
fwd = bck->fd; |
p->bk = bck; |
p->fd = fwd; |
bck->fd = p; |
fwd->bk = p; |
|
set_head(p, size | PREV_INUSE); |
set_foot(p, size); |
|
check_free_chunk(p); |
} |
|
/* |
If the chunk borders the current high end of memory, |
consolidate into top |
*/ |
|
else { |
size += nextsize; |
set_head(p, size | PREV_INUSE); |
av->top = p; |
check_chunk(p); |
} |
|
/* |
If freeing a large space, consolidate possibly-surrounding |
chunks. Then, if the total unused topmost memory exceeds trim |
threshold, ask malloc_trim to reduce top. |
|
Unless max_fast is 0, we don't know if there are fastbins |
bordering top, so we cannot tell for sure whether threshold |
has been reached unless fastbins are consolidated. But we |
don't want to consolidate on each free. As a compromise, |
consolidation is performed if FASTBIN_CONSOLIDATION_THRESHOLD |
is reached. |
*/ |
|
if ((unsigned long)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) { |
if (have_fastchunks(av)) |
__malloc_consolidate(av); |
|
if ((unsigned long)(chunksize(av->top)) >= |
(unsigned long)(av->trim_threshold)) |
__malloc_trim(av->top_pad, av); |
} |
|
} |
/* |
If the chunk was allocated via mmap, release via munmap() |
Note that if HAVE_MMAP is false but chunk_is_mmapped is |
true, then user must have overwritten memory. There's nothing |
we can do to catch this error unless DEBUG is set, in which case |
check_inuse_chunk (above) will have triggered error. |
*/ |
|
else { |
int ret; |
size_t offset = p->prev_size; |
av->n_mmaps--; |
av->mmapped_mem -= (size + offset); |
ret = munmap((char*)p - offset, size + offset); |
/* munmap returns non-zero on failure */ |
assert(ret == 0); |
} |
UNLOCK; |
} |
|
/malloc-standard/mallinfo.c
0,0 → 1,81
/* |
This is a version (aka dlmalloc) of malloc/free/realloc written by |
Doug Lea and released to the public domain. Use, modify, and |
redistribute this code without permission or acknowledgement in any |
way you wish. Send questions, comments, complaints, performance |
data, etc to dl@cs.oswego.edu |
|
VERSION 2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) |
|
Note: There may be an updated version of this malloc obtainable at |
ftp://gee.cs.oswego.edu/pub/misc/malloc.c |
Check before installing! |
|
Hacked up for uClibc by Erik Andersen <andersen@codepoet.org> |
*/ |
|
#include "malloc.h" |
|
|
/* ------------------------------ mallinfo ------------------------------ */ |
struct mallinfo mallinfo(void) |
{ |
mstate av; |
struct mallinfo mi; |
int i; |
mbinptr b; |
mchunkptr p; |
size_t avail; |
size_t fastavail; |
int nblocks; |
int nfastblocks; |
|
LOCK; |
av = get_malloc_state(); |
/* Ensure initialization */ |
if (av->top == 0) { |
__malloc_consolidate(av); |
} |
|
check_malloc_state(); |
|
/* Account for top */ |
avail = chunksize(av->top); |
nblocks = 1; /* top always exists */ |
|
/* traverse fastbins */ |
nfastblocks = 0; |
fastavail = 0; |
|
for (i = 0; i < NFASTBINS; ++i) { |
for (p = av->fastbins[i]; p != 0; p = p->fd) { |
++nfastblocks; |
fastavail += chunksize(p); |
} |
} |
|
avail += fastavail; |
|
/* traverse regular bins */ |
for (i = 1; i < NBINS; ++i) { |
b = bin_at(av, i); |
for (p = last(b); p != b; p = p->bk) { |
++nblocks; |
avail += chunksize(p); |
} |
} |
|
mi.smblks = nfastblocks; |
mi.ordblks = nblocks; |
mi.fordblks = avail; |
mi.uordblks = av->sbrked_mem - avail; |
mi.arena = av->sbrked_mem; |
mi.hblks = av->n_mmaps; |
mi.hblkhd = av->mmapped_mem; |
mi.fsmblks = fastavail; |
mi.keepcost = chunksize(av->top); |
mi.usmblks = av->max_total_mem; |
UNLOCK; |
return mi; |
} |
|
/malloc-standard/realloc.c
0,0 → 1,237
/* |
This is a version (aka dlmalloc) of malloc/free/realloc written by |
Doug Lea and released to the public domain. Use, modify, and |
redistribute this code without permission or acknowledgement in any |
way you wish. Send questions, comments, complaints, performance |
data, etc to dl@cs.oswego.edu |
|
VERSION 2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) |
|
Note: There may be an updated version of this malloc obtainable at |
ftp://gee.cs.oswego.edu/pub/misc/malloc.c |
Check before installing! |
|
Hacked up for uClibc by Erik Andersen <andersen@codepoet.org> |
*/ |
|
#include "malloc.h" |
|
|
|
/* ------------------------------ realloc ------------------------------ */ |
void* realloc(void* oldmem, size_t bytes) |
{ |
mstate av; |
|
size_t nb; /* padded request size */ |
|
mchunkptr oldp; /* chunk corresponding to oldmem */ |
size_t oldsize; /* its size */ |
|
mchunkptr newp; /* chunk to return */ |
size_t newsize; /* its size */ |
void* newmem; /* corresponding user mem */ |
|
mchunkptr next; /* next contiguous chunk after oldp */ |
|
mchunkptr remainder; /* extra space at end of newp */ |
unsigned long remainder_size; /* its size */ |
|
mchunkptr bck; /* misc temp for linking */ |
mchunkptr fwd; /* misc temp for linking */ |
|
unsigned long copysize; /* bytes to copy */ |
unsigned int ncopies; /* size_t words to copy */ |
size_t* s; /* copy source */ |
size_t* d; /* copy destination */ |
|
|
/* Check for special cases. */ |
if (! oldmem) |
return malloc(bytes); |
if (! bytes) { |
free (oldmem); |
return malloc(bytes); |
} |
|
LOCK; |
av = get_malloc_state(); |
checked_request2size(bytes, nb); |
|
oldp = mem2chunk(oldmem); |
oldsize = chunksize(oldp); |
|
check_inuse_chunk(oldp); |
|
if (!chunk_is_mmapped(oldp)) { |
|
if ((unsigned long)(oldsize) >= (unsigned long)(nb)) { |
/* already big enough; split below */ |
newp = oldp; |
newsize = oldsize; |
} |
|
else { |
next = chunk_at_offset(oldp, oldsize); |
|
/* Try to expand forward into top */ |
if (next == av->top && |
(unsigned long)(newsize = oldsize + chunksize(next)) >= |
(unsigned long)(nb + MINSIZE)) { |
set_head_size(oldp, nb); |
av->top = chunk_at_offset(oldp, nb); |
set_head(av->top, (newsize - nb) | PREV_INUSE); |
UNLOCK; |
return chunk2mem(oldp); |
} |
|
/* Try to expand forward into next chunk; split off remainder below */ |
else if (next != av->top && |
!inuse(next) && |
(unsigned long)(newsize = oldsize + chunksize(next)) >= |
(unsigned long)(nb)) { |
newp = oldp; |
unlink(next, bck, fwd); |
} |
|
/* allocate, copy, free */ |
else { |
newmem = malloc(nb - MALLOC_ALIGN_MASK); |
if (newmem == 0) { |
UNLOCK; |
return 0; /* propagate failure */ |
} |
|
newp = mem2chunk(newmem); |
newsize = chunksize(newp); |
|
/* |
Avoid copy if newp is next chunk after oldp. |
*/ |
if (newp == next) { |
newsize += oldsize; |
newp = oldp; |
} |
else { |
/* |
Unroll copy of <= 36 bytes (72 if 8byte sizes) |
We know that contents have an odd number of |
size_t-sized words; minimally 3. |
*/ |
|
copysize = oldsize - (sizeof(size_t)); |
s = (size_t*)(oldmem); |
d = (size_t*)(newmem); |
ncopies = copysize / sizeof(size_t); |
assert(ncopies >= 3); |
|
if (ncopies > 9) |
memcpy(d, s, copysize); |
|
else { |
*(d+0) = *(s+0); |
*(d+1) = *(s+1); |
*(d+2) = *(s+2); |
if (ncopies > 4) { |
*(d+3) = *(s+3); |
*(d+4) = *(s+4); |
if (ncopies > 6) { |
*(d+5) = *(s+5); |
*(d+6) = *(s+6); |
if (ncopies > 8) { |
*(d+7) = *(s+7); |
*(d+8) = *(s+8); |
} |
} |
} |
} |
|
free(oldmem); |
check_inuse_chunk(newp); |
UNLOCK; |
return chunk2mem(newp); |
} |
} |
} |
|
/* If possible, free extra space in old or extended chunk */ |
|
assert((unsigned long)(newsize) >= (unsigned long)(nb)); |
|
remainder_size = newsize - nb; |
|
if (remainder_size < MINSIZE) { /* not enough extra to split off */ |
set_head_size(newp, newsize); |
set_inuse_bit_at_offset(newp, newsize); |
} |
else { /* split remainder */ |
remainder = chunk_at_offset(newp, nb); |
set_head_size(newp, nb); |
set_head(remainder, remainder_size | PREV_INUSE); |
/* Mark remainder as inuse so free() won't complain */ |
set_inuse_bit_at_offset(remainder, remainder_size); |
free(chunk2mem(remainder)); |
} |
|
check_inuse_chunk(newp); |
UNLOCK; |
return chunk2mem(newp); |
} |
|
/* |
Handle mmap cases |
*/ |
|
else { |
size_t offset = oldp->prev_size; |
size_t pagemask = av->pagesize - 1; |
char *cp; |
unsigned long sum; |
|
/* Note the extra (sizeof(size_t)) overhead */ |
newsize = (nb + offset + (sizeof(size_t)) + pagemask) & ~pagemask; |
|
/* don't need to remap if still within same page */ |
if (oldsize == newsize - offset) { |
UNLOCK; |
return oldmem; |
} |
|
cp = (char*)mremap((char*)oldp - offset, oldsize + offset, newsize, 1); |
|
if (cp != (char*)MORECORE_FAILURE) { |
|
newp = (mchunkptr)(cp + offset); |
set_head(newp, (newsize - offset)|IS_MMAPPED); |
|
assert(aligned_OK(chunk2mem(newp))); |
assert((newp->prev_size == offset)); |
|
/* update statistics */ |
sum = av->mmapped_mem += newsize - oldsize; |
if (sum > (unsigned long)(av->max_mmapped_mem)) |
av->max_mmapped_mem = sum; |
sum += av->sbrked_mem; |
if (sum > (unsigned long)(av->max_total_mem)) |
av->max_total_mem = sum; |
|
UNLOCK; |
return chunk2mem(newp); |
} |
|
/* Note the extra (sizeof(size_t)) overhead. */ |
if ((unsigned long)(oldsize) >= (unsigned long)(nb + (sizeof(size_t)))) |
newmem = oldmem; /* do nothing */ |
else { |
/* Must alloc, copy, free. */ |
newmem = malloc(nb - MALLOC_ALIGN_MASK); |
if (newmem != 0) { |
memcpy(newmem, oldmem, oldsize - 2*(sizeof(size_t))); |
free(oldmem); |
} |
} |
UNLOCK; |
return newmem; |
} |
} |
|
/malloc-standard/malloc.c
0,0 → 1,1160
/* |
This is a version (aka dlmalloc) of malloc/free/realloc written by |
Doug Lea and released to the public domain. Use, modify, and |
redistribute this code without permission or acknowledgement in any |
way you wish. Send questions, comments, complaints, performance |
data, etc to dl@cs.oswego.edu |
|
VERSION 2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) |
|
Note: There may be an updated version of this malloc obtainable at |
ftp://gee.cs.oswego.edu/pub/misc/malloc.c |
Check before installing! |
|
Hacked up for uClibc by Erik Andersen <andersen@codepoet.org> |
*/ |
|
#define _GNU_SOURCE |
#include "malloc.h" |
|
|
#ifdef __UCLIBC_HAS_THREADS__ |
pthread_mutex_t __malloc_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; |
#endif |
|
/* |
There is exactly one instance of this struct in this malloc. |
If you are adapting this malloc in a way that does NOT use a static |
malloc_state, you MUST explicitly zero-fill it before using. This |
malloc relies on the property that malloc_state is initialized to |
all zeroes (as is true of C statics). |
*/ |
struct malloc_state __malloc_state; /* never directly referenced */ |
|
/* forward declaration */ |
static int __malloc_largebin_index(unsigned int sz); |
|
#ifdef __MALLOC_DEBUGGING |
|
/* |
Debugging support |
|
Because freed chunks may be overwritten with bookkeeping fields, this |
malloc will often die when freed memory is overwritten by user |
programs. This can be very effective (albeit in an annoying way) |
in helping track down dangling pointers. |
|
If you compile with -D__MALLOC_DEBUGGING, a number of assertion checks are |
enabled that will catch more memory errors. You probably won't be |
able to make much sense of the actual assertion errors, but they |
should help you locate incorrectly overwritten memory. The |
checking is fairly extensive, and will slow down execution |
noticeably. Calling malloc_stats or mallinfo with __MALLOC_DEBUGGING set will |
attempt to check every non-mmapped allocated and free chunk in the |
course of computing the summmaries. (By nature, mmapped regions |
cannot be checked very much automatically.) |
|
Setting __MALLOC_DEBUGGING may also be helpful if you are trying to modify |
this code. The assertions in the check routines spell out in more |
detail the assumptions and invariants underlying the algorithms. |
|
Setting __MALLOC_DEBUGGING does NOT provide an automated mechanism for checking |
that all accesses to malloced memory stay within their |
bounds. However, there are several add-ons and adaptations of this |
or other mallocs available that do this. |
*/ |
|
/* Properties of all chunks */ |
void __do_check_chunk(mchunkptr p) |
{ |
mstate av = get_malloc_state(); |
#ifdef __DOASSERTS__ |
/* min and max possible addresses assuming contiguous allocation */ |
char* max_address = (char*)(av->top) + chunksize(av->top); |
char* min_address = max_address - av->sbrked_mem; |
unsigned long sz = chunksize(p); |
#endif |
|
if (!chunk_is_mmapped(p)) { |
|
/* Has legal address ... */ |
if (p != av->top) { |
if (contiguous(av)) { |
assert(((char*)p) >= min_address); |
assert(((char*)p + sz) <= ((char*)(av->top))); |
} |
} |
else { |
/* top size is always at least MINSIZE */ |
assert((unsigned long)(sz) >= MINSIZE); |
/* top predecessor always marked inuse */ |
assert(prev_inuse(p)); |
} |
|
} |
else { |
/* address is outside main heap */ |
if (contiguous(av) && av->top != initial_top(av)) { |
assert(((char*)p) < min_address || ((char*)p) > max_address); |
} |
/* chunk is page-aligned */ |
assert(((p->prev_size + sz) & (av->pagesize-1)) == 0); |
/* mem is aligned */ |
assert(aligned_OK(chunk2mem(p))); |
} |
} |
|
/* Properties of free chunks */ |
void __do_check_free_chunk(mchunkptr p) |
{ |
size_t sz = p->size & ~PREV_INUSE; |
#ifdef __DOASSERTS__ |
mstate av = get_malloc_state(); |
mchunkptr next = chunk_at_offset(p, sz); |
#endif |
|
__do_check_chunk(p); |
|
/* Chunk must claim to be free ... */ |
assert(!inuse(p)); |
assert (!chunk_is_mmapped(p)); |
|
/* Unless a special marker, must have OK fields */ |
if ((unsigned long)(sz) >= MINSIZE) |
{ |
assert((sz & MALLOC_ALIGN_MASK) == 0); |
assert(aligned_OK(chunk2mem(p))); |
/* ... matching footer field */ |
assert(next->prev_size == sz); |
/* ... and is fully consolidated */ |
assert(prev_inuse(p)); |
assert (next == av->top || inuse(next)); |
|
/* ... and has minimally sane links */ |
assert(p->fd->bk == p); |
assert(p->bk->fd == p); |
} |
else /* markers are always of size (sizeof(size_t)) */ |
assert(sz == (sizeof(size_t))); |
} |
|
/* Properties of inuse chunks */ |
void __do_check_inuse_chunk(mchunkptr p) |
{ |
mstate av = get_malloc_state(); |
mchunkptr next; |
__do_check_chunk(p); |
|
if (chunk_is_mmapped(p)) |
return; /* mmapped chunks have no next/prev */ |
|
/* Check whether it claims to be in use ... */ |
assert(inuse(p)); |
|
next = next_chunk(p); |
|
/* ... and is surrounded by OK chunks. |
Since more things can be checked with free chunks than inuse ones, |
if an inuse chunk borders them and debug is on, it's worth doing them. |
*/ |
if (!prev_inuse(p)) { |
/* Note that we cannot even look at prev unless it is not inuse */ |
mchunkptr prv = prev_chunk(p); |
assert(next_chunk(prv) == p); |
__do_check_free_chunk(prv); |
} |
|
if (next == av->top) { |
assert(prev_inuse(next)); |
assert(chunksize(next) >= MINSIZE); |
} |
else if (!inuse(next)) |
__do_check_free_chunk(next); |
} |
|
/* Properties of chunks recycled from fastbins */ |
void __do_check_remalloced_chunk(mchunkptr p, size_t s) |
{ |
#ifdef __DOASSERTS__ |
size_t sz = p->size & ~PREV_INUSE; |
#endif |
|
__do_check_inuse_chunk(p); |
|
/* Legal size ... */ |
assert((sz & MALLOC_ALIGN_MASK) == 0); |
assert((unsigned long)(sz) >= MINSIZE); |
/* ... and alignment */ |
assert(aligned_OK(chunk2mem(p))); |
/* chunk is less than MINSIZE more than request */ |
assert((long)(sz) - (long)(s) >= 0); |
assert((long)(sz) - (long)(s + MINSIZE) < 0); |
} |
|
/* Properties of nonrecycled chunks at the point they are malloced */ |
void __do_check_malloced_chunk(mchunkptr p, size_t s) |
{ |
/* same as recycled case ... */ |
__do_check_remalloced_chunk(p, s); |
|
/* |
... plus, must obey implementation invariant that prev_inuse is |
always true of any allocated chunk; i.e., that each allocated |
chunk borders either a previously allocated and still in-use |
chunk, or the base of its memory arena. This is ensured |
by making all allocations from the the `lowest' part of any found |
chunk. This does not necessarily hold however for chunks |
recycled via fastbins. |
*/ |
|
assert(prev_inuse(p)); |
} |
|
|
/* |
Properties of malloc_state. |
|
This may be useful for debugging malloc, as well as detecting user |
programmer errors that somehow write into malloc_state. |
|
If you are extending or experimenting with this malloc, you can |
probably figure out how to hack this routine to print out or |
display chunk addresses, sizes, bins, and other instrumentation. |
*/ |
void __do_check_malloc_state(void) |
{ |
mstate av = get_malloc_state(); |
int i; |
mchunkptr p; |
mchunkptr q; |
mbinptr b; |
unsigned int binbit; |
int empty; |
unsigned int idx; |
size_t size; |
unsigned long total = 0; |
int max_fast_bin; |
|
/* internal size_t must be no wider than pointer type */ |
assert(sizeof(size_t) <= sizeof(char*)); |
|
/* alignment is a power of 2 */ |
assert((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-1)) == 0); |
|
/* cannot run remaining checks until fully initialized */ |
if (av->top == 0 || av->top == initial_top(av)) |
return; |
|
/* pagesize is a power of 2 */ |
assert((av->pagesize & (av->pagesize-1)) == 0); |
|
/* properties of fastbins */ |
|
/* max_fast is in allowed range */ |
assert(get_max_fast(av) <= request2size(MAX_FAST_SIZE)); |
|
max_fast_bin = fastbin_index(av->max_fast); |
|
for (i = 0; i < NFASTBINS; ++i) { |
p = av->fastbins[i]; |
|
/* all bins past max_fast are empty */ |
if (i > max_fast_bin) |
assert(p == 0); |
|
while (p != 0) { |
/* each chunk claims to be inuse */ |
__do_check_inuse_chunk(p); |
total += chunksize(p); |
/* chunk belongs in this bin */ |
assert(fastbin_index(chunksize(p)) == i); |
p = p->fd; |
} |
} |
|
if (total != 0) |
assert(have_fastchunks(av)); |
else if (!have_fastchunks(av)) |
assert(total == 0); |
|
/* check normal bins */ |
for (i = 1; i < NBINS; ++i) { |
b = bin_at(av,i); |
|
/* binmap is accurate (except for bin 1 == unsorted_chunks) */ |
if (i >= 2) { |
binbit = get_binmap(av,i); |
empty = last(b) == b; |
if (!binbit) |
assert(empty); |
else if (!empty) |
assert(binbit); |
} |
|
for (p = last(b); p != b; p = p->bk) { |
/* each chunk claims to be free */ |
__do_check_free_chunk(p); |
size = chunksize(p); |
total += size; |
if (i >= 2) { |
/* chunk belongs in bin */ |
idx = bin_index(size); |
assert(idx == i); |
/* lists are sorted */ |
if ((unsigned long) size >= (unsigned long)(FIRST_SORTED_BIN_SIZE)) { |
assert(p->bk == b || |
(unsigned long)chunksize(p->bk) >= |
(unsigned long)chunksize(p)); |
} |
} |
/* chunk is followed by a legal chain of inuse chunks */ |
for (q = next_chunk(p); |
(q != av->top && inuse(q) && |
(unsigned long)(chunksize(q)) >= MINSIZE); |
q = next_chunk(q)) |
__do_check_inuse_chunk(q); |
} |
} |
|
/* top chunk is OK */ |
__do_check_chunk(av->top); |
|
/* sanity checks for statistics */ |
|
assert(total <= (unsigned long)(av->max_total_mem)); |
assert(av->n_mmaps >= 0); |
assert(av->n_mmaps <= av->max_n_mmaps); |
|
assert((unsigned long)(av->sbrked_mem) <= |
(unsigned long)(av->max_sbrked_mem)); |
|
assert((unsigned long)(av->mmapped_mem) <= |
(unsigned long)(av->max_mmapped_mem)); |
|
assert((unsigned long)(av->max_total_mem) >= |
(unsigned long)(av->mmapped_mem) + (unsigned long)(av->sbrked_mem)); |
} |
#endif |
|
|
/* ----------- Routines dealing with system allocation -------------- */ |
|
/* |
sysmalloc handles malloc cases requiring more memory from the system. |
On entry, it is assumed that av->top does not have enough |
space to service request for nb bytes, thus requiring that av->top |
be extended or replaced. |
*/ |
static void* __malloc_alloc(size_t nb, mstate av) |
{ |
mchunkptr old_top; /* incoming value of av->top */ |
size_t old_size; /* its size */ |
char* old_end; /* its end address */ |
|
long size; /* arg to first MORECORE or mmap call */ |
char* brk; /* return value from MORECORE */ |
|
long correction; /* arg to 2nd MORECORE call */ |
char* snd_brk; /* 2nd return val */ |
|
size_t front_misalign; /* unusable bytes at front of new space */ |
size_t end_misalign; /* partial page left at end of new space */ |
char* aligned_brk; /* aligned offset into brk */ |
|
mchunkptr p; /* the allocated/returned chunk */ |
mchunkptr remainder; /* remainder from allocation */ |
unsigned long remainder_size; /* its size */ |
|
unsigned long sum; /* for updating stats */ |
|
size_t pagemask = av->pagesize - 1; |
|
/* |
If there is space available in fastbins, consolidate and retry |
malloc from scratch rather than getting memory from system. This |
can occur only if nb is in smallbin range so we didn't consolidate |
upon entry to malloc. It is much easier to handle this case here |
than in malloc proper. |
*/ |
|
if (have_fastchunks(av)) { |
assert(in_smallbin_range(nb)); |
__malloc_consolidate(av); |
return malloc(nb - MALLOC_ALIGN_MASK); |
} |
|
|
/* |
If have mmap, and the request size meets the mmap threshold, and |
the system supports mmap, and there are few enough currently |
allocated mmapped regions, try to directly map this request |
rather than expanding top. |
*/ |
|
if ((unsigned long)(nb) >= (unsigned long)(av->mmap_threshold) && |
(av->n_mmaps < av->n_mmaps_max)) { |
|
char* mm; /* return value from mmap call*/ |
|
/* |
Round up size to nearest page. For mmapped chunks, the overhead |
is one (sizeof(size_t)) unit larger than for normal chunks, because there |
is no following chunk whose prev_size field could be used. |
*/ |
size = (nb + (sizeof(size_t)) + MALLOC_ALIGN_MASK + pagemask) & ~pagemask; |
|
/* Don't try if size wraps around 0 */ |
if ((unsigned long)(size) > (unsigned long)(nb)) { |
|
mm = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE)); |
|
if (mm != (char*)(MORECORE_FAILURE)) { |
|
/* |
The offset to the start of the mmapped region is stored |
in the prev_size field of the chunk. This allows us to adjust |
returned start address to meet alignment requirements here |
and in memalign(), and still be able to compute proper |
address argument for later munmap in free() and realloc(). |
*/ |
|
front_misalign = (size_t)chunk2mem(mm) & MALLOC_ALIGN_MASK; |
if (front_misalign > 0) { |
correction = MALLOC_ALIGNMENT - front_misalign; |
p = (mchunkptr)(mm + correction); |
p->prev_size = correction; |
set_head(p, (size - correction) |IS_MMAPPED); |
} |
else { |
p = (mchunkptr)mm; |
p->prev_size = 0; |
set_head(p, size|IS_MMAPPED); |
} |
|
/* update statistics */ |
|
if (++av->n_mmaps > av->max_n_mmaps) |
av->max_n_mmaps = av->n_mmaps; |
|
sum = av->mmapped_mem += size; |
if (sum > (unsigned long)(av->max_mmapped_mem)) |
av->max_mmapped_mem = sum; |
sum += av->sbrked_mem; |
if (sum > (unsigned long)(av->max_total_mem)) |
av->max_total_mem = sum; |
|
check_chunk(p); |
|
return chunk2mem(p); |
} |
} |
} |
|
/* Record incoming configuration of top */ |
|
old_top = av->top; |
old_size = chunksize(old_top); |
old_end = (char*)(chunk_at_offset(old_top, old_size)); |
|
brk = snd_brk = (char*)(MORECORE_FAILURE); |
|
/* If not the first time through, we require old_size to |
* be at least MINSIZE and to have prev_inuse set. */ |
|
assert((old_top == initial_top(av) && old_size == 0) || |
((unsigned long) (old_size) >= MINSIZE && |
prev_inuse(old_top))); |
|
/* Precondition: not enough current space to satisfy nb request */ |
assert((unsigned long)(old_size) < (unsigned long)(nb + MINSIZE)); |
|
/* Precondition: all fastbins are consolidated */ |
assert(!have_fastchunks(av)); |
|
|
/* Request enough space for nb + pad + overhead */ |
|
size = nb + av->top_pad + MINSIZE; |
|
/* |
If contiguous, we can subtract out existing space that we hope to |
combine with new space. We add it back later only if |
we don't actually get contiguous space. |
*/ |
|
if (contiguous(av)) |
size -= old_size; |
|
/* |
Round to a multiple of page size. |
If MORECORE is not contiguous, this ensures that we only call it |
with whole-page arguments. And if MORECORE is contiguous and |
this is not first time through, this preserves page-alignment of |
previous calls. Otherwise, we correct to page-align below. |
*/ |
|
size = (size + pagemask) & ~pagemask; |
|
/* |
Don't try to call MORECORE if argument is so big as to appear |
negative. Note that since mmap takes size_t arg, it may succeed |
below even if we cannot call MORECORE. |
*/ |
|
if (size > 0) |
brk = (char*)(MORECORE(size)); |
|
/* |
If have mmap, try using it as a backup when MORECORE fails or |
cannot be used. This is worth doing on systems that have "holes" in |
address space, so sbrk cannot extend to give contiguous space, but |
space is available elsewhere. Note that we ignore mmap max count |
and threshold limits, since the space will not be used as a |
segregated mmap region. |
*/ |
|
if (brk == (char*)(MORECORE_FAILURE)) { |
|
/* Cannot merge with old top, so add its size back in */ |
if (contiguous(av)) |
size = (size + old_size + pagemask) & ~pagemask; |
|
/* If we are relying on mmap as backup, then use larger units */ |
if ((unsigned long)(size) < (unsigned long)(MMAP_AS_MORECORE_SIZE)) |
size = MMAP_AS_MORECORE_SIZE; |
|
/* Don't try if size wraps around 0 */ |
if ((unsigned long)(size) > (unsigned long)(nb)) { |
|
brk = (char*)(MMAP(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE)); |
|
if (brk != (char*)(MORECORE_FAILURE)) { |
|
/* We do not need, and cannot use, another sbrk call to find end */ |
snd_brk = brk + size; |
|
/* Record that we no longer have a contiguous sbrk region. |
After the first time mmap is used as backup, we do not |
ever rely on contiguous space since this could incorrectly |
bridge regions. |
*/ |
set_noncontiguous(av); |
} |
} |
} |
|
if (brk != (char*)(MORECORE_FAILURE)) { |
av->sbrked_mem += size; |
|
/* |
If MORECORE extends previous space, we can likewise extend top size. |
*/ |
|
if (brk == old_end && snd_brk == (char*)(MORECORE_FAILURE)) { |
set_head(old_top, (size + old_size) | PREV_INUSE); |
} |
|
/* |
Otherwise, make adjustments: |
|
* If the first time through or noncontiguous, we need to call sbrk |
just to find out where the end of memory lies. |
|
* We need to ensure that all returned chunks from malloc will meet |
MALLOC_ALIGNMENT |
|
* If there was an intervening foreign sbrk, we need to adjust sbrk |
request size to account for fact that we will not be able to |
combine new space with existing space in old_top. |
|
* Almost all systems internally allocate whole pages at a time, in |
which case we might as well use the whole last page of request. |
So we allocate enough more memory to hit a page boundary now, |
which in turn causes future contiguous calls to page-align. |
*/ |
|
else { |
front_misalign = 0; |
end_misalign = 0; |
correction = 0; |
aligned_brk = brk; |
|
/* |
If MORECORE returns an address lower than we have seen before, |
we know it isn't really contiguous. This and some subsequent |
checks help cope with non-conforming MORECORE functions and |
the presence of "foreign" calls to MORECORE from outside of |
malloc or by other threads. We cannot guarantee to detect |
these in all cases, but cope with the ones we do detect. |
*/ |
if (contiguous(av) && old_size != 0 && brk < old_end) { |
set_noncontiguous(av); |
} |
|
/* handle contiguous cases */ |
if (contiguous(av)) { |
|
/* We can tolerate forward non-contiguities here (usually due |
to foreign calls) but treat them as part of our space for |
stats reporting. */ |
if (old_size != 0) |
av->sbrked_mem += brk - old_end; |
|
/* Guarantee alignment of first new chunk made from this space */ |
|
front_misalign = (size_t)chunk2mem(brk) & MALLOC_ALIGN_MASK; |
if (front_misalign > 0) { |
|
/* |
Skip over some bytes to arrive at an aligned position. |
We don't need to specially mark these wasted front bytes. |
They will never be accessed anyway because |
prev_inuse of av->top (and any chunk created from its start) |
is always true after initialization. |
*/ |
|
correction = MALLOC_ALIGNMENT - front_misalign; |
aligned_brk += correction; |
} |
|
/* |
If this isn't adjacent to existing space, then we will not |
be able to merge with old_top space, so must add to 2nd request. |
*/ |
|
correction += old_size; |
|
/* Extend the end address to hit a page boundary */ |
end_misalign = (size_t)(brk + size + correction); |
correction += ((end_misalign + pagemask) & ~pagemask) - end_misalign; |
|
assert(correction >= 0); |
snd_brk = (char*)(MORECORE(correction)); |
|
if (snd_brk == (char*)(MORECORE_FAILURE)) { |
/* |
If can't allocate correction, try to at least find out current |
brk. It might be enough to proceed without failing. |
*/ |
correction = 0; |
snd_brk = (char*)(MORECORE(0)); |
} |
else if (snd_brk < brk) { |
/* |
If the second call gives noncontiguous space even though |
it says it won't, the only course of action is to ignore |
results of second call, and conservatively estimate where |
the first call left us. Also set noncontiguous, so this |
won't happen again, leaving at most one hole. |
|
Note that this check is intrinsically incomplete. Because |
MORECORE is allowed to give more space than we ask for, |
there is no reliable way to detect a noncontiguity |
producing a forward gap for the second call. |
*/ |
snd_brk = brk + size; |
correction = 0; |
set_noncontiguous(av); |
} |
|
} |
|
/* handle non-contiguous cases */ |
else { |
/* MORECORE/mmap must correctly align */ |
assert(aligned_OK(chunk2mem(brk))); |
|
/* Find out current end of memory */ |
if (snd_brk == (char*)(MORECORE_FAILURE)) { |
snd_brk = (char*)(MORECORE(0)); |
av->sbrked_mem += snd_brk - brk - size; |
} |
} |
|
/* Adjust top based on results of second sbrk */ |
if (snd_brk != (char*)(MORECORE_FAILURE)) { |
av->top = (mchunkptr)aligned_brk; |
set_head(av->top, (snd_brk - aligned_brk + correction) | PREV_INUSE); |
av->sbrked_mem += correction; |
|
/* |
If not the first time through, we either have a |
gap due to foreign sbrk or a non-contiguous region. Insert a |
double fencepost at old_top to prevent consolidation with space |
we don't own. These fenceposts are artificial chunks that are |
marked as inuse and are in any case too small to use. We need |
two to make sizes and alignments work out. |
*/ |
|
if (old_size != 0) { |
/* Shrink old_top to insert fenceposts, keeping size a |
multiple of MALLOC_ALIGNMENT. We know there is at least |
enough space in old_top to do this. |
*/ |
old_size = (old_size - 3*(sizeof(size_t))) & ~MALLOC_ALIGN_MASK; |
set_head(old_top, old_size | PREV_INUSE); |
|
/* |
Note that the following assignments completely overwrite |
old_top when old_size was previously MINSIZE. This is |
intentional. We need the fencepost, even if old_top otherwise gets |
lost. |
*/ |
chunk_at_offset(old_top, old_size )->size = |
(sizeof(size_t))|PREV_INUSE; |
|
chunk_at_offset(old_top, old_size + (sizeof(size_t)))->size = |
(sizeof(size_t))|PREV_INUSE; |
|
/* If possible, release the rest, suppressing trimming. */ |
if (old_size >= MINSIZE) { |
size_t tt = av->trim_threshold; |
av->trim_threshold = (size_t)(-1); |
free(chunk2mem(old_top)); |
av->trim_threshold = tt; |
} |
} |
} |
} |
|
/* Update statistics */ |
sum = av->sbrked_mem; |
if (sum > (unsigned long)(av->max_sbrked_mem)) |
av->max_sbrked_mem = sum; |
|
sum += av->mmapped_mem; |
if (sum > (unsigned long)(av->max_total_mem)) |
av->max_total_mem = sum; |
|
check_malloc_state(); |
|
/* finally, do the allocation */ |
|
p = av->top; |
size = chunksize(p); |
|
/* check that one of the above allocation paths succeeded */ |
if ((unsigned long)(size) >= (unsigned long)(nb + MINSIZE)) { |
remainder_size = size - nb; |
remainder = chunk_at_offset(p, nb); |
av->top = remainder; |
set_head(p, nb | PREV_INUSE); |
set_head(remainder, remainder_size | PREV_INUSE); |
check_malloced_chunk(p, nb); |
return chunk2mem(p); |
} |
|
} |
|
/* catch all failure paths */ |
errno = ENOMEM; |
return 0; |
} |
|
|
/* |
Compute index for size. We expect this to be inlined when |
compiled with optimization, else not, which works out well. |
*/ |
static int __malloc_largebin_index(unsigned int sz) |
{ |
unsigned int x = sz >> SMALLBIN_WIDTH; |
unsigned int m; /* bit position of highest set bit of m */ |
|
if (x >= 0x10000) return NBINS-1; |
|
/* On intel, use BSRL instruction to find highest bit */ |
#if defined(__GNUC__) && defined(i386) |
|
__asm__("bsrl %1,%0\n\t" |
: "=r" (m) |
: "g" (x)); |
|
#else |
{ |
/* |
Based on branch-free nlz algorithm in chapter 5 of Henry |
S. Warren Jr's book "Hacker's Delight". |
*/ |
|
unsigned int n = ((x - 0x100) >> 16) & 8; |
x <<= n; |
m = ((x - 0x1000) >> 16) & 4; |
n += m; |
x <<= m; |
m = ((x - 0x4000) >> 16) & 2; |
n += m; |
x = (x << m) >> 14; |
m = 13 - n + (x & ~(x>>1)); |
} |
#endif |
|
/* Use next 2 bits to create finer-granularity bins */ |
return NSMALLBINS + (m << 2) + ((sz >> (m + 6)) & 3); |
} |
|
|
|
/* ---------------------------------------------------------------------- |
* |
* PUBLIC STUFF |
* |
* ----------------------------------------------------------------------*/ |
|
|
/* ------------------------------ malloc ------------------------------ */ |
void* malloc(size_t bytes) |
{ |
mstate av; |
|
size_t nb; /* normalized request size */ |
unsigned int idx; /* associated bin index */ |
mbinptr bin; /* associated bin */ |
mfastbinptr* fb; /* associated fastbin */ |
|
mchunkptr victim; /* inspected/selected chunk */ |
size_t size; /* its size */ |
int victim_index; /* its bin index */ |
|
mchunkptr remainder; /* remainder from a split */ |
unsigned long remainder_size; /* its size */ |
|
unsigned int block; /* bit map traverser */ |
unsigned int bit; /* bit map traverser */ |
unsigned int map; /* current word of binmap */ |
|
mchunkptr fwd; /* misc temp for linking */ |
mchunkptr bck; /* misc temp for linking */ |
void * sysmem; |
|
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 |
to obtain a size of at least MINSIZE, the smallest allocatable |
size. Also, checked_request2size traps (returning 0) request sizes |
that are so large that they wrap around zero when padded and |
aligned. |
*/ |
|
checked_request2size(bytes, nb); |
|
/* |
Bypass search if no frees yet |
*/ |
if (!have_anychunks(av)) { |
if (av->max_fast == 0) /* initialization check */ |
__malloc_consolidate(av); |
goto use_top; |
} |
|
/* |
If the size qualifies as a fastbin, first check corresponding bin. |
*/ |
|
if ((unsigned long)(nb) <= (unsigned long)(av->max_fast)) { |
fb = &(av->fastbins[(fastbin_index(nb))]); |
if ( (victim = *fb) != 0) { |
*fb = victim->fd; |
check_remalloced_chunk(victim, nb); |
UNLOCK; |
return chunk2mem(victim); |
} |
} |
|
/* |
If a small request, check regular bin. Since these "smallbins" |
hold one size each, no searching within bins is necessary. |
(For a large request, we need to wait until unsorted chunks are |
processed to find best fit. But for small ones, fits are exact |
anyway, so we can check now, which is faster.) |
*/ |
|
if (in_smallbin_range(nb)) { |
idx = smallbin_index(nb); |
bin = bin_at(av,idx); |
|
if ( (victim = last(bin)) != bin) { |
bck = victim->bk; |
set_inuse_bit_at_offset(victim, nb); |
bin->bk = bck; |
bck->fd = bin; |
|
check_malloced_chunk(victim, nb); |
UNLOCK; |
return chunk2mem(victim); |
} |
} |
|
/* If this is a large request, consolidate fastbins before continuing. |
While it might look excessive to kill all fastbins before |
even seeing if there is space available, this avoids |
fragmentation problems normally associated with fastbins. |
Also, in practice, programs tend to have runs of either small or |
large requests, but less often mixtures, so consolidation is not |
invoked all that often in most programs. And the programs that |
it is called frequently in otherwise tend to fragment. |
*/ |
|
else { |
idx = __malloc_largebin_index(nb); |
if (have_fastchunks(av)) |
__malloc_consolidate(av); |
} |
|
/* |
Process recently freed or remaindered chunks, taking one only if |
it is exact fit, or, if this a small request, the chunk is remainder from |
the most recent non-exact fit. Place other traversed chunks in |
bins. Note that this step is the only place in any routine where |
chunks are placed in bins. |
*/ |
|
while ( (victim = unsorted_chunks(av)->bk) != unsorted_chunks(av)) { |
bck = victim->bk; |
size = chunksize(victim); |
|
/* If a small request, try to use last remainder if it is the |
only chunk in unsorted bin. This helps promote locality for |
runs of consecutive small requests. This is the only |
exception to best-fit, and applies only when there is |
no exact fit for a small chunk. |
*/ |
|
if (in_smallbin_range(nb) && |
bck == unsorted_chunks(av) && |
victim == av->last_remainder && |
(unsigned long)(size) > (unsigned long)(nb + MINSIZE)) { |
|
/* split and reattach remainder */ |
remainder_size = size - nb; |
remainder = chunk_at_offset(victim, nb); |
unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder; |
av->last_remainder = remainder; |
remainder->bk = remainder->fd = unsorted_chunks(av); |
|
set_head(victim, nb | PREV_INUSE); |
set_head(remainder, remainder_size | PREV_INUSE); |
set_foot(remainder, remainder_size); |
|
check_malloced_chunk(victim, nb); |
UNLOCK; |
return chunk2mem(victim); |
} |
|
/* remove from unsorted list */ |
unsorted_chunks(av)->bk = bck; |
bck->fd = unsorted_chunks(av); |
|
/* Take now instead of binning if exact fit */ |
|
if (size == nb) { |
set_inuse_bit_at_offset(victim, size); |
check_malloced_chunk(victim, nb); |
UNLOCK; |
return chunk2mem(victim); |
} |
|
/* place chunk in bin */ |
|
if (in_smallbin_range(size)) { |
victim_index = smallbin_index(size); |
bck = bin_at(av, victim_index); |
fwd = bck->fd; |
} |
else { |
victim_index = __malloc_largebin_index(size); |
bck = bin_at(av, victim_index); |
fwd = bck->fd; |
|
if (fwd != bck) { |
/* if smaller than smallest, place first */ |
if ((unsigned long)(size) < (unsigned long)(bck->bk->size)) { |
fwd = bck; |
bck = bck->bk; |
} |
else if ((unsigned long)(size) >= |
(unsigned long)(FIRST_SORTED_BIN_SIZE)) { |
|
/* maintain large bins in sorted order */ |
size |= PREV_INUSE; /* Or with inuse bit to speed comparisons */ |
while ((unsigned long)(size) < (unsigned long)(fwd->size)) |
fwd = fwd->fd; |
bck = fwd->bk; |
} |
} |
} |
|
mark_bin(av, victim_index); |
victim->bk = bck; |
victim->fd = fwd; |
fwd->bk = victim; |
bck->fd = victim; |
} |
|
/* |
If a large request, scan through the chunks of current bin to |
find one that fits. (This will be the smallest that fits unless |
FIRST_SORTED_BIN_SIZE has been changed from default.) This is |
the only step where an unbounded number of chunks might be |
scanned without doing anything useful with them. However the |
lists tend to be short. |
*/ |
|
if (!in_smallbin_range(nb)) { |
bin = bin_at(av, idx); |
|
for (victim = last(bin); victim != bin; victim = victim->bk) { |
size = chunksize(victim); |
|
if ((unsigned long)(size) >= (unsigned long)(nb)) { |
remainder_size = size - nb; |
unlink(victim, bck, fwd); |
|
/* Exhaust */ |
if (remainder_size < MINSIZE) { |
set_inuse_bit_at_offset(victim, size); |
check_malloced_chunk(victim, nb); |
UNLOCK; |
return chunk2mem(victim); |
} |
/* Split */ |
else { |
remainder = chunk_at_offset(victim, nb); |
unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder; |
remainder->bk = remainder->fd = unsorted_chunks(av); |
set_head(victim, nb | PREV_INUSE); |
set_head(remainder, remainder_size | PREV_INUSE); |
set_foot(remainder, remainder_size); |
check_malloced_chunk(victim, nb); |
UNLOCK; |
return chunk2mem(victim); |
} |
} |
} |
} |
|
/* |
Search for a chunk by scanning bins, starting with next largest |
bin. This search is strictly by best-fit; i.e., the smallest |
(with ties going to approximately the least recently used) chunk |
that fits is selected. |
|
The bitmap avoids needing to check that most blocks are nonempty. |
*/ |
|
++idx; |
bin = bin_at(av,idx); |
block = idx2block(idx); |
map = av->binmap[block]; |
bit = idx2bit(idx); |
|
for (;;) { |
|
/* Skip rest of block if there are no more set bits in this block. */ |
if (bit > map || bit == 0) { |
do { |
if (++block >= BINMAPSIZE) /* out of bins */ |
goto use_top; |
} while ( (map = av->binmap[block]) == 0); |
|
bin = bin_at(av, (block << BINMAPSHIFT)); |
bit = 1; |
} |
|
/* Advance to bin with set bit. There must be one. */ |
while ((bit & map) == 0) { |
bin = next_bin(bin); |
bit <<= 1; |
assert(bit != 0); |
} |
|
/* Inspect the bin. It is likely to be non-empty */ |
victim = last(bin); |
|
/* If a false alarm (empty bin), clear the bit. */ |
if (victim == bin) { |
av->binmap[block] = map &= ~bit; /* Write through */ |
bin = next_bin(bin); |
bit <<= 1; |
} |
|
else { |
size = chunksize(victim); |
|
/* We know the first chunk in this bin is big enough to use. */ |
assert((unsigned long)(size) >= (unsigned long)(nb)); |
|
remainder_size = size - nb; |
|
/* unlink */ |
bck = victim->bk; |
bin->bk = bck; |
bck->fd = bin; |
|
/* Exhaust */ |
if (remainder_size < MINSIZE) { |
set_inuse_bit_at_offset(victim, size); |
check_malloced_chunk(victim, nb); |
UNLOCK; |
return chunk2mem(victim); |
} |
|
/* Split */ |
else { |
remainder = chunk_at_offset(victim, nb); |
|
unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder; |
remainder->bk = remainder->fd = unsorted_chunks(av); |
/* advertise as last remainder */ |
if (in_smallbin_range(nb)) |
av->last_remainder = remainder; |
|
set_head(victim, nb | PREV_INUSE); |
set_head(remainder, remainder_size | PREV_INUSE); |
set_foot(remainder, remainder_size); |
check_malloced_chunk(victim, nb); |
UNLOCK; |
return chunk2mem(victim); |
} |
} |
} |
|
use_top: |
/* |
If large enough, split off the chunk bordering the end of memory |
(held in av->top). Note that this is in accord with the best-fit |
search rule. In effect, av->top is treated as larger (and thus |
less well fitting) than any other available chunk since it can |
be extended to be as large as necessary (up to system |
limitations). |
|
We require that av->top always exists (i.e., has size >= |
MINSIZE) after initialization, so if it would otherwise be |
exhuasted by current request, it is replenished. (The main |
reason for ensuring it exists is that we may need MINSIZE space |
to put in fenceposts in sysmalloc.) |
*/ |
|
victim = av->top; |
size = chunksize(victim); |
|
if ((unsigned long)(size) >= (unsigned long)(nb + MINSIZE)) { |
remainder_size = size - nb; |
remainder = chunk_at_offset(victim, nb); |
av->top = remainder; |
set_head(victim, nb | PREV_INUSE); |
set_head(remainder, remainder_size | PREV_INUSE); |
|
check_malloced_chunk(victim, nb); |
UNLOCK; |
return chunk2mem(victim); |
} |
|
/* If no space in top, relay to handle system-dependent cases */ |
sysmem = __malloc_alloc(nb, av); |
UNLOCK; |
return sysmem; |
} |
|
/malloc-standard/mallopt.c
0,0 → 1,64
/* |
This is a version (aka dlmalloc) of malloc/free/realloc written by |
Doug Lea and released to the public domain. Use, modify, and |
redistribute this code without permission or acknowledgement in any |
way you wish. Send questions, comments, complaints, performance |
data, etc to dl@cs.oswego.edu |
|
VERSION 2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) |
|
Note: There may be an updated version of this malloc obtainable at |
ftp://gee.cs.oswego.edu/pub/misc/malloc.c |
Check before installing! |
|
Hacked up for uClibc by Erik Andersen <andersen@codepoet.org> |
*/ |
|
#include "malloc.h" |
|
|
/* ------------------------------ mallopt ------------------------------ */ |
int mallopt(int param_number, int value) |
{ |
int ret; |
mstate av; |
|
ret = 0; |
|
LOCK; |
av = get_malloc_state(); |
/* Ensure initialization/consolidation */ |
__malloc_consolidate(av); |
|
switch(param_number) { |
case M_MXFAST: |
if (value >= 0 && value <= MAX_FAST_SIZE) { |
set_max_fast(av, value); |
ret = 1; |
} |
break; |
|
case M_TRIM_THRESHOLD: |
av->trim_threshold = value; |
ret = 1; |
break; |
|
case M_TOP_PAD: |
av->top_pad = value; |
ret = 1; |
break; |
|
case M_MMAP_THRESHOLD: |
av->mmap_threshold = value; |
ret = 1; |
break; |
|
case M_MMAP_MAX: |
av->n_mmaps_max = value; |
ret = 1; |
break; |
} |
UNLOCK; |
return ret; |
} |
|
/malloc-standard/memalign.c
0,0 → 1,126
/* |
This is a version (aka dlmalloc) of malloc/free/realloc written by |
Doug Lea and released to the public domain. Use, modify, and |
redistribute this code without permission or acknowledgement in any |
way you wish. Send questions, comments, complaints, performance |
data, etc to dl@cs.oswego.edu |
|
VERSION 2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) |
|
Note: There may be an updated version of this malloc obtainable at |
ftp://gee.cs.oswego.edu/pub/misc/malloc.c |
Check before installing! |
|
Hacked up for uClibc by Erik Andersen <andersen@codepoet.org> |
*/ |
|
#include <features.h> |
#include <stddef.h> |
#include <unistd.h> |
#include <errno.h> |
#include <string.h> |
#include "malloc.h" |
|
|
/* ------------------------------ memalign ------------------------------ */ |
void* memalign(size_t alignment, size_t bytes) |
{ |
size_t nb; /* padded request size */ |
char* m; /* memory returned by malloc call */ |
mchunkptr p; /* corresponding chunk */ |
char* brk; /* alignment point within p */ |
mchunkptr newp; /* chunk to return */ |
size_t newsize; /* its size */ |
size_t leadsize; /* leading space before alignment point */ |
mchunkptr remainder; /* spare room at end to split off */ |
unsigned long remainder_size; /* its size */ |
size_t size; |
|
/* If need less alignment than we give anyway, just relay to malloc */ |
|
if (alignment <= MALLOC_ALIGNMENT) return malloc(bytes); |
|
/* Otherwise, ensure that it is at least a minimum chunk size */ |
|
if (alignment < MINSIZE) alignment = MINSIZE; |
|
/* Make sure alignment is power of 2 (in case MINSIZE is not). */ |
if ((alignment & (alignment - 1)) != 0) { |
size_t a = MALLOC_ALIGNMENT * 2; |
while ((unsigned long)a < (unsigned long)alignment) a <<= 1; |
alignment = a; |
} |
|
LOCK; |
checked_request2size(bytes, nb); |
|
/* Strategy: find a spot within that chunk that meets the alignment |
* request, and then possibly free the leading and trailing space. */ |
|
|
/* Call malloc with worst case padding to hit alignment. */ |
|
m = (char*)(malloc(nb + alignment + MINSIZE)); |
|
if (m == 0) { |
UNLOCK; |
return 0; /* propagate failure */ |
} |
|
p = mem2chunk(m); |
|
if ((((unsigned long)(m)) % alignment) != 0) { /* misaligned */ |
|
/* |
Find an aligned spot inside chunk. Since we need to give back |
leading space in a chunk of at least MINSIZE, if the first |
calculation places us at a spot with less than MINSIZE leader, |
we can move to the next aligned spot -- we've allocated enough |
total room so that this is always possible. |
*/ |
|
brk = (char*)mem2chunk((unsigned long)(((unsigned long)(m + alignment - 1)) & |
-((signed long) alignment))); |
if ((unsigned long)(brk - (char*)(p)) < MINSIZE) |
brk += alignment; |
|
newp = (mchunkptr)brk; |
leadsize = brk - (char*)(p); |
newsize = chunksize(p) - leadsize; |
|
/* For mmapped chunks, just adjust offset */ |
if (chunk_is_mmapped(p)) { |
newp->prev_size = p->prev_size + leadsize; |
set_head(newp, newsize|IS_MMAPPED); |
UNLOCK; |
return chunk2mem(newp); |
} |
|
/* Otherwise, give back leader, use the rest */ |
set_head(newp, newsize | PREV_INUSE); |
set_inuse_bit_at_offset(newp, newsize); |
set_head_size(p, leadsize); |
free(chunk2mem(p)); |
p = newp; |
|
assert (newsize >= nb && |
(((unsigned long)(chunk2mem(p))) % alignment) == 0); |
} |
|
/* Also give back spare room at the end */ |
if (!chunk_is_mmapped(p)) { |
size = chunksize(p); |
if ((unsigned long)(size) > (unsigned long)(nb + MINSIZE)) { |
remainder_size = size - nb; |
remainder = chunk_at_offset(p, nb); |
set_head(remainder, remainder_size | PREV_INUSE); |
set_head_size(p, nb); |
free(chunk2mem(remainder)); |
} |
} |
|
check_inuse_chunk(p); |
UNLOCK; |
return chunk2mem(p); |
} |
|
/malloc-standard/Makefile
0,0 → 1,51
# Makefile for uClibc |
# |
# Copyright (C) 2000 by Lineo, inc. |
# Copyright (C) 2000,2001 Erik Andersen <andersen@uclibc.org> |
# |
# This program is free software; you can redistribute it and/or modify it under |
# the terms of the GNU Library General Public License as published by the Free |
# Software Foundation; either version 2 of the License, or (at your option) any |
# later version. |
# |
# This program 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 Library General Public License 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 |
# |
# Derived in part from the Linux-8086 C library, the GNU C Library, and several |
# other sundry sources. Files within this library are copyright by their |
# respective copyright holders. |
|
TOPDIR=../../../ |
include $(TOPDIR)Rules.mak |
|
# Turn on malloc debugging if requested |
ifeq ($(UCLIBC_MALLOC_DEBUGGING),y) |
CFLAGS += -D__MALLOC_DEBUGGING |
endif |
|
# 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 |
COBJS=$(patsubst %.c,%.o, $(CSRC)) |
OBJS=$(COBJS) |
|
all: $(OBJS) $(LIBC) |
|
$(LIBC): ar-target |
|
ar-target: $(OBJS) |
$(AR) $(ARFLAGS) $(LIBC) $(OBJS) |
|
$(COBJS): %.o : %.c |
$(CC) $(CFLAGS) -c $< -o $@ |
$(STRIPTOOL) -x -R .note -R .comment $*.o |
|
clean: |
$(RM) *.[oa] *~ core |
|
/malloc-standard/malloc.h
0,0 → 1,953
/* |
This is a version (aka dlmalloc) of malloc/free/realloc written by |
Doug Lea and released to the public domain. Use, modify, and |
redistribute this code without permission or acknowledgement in any |
way you wish. Send questions, comments, complaints, performance |
data, etc to dl@cs.oswego.edu |
|
VERSION 2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) |
|
Note: There may be an updated version of this malloc obtainable at |
ftp://gee.cs.oswego.edu/pub/misc/malloc.c |
Check before installing! |
|
Hacked up for uClibc by Erik Andersen <andersen@codepoet.org> |
*/ |
|
#include <features.h> |
#include <stddef.h> |
#include <unistd.h> |
#include <errno.h> |
#include <string.h> |
#include <malloc.h> |
|
|
#ifdef __UCLIBC_HAS_THREADS__ |
#include <pthread.h> |
extern pthread_mutex_t __malloc_lock; |
# define LOCK __pthread_mutex_lock(&__malloc_lock) |
# define UNLOCK __pthread_mutex_unlock(&__malloc_lock); |
#else |
# define LOCK |
# define UNLOCK |
#endif |
|
|
|
/* |
MALLOC_ALIGNMENT is the minimum alignment for malloc'ed chunks. |
It must be a power of two at least 2 * (sizeof(size_t)), even on machines |
for which smaller alignments would suffice. It may be defined as |
larger than this though. Note however that code and data structures |
are optimized for the case of 8-byte alignment. |
*/ |
#ifndef MALLOC_ALIGNMENT |
#define MALLOC_ALIGNMENT (2 * (sizeof(size_t))) |
#endif |
|
/* The corresponding bit mask value */ |
#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1) |
|
/* |
TRIM_FASTBINS controls whether free() of a very small chunk can |
immediately lead to trimming. Setting to true (1) can reduce memory |
footprint, but will almost always slow down programs that use a lot |
of small chunks. |
|
Define this only if you are willing to give up some speed to more |
aggressively reduce system-level memory footprint when releasing |
memory in programs that use many small chunks. You can get |
essentially the same effect by setting MXFAST to 0, but this can |
lead to even greater slowdowns in programs using many small chunks. |
TRIM_FASTBINS is an in-between compile-time option, that disables |
only those chunks bordering topmost memory from being placed in |
fastbins. |
*/ |
#ifndef TRIM_FASTBINS |
#define TRIM_FASTBINS 0 |
#endif |
|
|
/* |
MORECORE-related declarations. By default, rely on sbrk |
*/ |
|
|
/* |
MORECORE is the name of the routine to call to obtain more memory |
from the system. See below for general guidance on writing |
alternative MORECORE functions, as well as a version for WIN32 and a |
sample version for pre-OSX macos. |
*/ |
#ifndef MORECORE |
#define MORECORE sbrk |
#endif |
|
/* |
MORECORE_FAILURE is the value returned upon failure of MORECORE |
as well as mmap. Since it cannot be an otherwise valid memory address, |
and must reflect values of standard sys calls, you probably ought not |
try to redefine it. |
*/ |
#ifndef MORECORE_FAILURE |
#define MORECORE_FAILURE (-1) |
#endif |
|
/* |
If MORECORE_CONTIGUOUS is true, take advantage of fact that |
consecutive calls to MORECORE with positive arguments always return |
contiguous increasing addresses. This is true of unix sbrk. Even |
if not defined, when regions happen to be contiguous, malloc will |
permit allocations spanning regions obtained from different |
calls. But defining this when applicable enables some stronger |
consistency checks and space efficiencies. |
*/ |
#ifndef MORECORE_CONTIGUOUS |
#define MORECORE_CONTIGUOUS 1 |
#endif |
|
/* |
MMAP_AS_MORECORE_SIZE is the minimum mmap size argument to use if |
sbrk fails, and mmap is used as a backup (which is done only if |
HAVE_MMAP). The value must be a multiple of page size. This |
backup strategy generally applies only when systems have "holes" in |
address space, so sbrk cannot perform contiguous expansion, but |
there is still space available on system. On systems for which |
this is known to be useful (i.e. most linux kernels), this occurs |
only when programs allocate huge amounts of memory. Between this, |
and the fact that mmap regions tend to be limited, the size should |
be large, to avoid too many mmap calls and thus avoid running out |
of kernel resources. |
*/ |
#ifndef MMAP_AS_MORECORE_SIZE |
#define MMAP_AS_MORECORE_SIZE (1024 * 1024) |
#endif |
|
/* |
The system page size. To the extent possible, this malloc manages |
memory from the system in page-size units. Note that this value is |
cached during initialization into a field of malloc_state. So even |
if malloc_getpagesize is a function, it is only called once. |
|
The following mechanics for getpagesize were adapted from bsd/gnu |
getpagesize.h. If none of the system-probes here apply, a value of |
4096 is used, which should be OK: If they don't apply, then using |
the actual value probably doesn't impact performance. |
*/ |
#ifndef malloc_getpagesize |
# include <unistd.h> |
# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) |
#else /* just guess */ |
# define malloc_getpagesize (4096) |
#endif |
|
|
/* mallopt tuning options */ |
|
/* |
M_MXFAST is the maximum request size used for "fastbins", special bins |
that hold returned chunks without consolidating their spaces. This |
enables future requests for chunks of the same size to be handled |
very quickly, but can increase fragmentation, and thus increase the |
overall memory footprint of a program. |
|
This malloc manages fastbins very conservatively yet still |
efficiently, so fragmentation is rarely a problem for values less |
than or equal to the default. The maximum supported value of MXFAST |
is 80. You wouldn't want it any higher than this anyway. Fastbins |
are designed especially for use with many small structs, objects or |
strings -- the default handles structs/objects/arrays with sizes up |
to 16 4byte fields, or small strings representing words, tokens, |
etc. Using fastbins for larger objects normally worsens |
fragmentation without improving speed. |
|
M_MXFAST is set in REQUEST size units. It is internally used in |
chunksize units, which adds padding and alignment. You can reduce |
M_MXFAST to 0 to disable all use of fastbins. This causes the malloc |
algorithm to be a closer approximation of fifo-best-fit in all cases, |
not just for larger requests, but will generally cause it to be |
slower. |
*/ |
|
|
/* M_MXFAST is a standard SVID/XPG tuning option, usually listed in malloc.h */ |
#ifndef M_MXFAST |
#define M_MXFAST 1 |
#endif |
|
#ifndef DEFAULT_MXFAST |
#define DEFAULT_MXFAST 64 |
#endif |
|
|
/* |
M_TRIM_THRESHOLD is the maximum amount of unused top-most memory |
to keep before releasing via malloc_trim in free(). |
|
Automatic trimming is mainly useful in long-lived programs. |
Because trimming via sbrk can be slow on some systems, and can |
sometimes be wasteful (in cases where programs immediately |
afterward allocate more large chunks) the value should be high |
enough so that your overall system performance would improve by |
releasing this much memory. |
|
The trim threshold and the mmap control parameters (see below) |
can be traded off with one another. Trimming and mmapping are |
two different ways of releasing unused memory back to the |
system. Between these two, it is often possible to keep |
system-level demands of a long-lived program down to a bare |
minimum. For example, in one test suite of sessions measuring |
the XF86 X server on Linux, using a trim threshold of 128K and a |
mmap threshold of 192K led to near-minimal long term resource |
consumption. |
|
If you are using this malloc in a long-lived program, it should |
pay to experiment with these values. As a rough guide, you |
might set to a value close to the average size of a process |
(program) running on your system. Releasing this much memory |
would allow such a process to run in memory. Generally, it's |
worth it to tune for trimming rather tham memory mapping when a |
program undergoes phases where several large chunks are |
allocated and released in ways that can reuse each other's |
storage, perhaps mixed with phases where there are no such |
chunks at all. And in well-behaved long-lived programs, |
controlling release of large blocks via trimming versus mapping |
is usually faster. |
|
However, in most programs, these parameters serve mainly as |
protection against the system-level effects of carrying around |
massive amounts of unneeded memory. Since frequent calls to |
sbrk, mmap, and munmap otherwise degrade performance, the default |
parameters are set to relatively high values that serve only as |
safeguards. |
|
The trim value must be greater than page size to have any useful |
effect. To disable trimming completely, you can set to |
(unsigned long)(-1) |
|
Trim settings interact with fastbin (MXFAST) settings: Unless |
TRIM_FASTBINS is defined, automatic trimming never takes place upon |
freeing a chunk with size less than or equal to MXFAST. Trimming is |
instead delayed until subsequent freeing of larger chunks. However, |
you can still force an attempted trim by calling malloc_trim. |
|
Also, trimming is not generally possible in cases where |
the main arena is obtained via mmap. |
|
Note that the trick some people use of mallocing a huge space and |
then freeing it at program startup, in an attempt to reserve system |
memory, doesn't have the intended effect under automatic trimming, |
since that memory will immediately be returned to the system. |
*/ |
#define M_TRIM_THRESHOLD -1 |
|
#ifndef DEFAULT_TRIM_THRESHOLD |
#define DEFAULT_TRIM_THRESHOLD (256 * 1024) |
#endif |
|
/* |
M_TOP_PAD is the amount of extra `padding' space to allocate or |
retain whenever sbrk is called. It is used in two ways internally: |
|
* When sbrk is called to extend the top of the arena to satisfy |
a new malloc request, this much padding is added to the sbrk |
request. |
|
* When malloc_trim is called automatically from free(), |
it is used as the `pad' argument. |
|
In both cases, the actual amount of padding is rounded |
so that the end of the arena is always a system page boundary. |
|
The main reason for using padding is to avoid calling sbrk so |
often. Having even a small pad greatly reduces the likelihood |
that nearly every malloc request during program start-up (or |
after trimming) will invoke sbrk, which needlessly wastes |
time. |
|
Automatic rounding-up to page-size units is normally sufficient |
to avoid measurable overhead, so the default is 0. However, in |
systems where sbrk is relatively slow, it can pay to increase |
this value, at the expense of carrying around more memory than |
the program needs. |
*/ |
#define M_TOP_PAD -2 |
|
#ifndef DEFAULT_TOP_PAD |
#define DEFAULT_TOP_PAD (0) |
#endif |
|
/* |
M_MMAP_THRESHOLD is the request size threshold for using mmap() |
to service a request. Requests of at least this size that cannot |
be allocated using already-existing space will be serviced via mmap. |
(If enough normal freed space already exists it is used instead.) |
|
Using mmap segregates relatively large chunks of memory so that |
they can be individually obtained and released from the host |
system. A request serviced through mmap is never reused by any |
other request (at least not directly; the system may just so |
happen to remap successive requests to the same locations). |
|
Segregating space in this way has the benefits that: |
|
1. Mmapped space can ALWAYS be individually released back |
to the system, which helps keep the system level memory |
demands of a long-lived program low. |
2. Mapped memory can never become `locked' between |
other chunks, as can happen with normally allocated chunks, which |
means that even trimming via malloc_trim would not release them. |
3. On some systems with "holes" in address spaces, mmap can obtain |
memory that sbrk cannot. |
|
However, it has the disadvantages that: |
|
1. The space cannot be reclaimed, consolidated, and then |
used to service later requests, as happens with normal chunks. |
2. It can lead to more wastage because of mmap page alignment |
requirements |
3. It causes malloc performance to be more dependent on host |
system memory management support routines which may vary in |
implementation quality and may impose arbitrary |
limitations. Generally, servicing a request via normal |
malloc steps is faster than going through a system's mmap. |
|
The advantages of mmap nearly always outweigh disadvantages for |
"large" chunks, but the value of "large" varies across systems. The |
default is an empirically derived value that works well in most |
systems. |
*/ |
#define M_MMAP_THRESHOLD -3 |
|
#ifndef DEFAULT_MMAP_THRESHOLD |
#define DEFAULT_MMAP_THRESHOLD (256 * 1024) |
#endif |
|
/* |
M_MMAP_MAX is the maximum number of requests to simultaneously |
service using mmap. This parameter exists because |
. Some systems have a limited number of internal tables for |
use by mmap, and using more than a few of them may degrade |
performance. |
|
The default is set to a value that serves only as a safeguard. |
Setting to 0 disables use of mmap for servicing large requests. If |
HAVE_MMAP is not set, the default value is 0, and attempts to set it |
to non-zero values in mallopt will fail. |
*/ |
#define M_MMAP_MAX -4 |
|
#ifndef DEFAULT_MMAP_MAX |
#define DEFAULT_MMAP_MAX (65536) |
#endif |
|
|
/* ------------------ MMAP support ------------------ */ |
#include <fcntl.h> |
#include <sys/mman.h> |
|
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) |
#define MAP_ANONYMOUS MAP_ANON |
#endif |
|
#define MMAP(addr, size, prot, flags) \ |
(mmap((addr), (size), (prot), (flags)|MAP_ANONYMOUS, -1, 0)) |
|
|
/* ----------------------- Chunk representations ----------------------- */ |
|
|
/* |
This struct declaration is misleading (but accurate and necessary). |
It declares a "view" into memory allowing access to necessary |
fields at known offsets from a given base. See explanation below. |
*/ |
|
struct malloc_chunk { |
|
size_t prev_size; /* Size of previous chunk (if free). */ |
size_t size; /* Size in bytes, including overhead. */ |
|
struct malloc_chunk* fd; /* double links -- used only if free. */ |
struct malloc_chunk* bk; |
}; |
|
|
typedef struct malloc_chunk* mchunkptr; |
|
/* |
malloc_chunk details: |
|
(The following includes lightly edited explanations by Colin Plumb.) |
|
Chunks of memory are maintained using a `boundary tag' method as |
described in e.g., Knuth or Standish. (See the paper by Paul |
Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a |
survey of such techniques.) Sizes of free chunks are stored both |
in the front of each chunk and at the end. This makes |
consolidating fragmented chunks into bigger chunks very fast. The |
size fields also hold bits representing whether chunks are free or |
in use. |
|
An allocated chunk looks like this: |
|
|
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Size of previous chunk, if allocated | | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Size of chunk, in bytes |P| |
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| User data starts here... . |
. . |
. (malloc_usable_space() bytes) . |
. | |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Size of chunk | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
|
Where "chunk" is the front of the chunk for the purpose of most of |
the malloc code, but "mem" is the pointer that is returned to the |
user. "Nextchunk" is the beginning of the next contiguous chunk. |
|
Chunks always begin on even word boundries, so the mem portion |
(which is returned to the user) is also on an even word boundary, and |
thus at least double-word aligned. |
|
Free chunks are stored in circular doubly-linked lists, and look like this: |
|
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Size of previous chunk | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
`head:' | Size of chunk, in bytes |P| |
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Forward pointer to next chunk in list | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Back pointer to previous chunk in list | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Unused space (may be 0 bytes long) . |
. . |
. | |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
`foot:' | Size of chunk, in bytes | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
The P (PREV_INUSE) bit, stored in the unused low-order bit of the |
chunk size (which is always a multiple of two words), is an in-use |
bit for the *previous* chunk. If that bit is *clear*, then the |
word before the current chunk size contains the previous chunk |
size, and can be used to find the front of the previous chunk. |
The very first chunk allocated always has this bit set, |
preventing access to non-existent (or non-owned) memory. If |
prev_inuse is set for any given chunk, then you CANNOT determine |
the size of the previous chunk, and might even get a memory |
addressing fault when trying to do so. |
|
Note that the `foot' of the current chunk is actually represented |
as the prev_size of the NEXT chunk. This makes it easier to |
deal with alignments etc but can be very confusing when trying |
to extend or adapt this code. |
|
The two exceptions to all this are |
|
1. The special chunk `top' doesn't bother using the |
trailing size field since there is no next contiguous chunk |
that would have to index off it. After initialization, `top' |
is forced to always exist. If it would become less than |
MINSIZE bytes long, it is replenished. |
|
2. Chunks allocated via mmap, which have the second-lowest-order |
bit (IS_MMAPPED) set in their size fields. Because they are |
allocated one-by-one, each must contain its own trailing size field. |
|
*/ |
|
/* |
---------- Size and alignment checks and conversions ---------- |
*/ |
|
/* conversion from malloc headers to user pointers, and back */ |
|
#define chunk2mem(p) ((void*)((char*)(p) + 2*(sizeof(size_t)))) |
#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*(sizeof(size_t)))) |
|
/* The smallest possible chunk */ |
#define MIN_CHUNK_SIZE (sizeof(struct malloc_chunk)) |
|
/* The smallest size we can malloc is an aligned minimal chunk */ |
|
#define MINSIZE \ |
(unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)) |
|
/* Check if m has acceptable alignment */ |
|
#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0) |
|
|
/* Check if a request is so large that it would wrap around zero when |
padded and aligned. To simplify some other code, the bound is made |
low enough so that adding MINSIZE will also not wrap around sero. |
*/ |
|
#define REQUEST_OUT_OF_RANGE(req) \ |
((unsigned long)(req) >= \ |
(unsigned long)(size_t)(-2 * MINSIZE)) |
|
/* pad request bytes into a usable size -- internal version */ |
|
#define request2size(req) \ |
(((req) + (sizeof(size_t)) + MALLOC_ALIGN_MASK < MINSIZE) ? \ |
MINSIZE : \ |
((req) + (sizeof(size_t)) + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) |
|
/* Same, except also perform argument check */ |
|
#define checked_request2size(req, sz) \ |
if (REQUEST_OUT_OF_RANGE(req)) { \ |
errno = ENOMEM; \ |
return 0; \ |
} \ |
(sz) = request2size(req); |
|
/* |
--------------- Physical chunk operations --------------- |
*/ |
|
|
/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */ |
#define PREV_INUSE 0x1 |
|
/* extract inuse bit of previous chunk */ |
#define prev_inuse(p) ((p)->size & PREV_INUSE) |
|
|
/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */ |
#define IS_MMAPPED 0x2 |
|
/* check for mmap()'ed chunk */ |
#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED) |
|
/* Bits to mask off when extracting size |
|
Note: IS_MMAPPED is intentionally not masked off from size field in |
macros for which mmapped chunks should never be seen. This should |
cause helpful core dumps to occur if it is tried by accident by |
people extending or adapting this malloc. |
*/ |
#define SIZE_BITS (PREV_INUSE|IS_MMAPPED) |
|
/* Get size, ignoring use bits */ |
#define chunksize(p) ((p)->size & ~(SIZE_BITS)) |
|
|
/* Ptr to next physical malloc_chunk. */ |
#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) )) |
|
/* Ptr to previous physical malloc_chunk */ |
#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) )) |
|
/* Treat space at ptr + offset as a chunk */ |
#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) |
|
/* extract p's inuse bit */ |
#define inuse(p)\ |
((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE) |
|
/* set/clear chunk as being inuse without otherwise disturbing */ |
#define set_inuse(p)\ |
((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE |
|
#define clear_inuse(p)\ |
((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE) |
|
|
/* check/set/clear inuse bits in known places */ |
#define inuse_bit_at_offset(p, s)\ |
(((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE) |
|
#define set_inuse_bit_at_offset(p, s)\ |
(((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE) |
|
#define clear_inuse_bit_at_offset(p, s)\ |
(((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE)) |
|
|
/* Set size at head, without disturbing its use bit */ |
#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s))) |
|
/* Set size/use field */ |
#define set_head(p, s) ((p)->size = (s)) |
|
/* Set size at footer (only when chunk is not in use) */ |
#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s)) |
|
|
/* -------------------- Internal data structures -------------------- */ |
|
/* |
Bins |
|
An array of bin headers for free chunks. Each bin is doubly |
linked. The bins are approximately proportionally (log) spaced. |
There are a lot of these bins (128). This may look excessive, but |
works very well in practice. Most bins hold sizes that are |
unusual as malloc request sizes, but are more usual for fragments |
and consolidated sets of chunks, which is what these bins hold, so |
they can be found quickly. All procedures maintain the invariant |
that no consolidated chunk physically borders another one, so each |
chunk in a list is known to be preceeded and followed by either |
inuse chunks or the ends of memory. |
|
Chunks in bins are kept in size order, with ties going to the |
approximately least recently used chunk. Ordering isn't needed |
for the small bins, which all contain the same-sized chunks, but |
facilitates best-fit allocation for larger chunks. These lists |
are just sequential. Keeping them in order almost never requires |
enough traversal to warrant using fancier ordered data |
structures. |
|
Chunks of the same size are linked with the most |
recently freed at the front, and allocations are taken from the |
back. This results in LRU (FIFO) allocation order, which tends |
to give each chunk an equal opportunity to be consolidated with |
adjacent freed chunks, resulting in larger free chunks and less |
fragmentation. |
|
To simplify use in double-linked lists, each bin header acts |
as a malloc_chunk. This avoids special-casing for headers. |
But to conserve space and improve locality, we allocate |
only the fd/bk pointers of bins, and then use repositioning tricks |
to treat these as the fields of a malloc_chunk*. |
*/ |
|
typedef struct malloc_chunk* mbinptr; |
|
/* addressing -- note that bin_at(0) does not exist */ |
#define bin_at(m, i) ((mbinptr)((char*)&((m)->bins[(i)<<1]) - ((sizeof(size_t))<<1))) |
|
/* analog of ++bin */ |
#define next_bin(b) ((mbinptr)((char*)(b) + (sizeof(mchunkptr)<<1))) |
|
/* Reminders about list directionality within bins */ |
#define first(b) ((b)->fd) |
#define last(b) ((b)->bk) |
|
/* Take a chunk off a bin list */ |
#define unlink(P, BK, FD) { \ |
FD = P->fd; \ |
BK = P->bk; \ |
FD->bk = BK; \ |
BK->fd = FD; \ |
} |
|
/* |
Indexing |
|
Bins for sizes < 512 bytes contain chunks of all the same size, spaced |
8 bytes apart. Larger bins are approximately logarithmically spaced: |
|
64 bins of size 8 |
32 bins of size 64 |
16 bins of size 512 |
8 bins of size 4096 |
4 bins of size 32768 |
2 bins of size 262144 |
1 bin of size what's left |
|
The bins top out around 1MB because we expect to service large |
requests via mmap. |
*/ |
|
#define NBINS 96 |
#define NSMALLBINS 32 |
#define SMALLBIN_WIDTH 8 |
#define MIN_LARGE_SIZE 256 |
|
#define in_smallbin_range(sz) \ |
((unsigned long)(sz) < (unsigned long)MIN_LARGE_SIZE) |
|
#define smallbin_index(sz) (((unsigned)(sz)) >> 3) |
|
#define bin_index(sz) \ |
((in_smallbin_range(sz)) ? smallbin_index(sz) : __malloc_largebin_index(sz)) |
|
/* |
FIRST_SORTED_BIN_SIZE is the chunk size corresponding to the |
first bin that is maintained in sorted order. This must |
be the smallest size corresponding to a given bin. |
|
Normally, this should be MIN_LARGE_SIZE. But you can weaken |
best fit guarantees to sometimes speed up malloc by increasing value. |
Doing this means that malloc may choose a chunk that is |
non-best-fitting by up to the width of the bin. |
|
Some useful cutoff values: |
512 - all bins sorted |
2560 - leaves bins <= 64 bytes wide unsorted |
12288 - leaves bins <= 512 bytes wide unsorted |
65536 - leaves bins <= 4096 bytes wide unsorted |
262144 - leaves bins <= 32768 bytes wide unsorted |
-1 - no bins sorted (not recommended!) |
*/ |
|
#define FIRST_SORTED_BIN_SIZE MIN_LARGE_SIZE |
/* #define FIRST_SORTED_BIN_SIZE 65536 */ |
|
/* |
Unsorted chunks |
|
All remainders from chunk splits, as well as all returned chunks, |
are first placed in the "unsorted" bin. They are then placed |
in regular bins after malloc gives them ONE chance to be used before |
binning. So, basically, the unsorted_chunks list acts as a queue, |
with chunks being placed on it in free (and __malloc_consolidate), |
and taken off (to be either used or placed in bins) in malloc. |
*/ |
|
/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */ |
#define unsorted_chunks(M) (bin_at(M, 1)) |
|
/* |
Top |
|
The top-most available chunk (i.e., the one bordering the end of |
available memory) is treated specially. It is never included in |
any bin, is used only if no other chunk is available, and is |
released back to the system if it is very large (see |
M_TRIM_THRESHOLD). Because top initially |
points to its own bin with initial zero size, thus forcing |
extension on the first malloc request, we avoid having any special |
code in malloc to check whether it even exists yet. But we still |
need to do so when getting memory from system, so we make |
initial_top treat the bin as a legal but unusable chunk during the |
interval between initialization and the first call to |
__malloc_alloc. (This is somewhat delicate, since it relies on |
the 2 preceding words to be zero during this interval as well.) |
*/ |
|
/* Conveniently, the unsorted bin can be used as dummy top on first call */ |
#define initial_top(M) (unsorted_chunks(M)) |
|
/* |
Binmap |
|
To help compensate for the large number of bins, a one-level index |
structure is used for bin-by-bin searching. `binmap' is a |
bitvector recording whether bins are definitely empty so they can |
be skipped over during during traversals. The bits are NOT always |
cleared as soon as bins are empty, but instead only |
when they are noticed to be empty during traversal in malloc. |
*/ |
|
/* Conservatively use 32 bits per map word, even if on 64bit system */ |
#define BINMAPSHIFT 5 |
#define BITSPERMAP (1U << BINMAPSHIFT) |
#define BINMAPSIZE (NBINS / BITSPERMAP) |
|
#define idx2block(i) ((i) >> BINMAPSHIFT) |
#define idx2bit(i) ((1U << ((i) & ((1U << BINMAPSHIFT)-1)))) |
|
#define mark_bin(m,i) ((m)->binmap[idx2block(i)] |= idx2bit(i)) |
#define unmark_bin(m,i) ((m)->binmap[idx2block(i)] &= ~(idx2bit(i))) |
#define get_binmap(m,i) ((m)->binmap[idx2block(i)] & idx2bit(i)) |
|
/* |
Fastbins |
|
An array of lists holding recently freed small chunks. Fastbins |
are not doubly linked. It is faster to single-link them, and |
since chunks are never removed from the middles of these lists, |
double linking is not necessary. Also, unlike regular bins, they |
are not even processed in FIFO order (they use faster LIFO) since |
ordering doesn't much matter in the transient contexts in which |
fastbins are normally used. |
|
Chunks in fastbins keep their inuse bit set, so they cannot |
be consolidated with other free chunks. __malloc_consolidate |
releases all chunks in fastbins and consolidates them with |
other free chunks. |
*/ |
|
typedef struct malloc_chunk* mfastbinptr; |
|
/* offset 2 to use otherwise unindexable first 2 bins */ |
#define fastbin_index(sz) ((((unsigned int)(sz)) >> 3) - 2) |
|
/* The maximum fastbin request size we support */ |
#define MAX_FAST_SIZE 80 |
|
#define NFASTBINS (fastbin_index(request2size(MAX_FAST_SIZE))+1) |
|
/* |
FASTBIN_CONSOLIDATION_THRESHOLD is the size of a chunk in free() |
that triggers automatic consolidation of possibly-surrounding |
fastbin chunks. This is a heuristic, so the exact value should not |
matter too much. It is defined at half the default trim threshold as a |
compromise heuristic to only attempt consolidation if it is likely |
to lead to trimming. However, it is not dynamically tunable, since |
consolidation reduces fragmentation surrounding loarge chunks even |
if trimming is not used. |
*/ |
|
#define FASTBIN_CONSOLIDATION_THRESHOLD \ |
((unsigned long)(DEFAULT_TRIM_THRESHOLD) >> 1) |
|
/* |
Since the lowest 2 bits in max_fast don't matter in size comparisons, |
they are used as flags. |
*/ |
|
/* |
ANYCHUNKS_BIT held in max_fast indicates that there may be any |
freed chunks at all. It is set true when entering a chunk into any |
bin. |
*/ |
|
#define ANYCHUNKS_BIT (1U) |
|
#define have_anychunks(M) (((M)->max_fast & ANYCHUNKS_BIT)) |
#define set_anychunks(M) ((M)->max_fast |= ANYCHUNKS_BIT) |
#define clear_anychunks(M) ((M)->max_fast &= ~ANYCHUNKS_BIT) |
|
/* |
FASTCHUNKS_BIT held in max_fast indicates that there are probably |
some fastbin chunks. It is set true on entering a chunk into any |
fastbin, and cleared only in __malloc_consolidate. |
*/ |
|
#define FASTCHUNKS_BIT (2U) |
|
#define have_fastchunks(M) (((M)->max_fast & FASTCHUNKS_BIT)) |
#define set_fastchunks(M) ((M)->max_fast |= (FASTCHUNKS_BIT|ANYCHUNKS_BIT)) |
#define clear_fastchunks(M) ((M)->max_fast &= ~(FASTCHUNKS_BIT)) |
|
/* Set value of max_fast. Use impossibly small value if 0. */ |
#define set_max_fast(M, s) \ |
(M)->max_fast = (((s) == 0)? SMALLBIN_WIDTH: request2size(s)) | \ |
((M)->max_fast & (FASTCHUNKS_BIT|ANYCHUNKS_BIT)) |
|
#define get_max_fast(M) \ |
((M)->max_fast & ~(FASTCHUNKS_BIT | ANYCHUNKS_BIT)) |
|
|
/* |
morecore_properties is a status word holding dynamically discovered |
or controlled properties of the morecore function |
*/ |
|
#define MORECORE_CONTIGUOUS_BIT (1U) |
|
#define contiguous(M) \ |
(((M)->morecore_properties & MORECORE_CONTIGUOUS_BIT)) |
#define noncontiguous(M) \ |
(((M)->morecore_properties & MORECORE_CONTIGUOUS_BIT) == 0) |
#define set_contiguous(M) \ |
((M)->morecore_properties |= MORECORE_CONTIGUOUS_BIT) |
#define set_noncontiguous(M) \ |
((M)->morecore_properties &= ~MORECORE_CONTIGUOUS_BIT) |
|
|
/* |
----------- Internal state representation and initialization ----------- |
*/ |
|
struct malloc_state { |
|
/* The maximum chunk size to be eligible for fastbin */ |
size_t max_fast; /* low 2 bits used as flags */ |
|
/* Fastbins */ |
mfastbinptr fastbins[NFASTBINS]; |
|
/* Base of the topmost chunk -- not otherwise kept in a bin */ |
mchunkptr top; |
|
/* The remainder from the most recent split of a small request */ |
mchunkptr last_remainder; |
|
/* Normal bins packed as described above */ |
mchunkptr bins[NBINS * 2]; |
|
/* Bitmap of bins. Trailing zero map handles cases of largest binned size */ |
unsigned int binmap[BINMAPSIZE+1]; |
|
/* Tunable parameters */ |
unsigned long trim_threshold; |
size_t top_pad; |
size_t mmap_threshold; |
|
/* Memory map support */ |
int n_mmaps; |
int n_mmaps_max; |
int max_n_mmaps; |
|
/* Cache malloc_getpagesize */ |
unsigned int pagesize; |
|
/* Track properties of MORECORE */ |
unsigned int morecore_properties; |
|
/* Statistics */ |
size_t mmapped_mem; |
size_t sbrked_mem; |
size_t max_sbrked_mem; |
size_t max_mmapped_mem; |
size_t max_total_mem; |
}; |
|
typedef struct malloc_state *mstate; |
|
/* |
There is exactly one instance of this struct in this malloc. |
If you are adapting this malloc in a way that does NOT use a static |
malloc_state, you MUST explicitly zero-fill it before using. This |
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 */ |
|
/* |
All uses of av_ are via get_malloc_state(). |
At most one "call" to get_malloc_state is made per invocation of |
the public versions of malloc and free, but other routines |
that in turn invoke malloc and/or free may call more then once. |
Also, it is called in check* routines if __MALLOC_DEBUGGING is set. |
*/ |
|
#define get_malloc_state() (&(__malloc_state)) |
|
/* External internal utilities operating on mstates */ |
void __malloc_consolidate(mstate); |
|
|
/* Debugging support */ |
#if ! __MALLOC_DEBUGGING |
|
#define check_chunk(P) |
#define check_free_chunk(P) |
#define check_inuse_chunk(P) |
#define check_remalloced_chunk(P,N) |
#define check_malloced_chunk(P,N) |
#define check_malloc_state() |
#define assert(x) ((void)0) |
|
|
#else |
|
#define check_chunk(P) __do_check_chunk(P) |
#define check_free_chunk(P) __do_check_free_chunk(P) |
#define check_inuse_chunk(P) __do_check_inuse_chunk(P) |
#define check_remalloced_chunk(P,N) __do_check_remalloced_chunk(P,N) |
#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); |
|
#include <assert.h> |
|
#endif |
/malloc-standard/calloc.c
0,0 → 1,93
/* |
This is a version (aka dlmalloc) of malloc/free/realloc written by |
Doug Lea and released to the public domain. Use, modify, and |
redistribute this code without permission or acknowledgement in any |
way you wish. Send questions, comments, complaints, performance |
data, etc to dl@cs.oswego.edu |
|
VERSION 2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) |
|
Note: There may be an updated version of this malloc obtainable at |
ftp://gee.cs.oswego.edu/pub/misc/malloc.c |
Check before installing! |
|
Hacked up for uClibc by Erik Andersen <andersen@codepoet.org> |
*/ |
|
#include "malloc.h" |
|
|
/* ------------------------------ calloc ------------------------------ */ |
void* calloc(size_t n_elements, size_t elem_size) |
{ |
mchunkptr p; |
unsigned long clearsize; |
unsigned long nclears; |
size_t size, *d; |
void* mem; |
|
|
/* guard vs integer overflow, but allow nmemb |
* to fall through and call malloc(0) */ |
size = n_elements * elem_size; |
if (n_elements && elem_size != (size / n_elements)) { |
__set_errno(ENOMEM); |
return NULL; |
} |
|
LOCK; |
mem = malloc(size); |
if (mem != 0) { |
p = mem2chunk(mem); |
|
if (!chunk_is_mmapped(p)) |
{ |
/* |
Unroll clear of <= 36 bytes (72 if 8byte sizes) |
We know that contents have an odd number of |
size_t-sized words; minimally 3. |
*/ |
|
d = (size_t*)mem; |
clearsize = chunksize(p) - (sizeof(size_t)); |
nclears = clearsize / sizeof(size_t); |
assert(nclears >= 3); |
|
if (nclears > 9) |
memset(d, 0, clearsize); |
|
else { |
*(d+0) = 0; |
*(d+1) = 0; |
*(d+2) = 0; |
if (nclears > 4) { |
*(d+3) = 0; |
*(d+4) = 0; |
if (nclears > 6) { |
*(d+5) = 0; |
*(d+6) = 0; |
if (nclears > 8) { |
*(d+7) = 0; |
*(d+8) = 0; |
} |
} |
} |
} |
} |
#if 0 |
else |
{ |
/* Standard unix mmap using /dev/zero clears memory so calloc |
* doesn't need to actually zero anything.... |
*/ |
d = (size_t*)mem; |
/* Note the additional (sizeof(size_t)) */ |
clearsize = chunksize(p) - 2*(sizeof(size_t)); |
memset(d, 0, clearsize); |
} |
#endif |
} |
UNLOCK; |
return mem; |
} |
|
/drand48_r.c
0,0 → 1,27
/* Copyright (C) 1995, 1996, 1997, 1998, 2001 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu <mailto:drepper@gnu.ai.mit.edu>>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <errno.h> |
#include <math.h> |
#include <stdlib.h> |
|
int drand48_r (struct drand48_data *buffer, double *result) |
{ |
return erand48_r (buffer->__x, buffer, result); |
} |
/erand48_r.c
0,0 → 1,51
/* Copyright (C) 1995, 1997, 2001 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu <mailto:drepper@gnu.ai.mit.edu>>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <ieee754.h> |
#include <stdlib.h> |
#include <limits.h> |
|
extern int __drand48_iterate(unsigned short xsubi[3], |
struct drand48_data *buffer); |
|
|
int erand48_r (xsubi, buffer, result) |
unsigned short int xsubi[3]; |
struct drand48_data *buffer; |
double *result; |
{ |
union ieee754_double temp; |
|
/* Compute next state. */ |
if (__drand48_iterate (xsubi, buffer) < 0) |
return -1; |
|
/* Construct a positive double with the 48 random bits distributed over |
its fractional part so the resulting FP number is [0.0,1.0). */ |
|
temp.ieee.negative = 0; |
temp.ieee.exponent = IEEE754_DOUBLE_BIAS; |
temp.ieee.mantissa0 = (xsubi[2] << 4) | (xsubi[1] >> 12); |
temp.ieee.mantissa1 = ((xsubi[1] & 0xfff) << 20) | (xsubi[0] << 4); |
|
/* Please note the lower 4 bits of mantissa1 are always 0. */ |
*result = temp.d - 1.0; |
|
return 0; |
} |
/malloc/heap_free.c
0,0 → 1,89
/* |
* libc/stdlib/malloc/heap_free.c -- return memory to a heap |
* |
* Copyright (C) 2002 NEC Corporation |
* Copyright (C) 2002 Miles Bader <miles@gnu.org> |
* |
* This file is subject to the terms and conditions of the GNU Lesser |
* General Public License. See the file COPYING.LIB in the main |
* directory of this archive for more details. |
* |
* Written by Miles Bader <miles@gnu.org> |
*/ |
|
#include <stdlib.h> |
|
#include "heap.h" |
|
|
/* 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) |
{ |
struct heap_free_area *fa, *prev_fa; |
void *end = (char *)mem + size; |
|
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: |
since we use a simple linked-list for the free-list, and we keep it in |
address-sorted order, it can become very expensive to insert something |
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) |
if (unlikely (HEAP_FREE_AREA_END (fa) >= mem)) |
break; |
|
if (fa && HEAP_FREE_AREA_START (fa) <= end) |
/* The free-area FA is adjacent to the new block, merge them. */ |
{ |
size_t fa_size = fa->size + size; |
|
if (HEAP_FREE_AREA_START (fa) == end) |
/* FA is just after the new block, grow down to encompass it. */ |
{ |
/* See if FA can now be merged with its predecessor. */ |
if (prev_fa && mem == HEAP_FREE_AREA_END (prev_fa)) |
/* Yup; merge PREV_FA's info into FA. */ |
{ |
fa_size += prev_fa->size; |
__heap_link_free_area_after (heap, fa, prev_fa->prev); |
} |
} |
else |
/* FA is just before the new block, expand to encompass it. */ |
{ |
struct heap_free_area *next_fa = fa->next; |
|
/* See if FA can now be merged with its successor. */ |
if (next_fa && end == HEAP_FREE_AREA_START (next_fa)) |
/* Yup; merge FA's info into NEXT_FA. */ |
{ |
fa_size += next_fa->size; |
__heap_link_free_area_after (heap, next_fa, prev_fa); |
fa = next_fa; |
} |
else |
/* FA can't be merged; move the descriptor for it to the tail-end |
of the memory block. */ |
{ |
/* The new descriptor is at the end of the extended block, |
SIZE bytes later than the old descriptor. */ |
fa = (struct heap_free_area *)((char *)fa + size); |
/* Update links with the neighbors in the list. */ |
__heap_link_free_area (heap, fa, prev_fa, next_fa); |
} |
} |
|
fa->size = fa_size; |
} |
else |
/* 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"); |
|
return fa; |
} |
/malloc/free.c
0,0 → 1,262
/* |
* libc/stdlib/malloc/free.c -- free function |
* |
* Copyright (C) 2002,03 NEC Electronics Corporation |
* Copyright (C) 2002,03 Miles Bader <miles@gnu.org> |
* |
* This file is subject to the terms and conditions of the GNU Lesser |
* General Public License. See the file COPYING.LIB in the main |
* directory of this archive for more details. |
* |
* Written by Miles Bader <miles@gnu.org> |
*/ |
|
#include <stdlib.h> |
#include <unistd.h> |
#include <sys/mman.h> |
|
#include "malloc.h" |
#include "heap.h" |
|
|
static void |
free_to_heap (void *mem, struct heap *heap) |
{ |
size_t size; |
struct heap_free_area *fa; |
|
/* Check for special cases. */ |
if (unlikely (! mem)) |
return; |
|
/* Normal free. */ |
|
MALLOC_DEBUG (1, "free: 0x%lx (base = 0x%lx, total_size = %d)", |
(long)mem, (long)MALLOC_BASE (mem), MALLOC_SIZE (mem)); |
|
size = MALLOC_SIZE (mem); |
mem = MALLOC_BASE (mem); |
|
__heap_lock (heap); |
|
/* Put MEM back in the heap, and get the free-area it was placed in. */ |
fa = __heap_free (heap, mem, size); |
|
/* See if the free-area FA has grown big enough that it should be |
unmapped. */ |
if (HEAP_FREE_AREA_SIZE (fa) < MALLOC_UNMAP_THRESHOLD) |
/* Nope, nothing left to do, just release the lock. */ |
__heap_unlock (heap); |
else |
/* Yup, try to unmap FA. */ |
{ |
unsigned long start = (unsigned long)HEAP_FREE_AREA_START (fa); |
unsigned long end = (unsigned long)HEAP_FREE_AREA_END (fa); |
#ifndef MALLOC_USE_SBRK |
# ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__ |
struct malloc_mmb *mmb, *prev_mmb; |
unsigned long mmb_start, mmb_end; |
# else /* !__UCLIBC_UCLINUX_BROKEN_MUNMAP__ */ |
unsigned long unmap_start, unmap_end; |
# endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */ |
#endif /* !MALLOC_USE_SBRK */ |
|
#ifdef MALLOC_USE_SBRK |
/* Get the sbrk lock so that the two possible calls to sbrk below |
are guaranteed to be contiguous. */ |
__malloc_lock_sbrk (); |
/* When using sbrk, we only shrink the heap from the end. It would |
be possible to allow _both_ -- shrinking via sbrk when possible, |
and otherwise shrinking via munmap, but this results in holes in |
memory that prevent the brk from every growing back down; since |
we only ever grow the heap via sbrk, this tends to produce a |
continuously growing brk (though the actual memory is unmapped), |
which could eventually run out of address space. Note that |
`sbrk(0)' shouldn't normally do a system call, so this test is |
reasonably cheap. */ |
if ((void *)end != sbrk (0)) |
{ |
MALLOC_DEBUG (-1, "not unmapping: 0x%lx - 0x%lx (%ld bytes)", |
start, end, end - start); |
__malloc_unlock_sbrk (); |
__heap_unlock (heap); |
return; |
} |
#endif |
|
MALLOC_DEBUG (0, "unmapping: 0x%lx - 0x%lx (%ld bytes)", |
start, end, end - start); |
|
/* Remove FA from the heap. */ |
__heap_delete (heap, fa); |
|
if (__heap_is_empty (heap)) |
/* We want to avoid the heap from losing all memory, so reserve |
a bit. This test is only a heuristic -- the existance of |
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 |
MALLOC_UNMAP_THRESHOLD is greater than MALLOC_MIN_SIZE, so |
we use the latter unconditionally here. */ |
__heap_free (heap, (void *)start, MALLOC_MIN_SIZE); |
start += MALLOC_MIN_SIZE; |
} |
|
#ifdef MALLOC_USE_SBRK |
|
/* Release the heap lock; we're still holding the sbrk lock. */ |
__heap_unlock (heap); |
/* Lower the brk. */ |
sbrk (start - end); |
/* Release the sbrk lock too; now we hold no locks. */ |
__malloc_unlock_sbrk (); |
|
#else /* !MALLOC_USE_SBRK */ |
|
# ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__ |
/* Using the uClinux broken munmap, we have to only munmap blocks |
exactly as we got them from mmap, so scan through our list of |
mmapped blocks, and return them in order. */ |
|
MALLOC_MMB_DEBUG (1, "walking mmb list for region 0x%x[%d]...", |
start, end - start); |
|
prev_mmb = 0; |
mmb = __malloc_mmapped_blocks; |
while (mmb |
&& ((mmb_end = (mmb_start = (unsigned long)mmb->mem) + mmb->size) |
<= end)) |
{ |
MALLOC_MMB_DEBUG (1, "considering mmb at 0x%x: 0x%x[%d]", |
(unsigned)mmb, mmb_start, mmb_end - mmb_start); |
|
if (mmb_start >= start |
/* If the space between START and MMB_START is non-zero, but |
too small to return to the heap, we can't unmap MMB. */ |
&& (start == mmb_start |
|| mmb_start - start > HEAP_MIN_FREE_AREA_SIZE)) |
{ |
struct malloc_mmb *next_mmb = mmb->next; |
|
if (mmb_end != end && mmb_end + HEAP_MIN_FREE_AREA_SIZE > end) |
/* There's too little space left at the end to deallocate |
this block, so give up. */ |
break; |
|
MALLOC_MMB_DEBUG (1, "unmapping mmb at 0x%x: 0x%x[%d]", |
(unsigned)mmb, mmb_start, mmb_end - mmb_start); |
|
if (mmb_start != start) |
/* We're going to unmap a part of the heap that begins after |
start, so put the intervening region back into the heap. */ |
{ |
MALLOC_MMB_DEBUG (0, "putting intervening region back into heap: 0x%x[%d]", |
start, mmb_start - start); |
__heap_free (heap, (void *)start, mmb_start - start); |
} |
|
MALLOC_MMB_DEBUG_INDENT (-1); |
|
/* Unlink MMB from the list. */ |
if (prev_mmb) |
prev_mmb->next = next_mmb; |
else |
__malloc_mmapped_blocks = next_mmb; |
|
/* Start searching again from the end of this block. */ |
start = mmb_end; |
|
/* 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); |
|
/* Do the actual munmap. */ |
munmap ((void *)mmb_start, mmb_end - mmb_start); |
|
__heap_lock (heap); |
|
# ifdef __UCLIBC_HAS_THREADS__ |
/* In a multi-threaded program, it's possible that PREV_MMB has |
been invalidated by another thread when we released the |
heap lock to do the munmap system call, so just start over |
from the beginning of the list. It sucks, but oh well; |
it's probably not worth the bother to do better. */ |
prev_mmb = 0; |
mmb = __malloc_mmapped_blocks; |
# else |
mmb = next_mmb; |
# endif |
} |
else |
{ |
prev_mmb = mmb; |
mmb = mmb->next; |
} |
|
MALLOC_MMB_DEBUG_INDENT (-1); |
} |
|
if (start != end) |
/* Hmm, well there's something we couldn't unmap, so put it back |
into the heap. */ |
{ |
MALLOC_MMB_DEBUG (0, "putting tail region back into heap: 0x%x[%d]", |
start, end - start); |
__heap_free (heap, (void *)start, end - start); |
} |
|
/* Finally release the lock for good. */ |
__heap_unlock (heap); |
|
MALLOC_MMB_DEBUG_INDENT (-1); |
|
# else /* !__UCLIBC_UCLINUX_BROKEN_MUNMAP__ */ |
|
/* MEM/LEN may not be page-aligned, so we have to page-align them, |
and return any left-over bits on the end to the heap. */ |
unmap_start = MALLOC_ROUND_UP_TO_PAGE_SIZE (start); |
unmap_end = MALLOC_ROUND_DOWN_TO_PAGE_SIZE (end); |
|
/* We have to be careful that any left-over bits are large enough to |
return. Note that we _don't check_ to make sure there's room to |
grow/shrink the start/end by another page, we just assume that |
the unmap threshold is high enough so that this is always safe |
(i.e., it should probably be at least 3 pages). */ |
if (unmap_start > start) |
{ |
if (unmap_start - start < HEAP_MIN_FREE_AREA_SIZE) |
unmap_start += MALLOC_PAGE_SIZE; |
__heap_free (heap, (void *)start, unmap_start - start); |
} |
if (end > unmap_end) |
{ |
if (end - unmap_end < HEAP_MIN_FREE_AREA_SIZE) |
unmap_end -= MALLOC_PAGE_SIZE; |
__heap_free (heap, (void *)unmap_end, end - unmap_end); |
} |
|
/* Release the heap lock before we do the system call. */ |
__heap_unlock (heap); |
|
if (unmap_end > unmap_start) |
/* Finally, actually unmap the memory. */ |
munmap ((void *)unmap_start, unmap_end - unmap_start); |
|
# endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */ |
|
#endif /* MALLOC_USE_SBRK */ |
} |
|
MALLOC_DEBUG_INDENT (-1); |
} |
|
void |
free (void *mem) |
{ |
free_to_heap (mem, &__malloc_heap); |
} |
/malloc/realloc.c
0,0 → 1,91
/* |
* libc/stdlib/malloc/realloc.c -- realloc function |
* |
* Copyright (C) 2002 NEC Corporation |
* Copyright (C) 2002 Miles Bader <miles@gnu.org> |
* |
* This file is subject to the terms and conditions of the GNU Lesser |
* General Public License. See the file COPYING.LIB in the main |
* directory of this archive for more details. |
* |
* Written by Miles Bader <miles@gnu.org> |
*/ |
|
#include <stdlib.h> |
#include <string.h> |
#include <errno.h> |
|
#include "malloc.h" |
#include "heap.h" |
|
|
void * |
realloc (void *mem, size_t new_size) |
{ |
size_t size; |
char *base_mem; |
|
/* Check for special cases. */ |
if (! mem) |
return malloc (new_size); |
if (! new_size) |
{ |
free (mem); |
return malloc (new_size); |
} |
|
/* Normal realloc. */ |
|
base_mem = MALLOC_BASE (mem); |
size = MALLOC_SIZE (mem); |
|
/* Include extra space to record the size of the allocated block. |
Also make sure that we're dealing in a multiple of the heap |
allocation unit (SIZE is already guaranteed to be so).*/ |
new_size = HEAP_ADJUST_SIZE (new_size + MALLOC_HEADER_SIZE); |
|
MALLOC_DEBUG (1, "realloc: 0x%lx, %d (base = 0x%lx, total_size = %d)", |
(long)mem, new_size, (long)base_mem, size); |
|
if (new_size > size) |
/* Grow the block. */ |
{ |
size_t extra = new_size - size; |
|
__heap_lock (&__malloc_heap); |
extra = __heap_alloc_at (&__malloc_heap, base_mem + size, extra); |
__heap_unlock (&__malloc_heap); |
|
if (extra) |
/* Record the changed size. */ |
MALLOC_SET_SIZE (base_mem, size + extra); |
else |
/* Our attempts to extend MEM in place failed, just |
allocate-and-copy. */ |
{ |
void *new_mem = malloc (new_size - MALLOC_HEADER_SIZE); |
if (new_mem) |
{ |
memcpy (new_mem, mem, size - MALLOC_HEADER_SIZE); |
free (mem); |
} |
mem = new_mem; |
} |
} |
else if (new_size + MALLOC_REALLOC_MIN_FREE_SIZE <= size) |
/* Shrink the block. */ |
{ |
__heap_lock (&__malloc_heap); |
__heap_free (&__malloc_heap, base_mem + new_size, size - new_size); |
__heap_unlock (&__malloc_heap); |
MALLOC_SET_SIZE (base_mem, new_size); |
} |
|
if (mem) |
MALLOC_DEBUG (-1, "realloc: returning 0x%lx (base:0x%lx, total_size:%d)", |
(long)mem, (long)MALLOC_BASE(mem), (long)MALLOC_SIZE(mem)); |
else |
MALLOC_DEBUG (-1, "realloc: returning 0"); |
|
return mem; |
} |
/malloc/heap.h
0,0 → 1,254
/* |
* libc/stdlib/malloc/heap.h -- heap allocator used for malloc |
* |
* Copyright (C) 2002,03 NEC Electronics Corporation |
* Copyright (C) 2002,03 Miles Bader <miles@gnu.org> |
* |
* This file is subject to the terms and conditions of the GNU Lesser |
* General Public License. See the file COPYING.LIB in the main |
* directory of this archive for more details. |
* |
* Written by Miles Bader <miles@gnu.org> |
*/ |
|
#include <features.h> |
|
|
/* On multi-threaded systems, the heap includes a lock. */ |
#ifdef __UCLIBC_HAS_THREADS__ |
# include <pthread.h> |
# define HEAP_USE_LOCKING |
#endif |
|
|
/* 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 |
#define HEAP_GRANULARITY (sizeof (HEAP_GRANULARITY_TYPE)) |
|
|
/* 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 |
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 |
|
/* 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), |
so one might call it a `footer'. */ |
struct heap_free_area |
{ |
size_t size; |
struct heap_free_area *next, *prev; |
}; |
|
/* Return the address of the end of the frea area FA. */ |
#define HEAP_FREE_AREA_END(fa) ((void *)(fa + 1)) |
/* Return the address of the beginning of the frea area FA. FA is |
evaulated multiple times. */ |
#define HEAP_FREE_AREA_START(fa) ((void *)((char *)(fa + 1) - (fa)->size)) |
/* Return the size of the frea area FA. */ |
#define HEAP_FREE_AREA_SIZE(fa) ((fa)->size) |
|
/* This rather clumsy macro allows one to declare a static free-area for |
passing to HEAP_INIT_WITH_FA initializer macro. This is only use for |
which NAME is allowed. */ |
#define HEAP_DECLARE_STATIC_FREE_AREA(name, size) \ |
static struct \ |
{ \ |
HEAP_GRANULARITY_TYPE aligned_space; \ |
char space[HEAP_ADJUST_SIZE(size) \ |
- sizeof (struct heap_free_area) \ |
- HEAP_GRANULARITY]; \ |
struct heap_free_area _fa; \ |
} name = { (HEAP_GRANULARITY_TYPE)0, "", { HEAP_ADJUST_SIZE(size), 0, 0 } } |
|
|
/* Rounds SZ up to be a multiple of HEAP_GRANULARITY. */ |
#define HEAP_ADJUST_SIZE(sz) \ |
(((sz) + HEAP_GRANULARITY - 1) & ~(HEAP_GRANULARITY - 1)) |
|
|
/* The minimum allocatable size. */ |
#define HEAP_MIN_SIZE HEAP_ADJUST_SIZE (sizeof (struct heap_free_area)) |
|
/* The minimum size of a free area; if allocating memory from a free-area |
would make the free-area smaller than this, the allocation is simply |
given the whole free-area instead. It must include at least enough room |
to hold a struct heap_free_area, plus some extra to avoid excessive heap |
fragmentation (thus increasing speed). This is only a heuristic -- it's |
possible for smaller free-areas than this to exist (say, by realloc |
returning the tail-end of a previous allocation), but __heap_alloc will |
try to get rid of them when possible. */ |
#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; |
#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); |
|
/* 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); |
|
|
#ifdef HEAP_USE_LOCKING |
# define __heap_lock(heap) __pthread_mutex_lock (&(heap)->lock) |
# define __heap_unlock(heap) __pthread_mutex_unlock (&(heap)->lock) |
#else /* !__UCLIBC_HAS_THREADS__ */ |
/* Without threads, mutex operations are a nop. */ |
# define __heap_lock(heap) (void)0 |
# define __heap_unlock(heap) (void)0 |
#endif /* HEAP_USE_LOCKING */ |
|
|
/* Delete the free-area FA from HEAP. */ |
static inline void |
__heap_delete (struct heap *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; |
} |
|
|
/* Link the free-area FA between the existing free-area's PREV and NEXT in |
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, |
struct heap_free_area *prev, |
struct heap_free_area *next) |
{ |
fa->next = next; |
fa->prev = prev; |
|
if (prev) |
prev->next = fa; |
else |
heap->free_areas = fa; |
if (next) |
next->prev = fa; |
} |
|
/* Update the mutual links between the free-areas PREV and FA in HEAP. |
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, |
struct heap_free_area *fa, |
struct heap_free_area *prev) |
{ |
if (prev) |
prev->next = fa; |
else |
heap->free_areas = fa; |
fa->prev = prev; |
} |
|
/* Add a new free-area MEM, of length SIZE, in between the existing |
free-area's PREV and NEXT in HEAP, and return a pointer to its header. |
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, |
struct heap_free_area *prev, |
struct heap_free_area *next) |
{ |
struct heap_free_area *fa = (struct heap_free_area *) |
((char *)mem + size - sizeof (struct heap_free_area)); |
|
fa->size = size; |
|
__heap_link_free_area (heap, fa, prev, next); |
|
return fa; |
} |
|
|
/* 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, |
struct heap_free_area *fa, size_t size) |
{ |
size_t fa_size = fa->size; |
|
if (fa_size < size + HEAP_MIN_FREE_AREA_SIZE) |
/* There's not enough room left over in FA after allocating the block, so |
just use the whole thing, removing it from the list of free areas. */ |
{ |
__heap_delete (heap, fa); |
/* Remember that we've alloced the whole area. */ |
size = fa_size; |
} |
else |
/* Reduce size of FA to account for this allocation. */ |
fa->size = fa_size - size; |
|
return size; |
} |
|
|
/* 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); |
|
/* 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); |
|
/* 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); |
|
/* Return true if HEAP contains absolutely no memory. */ |
#define __heap_is_empty(heap) (! (heap)->free_areas) |
/malloc/heap_debug.c
0,0 → 1,142
/* |
* libc/stdlib/malloc/heap_debug.c -- optional heap debugging routines |
* |
* Copyright (C) 2002 NEC Corporation |
* Copyright (C) 2002 Miles Bader <miles@gnu.org> |
* |
* This file is subject to the terms and conditions of the GNU Lesser |
* General Public License. See the file COPYING.LIB in the main |
* directory of this archive for more details. |
* |
* Written by Miles Bader <miles@gnu.org> |
*/ |
|
#include <stdlib.h> |
#include <stdio.h> |
#include <stdarg.h> |
#include <string.h> |
|
#include "malloc.h" |
#include "heap.h" |
|
|
#ifdef HEAP_DEBUGGING |
int __heap_debug = 0; |
#endif |
|
|
static void |
__heap_dump_freelist (struct heap *heap) |
{ |
struct heap_free_area *fa; |
for (fa = heap->free_areas; fa; fa = fa->next) |
__malloc_debug_printf (0, |
"0x%lx: 0x%lx - 0x%lx (%d)\tP=0x%lx, N=0x%lx", |
(long)fa, |
(long)HEAP_FREE_AREA_START (fa), |
(long)HEAP_FREE_AREA_END (fa), |
fa->size, |
(long)fa->prev, |
(long)fa->next); |
} |
|
/* Output a text representation of HEAP to stderr, labelling it with STR. */ |
void |
__heap_dump (struct heap *heap, const char *str) |
{ |
static int recursed = 0; |
|
if (! recursed) |
{ |
__heap_check (heap, str); |
|
recursed = 1; |
|
__malloc_debug_printf (1, "%s: heap @0x%lx:", str, (long)heap); |
__heap_dump_freelist (heap); |
__malloc_debug_indent (-1); |
|
recursed = 0; |
} |
} |
|
|
/* Output an error message to stderr, and exit. STR is printed with the |
failure message. */ |
static void |
__heap_check_failure (struct heap *heap, struct heap_free_area *fa, |
const char *str, char *fmt, ...) |
{ |
va_list val; |
|
if (str) |
fprintf (stderr, "\nHEAP CHECK FAILURE %s: ", str); |
else |
fprintf (stderr, "\nHEAP CHECK FAILURE: "); |
|
va_start (val, fmt); |
vfprintf (stderr, fmt, val); |
va_end (val); |
|
putc ('\n', stderr); |
|
__malloc_debug_set_indent (0); |
__malloc_debug_printf (1, "heap dump:"); |
__heap_dump_freelist (heap); |
|
exit (22); |
} |
|
/* 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) |
{ |
typedef unsigned long ul_t; |
struct heap_free_area *fa, *prev; |
struct heap_free_area *first_fa = heap->free_areas; |
|
if (first_fa && first_fa->prev) |
__heap_check_failure (heap, first_fa, str, |
"first free-area has non-zero prev pointer:\n\ |
first free-area = 0x%lx\n\ |
(0x%lx)->prev = 0x%lx\n", |
(ul_t)first_fa, |
(ul_t)first_fa, (ul_t)first_fa->prev); |
|
for (prev = 0, fa = first_fa; fa; prev = fa, fa = fa->next) |
{ |
if (((ul_t)HEAP_FREE_AREA_END (fa) & (HEAP_GRANULARITY - 1)) |
|| (fa->size & (HEAP_GRANULARITY - 1))) |
__heap_check_failure (heap, fa, str, "alignment error:\n\ |
(0x%lx)->start = 0x%lx\n\ |
(0x%lx)->size = 0x%lx\n", |
(ul_t)fa, |
(ul_t)HEAP_FREE_AREA_START (fa), |
(ul_t)fa, fa->size); |
|
if (fa->prev != prev) |
__heap_check_failure (heap, fa, str, "prev pointer corrupted:\n\ |
(0x%lx)->next = 0x%lx\n\ |
(0x%lx)->prev = 0x%lx\n", |
(ul_t)prev, (ul_t)prev->next, |
(ul_t)fa, (ul_t)fa->prev); |
|
if (prev) |
{ |
ul_t start = (ul_t)HEAP_FREE_AREA_START (fa); |
ul_t prev_end = (ul_t)HEAP_FREE_AREA_END (prev); |
|
if (prev_end >= start) |
__heap_check_failure (heap, fa, str, |
"start %s with prev free-area end:\n\ |
(0x%lx)->prev = 0x%lx\n\ |
(0x%lx)->start = 0x%lx\n\ |
(0x%lx)->end = 0x%lx\n", |
(prev_end == start ? "unmerged" : "overlaps"), |
(ul_t)fa, (ul_t)prev, |
(ul_t)fa, start, |
(ul_t)prev, prev_end); |
} |
} |
} |
/malloc/heap_alloc.c
0,0 → 1,51
/* |
* libc/stdlib/malloc/heap_alloc.c -- allocate memory from a heap |
* |
* Copyright (C) 2002 NEC Corporation |
* Copyright (C) 2002 Miles Bader <miles@gnu.org> |
* |
* This file is subject to the terms and conditions of the GNU Lesser |
* General Public License. See the file COPYING.LIB in the main |
* directory of this archive for more details. |
* |
* Written by Miles Bader <miles@gnu.org> |
*/ |
|
#include <stdlib.h> |
|
#include "heap.h" |
|
|
/* 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). */ |
void * |
__heap_alloc (struct heap *heap, size_t *size) |
{ |
struct heap_free_area *fa; |
size_t _size = *size; |
void *mem = 0; |
|
_size = HEAP_ADJUST_SIZE (_size); |
|
if (_size < sizeof (struct heap_free_area)) |
/* Because we sometimes must use a freed block to hold a free-area node, |
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"); |
|
/* Look for a free area that can contain _SIZE bytes. */ |
for (fa = heap->free_areas; fa; fa = fa->next) |
if (fa->size >= _size) |
{ |
/* Found one! */ |
mem = HEAP_FREE_AREA_START (fa); |
*size = __heap_free_area_alloc (heap, fa, _size); |
break; |
} |
|
HEAP_DEBUG (heap, "after __heap_alloc"); |
|
return mem; |
} |
/malloc/malloc.c
0,0 → 1,211
/* |
* libc/stdlib/malloc/malloc.c -- malloc function |
* |
* Copyright (C) 2002,03 NEC Electronics Corporation |
* Copyright (C) 2002,03 Miles Bader <miles@gnu.org> |
* |
* This file is subject to the terms and conditions of the GNU Lesser |
* General Public License. See the file COPYING.LIB in the main |
* directory of this archive for more details. |
* |
* Written by Miles Bader <miles@gnu.org> |
*/ |
|
#include <stdlib.h> |
#include <unistd.h> |
#include <errno.h> |
#include <sys/mman.h> |
|
#include "malloc.h" |
#include "heap.h" |
|
|
/* 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); |
|
#if defined(MALLOC_USE_LOCKING) && defined(MALLOC_USE_SBRK) |
/* A lock protecting our use of sbrk. */ |
malloc_mutex_t __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 |
malloc has mmapped, ordered by the block address. */ |
struct malloc_mmb *__malloc_mmapped_blocks = 0; |
|
/* 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. */ |
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); |
#endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */ |
|
|
static void * |
malloc_from_heap (size_t size, struct heap *heap) |
{ |
void *mem; |
|
MALLOC_DEBUG (1, "malloc: %d bytes", size); |
|
/* Include extra space to record the size of the allocated block. */ |
size += MALLOC_HEADER_SIZE; |
|
__heap_lock (heap); |
|
/* First try to get memory that's already in our heap. */ |
mem = __heap_alloc (heap, &size); |
|
__heap_unlock (heap); |
|
if (unlikely (! mem)) |
/* We couldn't allocate from the heap, so grab some more |
from the system, add it to the heap, and try again. */ |
{ |
/* If we're trying to allocate a block bigger than the default |
MALLOC_HEAP_EXTEND_SIZE, make sure we get enough to hold it. */ |
void *block; |
size_t block_size |
= (size < MALLOC_HEAP_EXTEND_SIZE |
? MALLOC_HEAP_EXTEND_SIZE |
: MALLOC_ROUND_UP_TO_PAGE_SIZE (size)); |
|
/* Allocate the new heap block. */ |
#ifdef MALLOC_USE_SBRK |
|
__malloc_lock_sbrk (); |
|
/* Use sbrk we can, as it's faster than mmap, and guarantees |
contiguous allocation. */ |
block = sbrk (block_size); |
if (likely (block != (void *)-1)) |
{ |
/* Because sbrk can return results of arbitrary |
alignment, align the result to a MALLOC_ALIGNMENT boundary. */ |
long aligned_block = MALLOC_ROUND_UP ((long)block, MALLOC_ALIGNMENT); |
if (block != (void *)aligned_block) |
/* Have to adjust. We should only have to actually do this |
the first time (after which we will have aligned the brk |
correctly). */ |
{ |
/* Move the brk to reflect the alignment; our next allocation |
should start on exactly the right alignment. */ |
sbrk (aligned_block - (long)block); |
block = (void *)aligned_block; |
} |
} |
|
__malloc_unlock_sbrk (); |
|
#else /* !MALLOC_USE_SBRK */ |
|
/* Otherwise, use mmap. */ |
block = mmap (0, block_size, PROT_READ | PROT_WRITE, |
MAP_SHARED | MAP_ANONYMOUS, 0, 0); |
|
#endif /* MALLOC_USE_SBRK */ |
|
if (likely (block != (void *)-1)) |
{ |
#if !defined(MALLOC_USE_SBRK) && defined(__UCLIBC_UCLINUX_BROKEN_MUNMAP__) |
struct malloc_mmb *mmb, *prev_mmb, *new_mmb; |
#endif |
|
MALLOC_DEBUG (1, "adding system memroy to heap: 0x%lx - 0x%lx (%d bytes)", |
(long)block, (long)block + block_size, block_size); |
|
/* Get back the heap lock. */ |
__heap_lock (heap); |
|
/* Put BLOCK into the heap. */ |
__heap_free (heap, block, block_size); |
|
MALLOC_DEBUG_INDENT (-1); |
|
/* 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. */ |
|
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; |
|
if (prev_mmb) |
prev_mmb->next = new_mmb; |
else |
__malloc_mmapped_blocks = new_mmb; |
|
MALLOC_MMB_DEBUG (0, "new mmb at 0x%x: 0x%x[%d]", |
(unsigned)new_mmb, |
(unsigned)new_mmb->mem, block_size); |
#endif /* !MALLOC_USE_SBRK && __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */ |
} |
} |
|
if (likely (mem)) |
/* Record the size of the block and get the user address. */ |
{ |
mem = MALLOC_SETUP (mem, size); |
|
MALLOC_DEBUG (-1, "malloc: returning 0x%lx (base:0x%lx, total_size:%ld)", |
(long)mem, (long)MALLOC_BASE(mem), (long)MALLOC_SIZE(mem)); |
} |
else |
MALLOC_DEBUG (-1, "malloc: returning 0"); |
|
return mem; |
} |
|
void * |
malloc (size_t size) |
{ |
void *mem; |
#ifdef MALLOC_DEBUGGING |
static int debugging_initialized = 0; |
if (! debugging_initialized) |
{ |
debugging_initialized = 1; |
__malloc_debug_init (); |
} |
if (__malloc_check) |
__heap_check (&__malloc_heap, "malloc"); |
#endif |
|
#ifdef __MALLOC_GLIBC_COMPAT__ |
if (unlikely (size == 0)) |
size++; |
#else |
/* Some programs will call malloc (0). Lets be strict and return NULL */ |
if (unlikely (size == 0)) |
return 0; |
#endif |
|
/* Check if they are doing something dumb like malloc(-1) */ |
if (unlikely(((unsigned long)size > (unsigned long)(MALLOC_HEADER_SIZE*-2)))) |
goto oom; |
|
mem = malloc_from_heap (size, &__malloc_heap); |
if (unlikely (!mem)) |
{ |
oom: |
__set_errno (ENOMEM); |
return 0; |
} |
|
return mem; |
} |
/malloc/memalign.c
0,0 → 1,94
/* |
* libc/stdlib/malloc/memalign.c -- memalign (`aligned malloc') function |
* |
* Copyright (C) 2002 NEC Corporation |
* Copyright (C) 2002 Miles Bader <miles@gnu.org> |
* |
* This file is subject to the terms and conditions of the GNU Lesser |
* General Public License. See the file COPYING.LIB in the main |
* directory of this archive for more details. |
* |
* Written by Miles Bader <miles@gnu.org> |
*/ |
|
#include <stdlib.h> |
#include <unistd.h> |
#include <sys/mman.h> |
|
#include "malloc.h" |
#include "heap.h" |
|
|
#define MAX(x,y) ((x) > (y) ? (x) : (y)) |
|
/* |
______________________ TOTAL _________________________ |
/ \ |
+---------------+-------------------------+--------------+ |
| | | | |
+---------------+-------------------------+--------------+ |
\____ INIT ____/ \______ RETURNED _______/ \____ END ___/ |
*/ |
|
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; |
|
/* Make SIZE something we like. */ |
size = HEAP_ADJUST_SIZE (size); |
|
/* Use malloc to do the initial allocation, since it deals with getting |
system memory. We over-allocate enough to be sure that we'll get |
enough memory to hold a properly aligned block of size SIZE, |
_somewhere_ in the result. */ |
mem = malloc (size + 2 * alignment); |
if (! mem) |
/* Allocation failed, we can't do anything. */ |
return 0; |
if (alignment < MALLOC_ALIGNMENT) |
return mem; |
|
/* Remember the base-address, of the allocation, although we normally |
use the user-address for calculations, since that's where the |
alignment matters. */ |
base = MALLOC_BASE (mem); |
|
/* The bounds of the initial allocation. */ |
tot_addr = (unsigned long)mem; |
tot_end_addr = (unsigned long)base + MALLOC_SIZE (mem); |
|
/* Find a likely place inside MEM with the right alignment. */ |
addr = MALLOC_ROUND_UP (tot_addr, alignment); |
|
/* Unless TOT_ADDR was already aligned correctly, we need to return the |
initial part of MEM to the heap. */ |
if (addr != tot_addr) |
{ |
size_t init_size = addr - tot_addr; |
|
/* Ensure that memory returned to the heap is large enough. */ |
if (init_size < HEAP_MIN_SIZE) |
{ |
addr = MALLOC_ROUND_UP (tot_addr + HEAP_MIN_SIZE, alignment); |
init_size = addr - tot_addr; |
} |
|
__heap_free (heap, base, init_size); |
|
/* Remember that we've freed the initial part of MEM. */ |
base += init_size; |
} |
|
/* Return the end part of MEM to the heap, unless it's too small. */ |
end_addr = addr + size; |
if (end_addr + MALLOC_REALLOC_MIN_FREE_SIZE < tot_end_addr) |
__heap_free (heap, (void *)end_addr, tot_end_addr - end_addr); |
else |
/* We didn't free the end, so include it in the size. */ |
end_addr = tot_end_addr; |
|
return MALLOC_SETUP (base, end_addr - (unsigned long)base); |
} |
/malloc/heap_alloc_at.c
0,0 → 1,47
/* |
* libc/stdlib/malloc/heap_alloc_at.c -- allocate at a specific address |
* |
* Copyright (C) 2002 NEC Corporation |
* Copyright (C) 2002 Miles Bader <miles@gnu.org> |
* |
* This file is subject to the terms and conditions of the GNU Lesser |
* General Public License. See the file COPYING.LIB in the main |
* directory of this archive for more details. |
* |
* Written by Miles Bader <miles@gnu.org> |
*/ |
|
#include <stdlib.h> |
|
#include "heap.h" |
|
|
/* 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) |
{ |
struct heap_free_area *fa; |
size_t alloced = 0; |
|
size = HEAP_ADJUST_SIZE (size); |
|
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) |
{ |
void *fa_mem = HEAP_FREE_AREA_START (fa); |
if (fa_mem <= mem) |
{ |
if (fa_mem == mem && fa->size >= size) |
/* FA has the right addr, and is big enough! */ |
alloced = __heap_free_area_alloc (heap, fa, size); |
break; |
} |
} |
|
HEAP_DEBUG (heap, "after __heap_alloc_at"); |
|
return alloced; |
} |
/malloc/Makefile
0,0 → 1,58
# Makefile for uClibc |
# |
# Copyright (C) 2002,03 NEC Electronics Corporation |
# Copyright (C) 2002,03 Miles Bader <miles@gnu.org> |
# |
# This program is free software; you can redistribute it and/or modify it under |
# the terms of the GNU Library General Public License as published by the Free |
# Software Foundation; either version 2 of the License, or (at your option) any |
# later version. |
# |
# This program 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 Library General Public License 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 |
# |
# Derived in part from the Linux-8086 C library, the GNU C Library, and several |
# other sundry sources. Files within this library are copyright by their |
# respective copyright holders. |
|
TOPDIR=../../../ |
include $(TOPDIR)Rules.mak |
|
CSRC = 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 |
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 |
endif |
endif |
|
COBJS=$(patsubst %.c,%.o, $(CSRC)) |
OBJS=$(COBJS) |
|
all: $(OBJS) $(LIBC) |
|
$(LIBC): ar-target |
|
ar-target: $(OBJS) |
$(AR) $(ARFLAGS) $(LIBC) $(OBJS) |
|
malloc.o free.o realloc.o memalign.o: malloc.h |
$(COBJS): heap.h |
|
# Depend on uClinux_config.h to cache changes in __UCLIBC_MALLOC_DEBUGGING__ |
$(COBJS): %.o : %.c ../../../include/bits/uClibc_config.h |
$(CC) $(CFLAGS) -c $< -o $@ |
$(STRIPTOOL) -x -R .note -R .comment $*.o |
|
clean: |
$(RM) *.[oa] *~ core |
/malloc/malloc.h
0,0 → 1,214
/* |
* libc/stdlib/malloc/malloc.h -- small malloc implementation |
* |
* Copyright (C) 2002 NEC Corporation |
* Copyright (C) 2002 Miles Bader <miles@gnu.org> |
* |
* This file is subject to the terms and conditions of the GNU Lesser |
* General Public License. See the file COPYING.LIB in the main |
* directory of this archive for more details. |
* |
* Written by Miles Bader <miles@gnu.org> |
*/ |
|
/* The alignment we guarantee for malloc return values. */ |
#define MALLOC_ALIGNMENT (sizeof (double)) |
|
/* The system pagesize we assume; we really ought to get it with |
getpagesize, but gee, how annoying. */ |
#define MALLOC_PAGE_SIZE 4096 |
|
/* 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 |
satisfy a particularly big request). */ |
#define MALLOC_HEAP_EXTEND_SIZE MALLOC_PAGE_SIZE |
|
/* When a heap free-area grows above this size, try to unmap it, releasing |
the memory back to the system. */ |
#define MALLOC_UNMAP_THRESHOLD (8*MALLOC_PAGE_SIZE) |
/* When unmapping a free-area, retain this many bytes if it's the only one, |
to avoid completely emptying the heap. This is only a heuristic -- the |
existance of another free area, even if it's smaller than |
MALLOC_MIN_SIZE, will cause us not to reserve anything. */ |
#define MALLOC_MIN_SIZE (2*MALLOC_PAGE_SIZE) |
|
/* When realloc shrinks an allocation, it only does so if more than this |
many bytes will be freed; it must at at least HEAP_MIN_SIZE. Larger |
values increase speed (by reducing heap fragmentation) at the expense of |
space. */ |
#define MALLOC_REALLOC_MIN_FREE_SIZE (HEAP_MIN_SIZE + 16) |
|
|
/* For systems with an MMU, use sbrk to map/unmap memory for the malloc |
heap, instead of mmap/munmap. This is a tradeoff -- sbrk is faster than |
mmap/munmap, and guarantees contiguous allocation, but is also less |
flexible, and causes the heap to only be shrinkable from the end. */ |
#ifdef __UCLIBC_HAS_MMU__ |
# define MALLOC_USE_SBRK |
#endif |
|
|
/* The current implementation of munmap in uClinux doesn't work correctly: |
it requires that ever call to munmap exactly match a corresponding call |
to mmap (that is, it doesn't allow you to unmap only part of a |
previously allocated block, or to unmap two contiguous blocks with a |
single call to munmap). This behavior is broken, and uClinux should be |
fixed; however, until it is, we add code to work around the problem in |
malloc. */ |
#ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__ |
|
/* A structure recording a block of memory mmapped by malloc. */ |
struct malloc_mmb |
{ |
void *mem; /* the mmapped block */ |
size_t size; /* its size */ |
struct malloc_mmb *next; |
}; |
|
/* A list of all malloc_mmb structures describing blocsk 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; |
|
/* Define MALLOC_MMB_DEBUGGING to cause malloc to emit debugging info about |
about mmap block allocation/freeing by the `uclinux broken munmap' code |
to stderr, when the variable __malloc_mmb_debug is set to true. */ |
#ifdef MALLOC_MMB_DEBUGGING |
# include <stdio.h> |
extern int __malloc_mmb_debug; |
# define MALLOC_MMB_DEBUG(indent, fmt, args...) \ |
(__malloc_mmb_debug ? __malloc_debug_printf (indent, fmt , ##args) : 0) |
# define MALLOC_MMB_DEBUG_INDENT(indent) \ |
(__malloc_mmb_debug ? __malloc_debug_indent (indent) : 0) |
# ifndef MALLOC_DEBUGGING |
# define MALLOC_DEBUGGING |
# endif |
#else /* !MALLOC_MMB_DEBUGGING */ |
# define MALLOC_MMB_DEBUG(fmt, args...) (void)0 |
# define MALLOC_MMB_DEBUG_INDENT(indent) (void)0 |
#endif /* MALLOC_MMB_DEBUGGING */ |
|
#endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */ |
|
|
/* The size of a malloc allocation is stored in a size_t word |
MALLOC_ALIGNMENT bytes prior to the start address of the allocation: |
|
+--------+---------+-------------------+ |
| SIZE |(unused) | allocation ... | |
+--------+---------+-------------------+ |
^ BASE ^ ADDR |
^ ADDR - MALLOC_ALIGN |
*/ |
|
/* The amount of extra space used by the malloc header. */ |
#define MALLOC_HEADER_SIZE MALLOC_ALIGNMENT |
|
/* Set up the malloc header, and return the user address of a malloc block. */ |
#define MALLOC_SETUP(base, size) \ |
(MALLOC_SET_SIZE (base, size), (void *)((char *)base + MALLOC_HEADER_SIZE)) |
/* Set the size of a malloc allocation, given the base address. */ |
#define MALLOC_SET_SIZE(base, size) (*(size_t *)(base) = (size)) |
|
/* Return base-address of a malloc allocation, given the user address. */ |
#define MALLOC_BASE(addr) ((void *)((char *)addr - MALLOC_HEADER_SIZE)) |
/* Return the size of a malloc allocation, given the user address. */ |
#define MALLOC_SIZE(addr) (*(size_t *)MALLOC_BASE(addr)) |
|
|
/* Locking for multithreaded apps. */ |
#ifdef __UCLIBC_HAS_THREADS__ |
|
# include <pthread.h> |
|
# define MALLOC_USE_LOCKING |
|
typedef pthread_mutex_t malloc_mutex_t; |
# define MALLOC_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER |
|
# 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. */ |
# 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 */ |
|
|
/* 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); |
|
/* The number of spaces in a malloc debug indent level. */ |
#define MALLOC_DEBUG_INDENT_SIZE 3 |
|
extern int __malloc_debug, __malloc_check; |
|
# 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; |
|
/* 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, ...); |
|
/* Change the current debug print level by INDENT, and return the value. */ |
#define __malloc_debug_indent(indent) (__malloc_debug_cur_indent += indent) |
|
/* Set the current debug print level to LEVEL. */ |
#define __malloc_debug_set_indent(level) (__malloc_debug_cur_indent = level) |
|
#else /* !MALLOC_DEBUGGING */ |
# define MALLOC_DEBUG(fmt, args...) (void)0 |
# define MALLOC_DEBUG_INDENT(indent) (void)0 |
#endif /* MALLOC_DEBUGGING */ |
|
|
/* Return SZ rounded down to POWER_OF_2_SIZE (which must be power of 2). */ |
#define MALLOC_ROUND_DOWN(sz, power_of_2_size) \ |
((sz) & ~(power_of_2_size - 1)) |
/* Return SZ rounded to POWER_OF_2_SIZE (which must be power of 2). */ |
#define MALLOC_ROUND_UP(sz, power_of_2_size) \ |
MALLOC_ROUND_DOWN ((sz) + (power_of_2_size - 1), (power_of_2_size)) |
|
/* Return SZ rounded down to a multiple MALLOC_PAGE_SIZE. */ |
#define MALLOC_ROUND_DOWN_TO_PAGE_SIZE(sz) \ |
MALLOC_ROUND_DOWN (sz, MALLOC_PAGE_SIZE) |
/* Return SZ rounded up to a multiple MALLOC_PAGE_SIZE. */ |
#define MALLOC_ROUND_UP_TO_PAGE_SIZE(sz) \ |
MALLOC_ROUND_UP (sz, MALLOC_PAGE_SIZE) |
|
|
/* The malloc heap. */ |
extern struct heap __malloc_heap; |
/malloc/calloc.c
0,0 → 1,41
/* vi: set sw=4 ts=4: */ |
/* calloc for uClibc |
* |
* Copyright (C) 2002 by Erik Andersen <andersen@uclibc.org> |
* |
* This program is free software; you can redistribute it and/or modify it |
* under the terms of the GNU Library General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or (at your |
* option) any later version. |
* |
* This program 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 Library General Public License |
* 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 |
*/ |
|
#include <stdlib.h> |
#include <string.h> |
#include <errno.h> |
|
void * calloc(size_t nmemb, size_t lsize) |
{ |
void *result; |
size_t size=lsize * nmemb; |
|
/* guard vs integer overflow, but allow nmemb |
* to fall through and call malloc(0) */ |
if (nmemb && lsize != (size / nmemb)) { |
__set_errno(ENOMEM); |
return NULL; |
} |
if ((result=malloc(size)) != NULL) { |
memset(result, 0, size); |
} |
return result; |
} |
|
/malloc/malloc_debug.c
0,0 → 1,86
/* |
* libc/stdlib/malloc/malloc_debug.c -- malloc debugging support |
* |
* Copyright (C) 2002 NEC Corporation |
* Copyright (C) 2002 Miles Bader <miles@gnu.org> |
* |
* This file is subject to the terms and conditions of the GNU Lesser |
* General Public License. See the file COPYING.LIB in the main |
* directory of this archive for more details. |
* |
* Written by Miles Bader <miles@gnu.org> |
*/ |
|
#include <stdlib.h> |
#include <stdio.h> |
#include <unistd.h> |
#include <stdarg.h> |
|
#include "malloc.h" |
#include "heap.h" |
|
int __malloc_debug = 0, __malloc_check = 0; |
|
#ifdef MALLOC_MMB_DEBUGGING |
int __malloc_mmb_debug = 0; |
#endif |
|
/* Debugging output is indented this may levels. */ |
int __malloc_debug_cur_indent = 0; |
|
|
/* Print FMT and args indented at the current debug print level, followed |
by a newline, and change the level by INDENT. */ |
void |
__malloc_debug_printf (int indent, const char *fmt, ...) |
{ |
unsigned spaces = __malloc_debug_cur_indent * MALLOC_DEBUG_INDENT_SIZE; |
va_list val; |
|
while (spaces > 0) |
{ |
putc (' ', stderr); |
spaces--; |
} |
|
va_start (val, fmt); |
vfprintf (stderr, fmt, val); |
va_end (val); |
|
putc ('\n', stderr); |
|
__malloc_debug_indent (indent); |
} |
|
void |
__malloc_debug_init (void) |
{ |
char *ev = getenv ("MALLOC_DEBUG"); |
if (ev) |
{ |
int val = atoi (ev); |
|
if (val & 1) |
__malloc_check = 1; |
|
if (val & 2) |
__malloc_debug = 1; |
|
#ifdef MALLOC_MMB_DEBUGGING |
if (val & 4) |
__malloc_mmb_debug = 1; |
#endif |
|
#ifdef HEAP_DEBUGGING |
if (val & 8) |
__heap_debug = 1; |
#endif |
|
if (val) |
__malloc_debug_printf |
(0, "malloc_debug: initialized to %d (check = %d, dump = %d, dump_mmb = %d, dump_heap = %d)", |
val, |
!!(val & 1), !!(val & 2), |
!!(val & 4), !!(val & 8)); |
} |
} |
/getenv.c
0,0 → 1,41
/* getenv.c for uClibc |
Erik Andersen <andersen@codepoet.org> |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. |
*/ |
|
#include <string.h> |
#include <unistd.h> |
|
/* IEEE Std 1003.1-2001 says getenv need not be thread safe, so |
* don't bother locking access to __environ */ |
char *getenv(const char *var) |
{ |
int len; |
char **ep; |
|
if (!(ep=__environ)) |
return NULL; |
len = strlen(var); |
while(*ep) { |
if (memcmp(var, *ep, len) == 0 && (*ep)[len] == '=') { |
return *ep + len + 1; |
} |
ep++; |
} |
return NULL; |
} |
|
/pty-private.h
0,0 → 1,42
/* Internal defenitions and declarations for pseudo terminal functions. |
Copyright (C) 1998 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998. |
|
The GNU C Library is free software; you can redistribute it and/or |
modify it under the terms of the GNU Library General Public License as |
published by the Free Software Foundation; either version 2 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 |
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., 59 Temple Place - Suite 330, |
Boston, MA 02111-1307, USA. */ |
|
#ifndef _PTY_PRIVATE_H |
#define _PTY_PRIVATE_H 1 |
|
/* The group slave pseudo terminals belong to. */ |
#define TTY_GROUP "tty" |
|
/* The file descriptor connected to the master pseudo terminal. */ |
#define PTY_FILENO 3 |
|
/* Path to the helper program that implements `grantpt' in user space. */ |
#define _PATH_PT_CHOWN "/sbin/pt_chown" |
|
/* Exit codes for the helper program. */ |
enum /* failure modes */ |
{ |
FAIL_EBADF = 1, |
FAIL_EINVAL, |
FAIL_EACCES, |
FAIL_EXEC |
}; |
|
#endif /* pty-private.h */ |
/mkstemp64.c
0,0 → 1,30
/* Copyright (C) 1998 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 Library General Public License as |
published by the Free Software Foundation; either version 2 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 |
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., 59 Temple Place - Suite 330, |
Boston, MA 02111-1307, USA. */ |
|
#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 mkstemp64 (char *template) |
{ |
return __gen_tempname (template, __GT_BIGFILE); |
} |
/jrand48_r.c
0,0 → 1,38
/* Copyright (C) 1995, 1997, 1998, 2001 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu <mailto:drepper@gnu.ai.mit.edu>>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <stdlib.h> |
|
extern int __drand48_iterate(unsigned short xsubi[3], |
struct drand48_data *buffer); |
|
int jrand48_r (xsubi, buffer, result) |
unsigned short int xsubi[3]; |
struct drand48_data *buffer; |
long int *result; |
{ |
/* Compute next state. */ |
if (__drand48_iterate (xsubi, buffer) < 0) |
return -1; |
|
/* Store the result. */ |
*result = ((xsubi[2] << 16) | xsubi[1]) & 0xffffffffl; |
|
return 0; |
} |
/lrand48_r.c
0,0 → 1,29
/* Copyright (C) 1995, 1997, 1998, 2001 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu <mailto:drepper@gnu.ai.mit.edu>>, August 1995. |
|
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, write to the Free |
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
02111-1307 USA. */ |
|
#include <stdlib.h> |
|
int lrand48_r (struct drand48_data *buffer, long int *result) |
{ |
/* Be generous for the arguments, detect some errors. */ |
if (buffer == NULL) |
return -1; |
|
return nrand48_r (buffer->__x, buffer, result); |
} |