lib: c: combine libc and ulibc
libc is now made up of several independent components, each of which is individually compiled into a static library. they are then all combined into a single shared library.
This commit is contained in:
@@ -1,36 +1,30 @@
|
|||||||
set(source_dirs string stdio)
|
set(source_dirs core malloc)
|
||||||
foreach (dir ${source_dirs})
|
|
||||||
file(GLOB dir_sources ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.c)
|
|
||||||
file(GLOB dir_headers ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.h)
|
|
||||||
|
|
||||||
set(sources ${sources} ${dir_sources})
|
|
||||||
set(headers ${headers} ${dir_headers})
|
|
||||||
endforeach (dir)
|
|
||||||
|
|
||||||
file(GLOB runtime_sources
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/runtime/${CMAKE_SYSTEM_PROCESSOR}/*.s)
|
|
||||||
set_property(SOURCE ${runtime_sources} PROPERTY LANGUAGE C)
|
|
||||||
|
|
||||||
set(public_include_dirs
|
set(public_include_dirs
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include)
|
${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
add_subdirectory(runtime)
|
||||||
|
|
||||||
|
foreach (dir ${source_dirs})
|
||||||
|
add_subdirectory(${dir})
|
||||||
|
set(sources ${sources} ${component_sources})
|
||||||
|
set(headers ${headers} ${component_headers})
|
||||||
|
set(public_include_dirs ${public_include_dirs} ${component_public_include_dirs})
|
||||||
|
endforeach (dir)
|
||||||
|
|
||||||
rosetta_add_library(SHARED
|
rosetta_add_library(SHARED
|
||||||
NAME libc
|
NAME libc
|
||||||
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
|
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
|
||||||
SOURCES ${sources}
|
SOURCES ${sources}
|
||||||
HEADERS ${headers})
|
HEADERS ${headers})
|
||||||
|
|
||||||
rosetta_add_object_library(
|
|
||||||
NAME libc-rt STATIC
|
|
||||||
SOURCES ${runtime_sources})
|
|
||||||
|
|
||||||
sysroot_add_library(
|
sysroot_add_library(
|
||||||
NAME libc
|
NAME libc
|
||||||
HEADER_DIR /usr/include
|
HEADER_DIR /usr/include
|
||||||
LIB_DIR /usr/lib)
|
LIB_DIR /usr/lib)
|
||||||
sysroot_add_object_library(
|
|
||||||
NAME libc-rt
|
|
||||||
LIB_DIR /usr/lib)
|
|
||||||
bsp_add_library(
|
bsp_add_library(
|
||||||
NAME libc
|
NAME libc
|
||||||
LIB_DIR /usr/lib)
|
LIB_DIR /usr/lib)
|
||||||
|
|
||||||
|
target_link_libraries(libc libmango)
|
||||||
|
target_compile_definitions(libc PRIVATE ENABLE_GLOBAL_HEAP=1)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
set(source_dirs string stdio unistd stdlib)
|
set(source_dirs stdio string)
|
||||||
|
|
||||||
foreach (dir ${source_dirs})
|
foreach (dir ${source_dirs})
|
||||||
file(GLOB dir_sources ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.c)
|
file(GLOB dir_sources ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.c)
|
||||||
file(GLOB dir_headers ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.h)
|
file(GLOB dir_headers ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.h)
|
||||||
@@ -7,13 +8,16 @@ foreach (dir ${source_dirs})
|
|||||||
set(headers ${headers} ${dir_headers})
|
set(headers ${headers} ${dir_headers})
|
||||||
endforeach (dir)
|
endforeach (dir)
|
||||||
|
|
||||||
set(public_include_dirs
|
set(component_sources ${sources} PARENT_SCOPE)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include)
|
set(component_headers ${headers} PARENT_SCOPE)
|
||||||
|
|
||||||
rosetta_add_library(
|
rosetta_add_library(STATIC
|
||||||
NAME ulibc STATIC
|
NAME libc-core
|
||||||
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
|
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
|
||||||
SOURCES ${sources}
|
SOURCES ${sources}
|
||||||
HEADERS ${headers})
|
HEADERS ${headers})
|
||||||
|
|
||||||
target_link_libraries(ulibc libmango)
|
sysroot_add_library(
|
||||||
|
NAME libc-core
|
||||||
|
HEADER_DIR /usr/include
|
||||||
|
LIB_DIR /usr/lib)
|
||||||
342
lib/libc/core/string/strerror.c
Normal file
342
lib/libc/core/string/strerror.c
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
const char *strerror(int errnum)
|
||||||
|
{
|
||||||
|
switch (errnum) {
|
||||||
|
case SUCCESS:
|
||||||
|
return "Success";
|
||||||
|
case EPERM:
|
||||||
|
return "Operation not permitted";
|
||||||
|
case ENOENT:
|
||||||
|
return "No such file or directory";
|
||||||
|
case ESRCH:
|
||||||
|
return "No such process";
|
||||||
|
case EINTR:
|
||||||
|
return "Interrupted system call";
|
||||||
|
case EIO:
|
||||||
|
return "Input/output error";
|
||||||
|
case ENXIO:
|
||||||
|
return "Device not configured";
|
||||||
|
case E2BIG:
|
||||||
|
return "Argument list too long";
|
||||||
|
case ENOEXEC:
|
||||||
|
return "Exec format error";
|
||||||
|
case EBADF:
|
||||||
|
return "Bad file descriptor";
|
||||||
|
case ECHILD:
|
||||||
|
return "No child processes";
|
||||||
|
case EDEADLK:
|
||||||
|
return "Resource deadlock avoided";
|
||||||
|
case ENOMEM:
|
||||||
|
return "Cannot allocate memory";
|
||||||
|
case EACCES:
|
||||||
|
return "Permission denied";
|
||||||
|
case EFAULT:
|
||||||
|
return "Bad address";
|
||||||
|
case ENOTBLK:
|
||||||
|
return "Block device required";
|
||||||
|
case EBUSY:
|
||||||
|
return "Resource busy";
|
||||||
|
case EEXIST:
|
||||||
|
return "File exists";
|
||||||
|
case EXDEV:
|
||||||
|
return "Cross-device link";
|
||||||
|
case ENODEV:
|
||||||
|
return "Operation not supported by device";
|
||||||
|
case ENOTDIR:
|
||||||
|
return "Not a directory";
|
||||||
|
case EISDIR:
|
||||||
|
return "Is a directory";
|
||||||
|
case EINVAL:
|
||||||
|
return "Invalid argument";
|
||||||
|
case ENFILE:
|
||||||
|
return "Too many open files in system";
|
||||||
|
case EMFILE:
|
||||||
|
return "Too many open files";
|
||||||
|
case ENOTTY:
|
||||||
|
return "Inappropriate ioctl for device";
|
||||||
|
case ETXTBSY:
|
||||||
|
return "Text file busy";
|
||||||
|
case EFBIG:
|
||||||
|
return "File too large";
|
||||||
|
case ENOSPC:
|
||||||
|
return "No space left on device";
|
||||||
|
case ESPIPE:
|
||||||
|
return "Illegal seek";
|
||||||
|
case EROFS:
|
||||||
|
return "Read-only file system";
|
||||||
|
case EMLINK:
|
||||||
|
return "Too many links";
|
||||||
|
case EPIPE:
|
||||||
|
return "Broken pipe";
|
||||||
|
case EDOM:
|
||||||
|
return "Numerical argument out of domain";
|
||||||
|
case ERANGE:
|
||||||
|
return "Result too large";
|
||||||
|
case EAGAIN:
|
||||||
|
return "Resource temporarily unavailable";
|
||||||
|
case EINPROGRESS:
|
||||||
|
return "Operation now in progress";
|
||||||
|
case EALREADY:
|
||||||
|
return "Operation already in progress";
|
||||||
|
case ENOTSOCK:
|
||||||
|
return "Socket operation on non-socket";
|
||||||
|
case EDESTADDRREQ:
|
||||||
|
return "Destination address required";
|
||||||
|
case EMSGSIZE:
|
||||||
|
return "Message too long";
|
||||||
|
case EPROTOTYPE:
|
||||||
|
return "Protocol wrong type for socket";
|
||||||
|
case ENOPROTOOPT:
|
||||||
|
return "Protocol not available";
|
||||||
|
case EPROTONOSUPPORT:
|
||||||
|
return "Protocol not supported";
|
||||||
|
case ESOCKTNOSUPPORT:
|
||||||
|
return "Socket type not supported";
|
||||||
|
case ENOTSUP:
|
||||||
|
return "Operation not supported";
|
||||||
|
case EPFNOSUPPORT:
|
||||||
|
return "Protocol family not supported";
|
||||||
|
case EAFNOSUPPORT:
|
||||||
|
return "Address family not supported by protocol family";
|
||||||
|
case EADDRINUSE:
|
||||||
|
return "Address already in use";
|
||||||
|
case EADDRNOTAVAIL:
|
||||||
|
return "Can't assign requested address";
|
||||||
|
case ENETDOWN:
|
||||||
|
return "Network is down";
|
||||||
|
case ENETUNREACH:
|
||||||
|
return "Network is unreachable";
|
||||||
|
case ENETRESET:
|
||||||
|
return "Network dropped connection on reset";
|
||||||
|
case ECONNABORTED:
|
||||||
|
return "Software caused connection abort";
|
||||||
|
case ECONNRESET:
|
||||||
|
return "Connection reset by peer";
|
||||||
|
case ENOBUFS:
|
||||||
|
return "No buffer space available";
|
||||||
|
case EISCONN:
|
||||||
|
return "Socket is already connected";
|
||||||
|
case ENOTCONN:
|
||||||
|
return "Socket is not connected";
|
||||||
|
case ESHUTDOWN:
|
||||||
|
return "Can't send after socket shutdown";
|
||||||
|
case ETOOMANYREFS:
|
||||||
|
return "Too many references: can't splice";
|
||||||
|
case ETIMEDOUT:
|
||||||
|
return "Operation timed out";
|
||||||
|
case ECONNREFUSED:
|
||||||
|
return "Connection refused";
|
||||||
|
case ELOOP:
|
||||||
|
return "Too many levels of symbolic links";
|
||||||
|
case ENAMETOOLONG:
|
||||||
|
return "File name too long";
|
||||||
|
case EHOSTDOWN:
|
||||||
|
return "Host is down";
|
||||||
|
case EHOSTUNREACH:
|
||||||
|
return "No route to host";
|
||||||
|
case ENOTEMPTY:
|
||||||
|
return "Directory not empty";
|
||||||
|
case EPROCLIM:
|
||||||
|
return "Too many processes";
|
||||||
|
case EUSERS:
|
||||||
|
return "Too many users";
|
||||||
|
case EDQUOT:
|
||||||
|
return "Disc quota exceeded";
|
||||||
|
case ESTALE:
|
||||||
|
return "Stale NFS file handle";
|
||||||
|
case EREMOTE:
|
||||||
|
return "Too many levels of remote in path";
|
||||||
|
case EBADRPC:
|
||||||
|
return "RPC struct is bad";
|
||||||
|
case ERPCMISMATCH:
|
||||||
|
return "RPC version wrong";
|
||||||
|
case EPROGUNAVAIL:
|
||||||
|
return "RPC prog. not avail";
|
||||||
|
case EPROGMISMATCH:
|
||||||
|
return "Program version wrong";
|
||||||
|
case EPROCUNAVAIL:
|
||||||
|
return "Bad procedure for program";
|
||||||
|
case ENOLCK:
|
||||||
|
return "No locks available";
|
||||||
|
case ENOSYS:
|
||||||
|
return "Function not implemented";
|
||||||
|
case EFTYPE:
|
||||||
|
return "Inappropriate file type or format";
|
||||||
|
case EAUTH:
|
||||||
|
return "Authentication error";
|
||||||
|
case ENEEDAUTH:
|
||||||
|
return "Need authenticator";
|
||||||
|
case EPWROFF:
|
||||||
|
return "Device power is off";
|
||||||
|
case EDEVERR:
|
||||||
|
return "Device error";
|
||||||
|
case EOVERFLOW:
|
||||||
|
return "Value too large to be stored in data type";
|
||||||
|
case EBADEXEC:
|
||||||
|
return "Bad executable (or shared library)";
|
||||||
|
case EBADARCH:
|
||||||
|
return "Bad CPU type in executable";
|
||||||
|
case ESHLIBVERS:
|
||||||
|
return "Shared library version mismatch";
|
||||||
|
case EBADMACHO:
|
||||||
|
return "Malformed Mach-o file";
|
||||||
|
case ECANCELED:
|
||||||
|
return "Operation canceled";
|
||||||
|
case EIDRM:
|
||||||
|
return "Identifier removed";
|
||||||
|
case ENOMSG:
|
||||||
|
return "No message of desired type";
|
||||||
|
case EILSEQ:
|
||||||
|
return "Illegal byte sequence";
|
||||||
|
case ENOATTR:
|
||||||
|
return "Attribute not found";
|
||||||
|
case EBADMSG:
|
||||||
|
return "Bad message";
|
||||||
|
case EMULTIHOP:
|
||||||
|
return "EMULTIHOP (Reserved)";
|
||||||
|
case ENODATA:
|
||||||
|
return "No message available on STREAM";
|
||||||
|
case ENOLINK:
|
||||||
|
return "ENOLINK (Reserved)";
|
||||||
|
case ENOSR:
|
||||||
|
return "No STREAM resources";
|
||||||
|
case ENOSTR:
|
||||||
|
return "Not a STREAM";
|
||||||
|
case EPROTO:
|
||||||
|
return "Protocol error";
|
||||||
|
case ETIME:
|
||||||
|
return "STREAM ioctl timeout";
|
||||||
|
case EOPNOTSUPP:
|
||||||
|
return "Operation not supported on socket";
|
||||||
|
case ENOPOLICY:
|
||||||
|
return "Policy not found";
|
||||||
|
case ENOTRECOVERABLE:
|
||||||
|
return "State not recoverable";
|
||||||
|
case EOWNERDEAD:
|
||||||
|
return "Previous owner died";
|
||||||
|
case EQFULL:
|
||||||
|
return "Interface output queue is full";
|
||||||
|
default:
|
||||||
|
return "Unknown error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ENUM_STR(x) \
|
||||||
|
case x: \
|
||||||
|
return #x
|
||||||
|
|
||||||
|
const char *strerror_code(int errnum)
|
||||||
|
{
|
||||||
|
switch (errnum) {
|
||||||
|
ENUM_STR(SUCCESS);
|
||||||
|
ENUM_STR(EPERM);
|
||||||
|
ENUM_STR(ENOENT);
|
||||||
|
ENUM_STR(ESRCH);
|
||||||
|
ENUM_STR(EINTR);
|
||||||
|
ENUM_STR(EIO);
|
||||||
|
ENUM_STR(ENXIO);
|
||||||
|
ENUM_STR(E2BIG);
|
||||||
|
ENUM_STR(ENOEXEC);
|
||||||
|
ENUM_STR(EBADF);
|
||||||
|
ENUM_STR(ECHILD);
|
||||||
|
ENUM_STR(EDEADLK);
|
||||||
|
ENUM_STR(ENOMEM);
|
||||||
|
ENUM_STR(EACCES);
|
||||||
|
ENUM_STR(EFAULT);
|
||||||
|
ENUM_STR(ENOTBLK);
|
||||||
|
ENUM_STR(EBUSY);
|
||||||
|
ENUM_STR(EEXIST);
|
||||||
|
ENUM_STR(EXDEV);
|
||||||
|
ENUM_STR(ENODEV);
|
||||||
|
ENUM_STR(ENOTDIR);
|
||||||
|
ENUM_STR(EISDIR);
|
||||||
|
ENUM_STR(EINVAL);
|
||||||
|
ENUM_STR(ENFILE);
|
||||||
|
ENUM_STR(EMFILE);
|
||||||
|
ENUM_STR(ENOTTY);
|
||||||
|
ENUM_STR(ETXTBSY);
|
||||||
|
ENUM_STR(EFBIG);
|
||||||
|
ENUM_STR(ENOSPC);
|
||||||
|
ENUM_STR(ESPIPE);
|
||||||
|
ENUM_STR(EROFS);
|
||||||
|
ENUM_STR(EMLINK);
|
||||||
|
ENUM_STR(EPIPE);
|
||||||
|
ENUM_STR(EDOM);
|
||||||
|
ENUM_STR(ERANGE);
|
||||||
|
ENUM_STR(EAGAIN);
|
||||||
|
ENUM_STR(EINPROGRESS);
|
||||||
|
ENUM_STR(EALREADY);
|
||||||
|
ENUM_STR(ENOTSOCK);
|
||||||
|
ENUM_STR(EDESTADDRREQ);
|
||||||
|
ENUM_STR(EMSGSIZE);
|
||||||
|
ENUM_STR(EPROTOTYPE);
|
||||||
|
ENUM_STR(ENOPROTOOPT);
|
||||||
|
ENUM_STR(EPROTONOSUPPORT);
|
||||||
|
ENUM_STR(ESOCKTNOSUPPORT);
|
||||||
|
ENUM_STR(ENOTSUP);
|
||||||
|
ENUM_STR(EPFNOSUPPORT);
|
||||||
|
ENUM_STR(EAFNOSUPPORT);
|
||||||
|
ENUM_STR(EADDRINUSE);
|
||||||
|
ENUM_STR(EADDRNOTAVAIL);
|
||||||
|
ENUM_STR(ENETDOWN);
|
||||||
|
ENUM_STR(ENETUNREACH);
|
||||||
|
ENUM_STR(ENETRESET);
|
||||||
|
ENUM_STR(ECONNABORTED);
|
||||||
|
ENUM_STR(ECONNRESET);
|
||||||
|
ENUM_STR(ENOBUFS);
|
||||||
|
ENUM_STR(EISCONN);
|
||||||
|
ENUM_STR(ENOTCONN);
|
||||||
|
ENUM_STR(ESHUTDOWN);
|
||||||
|
ENUM_STR(ETOOMANYREFS);
|
||||||
|
ENUM_STR(ETIMEDOUT);
|
||||||
|
ENUM_STR(ECONNREFUSED);
|
||||||
|
ENUM_STR(ELOOP);
|
||||||
|
ENUM_STR(ENAMETOOLONG);
|
||||||
|
ENUM_STR(EHOSTDOWN);
|
||||||
|
ENUM_STR(EHOSTUNREACH);
|
||||||
|
ENUM_STR(ENOTEMPTY);
|
||||||
|
ENUM_STR(EPROCLIM);
|
||||||
|
ENUM_STR(EUSERS);
|
||||||
|
ENUM_STR(EDQUOT);
|
||||||
|
ENUM_STR(ESTALE);
|
||||||
|
ENUM_STR(EREMOTE);
|
||||||
|
ENUM_STR(EBADRPC);
|
||||||
|
ENUM_STR(ERPCMISMATCH);
|
||||||
|
ENUM_STR(EPROGUNAVAIL);
|
||||||
|
ENUM_STR(EPROGMISMATCH);
|
||||||
|
ENUM_STR(EPROCUNAVAIL);
|
||||||
|
ENUM_STR(ENOLCK);
|
||||||
|
ENUM_STR(ENOSYS);
|
||||||
|
ENUM_STR(EFTYPE);
|
||||||
|
ENUM_STR(EAUTH);
|
||||||
|
ENUM_STR(ENEEDAUTH);
|
||||||
|
ENUM_STR(EPWROFF);
|
||||||
|
ENUM_STR(EDEVERR);
|
||||||
|
ENUM_STR(EOVERFLOW);
|
||||||
|
ENUM_STR(EBADEXEC);
|
||||||
|
ENUM_STR(EBADARCH);
|
||||||
|
ENUM_STR(ESHLIBVERS);
|
||||||
|
ENUM_STR(EBADMACHO);
|
||||||
|
ENUM_STR(ECANCELED);
|
||||||
|
ENUM_STR(EIDRM);
|
||||||
|
ENUM_STR(ENOMSG);
|
||||||
|
ENUM_STR(EILSEQ);
|
||||||
|
ENUM_STR(ENOATTR);
|
||||||
|
ENUM_STR(EBADMSG);
|
||||||
|
ENUM_STR(EMULTIHOP);
|
||||||
|
ENUM_STR(ENODATA);
|
||||||
|
ENUM_STR(ENOLINK);
|
||||||
|
ENUM_STR(ENOSR);
|
||||||
|
ENUM_STR(ENOSTR);
|
||||||
|
ENUM_STR(EPROTO);
|
||||||
|
ENUM_STR(ETIME);
|
||||||
|
ENUM_STR(EOPNOTSUPP);
|
||||||
|
ENUM_STR(ENOPOLICY);
|
||||||
|
ENUM_STR(ENOTRECOVERABLE);
|
||||||
|
ENUM_STR(EOWNERDEAD);
|
||||||
|
ENUM_STR(EQFULL);
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
142
lib/libc/include/errno.h
Normal file
142
lib/libc/include/errno.h
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
#ifndef ERRNO_H_
|
||||||
|
#define ERRNO_H_
|
||||||
|
|
||||||
|
#define SUCCESS 0 /* Success */
|
||||||
|
#define EPERM 1 /* Operation not permitted */
|
||||||
|
#define ENOENT 2 /* No such file or directory */
|
||||||
|
#define ESRCH 3 /* No such process */
|
||||||
|
#define EINTR 4 /* Interrupted system call */
|
||||||
|
#define EIO 5 /* Input/output error */
|
||||||
|
#define ENXIO 6 /* Device not configured */
|
||||||
|
#define E2BIG 7 /* Argument list too long */
|
||||||
|
#define ENOEXEC 8 /* Exec format error */
|
||||||
|
#define EBADF 9 /* Bad file descriptor */
|
||||||
|
#define ECHILD 10 /* No child processes */
|
||||||
|
#define EDEADLK 11 /* Resource deadlock avoided */
|
||||||
|
#define ENOMEM 12 /* Cannot allocate memory */
|
||||||
|
#define EACCES 13 /* Permission denied */
|
||||||
|
#define EFAULT 14 /* Bad address */
|
||||||
|
#define ENOTBLK 15 /* Block device required */
|
||||||
|
#define EBUSY 16 /* Device / Resource busy */
|
||||||
|
#define EEXIST 17 /* File exists */
|
||||||
|
#define EXDEV 18 /* Cross-device link */
|
||||||
|
#define ENODEV 19 /* Operation not supported by device */
|
||||||
|
#define ENOTDIR 20 /* Not a directory */
|
||||||
|
#define EISDIR 21 /* Is a directory */
|
||||||
|
#define EINVAL 22 /* Invalid argument */
|
||||||
|
#define ENFILE 23 /* Too many open files in system */
|
||||||
|
#define EMFILE 24 /* Too many open files */
|
||||||
|
#define ENOTTY 25 /* Inappropriate ioctl for device */
|
||||||
|
#define ETXTBSY 26 /* Text file busy */
|
||||||
|
#define EFBIG 27 /* File too large */
|
||||||
|
#define ENOSPC 28 /* No space left on device */
|
||||||
|
#define ESPIPE 29 /* Illegal seek */
|
||||||
|
#define EROFS 30 /* Read-only file system */
|
||||||
|
#define EMLINK 31 /* Too many links */
|
||||||
|
#define EPIPE 32 /* Broken pipe */
|
||||||
|
|
||||||
|
/* math software */
|
||||||
|
#define EDOM 33 /* Numerical argument out of domain */
|
||||||
|
#define ERANGE 34 /* Result too large */
|
||||||
|
|
||||||
|
/* non-blocking and interrupt i/o */
|
||||||
|
#define EAGAIN 35 /* Resource temporarily unavailable */
|
||||||
|
#define EWOULDBLOCK EAGAIN /* Operation would block */
|
||||||
|
#define EINPROGRESS 36 /* Operation now in progress */
|
||||||
|
#define EALREADY 37 /* Operation already in progress */
|
||||||
|
|
||||||
|
/* ipc/network software -- argument errors */
|
||||||
|
#define ENOTSOCK 38 /* Socket operation on non-socket */
|
||||||
|
#define EDESTADDRREQ 39 /* Destination address required */
|
||||||
|
#define EMSGSIZE 40 /* Message too long */
|
||||||
|
#define EPROTOTYPE 41 /* Protocol wrong type for socket */
|
||||||
|
#define ENOPROTOOPT 42 /* Protocol not available */
|
||||||
|
#define EPROTONOSUPPORT 43 /* Protocol not supported */
|
||||||
|
#define ESOCKTNOSUPPORT 44 /* Socket type not supported */
|
||||||
|
#define ENOTSUP 45 /* Operation not supported */
|
||||||
|
#define EPFNOSUPPORT 46 /* Protocol family not supported */
|
||||||
|
#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */
|
||||||
|
#define EADDRINUSE 48 /* Address already in use */
|
||||||
|
#define EADDRNOTAVAIL 49 /* Can't assign requested address */
|
||||||
|
|
||||||
|
/* ipc/network software -- operational errors */
|
||||||
|
#define ENETDOWN 50 /* Network is down */
|
||||||
|
#define ENETUNREACH 51 /* Network is unreachable */
|
||||||
|
#define ENETRESET 52 /* Network dropped connection on reset */
|
||||||
|
#define ECONNABORTED 53 /* Software caused connection abort */
|
||||||
|
#define ECONNRESET 54 /* Connection reset by peer */
|
||||||
|
#define ENOBUFS 55 /* No buffer space available */
|
||||||
|
#define EISCONN 56 /* Socket is already connected */
|
||||||
|
#define ENOTCONN 57 /* Socket is not connected */
|
||||||
|
#define ESHUTDOWN 58 /* Can't send after socket shutdown */
|
||||||
|
#define ETOOMANYREFS 59 /* Too many references: can't splice */
|
||||||
|
#define ETIMEDOUT 60 /* Operation timed out */
|
||||||
|
#define ECONNREFUSED 61 /* Connection refused */
|
||||||
|
|
||||||
|
#define ELOOP 62 /* Too many levels of symbolic links */
|
||||||
|
#define ENAMETOOLONG 63 /* File name too long */
|
||||||
|
|
||||||
|
#define EHOSTDOWN 64 /* Host is down */
|
||||||
|
#define EHOSTUNREACH 65 /* No route to host */
|
||||||
|
#define ENOTEMPTY 66 /* Directory not empty */
|
||||||
|
|
||||||
|
/* quotas & mush */
|
||||||
|
#define EPROCLIM 67 /* Too many processes */
|
||||||
|
#define EUSERS 68 /* Too many users */
|
||||||
|
#define EDQUOT 69 /* Disc quota exceeded */
|
||||||
|
|
||||||
|
/* Network File System */
|
||||||
|
#define ESTALE 70 /* Stale NFS file handle */
|
||||||
|
#define EREMOTE 71 /* Too many levels of remote in path */
|
||||||
|
#define EBADRPC 72 /* RPC struct is bad */
|
||||||
|
#define ERPCMISMATCH 73 /* RPC version wrong */
|
||||||
|
#define EPROGUNAVAIL 74 /* RPC prog. not avail */
|
||||||
|
#define EPROGMISMATCH 75 /* Program version wrong */
|
||||||
|
#define EPROCUNAVAIL 76 /* Bad procedure for program */
|
||||||
|
|
||||||
|
#define ENOLCK 77 /* No locks available */
|
||||||
|
#define ENOSYS 78 /* Function not implemented */
|
||||||
|
|
||||||
|
#define EFTYPE 79 /* Inappropriate file type or format */
|
||||||
|
#define EAUTH 80 /* Authentication error */
|
||||||
|
#define ENEEDAUTH 81 /* Need authenticator */
|
||||||
|
|
||||||
|
/* Intelligent device errors */
|
||||||
|
#define EPWROFF 82 /* Device power is off */
|
||||||
|
#define EDEVERR 83 /* Device error, e.g. paper out */
|
||||||
|
|
||||||
|
#define EOVERFLOW 84 /* Value too large to be stored in data type */
|
||||||
|
|
||||||
|
/* Program loading errors */
|
||||||
|
#define EBADEXEC 85 /* Bad executable */
|
||||||
|
#define EBADARCH 86 /* Bad CPU type in executable */
|
||||||
|
#define ESHLIBVERS 87 /* Shared library version mismatch */
|
||||||
|
#define EBADMACHO 88 /* Malformed Macho file */
|
||||||
|
|
||||||
|
#define ECANCELED 89 /* Operation canceled */
|
||||||
|
|
||||||
|
#define EIDRM 90 /* Identifier removed */
|
||||||
|
#define ENOMSG 91 /* No message of desired type */
|
||||||
|
#define EILSEQ 92 /* Illegal byte sequence */
|
||||||
|
#define ENOATTR 93 /* Attribute not found */
|
||||||
|
|
||||||
|
#define EBADMSG 94 /* Bad message */
|
||||||
|
#define EMULTIHOP 95 /* Reserved */
|
||||||
|
#define ENODATA 96 /* No message available on STREAM */
|
||||||
|
#define ENOLINK 97 /* Reserved */
|
||||||
|
#define ENOSR 98 /* No STREAM resources */
|
||||||
|
#define ENOSTR 99 /* Not a STREAM */
|
||||||
|
#define EPROTO 100 /* Protocol error */
|
||||||
|
#define ETIME 101 /* STREAM ioctl timeout */
|
||||||
|
|
||||||
|
#define EOPNOTSUPP 102 /* Operation not supported on socket */
|
||||||
|
|
||||||
|
#define ENOPOLICY 103 /* No such policy registered */
|
||||||
|
|
||||||
|
#define ENOTRECOVERABLE 104 /* State not recoverable */
|
||||||
|
#define EOWNERDEAD 105 /* Previous owner died */
|
||||||
|
|
||||||
|
#define EQFULL 106 /* Interface output queue is full */
|
||||||
|
#define ELAST 106 /* Must be equal largest errno */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
extern const char *strerror(int errnum);
|
||||||
|
extern const char *strerror_code(int errnum);
|
||||||
|
|
||||||
extern size_t strlen(const char *s);
|
extern size_t strlen(const char *s);
|
||||||
|
|
||||||
extern int strcmp(const char *s1, const char *s2);
|
extern int strcmp(const char *s1, const char *s2);
|
||||||
|
|||||||
9
lib/libc/include/unistd.h
Normal file
9
lib/libc/include/unistd.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef UNISTD_H_
|
||||||
|
#define UNISTD_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern int open(const char *path, int flags);
|
||||||
|
extern int close(int fd);
|
||||||
|
|
||||||
|
#endif
|
||||||
33
lib/libc/malloc/CMakeLists.txt
Normal file
33
lib/libc/malloc/CMakeLists.txt
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
set(source_dirs stdlib)
|
||||||
|
|
||||||
|
file(GLOB sources *.c *.h)
|
||||||
|
|
||||||
|
foreach (dir ${source_dirs})
|
||||||
|
file(GLOB dir_sources ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.c)
|
||||||
|
file(GLOB dir_headers ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.h)
|
||||||
|
|
||||||
|
set(sources ${sources} ${dir_sources})
|
||||||
|
set(headers ${headers} ${dir_headers})
|
||||||
|
endforeach (dir)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE sub_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
|
||||||
|
set(headers ${headers} ${sub_headers})
|
||||||
|
|
||||||
|
set(component_sources ${sources} PARENT_SCOPE)
|
||||||
|
set(component_headers ${headers} PARENT_SCOPE)
|
||||||
|
set(component_public_include_dirs ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE)
|
||||||
|
|
||||||
|
rosetta_add_library(STATIC
|
||||||
|
NAME libc-malloc
|
||||||
|
PUBLIC_INCLUDE_DIRS
|
||||||
|
${public_include_dirs}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
|
SOURCES ${sources}
|
||||||
|
HEADERS ${headers})
|
||||||
|
|
||||||
|
sysroot_add_library(
|
||||||
|
NAME libc-malloc
|
||||||
|
HEADER_DIR /usr/include
|
||||||
|
LIB_DIR /usr/lib)
|
||||||
|
|
||||||
|
target_link_libraries(libc-malloc libc-core libmango)
|
||||||
112
lib/libc/malloc/heap.c
Normal file
112
lib/libc/malloc/heap.c
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
#include "liballoc.h"
|
||||||
|
|
||||||
|
#include <heap/heap.h>
|
||||||
|
#include <mango/handle.h>
|
||||||
|
#include <mango/log.h>
|
||||||
|
#include <mango/status.h>
|
||||||
|
#include <mango/task.h>
|
||||||
|
#include <mango/vm.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define HEAP_REGION_SIZE 0x40000000
|
||||||
|
#define HEAP_EXPAND_INCREMENT 0x100000
|
||||||
|
|
||||||
|
void *heap_alloc(heap_t *heap, size_t sz)
|
||||||
|
{
|
||||||
|
return _lbmalloc(heap, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *heap_realloc(heap_t *heap, void *p, size_t sz)
|
||||||
|
{
|
||||||
|
return _lbrealloc(heap, p, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *heap_calloc(heap_t *heap, size_t num, size_t itemsz)
|
||||||
|
{
|
||||||
|
return _lbcalloc(heap, num, itemsz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void heap_free(heap_t *heap, void *p)
|
||||||
|
{
|
||||||
|
_lbfree(heap, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static kern_status_t init_heap_region(heap_t *heap)
|
||||||
|
{
|
||||||
|
kern_handle_t self, address_space;
|
||||||
|
task_self(&self);
|
||||||
|
task_get_address_space(self, &address_space);
|
||||||
|
kern_handle_close(self);
|
||||||
|
|
||||||
|
kern_status_t status = vm_region_create(
|
||||||
|
address_space,
|
||||||
|
"libc-heap",
|
||||||
|
9,
|
||||||
|
VM_REGION_ANY_OFFSET,
|
||||||
|
HEAP_REGION_SIZE,
|
||||||
|
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
|
||||||
|
&heap->heap_region,
|
||||||
|
&heap->heap_base);
|
||||||
|
|
||||||
|
kern_handle_close(address_space);
|
||||||
|
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
return KERN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static kern_status_t expand_heap(heap_t *heap)
|
||||||
|
{
|
||||||
|
kern_handle_t vmo;
|
||||||
|
kern_status_t status = vm_object_create(
|
||||||
|
"libc-heap-data",
|
||||||
|
14,
|
||||||
|
HEAP_EXPAND_INCREMENT,
|
||||||
|
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
|
||||||
|
&vmo);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
virt_addr_t base = 0;
|
||||||
|
|
||||||
|
status = vm_region_map_relative(
|
||||||
|
heap->heap_region,
|
||||||
|
heap->heap_sys_alloc,
|
||||||
|
vmo,
|
||||||
|
0,
|
||||||
|
HEAP_EXPAND_INCREMENT,
|
||||||
|
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
|
||||||
|
&base);
|
||||||
|
|
||||||
|
kern_handle_close(vmo);
|
||||||
|
|
||||||
|
heap->heap_sys_alloc += HEAP_EXPAND_INCREMENT;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *heap_expand(heap_t *heap, size_t size)
|
||||||
|
{
|
||||||
|
kern_status_t status = KERN_OK;
|
||||||
|
if (heap->heap_region == KERN_HANDLE_INVALID) {
|
||||||
|
status = init_heap_region(heap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (heap->heap_req_alloc + size > heap->heap_sys_alloc) {
|
||||||
|
status = expand_heap(heap);
|
||||||
|
if (status != KERN_OK) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *p = (void *)(heap->heap_base + heap->heap_req_alloc);
|
||||||
|
heap->heap_req_alloc += size;
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
16
lib/libc/malloc/include/heap/_liballoc.h
Normal file
16
lib/libc/malloc/include/heap/_liballoc.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef HEAP__LIBALLOC_H_
|
||||||
|
#define HEAP__LIBALLOC_H_
|
||||||
|
|
||||||
|
struct liballoc_major;
|
||||||
|
struct liballoc_minor;
|
||||||
|
|
||||||
|
#define HEAP_INIT \
|
||||||
|
{ \
|
||||||
|
.heap_region = KERN_HANDLE_INVALID, \
|
||||||
|
.heap_liballoc = { \
|
||||||
|
.l_pageSize = 4096, \
|
||||||
|
.l_pageCount = 16, \
|
||||||
|
}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
50
lib/libc/malloc/include/heap/heap.h
Normal file
50
lib/libc/malloc/include/heap/heap.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#ifndef HEAP_H_
|
||||||
|
#define HEAP_H_
|
||||||
|
|
||||||
|
#include <heap/_liballoc.h>
|
||||||
|
#include <mango/types.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef enum heap_result {
|
||||||
|
HEAP_OK = 0,
|
||||||
|
HEAP_ERR_NO_MEMORY,
|
||||||
|
HEAP_ERR_INVALID_ARGUMENT,
|
||||||
|
} heap_result_t;
|
||||||
|
|
||||||
|
typedef struct heap {
|
||||||
|
kern_handle_t heap_region;
|
||||||
|
/* amount of space requested from the heap by the user */
|
||||||
|
size_t heap_req_alloc;
|
||||||
|
/* amount of space requested from the system by the heap */
|
||||||
|
size_t heap_sys_alloc;
|
||||||
|
/* base address of the heap */
|
||||||
|
virt_addr_t heap_base;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
struct liballoc_major *l_memRoot;
|
||||||
|
struct liballoc_major *l_bestBet;
|
||||||
|
|
||||||
|
unsigned int l_pageSize;
|
||||||
|
unsigned int l_pageCount;
|
||||||
|
unsigned long long l_allocated;
|
||||||
|
unsigned long long l_inuse;
|
||||||
|
|
||||||
|
long long l_warningCount;
|
||||||
|
long long l_errorCount;
|
||||||
|
long long l_possibleOverruns;
|
||||||
|
} heap_liballoc;
|
||||||
|
};
|
||||||
|
} heap_t;
|
||||||
|
|
||||||
|
extern kern_status_t heap_init(heap_t *heap, size_t size);
|
||||||
|
extern kern_status_t heap_destroy(heap_t *heap);
|
||||||
|
|
||||||
|
extern void *heap_alloc(heap_t *heap, size_t sz);
|
||||||
|
extern void *heap_realloc(heap_t *heap, void *p, size_t sz);
|
||||||
|
extern void *heap_calloc(heap_t *heap, size_t num, size_t itemsz);
|
||||||
|
extern void heap_free(heap_t *heap, void *p);
|
||||||
|
|
||||||
|
extern void *heap_expand(heap_t *heap, size_t size);
|
||||||
|
|
||||||
|
#endif
|
||||||
834
lib/libc/malloc/liballoc.c
Normal file
834
lib/libc/malloc/liballoc.c
Normal file
@@ -0,0 +1,834 @@
|
|||||||
|
#include "liballoc.h"
|
||||||
|
|
||||||
|
/** Durand's Amazing Super Duper Memory functions. */
|
||||||
|
|
||||||
|
#define VERSION "1.1"
|
||||||
|
#define ALIGNMENT \
|
||||||
|
16ul // 4ul ///< This is the byte alignment
|
||||||
|
// that memory must be allocated on. IMPORTANT for GTK and other
|
||||||
|
// stuff.
|
||||||
|
|
||||||
|
#define ALIGN_TYPE char /// unsigned char[16] /// unsigned short
|
||||||
|
#define ALIGN_INFO \
|
||||||
|
sizeof(ALIGN_TYPE) * 16 ///< Alignment information is stored right
|
||||||
|
///< before the pointer. This is the number of
|
||||||
|
///< bytes of information stored there.
|
||||||
|
|
||||||
|
#define USE_CASE1
|
||||||
|
#define USE_CASE2
|
||||||
|
#define USE_CASE3
|
||||||
|
#define USE_CASE4
|
||||||
|
#define USE_CASE5
|
||||||
|
|
||||||
|
/** This macro will conveniently align our pointer upwards */
|
||||||
|
#define ALIGN(ptr) \
|
||||||
|
if (ALIGNMENT > 1) { \
|
||||||
|
uintptr_t diff; \
|
||||||
|
ptr = (void *)((uintptr_t)ptr + ALIGN_INFO); \
|
||||||
|
diff = (uintptr_t)ptr & (ALIGNMENT - 1); \
|
||||||
|
if (diff != 0) { \
|
||||||
|
diff = ALIGNMENT - diff; \
|
||||||
|
ptr = (void *)((uintptr_t)ptr + diff); \
|
||||||
|
} \
|
||||||
|
*((ALIGN_TYPE *)((uintptr_t)ptr - ALIGN_INFO)) \
|
||||||
|
= diff + ALIGN_INFO; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UNALIGN(ptr) \
|
||||||
|
if (ALIGNMENT > 1) { \
|
||||||
|
uintptr_t diff \
|
||||||
|
= *((ALIGN_TYPE *)((uintptr_t)ptr - ALIGN_INFO)); \
|
||||||
|
if (diff < (ALIGNMENT + ALIGN_INFO)) { \
|
||||||
|
ptr = (void *)((uintptr_t)ptr - diff); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LIBALLOC_MAGIC 0xc001c0de
|
||||||
|
#define LIBALLOC_DEAD 0xdeaddead
|
||||||
|
|
||||||
|
#if defined DEBUG || defined INFO
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define FLUSH() fflush(stdout)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** A structure found at the top of all system allocated
|
||||||
|
* memory blocks. It details the usage of the memory block.
|
||||||
|
*/
|
||||||
|
struct liballoc_major {
|
||||||
|
struct liballoc_major *prev; ///< Linked list information.
|
||||||
|
struct liballoc_major *next; ///< Linked list information.
|
||||||
|
unsigned int pages; ///< The number of pages in the block.
|
||||||
|
unsigned int size; ///< The number of pages in the block.
|
||||||
|
unsigned int usage; ///< The number of bytes used in the block.
|
||||||
|
struct liballoc_minor *first; ///< A pointer to the first allocated
|
||||||
|
///< memory in the block.
|
||||||
|
};
|
||||||
|
|
||||||
|
/** This is a structure found at the beginning of all
|
||||||
|
* sections in a major block which were allocated by a
|
||||||
|
* malloc, calloc, realloc call.
|
||||||
|
*/
|
||||||
|
struct liballoc_minor {
|
||||||
|
struct liballoc_minor *prev; ///< Linked list information.
|
||||||
|
struct liballoc_minor *next; ///< Linked list information.
|
||||||
|
struct liballoc_major *block; ///< The owning block. A pointer to the
|
||||||
|
///< major structure.
|
||||||
|
unsigned int magic; ///< A magic number to idenfity correctness.
|
||||||
|
unsigned int size; ///< The size of the memory allocated. Could be 1
|
||||||
|
///< byte or more.
|
||||||
|
unsigned int req_size; ///< The size of memory requested.
|
||||||
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static struct liballoc_major *l_memRoot
|
||||||
|
= NULL; ///< The root memory block acquired from the system.
|
||||||
|
static struct liballoc_major *l_bestBet
|
||||||
|
= NULL; ///< The major with the most free memory.
|
||||||
|
|
||||||
|
static unsigned int l_pageSize
|
||||||
|
= 4096; ///< The size of an individual page. Set up in liballoc_init.
|
||||||
|
static unsigned int l_pageCount = 16; ///< The number of pages to request per
|
||||||
|
///< chunk. Set up in liballoc_init.
|
||||||
|
static unsigned long long l_allocated
|
||||||
|
= 0; ///< Running total of allocated memory.
|
||||||
|
static unsigned long long l_inuse = 0; ///< Running total of used memory.
|
||||||
|
|
||||||
|
static long long l_warningCount = 0; ///< Number of warnings encountered
|
||||||
|
static long long l_errorCount = 0; ///< Number of actual errors
|
||||||
|
static long long l_possibleOverruns = 0; ///< Number of possible overruns
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// *********** HELPER FUNCTIONS *******************************
|
||||||
|
|
||||||
|
static void *liballoc_memset(void *s, int c, size_t n)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
((char *)s)[i] = c;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
static void *liballoc_memcpy(void *s1, const void *s2, size_t n)
|
||||||
|
{
|
||||||
|
char *cdest;
|
||||||
|
char *csrc;
|
||||||
|
unsigned int *ldest = (unsigned int *)s1;
|
||||||
|
unsigned int *lsrc = (unsigned int *)s2;
|
||||||
|
|
||||||
|
while (n >= sizeof(unsigned int)) {
|
||||||
|
*ldest++ = *lsrc++;
|
||||||
|
n -= sizeof(unsigned int);
|
||||||
|
}
|
||||||
|
|
||||||
|
cdest = (char *)ldest;
|
||||||
|
csrc = (char *)lsrc;
|
||||||
|
|
||||||
|
while (n > 0) {
|
||||||
|
*cdest++ = *csrc++;
|
||||||
|
n -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined DEBUG || defined INFO
|
||||||
|
static void liballoc_dump()
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
struct liballoc_major *maj = l_memRoot;
|
||||||
|
struct liballoc_minor *min = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
printf("liballoc: ------ Memory data ---------------\n");
|
||||||
|
printf("liballoc: System memory allocated: %i bytes\n", l_allocated);
|
||||||
|
printf("liballoc: Memory in used (malloc'ed): %i bytes\n", l_inuse);
|
||||||
|
printf("liballoc: Warning count: %i\n", l_warningCount);
|
||||||
|
printf("liballoc: Error count: %i\n", l_errorCount);
|
||||||
|
printf("liballoc: Possible overruns: %i\n", l_possibleOverruns);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
while (maj != NULL) {
|
||||||
|
printf("liballoc: %x: total = %i, used = %i\n",
|
||||||
|
maj,
|
||||||
|
maj->size,
|
||||||
|
maj->usage);
|
||||||
|
|
||||||
|
min = maj->first;
|
||||||
|
while (min != NULL) {
|
||||||
|
printf("liballoc: %x: %i bytes\n", min, min->size);
|
||||||
|
min = min->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
maj = maj->next;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FLUSH();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CTX(n) (heap->heap_liballoc.n)
|
||||||
|
|
||||||
|
// ***************************************************************
|
||||||
|
|
||||||
|
static struct liballoc_major *allocate_new_page(heap_t *heap, unsigned int size)
|
||||||
|
{
|
||||||
|
unsigned int st;
|
||||||
|
struct liballoc_major *maj;
|
||||||
|
|
||||||
|
// This is how much space is required.
|
||||||
|
st = size + sizeof(struct liballoc_major);
|
||||||
|
st += sizeof(struct liballoc_minor);
|
||||||
|
|
||||||
|
// Perfect amount of space?
|
||||||
|
if ((st % CTX(l_pageSize)) == 0)
|
||||||
|
st = st / (CTX(l_pageSize));
|
||||||
|
else
|
||||||
|
st = st / (CTX(l_pageSize)) + 1;
|
||||||
|
// No, add the buffer.
|
||||||
|
|
||||||
|
// Make sure it's >= the minimum size.
|
||||||
|
if (st < CTX(l_pageCount))
|
||||||
|
st = CTX(l_pageCount);
|
||||||
|
|
||||||
|
maj = (struct liballoc_major *)liballoc_alloc(heap, st);
|
||||||
|
|
||||||
|
if (maj == NULL) {
|
||||||
|
CTX(l_warningCount) += 1;
|
||||||
|
#if defined DEBUG || defined INFO
|
||||||
|
printf("liballoc: WARNING: liballoc_alloc( %i ) return NULL\n",
|
||||||
|
st);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
return NULL; // uh oh, we ran out of memory.
|
||||||
|
}
|
||||||
|
|
||||||
|
maj->prev = NULL;
|
||||||
|
maj->next = NULL;
|
||||||
|
maj->pages = st;
|
||||||
|
maj->size = st * CTX(l_pageSize);
|
||||||
|
maj->usage = sizeof(struct liballoc_major);
|
||||||
|
maj->first = NULL;
|
||||||
|
|
||||||
|
CTX(l_allocated) += maj->size;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("liballoc: Resource allocated %x of %i pages (%i bytes) for %i "
|
||||||
|
"size.\n",
|
||||||
|
maj,
|
||||||
|
st,
|
||||||
|
maj->size,
|
||||||
|
size);
|
||||||
|
|
||||||
|
printf("liballoc: Total memory usage = %i KB\n",
|
||||||
|
(int)((l_allocated / (1024))));
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return maj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *PREFIX(malloc)(heap_t *heap, size_t req_size)
|
||||||
|
{
|
||||||
|
int startedBet = 0;
|
||||||
|
unsigned long long bestSize = 0;
|
||||||
|
void *p = NULL;
|
||||||
|
uintptr_t diff;
|
||||||
|
struct liballoc_major *maj;
|
||||||
|
struct liballoc_minor *min;
|
||||||
|
struct liballoc_minor *new_min;
|
||||||
|
unsigned long size = req_size;
|
||||||
|
|
||||||
|
// For alignment, we adjust size so there's enough space to align.
|
||||||
|
if (ALIGNMENT > 1) {
|
||||||
|
size += ALIGNMENT + ALIGN_INFO;
|
||||||
|
}
|
||||||
|
// So, ideally, we really want an alignment of 0 or 1 in order
|
||||||
|
// to save space.
|
||||||
|
|
||||||
|
liballoc_lock(heap);
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
CTX(l_warningCount) += 1;
|
||||||
|
#if defined DEBUG || defined INFO
|
||||||
|
printf("liballoc: WARNING: alloc( 0 ) called from %x\n",
|
||||||
|
__builtin_return_address(0));
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
liballoc_unlock(heap);
|
||||||
|
return PREFIX(malloc)(heap, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CTX(l_memRoot) == NULL) {
|
||||||
|
#if defined DEBUG || defined INFO
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("liballoc: initialization of liballoc " VERSION "\n");
|
||||||
|
#endif
|
||||||
|
atexit(liballoc_dump);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// This is the first time we are being used.
|
||||||
|
CTX(l_memRoot) = allocate_new_page(heap, size);
|
||||||
|
if (CTX(l_memRoot) == NULL) {
|
||||||
|
liballoc_unlock(heap);
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("liballoc: initial l_memRoot initialization "
|
||||||
|
"failed\n",
|
||||||
|
p);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("liballoc: set up first memory major %x\n", l_memRoot);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("liballoc: %x PREFIX(malloc)( %i ): ",
|
||||||
|
__builtin_return_address(0),
|
||||||
|
size);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Now we need to bounce through every major and find enough space....
|
||||||
|
|
||||||
|
maj = CTX(l_memRoot);
|
||||||
|
startedBet = 0;
|
||||||
|
|
||||||
|
// Start at the best bet....
|
||||||
|
if (CTX(l_bestBet) != NULL) {
|
||||||
|
bestSize = CTX(l_bestBet)->size - CTX(l_bestBet)->usage;
|
||||||
|
|
||||||
|
if (bestSize > (size + sizeof(struct liballoc_minor))) {
|
||||||
|
maj = CTX(l_bestBet);
|
||||||
|
startedBet = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (maj != NULL) {
|
||||||
|
diff = maj->size - maj->usage;
|
||||||
|
// free memory in the block
|
||||||
|
|
||||||
|
if (bestSize < diff) {
|
||||||
|
// Hmm.. this one has more memory then our bestBet.
|
||||||
|
// Remember!
|
||||||
|
CTX(l_bestBet) = maj;
|
||||||
|
bestSize = diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_CASE1
|
||||||
|
|
||||||
|
// CASE 1: There is not enough space in this major block.
|
||||||
|
if (diff < (size + sizeof(struct liballoc_minor))) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("CASE 1: Insufficient space in block %x\n", maj);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Another major block next to this one?
|
||||||
|
if (maj->next != NULL) {
|
||||||
|
maj = maj->next; // Hop to that one.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startedBet == 1) // If we started at the best bet,
|
||||||
|
{ // let's start all over again.
|
||||||
|
maj = CTX(l_memRoot);
|
||||||
|
startedBet = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new major block next to this one and...
|
||||||
|
maj->next = allocate_new_page(
|
||||||
|
heap,
|
||||||
|
size); // next one will be okay.
|
||||||
|
if (maj->next == NULL)
|
||||||
|
break; // no more memory.
|
||||||
|
maj->next->prev = maj;
|
||||||
|
maj = maj->next;
|
||||||
|
|
||||||
|
// .. fall through to CASE 2 ..
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_CASE2
|
||||||
|
|
||||||
|
// CASE 2: It's a brand new block.
|
||||||
|
if (maj->first == NULL) {
|
||||||
|
maj->first
|
||||||
|
= (struct liballoc_minor
|
||||||
|
*)((uintptr_t)maj
|
||||||
|
+ sizeof(struct liballoc_major));
|
||||||
|
|
||||||
|
maj->first->magic = LIBALLOC_MAGIC;
|
||||||
|
maj->first->prev = NULL;
|
||||||
|
maj->first->next = NULL;
|
||||||
|
maj->first->block = maj;
|
||||||
|
maj->first->size = size;
|
||||||
|
maj->first->req_size = req_size;
|
||||||
|
maj->usage += size + sizeof(struct liballoc_minor);
|
||||||
|
|
||||||
|
CTX(l_inuse) += size;
|
||||||
|
|
||||||
|
p = (void *)((uintptr_t)(maj->first)
|
||||||
|
+ sizeof(struct liballoc_minor));
|
||||||
|
|
||||||
|
ALIGN(p);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("CASE 2: returning %x\n", p);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
liballoc_unlock(heap); // release the lock
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_CASE3
|
||||||
|
|
||||||
|
// CASE 3: Block in use and enough space at the start of the
|
||||||
|
// block.
|
||||||
|
diff = (uintptr_t)(maj->first);
|
||||||
|
diff -= (uintptr_t)maj;
|
||||||
|
diff -= sizeof(struct liballoc_major);
|
||||||
|
|
||||||
|
if (diff >= (size + sizeof(struct liballoc_minor))) {
|
||||||
|
// Yes, space in front. Squeeze in.
|
||||||
|
maj->first->prev
|
||||||
|
= (struct liballoc_minor
|
||||||
|
*)((uintptr_t)maj
|
||||||
|
+ sizeof(struct liballoc_major));
|
||||||
|
maj->first->prev->next = maj->first;
|
||||||
|
maj->first = maj->first->prev;
|
||||||
|
|
||||||
|
maj->first->magic = LIBALLOC_MAGIC;
|
||||||
|
maj->first->prev = NULL;
|
||||||
|
maj->first->block = maj;
|
||||||
|
maj->first->size = size;
|
||||||
|
maj->first->req_size = req_size;
|
||||||
|
maj->usage += size + sizeof(struct liballoc_minor);
|
||||||
|
|
||||||
|
CTX(l_inuse) += size;
|
||||||
|
|
||||||
|
p = (void *)((uintptr_t)(maj->first)
|
||||||
|
+ sizeof(struct liballoc_minor));
|
||||||
|
ALIGN(p);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("CASE 3: returning %x\n", p);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
liballoc_unlock(heap); // release the lock
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_CASE4
|
||||||
|
|
||||||
|
// CASE 4: There is enough space in this block. But is it
|
||||||
|
// contiguous?
|
||||||
|
min = maj->first;
|
||||||
|
|
||||||
|
// Looping within the block now...
|
||||||
|
while (min != NULL) {
|
||||||
|
// CASE 4.1: End of minors in a block. Space from last
|
||||||
|
// and end?
|
||||||
|
if (min->next == NULL) {
|
||||||
|
// the rest of this block is free... is it big
|
||||||
|
// enough?
|
||||||
|
diff = (uintptr_t)(maj) + maj->size;
|
||||||
|
diff -= (uintptr_t)min;
|
||||||
|
diff -= sizeof(struct liballoc_minor);
|
||||||
|
diff -= min->size;
|
||||||
|
// minus already existing usage..
|
||||||
|
|
||||||
|
if (diff
|
||||||
|
>= (size + sizeof(struct liballoc_minor))) {
|
||||||
|
// yay....
|
||||||
|
min->next
|
||||||
|
= (struct liballoc_minor
|
||||||
|
*)((uintptr_t)min
|
||||||
|
+ sizeof(
|
||||||
|
struct
|
||||||
|
liballoc_minor)
|
||||||
|
+ min->size);
|
||||||
|
min->next->prev = min;
|
||||||
|
min = min->next;
|
||||||
|
min->next = NULL;
|
||||||
|
min->magic = LIBALLOC_MAGIC;
|
||||||
|
min->block = maj;
|
||||||
|
min->size = size;
|
||||||
|
min->req_size = req_size;
|
||||||
|
maj->usage += size
|
||||||
|
+ sizeof(struct
|
||||||
|
liballoc_minor);
|
||||||
|
|
||||||
|
CTX(l_inuse) += size;
|
||||||
|
|
||||||
|
p = (void *)((uintptr_t)min
|
||||||
|
+ sizeof(struct
|
||||||
|
liballoc_minor));
|
||||||
|
ALIGN(p);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("CASE 4.1: returning %x\n", p);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
liballoc_unlock(
|
||||||
|
heap); // release the lock
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CASE 4.2: Is there space between two minors?
|
||||||
|
if (min->next != NULL) {
|
||||||
|
// is the difference between here and next big
|
||||||
|
// enough?
|
||||||
|
diff = (uintptr_t)(min->next);
|
||||||
|
diff -= (uintptr_t)min;
|
||||||
|
diff -= sizeof(struct liballoc_minor);
|
||||||
|
diff -= min->size;
|
||||||
|
// minus our existing usage.
|
||||||
|
|
||||||
|
if (diff
|
||||||
|
>= (size + sizeof(struct liballoc_minor))) {
|
||||||
|
// yay......
|
||||||
|
new_min = (struct liballoc_minor
|
||||||
|
*)((uintptr_t)min
|
||||||
|
+ sizeof(
|
||||||
|
struct
|
||||||
|
liballoc_minor)
|
||||||
|
+ min->size);
|
||||||
|
|
||||||
|
new_min->magic = LIBALLOC_MAGIC;
|
||||||
|
new_min->next = min->next;
|
||||||
|
new_min->prev = min;
|
||||||
|
new_min->size = size;
|
||||||
|
new_min->req_size = req_size;
|
||||||
|
new_min->block = maj;
|
||||||
|
min->next->prev = new_min;
|
||||||
|
min->next = new_min;
|
||||||
|
maj->usage += size
|
||||||
|
+ sizeof(struct
|
||||||
|
liballoc_minor);
|
||||||
|
|
||||||
|
CTX(l_inuse) += size;
|
||||||
|
|
||||||
|
p = (void *)((uintptr_t)new_min
|
||||||
|
+ sizeof(struct
|
||||||
|
liballoc_minor));
|
||||||
|
ALIGN(p);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("CASE 4.2: returning %x\n", p);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
liballoc_unlock(
|
||||||
|
heap); // release the lock
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
} // min->next != NULL
|
||||||
|
|
||||||
|
min = min->next;
|
||||||
|
} // while min != NULL ...
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_CASE5
|
||||||
|
|
||||||
|
// CASE 5: Block full! Ensure next block and loop.
|
||||||
|
if (maj->next == NULL) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("CASE 5: block full\n");
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (startedBet == 1) {
|
||||||
|
maj = CTX(l_memRoot);
|
||||||
|
startedBet = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we've run out. we need more...
|
||||||
|
maj->next = allocate_new_page(
|
||||||
|
heap,
|
||||||
|
size); // next one guaranteed to be okay
|
||||||
|
if (maj->next == NULL)
|
||||||
|
break; // uh oh, no more memory.....
|
||||||
|
maj->next->prev = maj;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
maj = maj->next;
|
||||||
|
} // while (maj != NULL)
|
||||||
|
|
||||||
|
liballoc_unlock(heap); // release the lock
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("All cases exhausted. No memory available.\n");
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
#if defined DEBUG || defined INFO
|
||||||
|
printf("liballoc: WARNING: PREFIX(malloc)( %i ) returning NULL.\n",
|
||||||
|
size);
|
||||||
|
liballoc_dump();
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PREFIX(free)(heap_t *heap, void *ptr)
|
||||||
|
{
|
||||||
|
struct liballoc_minor *min;
|
||||||
|
struct liballoc_major *maj;
|
||||||
|
|
||||||
|
if (ptr == NULL) {
|
||||||
|
CTX(l_warningCount) += 1;
|
||||||
|
#if defined DEBUG || defined INFO
|
||||||
|
printf("liballoc: WARNING: PREFIX(free)( NULL ) called from "
|
||||||
|
"%x\n",
|
||||||
|
__builtin_return_address(0));
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UNALIGN(ptr);
|
||||||
|
|
||||||
|
liballoc_lock(heap); // lockit
|
||||||
|
|
||||||
|
min = (struct liballoc_minor *)((uintptr_t)ptr
|
||||||
|
- sizeof(struct liballoc_minor));
|
||||||
|
|
||||||
|
if (min->magic != LIBALLOC_MAGIC) {
|
||||||
|
CTX(l_errorCount) += 1;
|
||||||
|
|
||||||
|
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
|
||||||
|
if (((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF))
|
||||||
|
|| ((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF))
|
||||||
|
|| ((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))) {
|
||||||
|
CTX(l_possibleOverruns) += 1;
|
||||||
|
#if defined DEBUG || defined INFO
|
||||||
|
printf("liballoc: ERROR: Possible 1-3 byte overrun for "
|
||||||
|
"magic %x != %x\n",
|
||||||
|
min->magic,
|
||||||
|
LIBALLOC_MAGIC);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min->magic == LIBALLOC_DEAD) {
|
||||||
|
#if defined DEBUG || defined INFO
|
||||||
|
printf("liballoc: ERROR: multiple PREFIX(free)() "
|
||||||
|
"attempt on %x from %x.\n",
|
||||||
|
ptr,
|
||||||
|
__builtin_return_address(0));
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#if defined DEBUG || defined INFO
|
||||||
|
printf("liballoc: ERROR: Bad PREFIX(free)( %x ) called "
|
||||||
|
"from %x\n",
|
||||||
|
ptr,
|
||||||
|
__builtin_return_address(0));
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// being lied to...
|
||||||
|
liballoc_unlock(heap); // release the lock
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("liballoc: %x PREFIX(free)( %x ): ",
|
||||||
|
__builtin_return_address(0),
|
||||||
|
ptr);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
maj = min->block;
|
||||||
|
|
||||||
|
CTX(l_inuse) -= min->size;
|
||||||
|
|
||||||
|
maj->usage -= (min->size + sizeof(struct liballoc_minor));
|
||||||
|
min->magic = LIBALLOC_DEAD; // No mojo.
|
||||||
|
|
||||||
|
if (min->next != NULL)
|
||||||
|
min->next->prev = min->prev;
|
||||||
|
if (min->prev != NULL)
|
||||||
|
min->prev->next = min->next;
|
||||||
|
|
||||||
|
if (min->prev == NULL)
|
||||||
|
maj->first = min->next;
|
||||||
|
// Might empty the block. This was the first
|
||||||
|
// minor.
|
||||||
|
|
||||||
|
// We need to clean up after the majors now....
|
||||||
|
|
||||||
|
if (maj->first == NULL) // Block completely unused.
|
||||||
|
{
|
||||||
|
if (CTX(l_memRoot) == maj)
|
||||||
|
CTX(l_memRoot) = maj->next;
|
||||||
|
if (CTX(l_bestBet) == maj)
|
||||||
|
CTX(l_bestBet) = NULL;
|
||||||
|
if (maj->prev != NULL)
|
||||||
|
maj->prev->next = maj->next;
|
||||||
|
if (maj->next != NULL)
|
||||||
|
maj->next->prev = maj->prev;
|
||||||
|
CTX(l_allocated) -= maj->size;
|
||||||
|
|
||||||
|
liballoc_free(heap, maj, maj->pages);
|
||||||
|
} else {
|
||||||
|
if (CTX(l_bestBet) != NULL) {
|
||||||
|
int bestSize
|
||||||
|
= CTX(l_bestBet)->size - CTX(l_bestBet)->usage;
|
||||||
|
int majSize = maj->size - maj->usage;
|
||||||
|
|
||||||
|
if (majSize > bestSize)
|
||||||
|
CTX(l_bestBet) = maj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("OK\n");
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
liballoc_unlock(heap); // release the lock
|
||||||
|
}
|
||||||
|
|
||||||
|
void *PREFIX(calloc)(heap_t *heap, size_t nobj, size_t size)
|
||||||
|
{
|
||||||
|
int real_size;
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
real_size = nobj * size;
|
||||||
|
|
||||||
|
p = PREFIX(malloc)(heap, real_size);
|
||||||
|
|
||||||
|
liballoc_memset(p, 0, real_size);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *PREFIX(realloc)(heap_t *heap, void *p, size_t size)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
struct liballoc_minor *min;
|
||||||
|
unsigned int real_size;
|
||||||
|
|
||||||
|
// Honour the case of size == 0 => free old and return NULL
|
||||||
|
if (size == 0) {
|
||||||
|
PREFIX(free)(heap, p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the case of a NULL pointer, return a simple malloc.
|
||||||
|
if (p == NULL)
|
||||||
|
return PREFIX(malloc)(heap, size);
|
||||||
|
|
||||||
|
// Unalign the pointer if required.
|
||||||
|
ptr = p;
|
||||||
|
UNALIGN(ptr);
|
||||||
|
|
||||||
|
liballoc_lock(heap); // lockit
|
||||||
|
|
||||||
|
min = (struct liballoc_minor *)((uintptr_t)ptr
|
||||||
|
- sizeof(struct liballoc_minor));
|
||||||
|
|
||||||
|
// Ensure it is a valid structure.
|
||||||
|
if (min->magic != LIBALLOC_MAGIC) {
|
||||||
|
CTX(l_errorCount) += 1;
|
||||||
|
|
||||||
|
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
|
||||||
|
if (((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF))
|
||||||
|
|| ((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF))
|
||||||
|
|| ((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))) {
|
||||||
|
CTX(l_possibleOverruns) += 1;
|
||||||
|
#if defined DEBUG || defined INFO
|
||||||
|
printf("liballoc: ERROR: Possible 1-3 byte overrun for "
|
||||||
|
"magic %x != %x\n",
|
||||||
|
min->magic,
|
||||||
|
LIBALLOC_MAGIC);
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min->magic == LIBALLOC_DEAD) {
|
||||||
|
#if defined DEBUG || defined INFO
|
||||||
|
printf("liballoc: ERROR: multiple PREFIX(free)() "
|
||||||
|
"attempt on %x from %x.\n",
|
||||||
|
ptr,
|
||||||
|
__builtin_return_address(0));
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#if defined DEBUG || defined INFO
|
||||||
|
printf("liballoc: ERROR: Bad PREFIX(free)( %x ) called "
|
||||||
|
"from %x\n",
|
||||||
|
ptr,
|
||||||
|
__builtin_return_address(0));
|
||||||
|
FLUSH();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// being lied to...
|
||||||
|
liballoc_unlock(heap); // release the lock
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Definitely a memory block.
|
||||||
|
|
||||||
|
real_size = min->req_size;
|
||||||
|
|
||||||
|
if (real_size >= size) {
|
||||||
|
min->req_size = size;
|
||||||
|
liballoc_unlock(heap);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
liballoc_unlock(heap);
|
||||||
|
|
||||||
|
// If we got here then we're reallocating to a block bigger than us.
|
||||||
|
ptr = PREFIX(malloc)(heap, size); // We need to allocate new memory
|
||||||
|
liballoc_memcpy(ptr, p, real_size);
|
||||||
|
PREFIX(free)(heap, p);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int liballoc_lock(heap_t *heap)
|
||||||
|
{
|
||||||
|
/* TODO */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int liballoc_unlock(heap_t *heap)
|
||||||
|
{
|
||||||
|
/* TODO */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *liballoc_alloc(heap_t *heap, size_t sz)
|
||||||
|
{
|
||||||
|
return heap_expand(heap, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
int liballoc_free(heap_t *heap, void *p, size_t sz)
|
||||||
|
{
|
||||||
|
/* TODO */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
76
lib/libc/malloc/liballoc.h
Normal file
76
lib/libc/malloc/liballoc.h
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#ifndef _LIBALLOC_H
|
||||||
|
#define _LIBALLOC_H
|
||||||
|
|
||||||
|
#include <heap/heap.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/** \defgroup ALLOCHOOKS liballoc hooks
|
||||||
|
*
|
||||||
|
* These are the OS specific functions which need to
|
||||||
|
* be implemented on any platform that the library
|
||||||
|
* is expected to work on.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @{ */
|
||||||
|
|
||||||
|
// If we are told to not define our own size_t, then we skip the define.
|
||||||
|
// #define _HAVE_UINTPTR_T
|
||||||
|
// typedef unsigned long uintptr_t;
|
||||||
|
|
||||||
|
// This lets you prefix malloc and friends
|
||||||
|
#define PREFIX(func) _lb##func
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** This function is supposed to lock the memory data structures. It
|
||||||
|
* could be as simple as disabling interrupts or acquiring a spinlock.
|
||||||
|
* It's up to you to decide.
|
||||||
|
*
|
||||||
|
* \return 0 if the lock was acquired successfully. Anything else is
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
|
extern int liballoc_lock(heap_t *);
|
||||||
|
|
||||||
|
/** This function unlocks what was previously locked by the liballoc_lock
|
||||||
|
* function. If it disabled interrupts, it enables interrupts. If it
|
||||||
|
* had acquiried a spinlock, it releases the spinlock. etc.
|
||||||
|
*
|
||||||
|
* \return 0 if the lock was successfully released.
|
||||||
|
*/
|
||||||
|
extern int liballoc_unlock(heap_t *);
|
||||||
|
|
||||||
|
/** This is the hook into the local system which allocates pages. It
|
||||||
|
* accepts an integer parameter which is the number of pages
|
||||||
|
* required. The page size was set up in the liballoc_init function.
|
||||||
|
*
|
||||||
|
* \return NULL if the pages were not allocated.
|
||||||
|
* \return A pointer to the allocated memory.
|
||||||
|
*/
|
||||||
|
extern void *liballoc_alloc(heap_t *, size_t);
|
||||||
|
|
||||||
|
/** This frees previously allocated memory. The void* parameter passed
|
||||||
|
* to the function is the exact same value returned from a previous
|
||||||
|
* liballoc_alloc call.
|
||||||
|
*
|
||||||
|
* The integer value is the number of pages to free.
|
||||||
|
*
|
||||||
|
* \return 0 if the memory was successfully freed.
|
||||||
|
*/
|
||||||
|
extern int liballoc_free(heap_t *, void *, size_t);
|
||||||
|
|
||||||
|
extern void *PREFIX(malloc)(heap_t *, size_t); ///< The standard function.
|
||||||
|
extern void *PREFIX(
|
||||||
|
realloc)(heap_t *, void *, size_t); ///< The standard function.
|
||||||
|
extern void *PREFIX(
|
||||||
|
calloc)(heap_t *, size_t, size_t); ///< The standard function.
|
||||||
|
extern void PREFIX(free)(heap_t *, void *); ///< The standard function.
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#endif
|
||||||
44
lib/libc/malloc/stdlib/malloc.c
Normal file
44
lib/libc/malloc/stdlib/malloc.c
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#include <heap/heap.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_GLOBAL_HEAP
|
||||||
|
static heap_t global_heap = HEAP_INIT;
|
||||||
|
|
||||||
|
void *malloc(size_t count)
|
||||||
|
{
|
||||||
|
return heap_alloc(&global_heap, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *calloc(size_t count, size_t size)
|
||||||
|
{
|
||||||
|
return heap_calloc(&global_heap, count, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *realloc(void *p, size_t count)
|
||||||
|
{
|
||||||
|
return heap_realloc(&global_heap, p, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void *p)
|
||||||
|
{
|
||||||
|
heap_free(&global_heap, p);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void *malloc(size_t count)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *calloc(size_t count, size_t size)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *realloc(void *p, size_t count)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void *p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
11
lib/libc/runtime/CMakeLists.txt
Normal file
11
lib/libc/runtime/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
file(GLOB runtime_sources
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/*.s)
|
||||||
|
set_property(SOURCE ${runtime_sources} PROPERTY LANGUAGE C)
|
||||||
|
|
||||||
|
rosetta_add_object_library(
|
||||||
|
NAME libc-runtime STATIC
|
||||||
|
SOURCES ${runtime_sources})
|
||||||
|
|
||||||
|
sysroot_add_object_library(
|
||||||
|
NAME libc-runtime
|
||||||
|
LIB_DIR /usr/lib)
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#ifndef ERRNO_H_
|
|
||||||
#define ERRNO_H_
|
|
||||||
|
|
||||||
#define EINVAL 1
|
|
||||||
#define ENOMEM 2
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#ifndef STDIO_H_
|
|
||||||
#define STDIO_H_
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern int snprintf(char *buffer, size_t count, const char *format, ...);
|
|
||||||
extern int vsnprintf(
|
|
||||||
char *buffer,
|
|
||||||
size_t count,
|
|
||||||
const char *format,
|
|
||||||
va_list va);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#ifndef STRING_H_
|
|
||||||
#define STRING_H_
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
extern size_t strlen(const char *s);
|
|
||||||
|
|
||||||
extern int strcmp(const char *s1, const char *s2);
|
|
||||||
extern int strncmp(const char *s1, const char *s2, unsigned long n);
|
|
||||||
|
|
||||||
extern void *memset(void *str, int c, size_t n);
|
|
||||||
extern void *memcpy(void *dst, const void *src, size_t len);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef UNISTD_H_
|
|
||||||
#define UNISTD_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
extern void *sbrk(intptr_t increment);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
|||||||
void abort(void)
|
|
||||||
{
|
|
||||||
/* TODO */
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,637 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2023 Doug Lea
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
Default header file for malloc-2.8.x
|
|
||||||
Re-licensed 25 Sep 2023 with MIT-0 replacing obsolete CC0
|
|
||||||
See https://opensource.org/license/mit-0/
|
|
||||||
|
|
||||||
This header is for ANSI C/C++ only. You can set any of
|
|
||||||
the following #defines before including:
|
|
||||||
|
|
||||||
* If USE_DL_PREFIX is defined, it is assumed that malloc.c
|
|
||||||
was also compiled with this option, so all routines
|
|
||||||
have names starting with "dl".
|
|
||||||
|
|
||||||
* If HAVE_USR_INCLUDE_MALLOC_H is defined, it is assumed that this
|
|
||||||
file will be #included AFTER <malloc.h>. This is needed only if
|
|
||||||
your system defines a struct mallinfo that is incompatible with the
|
|
||||||
standard one declared here. Otherwise, you can include this file
|
|
||||||
INSTEAD of your system system <malloc.h>. At least on ANSI, all
|
|
||||||
declarations should be compatible with system versions
|
|
||||||
|
|
||||||
* If MSPACES is defined, declarations for mspace versions are included.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MALLOC_280_H
|
|
||||||
#define MALLOC_280_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stddef.h> /* for size_t */
|
|
||||||
|
|
||||||
#ifndef ONLY_MSPACES
|
|
||||||
#define ONLY_MSPACES 0 /* define to a value */
|
|
||||||
#elif ONLY_MSPACES != 0
|
|
||||||
#define ONLY_MSPACES 1
|
|
||||||
#endif /* ONLY_MSPACES */
|
|
||||||
#ifndef NO_MALLINFO
|
|
||||||
#define NO_MALLINFO 0
|
|
||||||
#endif /* NO_MALLINFO */
|
|
||||||
|
|
||||||
#ifndef MSPACES
|
|
||||||
#if ONLY_MSPACES
|
|
||||||
#define MSPACES 1
|
|
||||||
#else /* ONLY_MSPACES */
|
|
||||||
#define MSPACES 0
|
|
||||||
#endif /* ONLY_MSPACES */
|
|
||||||
#endif /* MSPACES */
|
|
||||||
|
|
||||||
#if !ONLY_MSPACES
|
|
||||||
|
|
||||||
#ifndef USE_DL_PREFIX
|
|
||||||
#define dlcalloc calloc
|
|
||||||
#define dlfree free
|
|
||||||
#define dlmalloc malloc
|
|
||||||
#define dlmemalign memalign
|
|
||||||
#define dlposix_memalign posix_memalign
|
|
||||||
#define dlrealloc realloc
|
|
||||||
#define dlvalloc valloc
|
|
||||||
#define dlpvalloc pvalloc
|
|
||||||
#define dlmallinfo mallinfo
|
|
||||||
#define dlmallopt mallopt
|
|
||||||
#define dlmalloc_trim malloc_trim
|
|
||||||
#define dlmalloc_stats malloc_stats
|
|
||||||
#define dlmalloc_usable_size malloc_usable_size
|
|
||||||
#define dlmalloc_footprint malloc_footprint
|
|
||||||
#define dlmalloc_max_footprint malloc_max_footprint
|
|
||||||
#define dlmalloc_footprint_limit malloc_footprint_limit
|
|
||||||
#define dlmalloc_set_footprint_limit malloc_set_footprint_limit
|
|
||||||
#define dlmalloc_inspect_all malloc_inspect_all
|
|
||||||
#define dlindependent_calloc independent_calloc
|
|
||||||
#define dlindependent_comalloc independent_comalloc
|
|
||||||
#define dlbulk_free bulk_free
|
|
||||||
#endif /* USE_DL_PREFIX */
|
|
||||||
|
|
||||||
#if !NO_MALLINFO
|
|
||||||
#ifndef HAVE_USR_INCLUDE_MALLOC_H
|
|
||||||
#ifndef _MALLOC_H
|
|
||||||
#ifndef MALLINFO_FIELD_TYPE
|
|
||||||
#define MALLINFO_FIELD_TYPE size_t
|
|
||||||
#endif /* MALLINFO_FIELD_TYPE */
|
|
||||||
#ifndef STRUCT_MALLINFO_DECLARED
|
|
||||||
#define STRUCT_MALLINFO_DECLARED 1
|
|
||||||
struct mallinfo {
|
|
||||||
MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */
|
|
||||||
MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */
|
|
||||||
MALLINFO_FIELD_TYPE smblks; /* always 0 */
|
|
||||||
MALLINFO_FIELD_TYPE hblks; /* always 0 */
|
|
||||||
MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */
|
|
||||||
MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */
|
|
||||||
MALLINFO_FIELD_TYPE fsmblks; /* always 0 */
|
|
||||||
MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
|
|
||||||
MALLINFO_FIELD_TYPE fordblks; /* total free space */
|
|
||||||
MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
|
|
||||||
};
|
|
||||||
#endif /* STRUCT_MALLINFO_DECLARED */
|
|
||||||
#endif /* _MALLOC_H */
|
|
||||||
#endif /* HAVE_USR_INCLUDE_MALLOC_H */
|
|
||||||
#endif /* !NO_MALLINFO */
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc(size_t n)
|
|
||||||
Returns a pointer to a newly allocated chunk of at least n bytes, or
|
|
||||||
null if no space is available, in which case errno is set to ENOMEM
|
|
||||||
on ANSI C systems.
|
|
||||||
|
|
||||||
If n is zero, malloc returns a minimum-sized chunk. (The minimum
|
|
||||||
size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
|
|
||||||
systems.) Note that size_t is an unsigned type, so calls with
|
|
||||||
arguments that would be negative if signed are interpreted as
|
|
||||||
requests for huge amounts of space, which will often fail. The
|
|
||||||
maximum supported value of n differs across systems, but is in all
|
|
||||||
cases less than the maximum representable value of a size_t.
|
|
||||||
*/
|
|
||||||
void* dlmalloc(size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
free(void* p)
|
|
||||||
Releases the chunk of memory pointed to by p, that had been previously
|
|
||||||
allocated using malloc or a related routine such as realloc.
|
|
||||||
It has no effect if p is null. If p was not malloced or already
|
|
||||||
freed, free(p) will by default cuase the current program to abort.
|
|
||||||
*/
|
|
||||||
void dlfree(void*);
|
|
||||||
|
|
||||||
/*
|
|
||||||
calloc(size_t n_elements, size_t element_size);
|
|
||||||
Returns a pointer to n_elements * element_size bytes, with all locations
|
|
||||||
set to zero.
|
|
||||||
*/
|
|
||||||
void* dlcalloc(size_t, size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
realloc(void* p, size_t n)
|
|
||||||
Returns a pointer to a chunk of size n that contains the same data
|
|
||||||
as does chunk p up to the minimum of (n, p's size) bytes, or null
|
|
||||||
if no space is available.
|
|
||||||
|
|
||||||
The returned pointer may or may not be the same as p. The algorithm
|
|
||||||
prefers extending p in most cases when possible, otherwise it
|
|
||||||
employs the equivalent of a malloc-copy-free sequence.
|
|
||||||
|
|
||||||
If p is null, realloc is equivalent to malloc.
|
|
||||||
|
|
||||||
If space is not available, realloc returns null, errno is set (if on
|
|
||||||
ANSI) and p is NOT freed.
|
|
||||||
|
|
||||||
if n is for fewer bytes than already held by p, the newly unused
|
|
||||||
space is lopped off and freed if possible. realloc with a size
|
|
||||||
argument of zero (re)allocates a minimum-sized chunk.
|
|
||||||
|
|
||||||
The old unix realloc convention of allowing the last-free'd chunk
|
|
||||||
to be used as an argument to realloc is not supported.
|
|
||||||
*/
|
|
||||||
void* dlrealloc(void*, size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
realloc_in_place(void* p, size_t n)
|
|
||||||
Resizes the space allocated for p to size n, only if this can be
|
|
||||||
done without moving p (i.e., only if there is adjacent space
|
|
||||||
available if n is greater than p's current allocated size, or n is
|
|
||||||
less than or equal to p's size). This may be used instead of plain
|
|
||||||
realloc if an alternative allocation strategy is needed upon failure
|
|
||||||
to expand space; for example, reallocation of a buffer that must be
|
|
||||||
memory-aligned or cleared. You can use realloc_in_place to trigger
|
|
||||||
these alternatives only when needed.
|
|
||||||
|
|
||||||
Returns p if successful; otherwise null.
|
|
||||||
*/
|
|
||||||
void* dlrealloc_in_place(void*, size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
memalign(size_t alignment, size_t n);
|
|
||||||
Returns a pointer to a newly allocated chunk of n bytes, aligned
|
|
||||||
in accord with the alignment argument.
|
|
||||||
|
|
||||||
The alignment argument should be a power of two. If the argument is
|
|
||||||
not a power of two, the nearest greater power is used.
|
|
||||||
8-byte alignment is guaranteed by normal malloc calls, so don't
|
|
||||||
bother calling memalign with an argument of 8 or less.
|
|
||||||
|
|
||||||
Overreliance on memalign is a sure way to fragment space.
|
|
||||||
*/
|
|
||||||
void* dlmemalign(size_t, size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
int posix_memalign(void** pp, size_t alignment, size_t n);
|
|
||||||
Allocates a chunk of n bytes, aligned in accord with the alignment
|
|
||||||
argument. Differs from memalign only in that it (1) assigns the
|
|
||||||
allocated memory to *pp rather than returning it, (2) fails and
|
|
||||||
returns EINVAL if the alignment is not a power of two (3) fails and
|
|
||||||
returns ENOMEM if memory cannot be allocated.
|
|
||||||
*/
|
|
||||||
int dlposix_memalign(void**, size_t, size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
valloc(size_t n);
|
|
||||||
Equivalent to memalign(pagesize, n), where pagesize is the page
|
|
||||||
size of the system. If the pagesize is unknown, 4096 is used.
|
|
||||||
*/
|
|
||||||
void* dlvalloc(size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
mallopt(int parameter_number, int parameter_value)
|
|
||||||
Sets tunable parameters The format is to provide a
|
|
||||||
(parameter-number, parameter-value) pair. mallopt then sets the
|
|
||||||
corresponding parameter to the argument value if it can (i.e., so
|
|
||||||
long as the value is meaningful), and returns 1 if successful else
|
|
||||||
0. SVID/XPG/ANSI defines four standard param numbers for mallopt,
|
|
||||||
normally defined in malloc.h. None of these are use in this malloc,
|
|
||||||
so setting them has no effect. But this malloc also supports other
|
|
||||||
options in mallopt:
|
|
||||||
|
|
||||||
Symbol param # default allowed param values
|
|
||||||
M_TRIM_THRESHOLD -1 2*1024*1024 any (-1U disables trimming)
|
|
||||||
M_GRANULARITY -2 page size any power of 2 >= page size
|
|
||||||
M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support)
|
|
||||||
*/
|
|
||||||
int dlmallopt(int, int);
|
|
||||||
|
|
||||||
#define M_TRIM_THRESHOLD (-1)
|
|
||||||
#define M_GRANULARITY (-2)
|
|
||||||
#define M_MMAP_THRESHOLD (-3)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_footprint();
|
|
||||||
Returns the number of bytes obtained from the system. The total
|
|
||||||
number of bytes allocated by malloc, realloc etc., is less than this
|
|
||||||
value. Unlike mallinfo, this function returns only a precomputed
|
|
||||||
result, so can be called frequently to monitor memory consumption.
|
|
||||||
Even if locks are otherwise defined, this function does not use them,
|
|
||||||
so results might not be up to date.
|
|
||||||
*/
|
|
||||||
size_t dlmalloc_footprint(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_max_footprint();
|
|
||||||
Returns the maximum number of bytes obtained from the system. This
|
|
||||||
value will be greater than current footprint if deallocated space
|
|
||||||
has been reclaimed by the system. The peak number of bytes allocated
|
|
||||||
by malloc, realloc etc., is less than this value. Unlike mallinfo,
|
|
||||||
this function returns only a precomputed result, so can be called
|
|
||||||
frequently to monitor memory consumption. Even if locks are
|
|
||||||
otherwise defined, this function does not use them, so results might
|
|
||||||
not be up to date.
|
|
||||||
*/
|
|
||||||
size_t dlmalloc_max_footprint(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_footprint_limit();
|
|
||||||
Returns the number of bytes that the heap is allowed to obtain from
|
|
||||||
the system, returning the last value returned by
|
|
||||||
malloc_set_footprint_limit, or the maximum size_t value if
|
|
||||||
never set. The returned value reflects a permission. There is no
|
|
||||||
guarantee that this number of bytes can actually be obtained from
|
|
||||||
the system.
|
|
||||||
*/
|
|
||||||
size_t dlmalloc_footprint_limit(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_set_footprint_limit();
|
|
||||||
Sets the maximum number of bytes to obtain from the system, causing
|
|
||||||
failure returns from malloc and related functions upon attempts to
|
|
||||||
exceed this value. The argument value may be subject to page
|
|
||||||
rounding to an enforceable limit; this actual value is returned.
|
|
||||||
Using an argument of the maximum possible size_t effectively
|
|
||||||
disables checks. If the argument is less than or equal to the
|
|
||||||
current malloc_footprint, then all future allocations that require
|
|
||||||
additional system memory will fail. However, invocation cannot
|
|
||||||
retroactively deallocate existing used memory.
|
|
||||||
*/
|
|
||||||
size_t dlmalloc_set_footprint_limit(size_t bytes);
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_inspect_all(void(*handler)(void *start,
|
|
||||||
void *end,
|
|
||||||
size_t used_bytes,
|
|
||||||
void* callback_arg),
|
|
||||||
void* arg);
|
|
||||||
Traverses the heap and calls the given handler for each managed
|
|
||||||
region, skipping all bytes that are (or may be) used for bookkeeping
|
|
||||||
purposes. Traversal does not include include chunks that have been
|
|
||||||
directly memory mapped. Each reported region begins at the start
|
|
||||||
address, and continues up to but not including the end address. The
|
|
||||||
first used_bytes of the region contain allocated data. If
|
|
||||||
used_bytes is zero, the region is unallocated. The handler is
|
|
||||||
invoked with the given callback argument. If locks are defined, they
|
|
||||||
are held during the entire traversal. It is a bad idea to invoke
|
|
||||||
other malloc functions from within the handler.
|
|
||||||
|
|
||||||
For example, to count the number of in-use chunks with size greater
|
|
||||||
than 1000, you could write:
|
|
||||||
static int count = 0;
|
|
||||||
void count_chunks(void* start, void* end, size_t used, void* arg) {
|
|
||||||
if (used >= 1000) ++count;
|
|
||||||
}
|
|
||||||
then:
|
|
||||||
malloc_inspect_all(count_chunks, NULL);
|
|
||||||
|
|
||||||
malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined.
|
|
||||||
*/
|
|
||||||
void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),
|
|
||||||
void* arg);
|
|
||||||
|
|
||||||
#if !NO_MALLINFO
|
|
||||||
/*
|
|
||||||
mallinfo()
|
|
||||||
Returns (by copy) a struct containing various summary statistics:
|
|
||||||
|
|
||||||
arena: current total non-mmapped bytes allocated from system
|
|
||||||
ordblks: the number of free chunks
|
|
||||||
smblks: always zero.
|
|
||||||
hblks: current number of mmapped regions
|
|
||||||
hblkhd: total bytes held in mmapped regions
|
|
||||||
usmblks: the maximum total allocated space. This will be greater
|
|
||||||
than current total if trimming has occurred.
|
|
||||||
fsmblks: always zero
|
|
||||||
uordblks: current total allocated space (normal or mmapped)
|
|
||||||
fordblks: total free space
|
|
||||||
keepcost: the maximum number of bytes that could ideally be released
|
|
||||||
back to system via malloc_trim. ("ideally" means that
|
|
||||||
it ignores page restrictions etc.)
|
|
||||||
|
|
||||||
Because these fields are ints, but internal bookkeeping may
|
|
||||||
be kept as longs, the reported values may wrap around zero and
|
|
||||||
thus be inaccurate.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct mallinfo dlmallinfo(void);
|
|
||||||
#endif /* NO_MALLINFO */
|
|
||||||
|
|
||||||
/*
|
|
||||||
independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
|
|
||||||
|
|
||||||
independent_calloc is similar to calloc, but instead of returning a
|
|
||||||
single cleared space, it returns an array of pointers to n_elements
|
|
||||||
independent elements that can hold contents of size elem_size, each
|
|
||||||
of which starts out cleared, and can be independently freed,
|
|
||||||
realloc'ed etc. The elements are guaranteed to be adjacently
|
|
||||||
allocated (this is not guaranteed to occur with multiple callocs or
|
|
||||||
mallocs), which may also improve cache locality in some
|
|
||||||
applications.
|
|
||||||
|
|
||||||
The "chunks" argument is optional (i.e., may be null, which is
|
|
||||||
probably the most typical usage). If it is null, the returned array
|
|
||||||
is itself dynamically allocated and should also be freed when it is
|
|
||||||
no longer needed. Otherwise, the chunks array must be of at least
|
|
||||||
n_elements in length. It is filled in with the pointers to the
|
|
||||||
chunks.
|
|
||||||
|
|
||||||
In either case, independent_calloc returns this pointer array, or
|
|
||||||
null if the allocation failed. If n_elements is zero and "chunks"
|
|
||||||
is null, it returns a chunk representing an array with zero elements
|
|
||||||
(which should be freed if not wanted).
|
|
||||||
|
|
||||||
Each element must be freed when it is no longer needed. This can be
|
|
||||||
done all at once using bulk_free.
|
|
||||||
|
|
||||||
independent_calloc simplifies and speeds up implementations of many
|
|
||||||
kinds of pools. It may also be useful when constructing large data
|
|
||||||
structures that initially have a fixed number of fixed-sized nodes,
|
|
||||||
but the number is not known at compile time, and some of the nodes
|
|
||||||
may later need to be freed. For example:
|
|
||||||
|
|
||||||
struct Node { int item; struct Node* next; };
|
|
||||||
|
|
||||||
struct Node* build_list() {
|
|
||||||
struct Node** pool;
|
|
||||||
int n = read_number_of_nodes_needed();
|
|
||||||
if (n <= 0) return 0;
|
|
||||||
pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
|
|
||||||
if (pool == 0) die();
|
|
||||||
// organize into a linked list...
|
|
||||||
struct Node* first = pool[0];
|
|
||||||
for (i = 0; i < n-1; ++i)
|
|
||||||
pool[i]->next = pool[i+1];
|
|
||||||
free(pool); // Can now free the array (or not, if it is needed later)
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
void** dlindependent_calloc(size_t, size_t, void**);
|
|
||||||
|
|
||||||
/*
|
|
||||||
independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
|
|
||||||
|
|
||||||
independent_comalloc allocates, all at once, a set of n_elements
|
|
||||||
chunks with sizes indicated in the "sizes" array. It returns
|
|
||||||
an array of pointers to these elements, each of which can be
|
|
||||||
independently freed, realloc'ed etc. The elements are guaranteed to
|
|
||||||
be adjacently allocated (this is not guaranteed to occur with
|
|
||||||
multiple callocs or mallocs), which may also improve cache locality
|
|
||||||
in some applications.
|
|
||||||
|
|
||||||
The "chunks" argument is optional (i.e., may be null). If it is null
|
|
||||||
the returned array is itself dynamically allocated and should also
|
|
||||||
be freed when it is no longer needed. Otherwise, the chunks array
|
|
||||||
must be of at least n_elements in length. It is filled in with the
|
|
||||||
pointers to the chunks.
|
|
||||||
|
|
||||||
In either case, independent_comalloc returns this pointer array, or
|
|
||||||
null if the allocation failed. If n_elements is zero and chunks is
|
|
||||||
null, it returns a chunk representing an array with zero elements
|
|
||||||
(which should be freed if not wanted).
|
|
||||||
|
|
||||||
Each element must be freed when it is no longer needed. This can be
|
|
||||||
done all at once using bulk_free.
|
|
||||||
|
|
||||||
independent_comallac differs from independent_calloc in that each
|
|
||||||
element may have a different size, and also that it does not
|
|
||||||
automatically clear elements.
|
|
||||||
|
|
||||||
independent_comalloc can be used to speed up allocation in cases
|
|
||||||
where several structs or objects must always be allocated at the
|
|
||||||
same time. For example:
|
|
||||||
|
|
||||||
struct Head { ... }
|
|
||||||
struct Foot { ... }
|
|
||||||
|
|
||||||
void send_message(char* msg) {
|
|
||||||
int msglen = strlen(msg);
|
|
||||||
size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
|
|
||||||
void* chunks[3];
|
|
||||||
if (independent_comalloc(3, sizes, chunks) == 0)
|
|
||||||
die();
|
|
||||||
struct Head* head = (struct Head*)(chunks[0]);
|
|
||||||
char* body = (char*)(chunks[1]);
|
|
||||||
struct Foot* foot = (struct Foot*)(chunks[2]);
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
In general though, independent_comalloc is worth using only for
|
|
||||||
larger values of n_elements. For small values, you probably won't
|
|
||||||
detect enough difference from series of malloc calls to bother.
|
|
||||||
|
|
||||||
Overuse of independent_comalloc can increase overall memory usage,
|
|
||||||
since it cannot reuse existing noncontiguous small chunks that
|
|
||||||
might be available for some of the elements.
|
|
||||||
*/
|
|
||||||
void** dlindependent_comalloc(size_t, size_t*, void**);
|
|
||||||
|
|
||||||
/*
|
|
||||||
bulk_free(void* array[], size_t n_elements)
|
|
||||||
Frees and clears (sets to null) each non-null pointer in the given
|
|
||||||
array. This is likely to be faster than freeing them one-by-one.
|
|
||||||
If footers are used, pointers that have been allocated in different
|
|
||||||
mspaces are not freed or cleared, and the count of all such pointers
|
|
||||||
is returned. For large arrays of pointers with poor locality, it
|
|
||||||
may be worthwhile to sort this array before calling bulk_free.
|
|
||||||
*/
|
|
||||||
size_t dlbulk_free(void**, size_t n_elements);
|
|
||||||
|
|
||||||
/*
|
|
||||||
pvalloc(size_t n);
|
|
||||||
Equivalent to valloc(minimum-page-that-holds(n)), that is,
|
|
||||||
round up n to nearest pagesize.
|
|
||||||
*/
|
|
||||||
void* dlpvalloc(size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_trim(size_t pad);
|
|
||||||
|
|
||||||
If possible, gives memory back to the system (via negative arguments
|
|
||||||
to sbrk) if there is unused memory at the `high' end of the malloc
|
|
||||||
pool or in unused MMAP segments. You can call this after freeing
|
|
||||||
large blocks of memory to potentially reduce the system-level memory
|
|
||||||
requirements of a program. However, it cannot guarantee to reduce
|
|
||||||
memory. Under some allocation patterns, some large free blocks of
|
|
||||||
memory will be locked between two used chunks, so they cannot be
|
|
||||||
given back to the system.
|
|
||||||
|
|
||||||
The `pad' argument to malloc_trim represents the amount of free
|
|
||||||
trailing space to leave untrimmed. If this argument is zero, only
|
|
||||||
the minimum amount of memory to maintain internal data structures
|
|
||||||
will be left. Non-zero arguments can be supplied to maintain enough
|
|
||||||
trailing space to service future expected allocations without having
|
|
||||||
to re-obtain memory from the system.
|
|
||||||
|
|
||||||
Malloc_trim returns 1 if it actually released any memory, else 0.
|
|
||||||
*/
|
|
||||||
int dlmalloc_trim(size_t);
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_stats();
|
|
||||||
Prints on stderr the amount of space obtained from the system (both
|
|
||||||
via sbrk and mmap), the maximum amount (which may be more than
|
|
||||||
current if malloc_trim and/or munmap got called), and the current
|
|
||||||
number of bytes allocated via malloc (or realloc, etc) but not yet
|
|
||||||
freed. Note that this is the number of bytes allocated, not the
|
|
||||||
number requested. It will be larger than the number requested
|
|
||||||
because of alignment and bookkeeping overhead. Because it includes
|
|
||||||
alignment wastage as being in use, this figure may be greater than
|
|
||||||
zero even when no user-level chunks are allocated.
|
|
||||||
|
|
||||||
The reported current and maximum system memory can be inaccurate if
|
|
||||||
a program makes other calls to system memory allocation functions
|
|
||||||
(normally sbrk) outside of malloc.
|
|
||||||
|
|
||||||
malloc_stats prints only the most commonly interesting statistics.
|
|
||||||
More information can be obtained by calling mallinfo.
|
|
||||||
|
|
||||||
malloc_stats is not compiled if NO_MALLOC_STATS is defined.
|
|
||||||
*/
|
|
||||||
void dlmalloc_stats(void);
|
|
||||||
|
|
||||||
#endif /* !ONLY_MSPACES */
|
|
||||||
|
|
||||||
/*
|
|
||||||
malloc_usable_size(void* p);
|
|
||||||
|
|
||||||
Returns the number of bytes you can actually use in
|
|
||||||
an allocated chunk, which may be more than you requested (although
|
|
||||||
often not) due to alignment and minimum size constraints.
|
|
||||||
You can use this many bytes without worrying about
|
|
||||||
overwriting other allocated objects. This is not a particularly great
|
|
||||||
programming practice. malloc_usable_size can be more useful in
|
|
||||||
debugging and assertions, for example:
|
|
||||||
|
|
||||||
p = malloc(n);
|
|
||||||
assert(malloc_usable_size(p) >= 256);
|
|
||||||
*/
|
|
||||||
size_t dlmalloc_usable_size(const void*);
|
|
||||||
|
|
||||||
#if MSPACES
|
|
||||||
|
|
||||||
/*
|
|
||||||
mspace is an opaque type representing an independent
|
|
||||||
region of space that supports mspace_malloc, etc.
|
|
||||||
*/
|
|
||||||
typedef void* mspace;
|
|
||||||
|
|
||||||
/*
|
|
||||||
create_mspace creates and returns a new independent space with the
|
|
||||||
given initial capacity, or, if 0, the default granularity size. It
|
|
||||||
returns null if there is no system memory available to create the
|
|
||||||
space. If argument locked is non-zero, the space uses a separate
|
|
||||||
lock to control access. The capacity of the space will grow
|
|
||||||
dynamically as needed to service mspace_malloc requests. You can
|
|
||||||
control the sizes of incremental increases of this space by
|
|
||||||
compiling with a different DEFAULT_GRANULARITY or dynamically
|
|
||||||
setting with mallopt(M_GRANULARITY, value).
|
|
||||||
*/
|
|
||||||
mspace create_mspace(size_t capacity, int locked);
|
|
||||||
|
|
||||||
/*
|
|
||||||
destroy_mspace destroys the given space, and attempts to return all
|
|
||||||
of its memory back to the system, returning the total number of
|
|
||||||
bytes freed. After destruction, the results of access to all memory
|
|
||||||
used by the space become undefined.
|
|
||||||
*/
|
|
||||||
size_t destroy_mspace(mspace msp);
|
|
||||||
|
|
||||||
/*
|
|
||||||
create_mspace_with_base uses the memory supplied as the initial base
|
|
||||||
of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
|
|
||||||
space is used for bookkeeping, so the capacity must be at least this
|
|
||||||
large. (Otherwise 0 is returned.) When this initial space is
|
|
||||||
exhausted, additional memory will be obtained from the system.
|
|
||||||
Destroying this space will deallocate all additionally allocated
|
|
||||||
space (if possible) but not the initial base.
|
|
||||||
*/
|
|
||||||
mspace create_mspace_with_base(void* base, size_t capacity, int locked);
|
|
||||||
|
|
||||||
/*
|
|
||||||
mspace_track_large_chunks controls whether requests for large chunks
|
|
||||||
are allocated in their own untracked mmapped regions, separate from
|
|
||||||
others in this mspace. By default large chunks are not tracked,
|
|
||||||
which reduces fragmentation. However, such chunks are not
|
|
||||||
necessarily released to the system upon destroy_mspace. Enabling
|
|
||||||
tracking by setting to true may increase fragmentation, but avoids
|
|
||||||
leakage when relying on destroy_mspace to release all memory
|
|
||||||
allocated using this space. The function returns the previous
|
|
||||||
setting.
|
|
||||||
*/
|
|
||||||
int mspace_track_large_chunks(mspace msp, int enable);
|
|
||||||
|
|
||||||
#if !NO_MALLINFO
|
|
||||||
/*
|
|
||||||
mspace_mallinfo behaves as mallinfo, but reports properties of
|
|
||||||
the given space.
|
|
||||||
*/
|
|
||||||
struct mallinfo mspace_mallinfo(mspace msp);
|
|
||||||
#endif /* NO_MALLINFO */
|
|
||||||
|
|
||||||
/*
|
|
||||||
An alias for mallopt.
|
|
||||||
*/
|
|
||||||
int mspace_mallopt(int, int);
|
|
||||||
|
|
||||||
/*
|
|
||||||
The following operate identically to their malloc counterparts
|
|
||||||
but operate only for the given mspace argument
|
|
||||||
*/
|
|
||||||
void* mspace_malloc(mspace msp, size_t bytes);
|
|
||||||
void mspace_free(mspace msp, void* mem);
|
|
||||||
void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
|
|
||||||
void* mspace_realloc(mspace msp, void* mem, size_t newsize);
|
|
||||||
void* mspace_realloc_in_place(mspace msp, void* mem, size_t newsize);
|
|
||||||
void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
|
|
||||||
void** mspace_independent_calloc(mspace msp, size_t n_elements,
|
|
||||||
size_t elem_size, void* chunks[]);
|
|
||||||
void** mspace_independent_comalloc(mspace msp, size_t n_elements,
|
|
||||||
size_t sizes[], void* chunks[]);
|
|
||||||
size_t mspace_bulk_free(mspace msp, void**, size_t n_elements);
|
|
||||||
size_t mspace_usable_size(const void* mem);
|
|
||||||
void mspace_malloc_stats(mspace msp);
|
|
||||||
int mspace_trim(mspace msp, size_t pad);
|
|
||||||
size_t mspace_footprint(mspace msp);
|
|
||||||
size_t mspace_max_footprint(mspace msp);
|
|
||||||
size_t mspace_footprint_limit(mspace msp);
|
|
||||||
size_t mspace_set_footprint_limit(mspace msp, size_t bytes);
|
|
||||||
void mspace_inspect_all(mspace msp,
|
|
||||||
void(*handler)(void *, void *, size_t, void*),
|
|
||||||
void* arg);
|
|
||||||
#endif /* MSPACES */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}; /* end of extern "C" */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* MALLOC_280_H */
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright (c) 1990, 1993
|
|
||||||
* The Regents of the University of California. All rights reserved.
|
|
||||||
*
|
|
||||||
* This code is derived from software contributed to Berkeley by
|
|
||||||
* Chris Torek.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 4. Neither the name of the University nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
typedef uintptr_t word;
|
|
||||||
#define wsize sizeof(word)
|
|
||||||
#define wmask (wsize - 1)
|
|
||||||
|
|
||||||
void *memcpy(void *dst0, const void *src0, size_t length)
|
|
||||||
{
|
|
||||||
char *dst = dst0;
|
|
||||||
const char *src = src0;
|
|
||||||
size_t t;
|
|
||||||
|
|
||||||
if (length == 0 || dst == src) /* nothing to do */
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Macros: loop-t-times; and loop-t-times, t>0
|
|
||||||
*/
|
|
||||||
#define TLOOP(s) \
|
|
||||||
if (t) \
|
|
||||||
TLOOP1(s)
|
|
||||||
#define TLOOP1(s) \
|
|
||||||
do { \
|
|
||||||
s; \
|
|
||||||
} while (--t)
|
|
||||||
|
|
||||||
if ((uintptr_t)dst < (uintptr_t)src) {
|
|
||||||
/*
|
|
||||||
* Copy forward.
|
|
||||||
*/
|
|
||||||
t = (uintptr_t)src; /* only need low bits */
|
|
||||||
if ((t | (uintptr_t)dst) & wmask) {
|
|
||||||
/*
|
|
||||||
* Try to align operands. This cannot be done
|
|
||||||
* unless the low bits match.
|
|
||||||
*/
|
|
||||||
if ((t ^ (uintptr_t)dst) & wmask || length < wsize)
|
|
||||||
t = length;
|
|
||||||
else
|
|
||||||
t = wsize - (t & wmask);
|
|
||||||
length -= t;
|
|
||||||
TLOOP1(*dst++ = *src++);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Copy whole words, then mop up any trailing bytes.
|
|
||||||
*/
|
|
||||||
t = length / wsize;
|
|
||||||
TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
|
|
||||||
t = length & wmask;
|
|
||||||
TLOOP(*dst++ = *src++);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Copy backwards. Otherwise essentially the same.
|
|
||||||
* Alignment works as before, except that it takes
|
|
||||||
* (t&wmask) bytes to align, not wsize-(t&wmask).
|
|
||||||
*/
|
|
||||||
src += length;
|
|
||||||
dst += length;
|
|
||||||
t = (uintptr_t)src;
|
|
||||||
if ((t | (uintptr_t)dst) & wmask) {
|
|
||||||
if ((t ^ (uintptr_t)dst) & wmask || length <= wsize)
|
|
||||||
t = length;
|
|
||||||
else
|
|
||||||
t &= wmask;
|
|
||||||
length -= t;
|
|
||||||
TLOOP1(*--dst = *--src);
|
|
||||||
}
|
|
||||||
t = length / wsize;
|
|
||||||
TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src);
|
|
||||||
t = length & wmask;
|
|
||||||
TLOOP(*--dst = *--src);
|
|
||||||
}
|
|
||||||
done:
|
|
||||||
return (dst0);
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
void *memset(void *str, int c, size_t n)
|
|
||||||
{
|
|
||||||
unsigned char val = (unsigned char)c;
|
|
||||||
unsigned char *buf = str;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < n; i++) {
|
|
||||||
buf[i] = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
int strcmp(const char *s1, const char *s2)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; s1[i] == s2[i]; i++)
|
|
||||||
if (s1[i] == '\0')
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return s1[i] - s2[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
int strncmp(const char *s1, const char *s2, unsigned long n)
|
|
||||||
{
|
|
||||||
for (; n > 0; s1++, s2++, --n)
|
|
||||||
if (*s1 != *s2)
|
|
||||||
return ((*(unsigned char *)s1 < *(unsigned char *)s2)
|
|
||||||
? -1
|
|
||||||
: 1);
|
|
||||||
else if (*s1 == '\0')
|
|
||||||
return 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#include <string.h>
|
|
||||||
|
|
||||||
size_t strlen(const char *str)
|
|
||||||
{
|
|
||||||
size_t res = 0;
|
|
||||||
while (str[res]) {
|
|
||||||
res++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
#include <mango/handle.h>
|
|
||||||
#include <mango/task.h>
|
|
||||||
#include <mango/types.h>
|
|
||||||
#include <mango/vm.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define BRK_SIZE 0x400000
|
|
||||||
|
|
||||||
static virt_addr_t brk_base = 0, brk_ptr = 0;
|
|
||||||
static kern_handle_t brk_region = KERN_HANDLE_INVALID;
|
|
||||||
static kern_handle_t brk_object = KERN_HANDLE_INVALID;
|
|
||||||
|
|
||||||
static void *init_brk(size_t size)
|
|
||||||
{
|
|
||||||
kern_status_t status = KERN_OK;
|
|
||||||
kern_handle_t self, address_space;
|
|
||||||
status = task_self(&self);
|
|
||||||
if (status != KERN_OK) {
|
|
||||||
return (void *)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = task_get_address_space(self, &address_space);
|
|
||||||
if (status != KERN_OK) {
|
|
||||||
kern_handle_close(self);
|
|
||||||
return (void *)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = vm_object_create(
|
|
||||||
"ulibc-brk",
|
|
||||||
10,
|
|
||||||
BRK_SIZE,
|
|
||||||
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
|
|
||||||
&brk_object);
|
|
||||||
if (status != KERN_OK) {
|
|
||||||
kern_handle_close(address_space);
|
|
||||||
kern_handle_close(self);
|
|
||||||
return (void *)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = vm_region_create(
|
|
||||||
address_space,
|
|
||||||
"ulibc-brk",
|
|
||||||
10,
|
|
||||||
VM_REGION_ANY_OFFSET,
|
|
||||||
BRK_SIZE,
|
|
||||||
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
|
|
||||||
&brk_region,
|
|
||||||
&brk_base);
|
|
||||||
if (status != KERN_OK) {
|
|
||||||
kern_handle_close(brk_object);
|
|
||||||
kern_handle_close(address_space);
|
|
||||||
kern_handle_close(self);
|
|
||||||
|
|
||||||
brk_object = KERN_HANDLE_INVALID;
|
|
||||||
return (void *)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = vm_region_map_relative(
|
|
||||||
brk_region,
|
|
||||||
0,
|
|
||||||
brk_object,
|
|
||||||
0,
|
|
||||||
BRK_SIZE,
|
|
||||||
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
|
|
||||||
NULL);
|
|
||||||
if (status != KERN_OK) {
|
|
||||||
kern_handle_close(brk_object);
|
|
||||||
kern_handle_close(brk_region);
|
|
||||||
kern_handle_close(address_space);
|
|
||||||
kern_handle_close(self);
|
|
||||||
|
|
||||||
brk_region = KERN_HANDLE_INVALID;
|
|
||||||
brk_object = KERN_HANDLE_INVALID;
|
|
||||||
return (void *)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
brk_ptr = brk_base;
|
|
||||||
return (void *)brk_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *sbrk(intptr_t increment)
|
|
||||||
{
|
|
||||||
kern_status_t status = KERN_OK;
|
|
||||||
if (brk_region == KERN_HANDLE_INVALID
|
|
||||||
|| brk_object == KERN_HANDLE_INVALID) {
|
|
||||||
init_brk(BRK_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (brk_ptr == 0 || brk_ptr >= brk_base + BRK_SIZE) {
|
|
||||||
return (void *)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *result = (void *)brk_ptr;
|
|
||||||
brk_ptr += increment;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user