Compare commits
14 Commits
267b893bf4
...
3a06c18e10
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a06c18e10 | |||
| e46c20b572 | |||
| 0a07db360c | |||
| 1f2bd09d57 | |||
| 72b5801292 | |||
| 5ad1babd03 | |||
| d0abe3333d | |||
| 5658e27445 | |||
| c4fd252f86 | |||
| a6a2526502 | |||
| faeefe28ab | |||
| 1c89acddbf | |||
| f47be0cd67 | |||
| 68714fa0e5 |
@@ -15,7 +15,7 @@ set(CMAKE_ASM_COMPILER ${ASM_COMPILER})
|
|||||||
|
|
||||||
SET(CMAKE_C_FLAGS "-ffreestanding -nostdlib -z max-page-size=0x1000 -m64 -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -D_64BIT -DBYTE_ORDER=1234" CACHE STRING "" FORCE)
|
SET(CMAKE_C_FLAGS "-ffreestanding -nostdlib -z max-page-size=0x1000 -m64 -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -D_64BIT -DBYTE_ORDER=1234" CACHE STRING "" FORCE)
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,-shared" CACHE STRING "" FORCE)
|
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,-shared" CACHE STRING "" FORCE)
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--dynamic-linker=/lib/ld64.so" CACHE STRING "" FORCE)
|
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--unresolved-symbols=report-all,--dynamic-linker=/lib/ld64.so" CACHE STRING "" FORCE)
|
||||||
|
|
||||||
set(CMAKE_C_OUTPUT_EXTENSION .o)
|
set(CMAKE_C_OUTPUT_EXTENSION .o)
|
||||||
set(CMAKE_CXX_OUTPUT_EXTENSION .o)
|
set(CMAKE_CXX_OUTPUT_EXTENSION .o)
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ function(rosetta_add_library)
|
|||||||
add_library(${static_lib_name} STATIC
|
add_library(${static_lib_name} STATIC
|
||||||
${arg_SOURCES}
|
${arg_SOURCES}
|
||||||
${arg_HEADERS})
|
${arg_HEADERS})
|
||||||
|
set_target_properties(${static_lib_name} PROPERTIES OUTPUT_NAME "${lib_name}")
|
||||||
set(targets ${targets} ${static_lib_name})
|
set(targets ${targets} ${static_lib_name})
|
||||||
|
|
||||||
if (arg_PUBLIC_INCLUDE_DIRS)
|
if (arg_PUBLIC_INCLUDE_DIRS)
|
||||||
@@ -90,7 +91,10 @@ function(rosetta_add_library)
|
|||||||
target_link_options(${shared_lib_name} PRIVATE -Wl,--soname,${soname})
|
target_link_options(${shared_lib_name} PRIVATE -Wl,--soname,${soname})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_include_directories(${targets} PUBLIC ${arg_PUBLIC_INCLUDE_DIRS})
|
foreach (target ${targets})
|
||||||
|
target_include_directories(${target} PUBLIC ${arg_PUBLIC_INCLUDE_DIRS})
|
||||||
|
endforeach (target)
|
||||||
|
|
||||||
set_target_properties(${targets} PROPERTIES
|
set_target_properties(${targets} PROPERTIES
|
||||||
POSITION_INDEPENDENT_CODE ON
|
POSITION_INDEPENDENT_CODE ON
|
||||||
src_header_dir ${CMAKE_CURRENT_SOURCE_DIR}/include
|
src_header_dir ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
interface fs {
|
interface fs {
|
||||||
msg open(string path, int flags) -> (int err);
|
msg open(string path, int flags) -> (int err);
|
||||||
msg uppercase(string old) -> (string new);
|
|
||||||
}
|
}
|
||||||
|
|||||||
2
kernel
2
kernel
Submodule kernel updated: f8a7a4285f...1d4cb882a8
@@ -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)
|
||||||
29
lib/libfs/CMakeLists.txt
Normal file
29
lib/libfs/CMakeLists.txt
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
file(GLOB sources
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/*.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/interface/*.c)
|
||||||
|
file(GLOB headers
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/*.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include/fs/*.h)
|
||||||
|
|
||||||
|
set(public_include_dirs
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
|
rosetta_add_library(
|
||||||
|
NAME libfs SHARED STATIC
|
||||||
|
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
|
||||||
|
SOURCES ${sources}
|
||||||
|
HEADERS ${headers})
|
||||||
|
|
||||||
|
sysroot_add_library(
|
||||||
|
NAME libfs
|
||||||
|
HEADER_DIR /usr/include
|
||||||
|
LIB_DIR /usr/lib)
|
||||||
|
sysroot_add_library(
|
||||||
|
NAME libfs-static
|
||||||
|
HEADER_DIR /usr/include
|
||||||
|
LIB_DIR /usr/lib)
|
||||||
|
|
||||||
|
target_link_libraries(libfs libmango interface::fs libc)
|
||||||
|
target_link_libraries(libfs-static libmango interface::fs libc-core)
|
||||||
|
|
||||||
|
set_target_properties(libfs-static PROPERTIES POSITION_INDEPENDENT_CODE FALSE)
|
||||||
35
lib/libfs/allocator.c
Normal file
35
lib/libfs/allocator.c
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#include <fs/allocator.h>
|
||||||
|
|
||||||
|
void *fs_alloc(struct fs_allocator *alloc, size_t count)
|
||||||
|
{
|
||||||
|
if (alloc->fs_alloc) {
|
||||||
|
return alloc->fs_alloc(alloc, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *fs_calloc(struct fs_allocator *alloc, size_t count, size_t sz)
|
||||||
|
{
|
||||||
|
if (alloc->fs_calloc) {
|
||||||
|
return alloc->fs_calloc(alloc, count, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *fs_realloc(struct fs_allocator *alloc, void *p, size_t count)
|
||||||
|
{
|
||||||
|
if (alloc->fs_realloc) {
|
||||||
|
return alloc->fs_realloc(alloc, p, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fs_free(struct fs_allocator *alloc, void *p)
|
||||||
|
{
|
||||||
|
if (alloc->fs_free) {
|
||||||
|
alloc->fs_free(alloc, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
691
lib/libfs/btree.c
Normal file
691
lib/libfs/btree.c
Normal file
@@ -0,0 +1,691 @@
|
|||||||
|
/*
|
||||||
|
The Clear BSD License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Max Wash
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted (subject to the limitations in the disclaimer
|
||||||
|
below) provided that the following conditions are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
- Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from this
|
||||||
|
software without specific prior written permission.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* templated AVL binary tree implementation
|
||||||
|
|
||||||
|
this file implements an extensible AVL binary tree data structure.
|
||||||
|
|
||||||
|
the primary rule of an AVL binary tree is that for a given node N,
|
||||||
|
the heights of N's left and right subtrees can differ by at most 1.
|
||||||
|
|
||||||
|
the height of a subtree is the length of the longest path between
|
||||||
|
the root of the subtree and a leaf node, including the root node itself.
|
||||||
|
|
||||||
|
the height of a leaf node is 1.
|
||||||
|
|
||||||
|
when a node is inserted into or deleted from the tree, this rule may
|
||||||
|
be broken, in which the tree must be rotated to restore the balance.
|
||||||
|
|
||||||
|
no more than one rotation is required for any insert operations,
|
||||||
|
while multiple rotations may be required for a delete operation.
|
||||||
|
|
||||||
|
there are four types of rotations that can be applied to a tree:
|
||||||
|
- left rotation
|
||||||
|
- right rotation
|
||||||
|
- double left rotations
|
||||||
|
- double right rotations
|
||||||
|
|
||||||
|
by enforcing the balance rule, for a tree with n nodes, the worst-case
|
||||||
|
performance for insert, delete, and search operations is guaranteed
|
||||||
|
to be O(log n).
|
||||||
|
|
||||||
|
this file intentionally excludes any kind of search function implementation.
|
||||||
|
it is up to the programmer to implement their own tree node type
|
||||||
|
using struct btree_node, and their own search function using struct btree.
|
||||||
|
this allows the programmer to define their own node types with complex
|
||||||
|
non-integer key types. btree.h contains a number of macros to help
|
||||||
|
define these functions. the macros do all the work, you just have to
|
||||||
|
provide a comparator function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "btree.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
|
#define IS_LEFT_CHILD(p, c) ((p) && (c) && ((p)->b_left == (c)))
|
||||||
|
#define IS_RIGHT_CHILD(p, c) ((p) && (c) && ((p)->b_right == (c)))
|
||||||
|
|
||||||
|
#define HAS_LEFT_CHILD(x) ((x) && ((x)->b_left))
|
||||||
|
#define HAS_RIGHT_CHILD(x) ((x) && ((x)->b_right))
|
||||||
|
|
||||||
|
#define HAS_NO_CHILDREN(x) ((x) && (!(x)->b_left) && (!(x)->b_right))
|
||||||
|
#define HAS_ONE_CHILD(x) \
|
||||||
|
((HAS_LEFT_CHILD(x) && !HAS_RIGHT_CHILD(x)) \
|
||||||
|
|| (!HAS_LEFT_CHILD(x) && HAS_RIGHT_CHILD(x)))
|
||||||
|
#define HAS_TWO_CHILDREN(x) (HAS_LEFT_CHILD(x) && HAS_RIGHT_CHILD(x))
|
||||||
|
|
||||||
|
#define HEIGHT(x) ((x) ? (x)->b_height : 0)
|
||||||
|
|
||||||
|
static inline void update_height(struct btree_node *x)
|
||||||
|
{
|
||||||
|
x->b_height = MAX(HEIGHT(x->b_left), HEIGHT((x->b_right))) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int bf(struct btree_node *x)
|
||||||
|
{
|
||||||
|
int bf = 0;
|
||||||
|
|
||||||
|
if (!x) {
|
||||||
|
return bf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x->b_right) {
|
||||||
|
bf += x->b_right->b_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x->b_left) {
|
||||||
|
bf -= x->b_left->b_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* perform a left rotation on a subtree
|
||||||
|
|
||||||
|
if you have a tree like this:
|
||||||
|
|
||||||
|
Z
|
||||||
|
/ \
|
||||||
|
X .
|
||||||
|
/ \
|
||||||
|
. Y
|
||||||
|
/ \
|
||||||
|
. .
|
||||||
|
|
||||||
|
and you perform a left rotation on node X,
|
||||||
|
you will get the following tree:
|
||||||
|
|
||||||
|
Z
|
||||||
|
/ \
|
||||||
|
Y .
|
||||||
|
/ \
|
||||||
|
X .
|
||||||
|
/ \
|
||||||
|
. .
|
||||||
|
|
||||||
|
note that this function does NOT update b_height for the rotated
|
||||||
|
nodes. it is up to you to call update_height_to_root().
|
||||||
|
*/
|
||||||
|
static void rotate_left(struct btree *tree, struct btree_node *x)
|
||||||
|
{
|
||||||
|
struct btree_node *y = x->b_right;
|
||||||
|
|
||||||
|
struct btree_node *p = x->b_parent;
|
||||||
|
|
||||||
|
if (y->b_left) {
|
||||||
|
y->b_left->b_parent = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
x->b_right = y->b_left;
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
tree->b_root = y;
|
||||||
|
} else if (x == p->b_left) {
|
||||||
|
p->b_left = y;
|
||||||
|
} else {
|
||||||
|
p->b_right = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
x->b_parent = y;
|
||||||
|
y->b_left = x;
|
||||||
|
y->b_parent = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_height_to_root(struct btree_node *x)
|
||||||
|
{
|
||||||
|
while (x) {
|
||||||
|
update_height(x);
|
||||||
|
x = x->b_parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* perform a right rotation on a subtree
|
||||||
|
|
||||||
|
if you have a tree like this:
|
||||||
|
|
||||||
|
Z
|
||||||
|
/ \
|
||||||
|
. X
|
||||||
|
/ \
|
||||||
|
Y .
|
||||||
|
/ \
|
||||||
|
. .
|
||||||
|
|
||||||
|
and you perform a right rotation on node X,
|
||||||
|
you will get the following tree:
|
||||||
|
|
||||||
|
Z
|
||||||
|
/ \
|
||||||
|
. Y
|
||||||
|
/ \
|
||||||
|
. X
|
||||||
|
/ \
|
||||||
|
. .
|
||||||
|
|
||||||
|
note that this function does NOT update b_height for the rotated
|
||||||
|
nodes. it is up to you to call update_height_to_root().
|
||||||
|
*/
|
||||||
|
static void rotate_right(struct btree *tree, struct btree_node *y)
|
||||||
|
{
|
||||||
|
struct btree_node *x = y->b_left;
|
||||||
|
|
||||||
|
struct btree_node *p = y->b_parent;
|
||||||
|
|
||||||
|
if (x->b_right) {
|
||||||
|
x->b_right->b_parent = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
y->b_left = x->b_right;
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
tree->b_root = x;
|
||||||
|
} else if (y == p->b_left) {
|
||||||
|
p->b_left = x;
|
||||||
|
} else {
|
||||||
|
p->b_right = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
y->b_parent = x;
|
||||||
|
x->b_right = y;
|
||||||
|
x->b_parent = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for a given node Z, perform a right rotation on Z's right child,
|
||||||
|
followed by a left rotation on Z itself.
|
||||||
|
|
||||||
|
if you have a tree like this:
|
||||||
|
|
||||||
|
Z
|
||||||
|
/ \
|
||||||
|
. X
|
||||||
|
/ \
|
||||||
|
Y .
|
||||||
|
/ \
|
||||||
|
. .
|
||||||
|
|
||||||
|
and you perform a double-left rotation on node Z,
|
||||||
|
you will get the following tree:
|
||||||
|
|
||||||
|
Y
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
Z X
|
||||||
|
/ \ / \
|
||||||
|
. . . .
|
||||||
|
|
||||||
|
note that, unlike rotate_left and rotate_right, this function
|
||||||
|
DOES update b_height for the rotated nodes (since it needs to be
|
||||||
|
done in a certain order).
|
||||||
|
*/
|
||||||
|
static void rotate_double_left(struct btree *tree, struct btree_node *z)
|
||||||
|
{
|
||||||
|
struct btree_node *x = z->b_right;
|
||||||
|
struct btree_node *y = x->b_left;
|
||||||
|
|
||||||
|
rotate_right(tree, x);
|
||||||
|
rotate_left(tree, z);
|
||||||
|
|
||||||
|
update_height(z);
|
||||||
|
update_height(x);
|
||||||
|
|
||||||
|
while (y) {
|
||||||
|
update_height(y);
|
||||||
|
y = y->b_parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for a given node Z, perform a left rotation on Z's left child,
|
||||||
|
followed by a right rotation on Z itself.
|
||||||
|
|
||||||
|
if you have a tree like this:
|
||||||
|
|
||||||
|
Z
|
||||||
|
/ \
|
||||||
|
X .
|
||||||
|
/ \
|
||||||
|
. Y
|
||||||
|
/ \
|
||||||
|
. .
|
||||||
|
|
||||||
|
and you perform a double-right rotation on node Z,
|
||||||
|
you will get the following tree:
|
||||||
|
|
||||||
|
Y
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
X Z
|
||||||
|
/ \ / \
|
||||||
|
. . . .
|
||||||
|
|
||||||
|
note that, unlike rotate_left and rotate_right, this function
|
||||||
|
DOES update b_height for the rotated nodes (since it needs to be
|
||||||
|
done in a certain order).
|
||||||
|
*/
|
||||||
|
static void rotate_double_right(struct btree *tree, struct btree_node *z)
|
||||||
|
{
|
||||||
|
struct btree_node *x = z->b_left;
|
||||||
|
struct btree_node *y = x->b_right;
|
||||||
|
|
||||||
|
rotate_left(tree, x);
|
||||||
|
rotate_right(tree, z);
|
||||||
|
|
||||||
|
update_height(z);
|
||||||
|
update_height(x);
|
||||||
|
|
||||||
|
while (y) {
|
||||||
|
update_height(y);
|
||||||
|
y = y->b_parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* run after an insert operation. checks that the balance factor
|
||||||
|
of the local subtree is within the range -1 <= BF <= 1. if it
|
||||||
|
is not, rotate the subtree to restore balance.
|
||||||
|
|
||||||
|
note that at most one rotation should be required after a node
|
||||||
|
is inserted into the tree.
|
||||||
|
|
||||||
|
this function depends on all nodes in the tree having
|
||||||
|
correct b_height values.
|
||||||
|
|
||||||
|
@param w the node that was just inserted into the tree
|
||||||
|
*/
|
||||||
|
static void insert_fixup(struct btree *tree, struct btree_node *w)
|
||||||
|
{
|
||||||
|
struct btree_node *z = NULL, *y = NULL, *x = NULL;
|
||||||
|
|
||||||
|
z = w;
|
||||||
|
while (z) {
|
||||||
|
if (bf(z) >= -1 && bf(z) <= 1) {
|
||||||
|
goto next_ancestor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_LEFT_CHILD(z, y)) {
|
||||||
|
if (IS_LEFT_CHILD(y, x)) {
|
||||||
|
rotate_right(tree, z);
|
||||||
|
update_height_to_root(z);
|
||||||
|
} else {
|
||||||
|
rotate_double_right(tree, z);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (IS_LEFT_CHILD(y, x)) {
|
||||||
|
rotate_double_left(tree, z);
|
||||||
|
} else {
|
||||||
|
rotate_left(tree, z);
|
||||||
|
update_height_to_root(z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next_ancestor:
|
||||||
|
x = y;
|
||||||
|
y = z;
|
||||||
|
z = z->b_parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* run after a delete operation. checks that the balance factor
|
||||||
|
of the local subtree is within the range -1 <= BF <= 1. if it
|
||||||
|
is not, rotate the subtree to restore balance.
|
||||||
|
|
||||||
|
note that, unlike insert_fixup, multiple rotations may be required
|
||||||
|
to restore balance after a node is deleted.
|
||||||
|
|
||||||
|
this function depends on all nodes in the tree having
|
||||||
|
correct b_height values.
|
||||||
|
|
||||||
|
@param w one of the following:
|
||||||
|
- the parent of the node that was deleted if the node
|
||||||
|
had no children.
|
||||||
|
- the parent of the node that replaced the deleted node
|
||||||
|
if the deleted node had two children.
|
||||||
|
- the node that replaced the node that was deleted, if
|
||||||
|
the node that was deleted had one child.
|
||||||
|
*/
|
||||||
|
static void delete_fixup(struct btree *tree, struct btree_node *w)
|
||||||
|
{
|
||||||
|
struct btree_node *z = w;
|
||||||
|
|
||||||
|
while (z) {
|
||||||
|
if (bf(z) > 1) {
|
||||||
|
if (bf(z->b_right) >= 0) {
|
||||||
|
rotate_left(tree, z);
|
||||||
|
update_height_to_root(z);
|
||||||
|
} else {
|
||||||
|
rotate_double_left(tree, z);
|
||||||
|
}
|
||||||
|
} else if (bf(z) < -1) {
|
||||||
|
if (bf(z->b_left) <= 0) {
|
||||||
|
rotate_right(tree, z);
|
||||||
|
update_height_to_root(z);
|
||||||
|
} else {
|
||||||
|
rotate_double_right(tree, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
z = z->b_parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* updates b_height for all nodes between the inserted node and the root
|
||||||
|
of the tree, and calls insert_fixup.
|
||||||
|
|
||||||
|
@param node the node that was just inserted into the tree.
|
||||||
|
*/
|
||||||
|
void btree_insert_fixup(struct btree *tree, struct btree_node *node)
|
||||||
|
{
|
||||||
|
node->b_height = 0;
|
||||||
|
|
||||||
|
struct btree_node *cur = node;
|
||||||
|
while (cur) {
|
||||||
|
update_height(cur);
|
||||||
|
cur = cur->b_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
insert_fixup(tree, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove a node from a tree.
|
||||||
|
|
||||||
|
this function assumes that `node` has no children, and therefore
|
||||||
|
doesn't need to be replaced.
|
||||||
|
|
||||||
|
updates b_height for all nodes between `node` and the tree root.
|
||||||
|
|
||||||
|
@param node the node to delete.
|
||||||
|
*/
|
||||||
|
static struct btree_node *remove_node_with_no_children(
|
||||||
|
struct btree *tree,
|
||||||
|
struct btree_node *node)
|
||||||
|
{
|
||||||
|
struct btree_node *w = node->b_parent;
|
||||||
|
struct btree_node *p = node->b_parent;
|
||||||
|
node->b_parent = NULL;
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
tree->b_root = NULL;
|
||||||
|
} else if (IS_LEFT_CHILD(p, node)) {
|
||||||
|
p->b_left = NULL;
|
||||||
|
} else {
|
||||||
|
p->b_right = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (p) {
|
||||||
|
update_height(p);
|
||||||
|
p = p->b_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove a node from a tree.
|
||||||
|
|
||||||
|
this function assumes that `node` has one child.
|
||||||
|
the child of `node` is inherited by `node`'s parent, and `node` is removed.
|
||||||
|
|
||||||
|
updates b_height for all nodes between the node that replaced
|
||||||
|
`node` and the tree root.
|
||||||
|
|
||||||
|
@param node the node to delete.
|
||||||
|
*/
|
||||||
|
static struct btree_node *replace_node_with_one_subtree(
|
||||||
|
struct btree *tree,
|
||||||
|
struct btree_node *node)
|
||||||
|
{
|
||||||
|
struct btree_node *p = node->b_parent;
|
||||||
|
struct btree_node *z = NULL;
|
||||||
|
|
||||||
|
if (HAS_LEFT_CHILD(node)) {
|
||||||
|
z = node->b_left;
|
||||||
|
} else {
|
||||||
|
z = node->b_right;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct btree_node *w = z;
|
||||||
|
if (!p) {
|
||||||
|
tree->b_root = z;
|
||||||
|
} else if (IS_LEFT_CHILD(p, node)) {
|
||||||
|
p->b_left = z;
|
||||||
|
} else if (IS_RIGHT_CHILD(p, node)) {
|
||||||
|
p->b_right = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
z->b_parent = p;
|
||||||
|
|
||||||
|
node->b_parent = NULL;
|
||||||
|
node->b_left = node->b_right = NULL;
|
||||||
|
|
||||||
|
while (z) {
|
||||||
|
update_height(z);
|
||||||
|
z = z->b_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove a node from a tree.
|
||||||
|
|
||||||
|
this function assumes that `node` has two children.
|
||||||
|
find the in-order successor Y of `node` (the largest node in `node`'s left
|
||||||
|
sub-tree), removes `node` from the tree and moves Y to where `node` used to
|
||||||
|
be.
|
||||||
|
|
||||||
|
if Y has a child (it will never have more than one), have Y's parent inherit
|
||||||
|
Y's child.
|
||||||
|
|
||||||
|
updates b_height for all nodes between the deepest node that was modified
|
||||||
|
and the tree root.
|
||||||
|
|
||||||
|
@param z the node to delete.
|
||||||
|
*/
|
||||||
|
static struct btree_node *replace_node_with_two_subtrees(
|
||||||
|
struct btree *tree,
|
||||||
|
struct btree_node *z)
|
||||||
|
{
|
||||||
|
/* x will replace z */
|
||||||
|
struct btree_node *x = z->b_left;
|
||||||
|
|
||||||
|
while (x->b_right) {
|
||||||
|
x = x->b_right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* y is the node that will replace x (if x has a left child) */
|
||||||
|
struct btree_node *y = x->b_left;
|
||||||
|
|
||||||
|
/* w is the starting point for the height update and fixup */
|
||||||
|
struct btree_node *w = x;
|
||||||
|
if (w->b_parent != z) {
|
||||||
|
w = w->b_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y) {
|
||||||
|
w = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_LEFT_CHILD(x->b_parent, x)) {
|
||||||
|
x->b_parent->b_left = y;
|
||||||
|
} else if (IS_RIGHT_CHILD(x->b_parent, x)) {
|
||||||
|
x->b_parent->b_right = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y) {
|
||||||
|
y->b_parent = x->b_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_LEFT_CHILD(z->b_parent, z)) {
|
||||||
|
z->b_parent->b_left = x;
|
||||||
|
} else if (IS_RIGHT_CHILD(z->b_parent, z)) {
|
||||||
|
z->b_parent->b_right = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
x->b_parent = z->b_parent;
|
||||||
|
x->b_left = z->b_left;
|
||||||
|
x->b_right = z->b_right;
|
||||||
|
|
||||||
|
if (x->b_left) {
|
||||||
|
x->b_left->b_parent = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x->b_right) {
|
||||||
|
x->b_right->b_parent = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!x->b_parent) {
|
||||||
|
tree->b_root = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct btree_node *cur = w;
|
||||||
|
while (cur) {
|
||||||
|
update_height(cur);
|
||||||
|
cur = cur->b_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* delete a node from the tree and re-balance it afterwards */
|
||||||
|
void btree_delete(struct btree *tree, struct btree_node *node)
|
||||||
|
{
|
||||||
|
struct btree_node *w = NULL;
|
||||||
|
|
||||||
|
if (HAS_NO_CHILDREN(node)) {
|
||||||
|
w = remove_node_with_no_children(tree, node);
|
||||||
|
} else if (HAS_ONE_CHILD(node)) {
|
||||||
|
w = replace_node_with_one_subtree(tree, node);
|
||||||
|
} else if (HAS_TWO_CHILDREN(node)) {
|
||||||
|
w = replace_node_with_two_subtrees(tree, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w) {
|
||||||
|
delete_fixup(tree, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
node->b_left = node->b_right = node->b_parent = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct btree_node *btree_first(struct btree *tree)
|
||||||
|
{
|
||||||
|
/* the first node in the tree is the node with the smallest key.
|
||||||
|
we keep moving left until we can't go any further */
|
||||||
|
struct btree_node *cur = tree->b_root;
|
||||||
|
if (!cur) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cur->b_left) {
|
||||||
|
cur = cur->b_left;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct btree_node *btree_last(struct btree *tree)
|
||||||
|
{
|
||||||
|
/* the first node in the tree is the node with the largest key.
|
||||||
|
we keep moving right until we can't go any further */
|
||||||
|
struct btree_node *cur = tree->b_root;
|
||||||
|
if (!cur) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cur->b_right) {
|
||||||
|
cur = cur->b_right;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct btree_node *btree_next(struct btree_node *node)
|
||||||
|
{
|
||||||
|
if (!node) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* there are two possibilities for the next node:
|
||||||
|
|
||||||
|
1. if `node` has a right sub-tree, every node in this sub-tree is
|
||||||
|
bigger than node. the in-order successor of `node` is the smallest
|
||||||
|
node in this subtree.
|
||||||
|
2. if `node` has no right sub-tree, we've reached the largest node in
|
||||||
|
the sub-tree rooted at `node`. we need to go back to our parent
|
||||||
|
and continue the search elsewhere.
|
||||||
|
*/
|
||||||
|
if (node->b_right) {
|
||||||
|
/* case 1: step into `node`'s right sub-tree and keep going
|
||||||
|
left to find the smallest node */
|
||||||
|
struct btree_node *cur = node->b_right;
|
||||||
|
while (cur->b_left) {
|
||||||
|
cur = cur->b_left;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* case 2: keep stepping back up towards the root of the tree.
|
||||||
|
if we encounter a step where we are our parent's left child,
|
||||||
|
we've found a parent with a value larger than us. this parent
|
||||||
|
is the in-order successor of `node` */
|
||||||
|
while (node->b_parent && node->b_parent->b_left != node) {
|
||||||
|
node = node->b_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node->b_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct btree_node *btree_prev(struct btree_node *node)
|
||||||
|
{
|
||||||
|
if (!node) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* there are two possibilities for the previous node:
|
||||||
|
|
||||||
|
1. if `node` has a left sub-tree, every node in this sub-tree is
|
||||||
|
smaller than `node`. the in-order predecessor of `node` is the
|
||||||
|
largest node in this subtree.
|
||||||
|
2. if `node` has no left sub-tree, we've reached the smallest node in
|
||||||
|
the sub-tree rooted at `node`. we need to go back to our parent
|
||||||
|
and continue the search elsewhere.
|
||||||
|
*/
|
||||||
|
if (node->b_left) {
|
||||||
|
/* case 1: step into `node`'s left sub-tree and keep going
|
||||||
|
right to find the largest node */
|
||||||
|
struct btree_node *cur = node->b_left;
|
||||||
|
while (cur->b_right) {
|
||||||
|
cur = cur->b_right;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* case 2: keep stepping back up towards the root of the tree.
|
||||||
|
if we encounter a step where we are our parent's right child,
|
||||||
|
we've found a parent with a value smaller than us. this parent
|
||||||
|
is the in-order predecessor of `node`. */
|
||||||
|
while (node->b_parent && node->b_parent->b_right != node) {
|
||||||
|
node = node->b_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node->b_parent;
|
||||||
|
}
|
||||||
475
lib/libfs/btree.h
Normal file
475
lib/libfs/btree.h
Normal file
@@ -0,0 +1,475 @@
|
|||||||
|
/*
|
||||||
|
The Clear BSD License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Max Wash
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted (subject to the limitations in the disclaimer
|
||||||
|
below) provided that the following conditions are met:
|
||||||
|
|
||||||
|
- Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
- Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from this
|
||||||
|
software without specific prior written permission.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FS_BTREE_H_
|
||||||
|
#define _FS_BTREE_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* if your custom structure contains a struct btree_node (i.e. it can be part of
|
||||||
|
a btree), you can use this macro to convert a struct btree_node* to a
|
||||||
|
your_type*
|
||||||
|
|
||||||
|
@param t the name of your custom type (something that can be passed to
|
||||||
|
offsetof)
|
||||||
|
@param m the name of the struct btree_node member variable within your custom
|
||||||
|
type.
|
||||||
|
@param v the struct btree_node pointer that you wish to convert. if this is
|
||||||
|
NULL, NULL will be returned.
|
||||||
|
*/
|
||||||
|
#define BTREE_CONTAINER(t, m, v) \
|
||||||
|
((void *)((v) ? (uintptr_t)(v) - (offsetof(t, m)) : 0))
|
||||||
|
|
||||||
|
/* defines a simple node insertion function.
|
||||||
|
this function assumes that your nodes have simple integer keys that can be
|
||||||
|
compared with the usual operators.
|
||||||
|
|
||||||
|
EXAMPLE:
|
||||||
|
if you have a tree node type like this:
|
||||||
|
|
||||||
|
struct my_tree_node {
|
||||||
|
int key;
|
||||||
|
struct btree_node base;
|
||||||
|
}
|
||||||
|
|
||||||
|
You would use the following call to generate an insert function for a tree
|
||||||
|
with this node type:
|
||||||
|
|
||||||
|
BTREE_DEFINE_SIMPLE_INSERT(struct my_tree_node, base, key,
|
||||||
|
my_tree_node_insert);
|
||||||
|
|
||||||
|
Which would emit a function defined like:
|
||||||
|
|
||||||
|
static void my_tree_node_insert(struct btree *tree, struct my_tree_node
|
||||||
|
*node);
|
||||||
|
|
||||||
|
@param node_type your custom tree node type. usually a structure that
|
||||||
|
contains a struct btree_node member.
|
||||||
|
@param container_node_member the name of the struct btree_node member
|
||||||
|
variable within your custom type.
|
||||||
|
@param container_key_member the name of the key member variable within your
|
||||||
|
custom type.
|
||||||
|
@param function_name the name of the function to generate.
|
||||||
|
*/
|
||||||
|
#define BTREE_DEFINE_SIMPLE_INSERT( \
|
||||||
|
node_type, \
|
||||||
|
container_node_member, \
|
||||||
|
container_key_member, \
|
||||||
|
function_name) \
|
||||||
|
void function_name(struct btree *tree, node_type *node) \
|
||||||
|
{ \
|
||||||
|
if (!tree->b_root) { \
|
||||||
|
tree->b_root = &node->container_node_member; \
|
||||||
|
btree_insert_fixup( \
|
||||||
|
tree, \
|
||||||
|
&node->container_node_member); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
struct btree_node *cur = tree->b_root; \
|
||||||
|
while (1) { \
|
||||||
|
node_type *cur_node = BTREE_CONTAINER( \
|
||||||
|
node_type, \
|
||||||
|
container_node_member, \
|
||||||
|
cur); \
|
||||||
|
struct btree_node *next = NULL; \
|
||||||
|
\
|
||||||
|
if (node->container_key_member \
|
||||||
|
> cur_node->container_key_member) { \
|
||||||
|
next = btree_right(cur); \
|
||||||
|
\
|
||||||
|
if (!next) { \
|
||||||
|
btree_put_right( \
|
||||||
|
cur, \
|
||||||
|
&node->container_node_member); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} else if ( \
|
||||||
|
node->container_key_member \
|
||||||
|
< cur_node->container_key_member) { \
|
||||||
|
next = btree_left(cur); \
|
||||||
|
\
|
||||||
|
if (!next) { \
|
||||||
|
btree_put_left( \
|
||||||
|
cur, \
|
||||||
|
&node->container_node_member); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
cur = next; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
btree_insert_fixup(tree, &node->container_node_member); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* defines a node insertion function.
|
||||||
|
this function should be used for trees with complex node keys that cannot be
|
||||||
|
directly compared. a comparator for your keys must be supplied.
|
||||||
|
|
||||||
|
EXAMPLE:
|
||||||
|
if you have a tree node type like this:
|
||||||
|
|
||||||
|
struct my_tree_node {
|
||||||
|
complex_key_t key;
|
||||||
|
struct btree_node base;
|
||||||
|
}
|
||||||
|
|
||||||
|
You would need to define a comparator function or macro with the following
|
||||||
|
signature:
|
||||||
|
|
||||||
|
int my_comparator(struct my_tree_node *a, struct my_tree_node *b);
|
||||||
|
|
||||||
|
Which implements the following:
|
||||||
|
|
||||||
|
return -1 if a < b
|
||||||
|
return 0 if a == b
|
||||||
|
return 1 if a > b
|
||||||
|
|
||||||
|
You would use the following call to generate an insert function for a tree
|
||||||
|
with this node type:
|
||||||
|
|
||||||
|
BTREE_DEFINE_INSERT(struct my_tree_node, base, key, my_tree_node_insert,
|
||||||
|
my_comparator);
|
||||||
|
|
||||||
|
Which would emit a function defined like:
|
||||||
|
|
||||||
|
static void my_tree_node_insert(struct btree *tree, struct my_tree_node
|
||||||
|
*node);
|
||||||
|
|
||||||
|
@param node_type your custom tree node type. usually a structure that
|
||||||
|
contains a struct btree_node member.
|
||||||
|
@param container_node_member the name of the struct btree_node member
|
||||||
|
variable within your custom type.
|
||||||
|
@param container_key_member the name of the key member variable within your
|
||||||
|
custom type.
|
||||||
|
@param function_name the name of the function to generate.
|
||||||
|
@param comparator the name of a comparator function or functional-macro that
|
||||||
|
conforms to the requirements listed above.
|
||||||
|
*/
|
||||||
|
#define BTREE_DEFINE_INSERT( \
|
||||||
|
node_type, \
|
||||||
|
container_node_member, \
|
||||||
|
container_key_member, \
|
||||||
|
function_name, \
|
||||||
|
comparator) \
|
||||||
|
void function_name(struct btree *tree, node_type *node) \
|
||||||
|
{ \
|
||||||
|
if (!tree->b_root) { \
|
||||||
|
tree->b_root = &node->container_node_member; \
|
||||||
|
btree_insert_fixup( \
|
||||||
|
tree, \
|
||||||
|
&node->container_node_member); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
struct btree_node *cur = tree->b_root; \
|
||||||
|
while (1) { \
|
||||||
|
node_type *cur_node = BTREE_CONTAINER( \
|
||||||
|
node_type, \
|
||||||
|
container_node_member, \
|
||||||
|
cur); \
|
||||||
|
struct btree_node *next = NULL; \
|
||||||
|
int cmp = comparator(node, cur_node); \
|
||||||
|
\
|
||||||
|
if (cmp == 1) { \
|
||||||
|
next = btree_right(cur); \
|
||||||
|
\
|
||||||
|
if (!next) { \
|
||||||
|
btree_put_right( \
|
||||||
|
cur, \
|
||||||
|
&node->container_node_member); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} else if (cmp == -1) { \
|
||||||
|
next = btree_left(cur); \
|
||||||
|
\
|
||||||
|
if (!next) { \
|
||||||
|
btree_put_left( \
|
||||||
|
cur, \
|
||||||
|
&node->container_node_member); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
cur = next; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
btree_insert_fixup(tree, &node->container_node_member); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* defines a simple tree search function.
|
||||||
|
this function assumes that your nodes have simple integer keys that can be
|
||||||
|
compared with the usual operators.
|
||||||
|
|
||||||
|
EXAMPLE:
|
||||||
|
if you have a tree node type like this:
|
||||||
|
|
||||||
|
struct my_tree_node {
|
||||||
|
int key;
|
||||||
|
struct btree_node base;
|
||||||
|
}
|
||||||
|
|
||||||
|
You would use the following call to generate a search function for a tree
|
||||||
|
with this node type:
|
||||||
|
|
||||||
|
BTREE_DEFINE_SIMPLE_GET(struct my_tree_node, int, base, key,
|
||||||
|
my_tree_node_get);
|
||||||
|
|
||||||
|
Which would emit a function defined like:
|
||||||
|
|
||||||
|
static struct my_tree_node *my_tree_node_get(struct btree *tree, int key);
|
||||||
|
|
||||||
|
@param node_type your custom tree node type. usually a structure that
|
||||||
|
contains a struct btree_node member.
|
||||||
|
@param key_type the type name of the key embedded in your custom tree node
|
||||||
|
type. this type must be compatible with the builtin comparison operators.
|
||||||
|
@param container_node_member the name of the struct btree_node member
|
||||||
|
variable within your custom type.
|
||||||
|
@param container_key_member the name of the key member variable within your
|
||||||
|
custom type.
|
||||||
|
@param function_name the name of the function to generate.
|
||||||
|
*/
|
||||||
|
#define BTREE_DEFINE_SIMPLE_GET( \
|
||||||
|
node_type, \
|
||||||
|
key_type, \
|
||||||
|
container_node_member, \
|
||||||
|
container_key_member, \
|
||||||
|
function_name) \
|
||||||
|
node_type *function_name(struct btree *tree, key_type key) \
|
||||||
|
{ \
|
||||||
|
struct btree_node *cur = tree->b_root; \
|
||||||
|
while (cur) { \
|
||||||
|
node_type *cur_node = BTREE_CONTAINER( \
|
||||||
|
node_type, \
|
||||||
|
container_node_member, \
|
||||||
|
cur); \
|
||||||
|
if (key > cur_node->container_key_member) { \
|
||||||
|
cur = btree_right(cur); \
|
||||||
|
} else if (key < cur_node->container_key_member) { \
|
||||||
|
cur = btree_left(cur); \
|
||||||
|
} else { \
|
||||||
|
return cur_node; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return NULL; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* perform an in-order traversal of a binary tree
|
||||||
|
|
||||||
|
If you have a tree defined like:
|
||||||
|
|
||||||
|
struct btree my_tree;
|
||||||
|
|
||||||
|
with nodes defined like:
|
||||||
|
|
||||||
|
struct my_tree_node {
|
||||||
|
int key;
|
||||||
|
struct btree_node base;
|
||||||
|
}
|
||||||
|
|
||||||
|
and you want to do something like:
|
||||||
|
|
||||||
|
foreach (struct my_tree_node *node : my_tree) { ... }
|
||||||
|
|
||||||
|
you should use this:
|
||||||
|
|
||||||
|
btree_foreach (struct my_tree_node, node, &my_tree, base) { ... }
|
||||||
|
|
||||||
|
@param iter_type the type name of the iterator variable. this should be the
|
||||||
|
tree's node type, and shouldn't be a pointer.
|
||||||
|
@param iter_name the name of the iterator variable.
|
||||||
|
@param tree_name a pointer to the tree to traverse.
|
||||||
|
@param node_member the name of the struct btree_node member variable within
|
||||||
|
the tree node type.
|
||||||
|
*/
|
||||||
|
#define btree_foreach(iter_type, iter_name, tree_name, node_member) \
|
||||||
|
for (iter_type *iter_name = BTREE_CONTAINER( \
|
||||||
|
iter_type, \
|
||||||
|
node_member, \
|
||||||
|
btree_first(tree_name)); \
|
||||||
|
iter_name; \
|
||||||
|
iter_name = BTREE_CONTAINER( \
|
||||||
|
iter_type, \
|
||||||
|
node_member, \
|
||||||
|
btree_next(&((iter_name)->node_member))))
|
||||||
|
|
||||||
|
/* perform an reverse in-order traversal of a binary tree
|
||||||
|
|
||||||
|
If you have a tree defined like:
|
||||||
|
|
||||||
|
struct btree my_tree;
|
||||||
|
|
||||||
|
with nodes defined like:
|
||||||
|
|
||||||
|
struct my_tree_node {
|
||||||
|
int key;
|
||||||
|
struct btree_node base;
|
||||||
|
}
|
||||||
|
|
||||||
|
and you want to do something like:
|
||||||
|
|
||||||
|
foreach (struct my_tree_node *node : reverse(my_tree)) { ... }
|
||||||
|
|
||||||
|
you should use this:
|
||||||
|
|
||||||
|
btree_foreach_r (struct my_tree_node, node, &my_tree, base) { ... }
|
||||||
|
|
||||||
|
@param iter_type the type name of the iterator variable. this should be the
|
||||||
|
tree's node type, and shouldn't be a pointer.
|
||||||
|
@param iter_name the name of the iterator variable.
|
||||||
|
@param tree_name a pointer to the tree to traverse.
|
||||||
|
@param node_member the name of the struct btree_node member variable within
|
||||||
|
the tree node type.
|
||||||
|
*/
|
||||||
|
#define btree_foreach_r(iter_type, iter_name, tree_name, node_member) \
|
||||||
|
for (iter_type *iter_name \
|
||||||
|
= BTREE_CONTAINER(iter_type, node_member, btree_last(tree_name)); \
|
||||||
|
iter_name; \
|
||||||
|
iter_name = BTREE_CONTAINER( \
|
||||||
|
iter_type, \
|
||||||
|
node_member, \
|
||||||
|
btree_prev(&((iter_name)->node_member))))
|
||||||
|
|
||||||
|
/* binary tree nodes. this *cannot* be used directly. you need to define a
|
||||||
|
custom node type that contains a member variable of type struct btree_node.
|
||||||
|
|
||||||
|
you would then use the supplied macros to define functions to manipulate your
|
||||||
|
custom binary tree.
|
||||||
|
*/
|
||||||
|
struct btree_node {
|
||||||
|
struct btree_node *b_parent, *b_left, *b_right;
|
||||||
|
unsigned short b_height;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* binary tree. unlike struct btree_node, you can define variables of type
|
||||||
|
* struct btree. */
|
||||||
|
struct btree {
|
||||||
|
struct btree_node *b_root;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* re-balance a binary tree after an insertion operation.
|
||||||
|
|
||||||
|
NOTE that, if you define an insertion function using BTREE_DEFINE_INSERT or
|
||||||
|
similar, this function will automatically called for you.
|
||||||
|
|
||||||
|
@param tree the tree to re-balance.
|
||||||
|
@param node the node that was just inserted into the tree.
|
||||||
|
*/
|
||||||
|
extern void btree_insert_fixup(struct btree *tree, struct btree_node *node);
|
||||||
|
|
||||||
|
/* delete a node from a binary tree and re-balance the tree afterwards.
|
||||||
|
|
||||||
|
@param tree the tree to delete from
|
||||||
|
@param node the node to delete.
|
||||||
|
*/
|
||||||
|
extern void btree_delete(struct btree *tree, struct btree_node *node);
|
||||||
|
|
||||||
|
/* get the first node in a binary tree.
|
||||||
|
|
||||||
|
this will be the node with the smallest key (i.e. the node that is
|
||||||
|
furthest-left from the root)
|
||||||
|
*/
|
||||||
|
extern struct btree_node *btree_first(struct btree *tree);
|
||||||
|
|
||||||
|
/* get the last node in a binary tree.
|
||||||
|
|
||||||
|
this will be the node with the largest key (i.e. the node that is
|
||||||
|
furthest-right from the root)
|
||||||
|
*/
|
||||||
|
extern struct btree_node *btree_last(struct btree *tree);
|
||||||
|
/* for any binary tree node, this function returns the node with the
|
||||||
|
* next-largest key value */
|
||||||
|
extern struct btree_node *btree_next(struct btree_node *node);
|
||||||
|
/* for any binary tree node, this function returns the node with the
|
||||||
|
* next-smallest key value */
|
||||||
|
extern struct btree_node *btree_prev(struct btree_node *node);
|
||||||
|
|
||||||
|
static inline bool btree_empty(const struct btree *tree)
|
||||||
|
{
|
||||||
|
return tree->b_root == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sets `child` as the immediate left-child of `parent` */
|
||||||
|
static inline void btree_put_left(
|
||||||
|
struct btree_node *parent,
|
||||||
|
struct btree_node *child)
|
||||||
|
{
|
||||||
|
parent->b_left = child;
|
||||||
|
child->b_parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sets `child` as the immediate right-child of `parent` */
|
||||||
|
static inline void btree_put_right(
|
||||||
|
struct btree_node *parent,
|
||||||
|
struct btree_node *child)
|
||||||
|
{
|
||||||
|
parent->b_right = child;
|
||||||
|
child->b_parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the immediate left-child of `node` */
|
||||||
|
static inline struct btree_node *btree_left(struct btree_node *node)
|
||||||
|
{
|
||||||
|
return node->b_left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the immediate right-child of `node` */
|
||||||
|
static inline struct btree_node *btree_right(struct btree_node *node)
|
||||||
|
{
|
||||||
|
return node->b_right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the immediate parent of `node` */
|
||||||
|
static inline struct btree_node *btree_parent(struct btree_node *node)
|
||||||
|
{
|
||||||
|
return node->b_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the height of `node`.
|
||||||
|
|
||||||
|
the height of a node is defined as the length of the longest path
|
||||||
|
between the node and a leaf node.
|
||||||
|
|
||||||
|
this count includes the node itself, so the height of a leaf node will be 1.
|
||||||
|
*/
|
||||||
|
static inline unsigned short btree_height(struct btree_node *node)
|
||||||
|
{
|
||||||
|
return node->b_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
86
lib/libfs/context.c
Normal file
86
lib/libfs/context.c
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#include "btree.h"
|
||||||
|
#include "file.h"
|
||||||
|
#include "interface.h"
|
||||||
|
|
||||||
|
#include <fs/allocator.h>
|
||||||
|
#include <fs/context.h>
|
||||||
|
|
||||||
|
BTREE_DEFINE_SIMPLE_GET(struct fs_file, unsigned long, f_node, f_id, get_file);
|
||||||
|
BTREE_DEFINE_SIMPLE_INSERT(struct fs_file, f_node, f_id, put_file);
|
||||||
|
|
||||||
|
struct fs_context {
|
||||||
|
struct fs_superblock *ctx_sb;
|
||||||
|
struct fs_allocator *ctx_alloc;
|
||||||
|
struct btree ctx_filelist;
|
||||||
|
|
||||||
|
struct fs_vtable ctx_vtable;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fs_context *fs_context_create(
|
||||||
|
struct fs_allocator *alloc,
|
||||||
|
struct fs_superblock *sb)
|
||||||
|
{
|
||||||
|
struct fs_context *ctx = fs_alloc(alloc, sizeof *ctx);
|
||||||
|
if (!ctx) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(ctx, 0x0, sizeof *ctx);
|
||||||
|
|
||||||
|
ctx->ctx_sb = sb;
|
||||||
|
ctx->ctx_alloc = alloc;
|
||||||
|
|
||||||
|
ctx->ctx_vtable.open = fs_msg_open;
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fs_context_destroy(struct fs_context *ctx)
|
||||||
|
{
|
||||||
|
fs_free(ctx->ctx_alloc, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fs_file *fs_context_open_file(struct fs_context *ctx, unsigned long id)
|
||||||
|
{
|
||||||
|
struct fs_file *f = get_file(&ctx->ctx_filelist, id);
|
||||||
|
if (!f) {
|
||||||
|
f = fs_alloc(ctx->ctx_alloc, sizeof *f);
|
||||||
|
if (!f) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(f, 0x0, sizeof *f);
|
||||||
|
|
||||||
|
f->f_id = id;
|
||||||
|
put_file(&ctx->ctx_filelist, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fs_context_close_file(struct fs_context *ctx, struct fs_file *f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fs_dentry *fs_context_resolve_path(
|
||||||
|
struct fs_context *ctx,
|
||||||
|
const char *path)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_status_t fs_context_dispatch_msg(
|
||||||
|
struct fs_context *ctx,
|
||||||
|
kern_handle_t channel,
|
||||||
|
struct msg_endpoint *sender,
|
||||||
|
struct msg_header *hdr)
|
||||||
|
{
|
||||||
|
return fs_dispatch(
|
||||||
|
channel,
|
||||||
|
&ctx->ctx_vtable,
|
||||||
|
sender,
|
||||||
|
hdr,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
ctx);
|
||||||
|
}
|
||||||
17
lib/libfs/file.h
Normal file
17
lib/libfs/file.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef _FS_FILE_H_
|
||||||
|
#define _FS_FILE_H_
|
||||||
|
|
||||||
|
#include "btree.h"
|
||||||
|
|
||||||
|
#include <fs/file.h>
|
||||||
|
|
||||||
|
struct fs_file {
|
||||||
|
/* id of the open file, equal to the koid of the port being used to
|
||||||
|
* access the file */
|
||||||
|
unsigned long f_id;
|
||||||
|
struct btree_node f_node;
|
||||||
|
|
||||||
|
const struct fs_file_ops *f_ops;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
19
lib/libfs/include/fs/allocator.h
Normal file
19
lib/libfs/include/fs/allocator.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef FS_ALLOCATOR_H_
|
||||||
|
#define FS_ALLOCATOR_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct fs_allocator {
|
||||||
|
void *fs_arg;
|
||||||
|
void *(*fs_alloc)(struct fs_allocator *, size_t);
|
||||||
|
void *(*fs_calloc)(struct fs_allocator *, size_t, size_t);
|
||||||
|
void *(*fs_realloc)(struct fs_allocator *, void *, size_t);
|
||||||
|
void (*fs_free)(struct fs_allocator *, void *);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void *fs_alloc(struct fs_allocator *alloc, size_t count);
|
||||||
|
extern void *fs_calloc(struct fs_allocator *alloc, size_t count, size_t sz);
|
||||||
|
extern void *fs_realloc(struct fs_allocator *alloc, void *p, size_t count);
|
||||||
|
extern void fs_free(struct fs_allocator *alloc, void *p);
|
||||||
|
|
||||||
|
#endif
|
||||||
31
lib/libfs/include/fs/context.h
Normal file
31
lib/libfs/include/fs/context.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef FS_CONTEXT_H_
|
||||||
|
#define FS_CONTEXT_H_
|
||||||
|
|
||||||
|
#include <rosetta/fs.h>
|
||||||
|
|
||||||
|
struct fs_file;
|
||||||
|
struct fs_context;
|
||||||
|
struct fs_allocator;
|
||||||
|
struct fs_superblock;
|
||||||
|
|
||||||
|
extern struct fs_context *fs_context_create(
|
||||||
|
struct fs_allocator *alloc,
|
||||||
|
struct fs_superblock *sb);
|
||||||
|
extern void fs_context_destroy(struct fs_context *ctx);
|
||||||
|
|
||||||
|
extern struct fs_file *fs_context_open_file(
|
||||||
|
struct fs_context *ctx,
|
||||||
|
unsigned long id);
|
||||||
|
extern void fs_context_close_file(struct fs_context *ctx, struct fs_file *f);
|
||||||
|
|
||||||
|
extern struct fs_dentry *fs_context_resolve_path(
|
||||||
|
struct fs_context *ctx,
|
||||||
|
const char *path);
|
||||||
|
|
||||||
|
extern kern_status_t fs_context_dispatch_msg(
|
||||||
|
struct fs_context *ctx,
|
||||||
|
kern_handle_t channel,
|
||||||
|
struct msg_endpoint *sender,
|
||||||
|
struct msg_header *hdr);
|
||||||
|
|
||||||
|
#endif
|
||||||
18
lib/libfs/include/fs/dentry.h
Normal file
18
lib/libfs/include/fs/dentry.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef FS_DENTRY_H_
|
||||||
|
#define FS_DENTRY_H_
|
||||||
|
|
||||||
|
struct fs_inode;
|
||||||
|
struct fs_superblock;
|
||||||
|
|
||||||
|
struct fs_dentry_ops {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fs_dentry {
|
||||||
|
struct fs_inode *d_inode;
|
||||||
|
struct fs_dentry *d_parent;
|
||||||
|
struct fs_superblock *d_sb;
|
||||||
|
const struct fs_dentry_ops *d_ops;
|
||||||
|
void *d_fsdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
15
lib/libfs/include/fs/file.h
Normal file
15
lib/libfs/include/fs/file.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef FS_FILE_H_
|
||||||
|
#define FS_FILE_H_
|
||||||
|
|
||||||
|
#include <mango/types.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct fs_file;
|
||||||
|
|
||||||
|
struct fs_file_ops {
|
||||||
|
ssize_t (*f_read)(struct fs_file *, void *, size_t);
|
||||||
|
ssize_t (*f_write)(struct fs_file *, const void *, size_t);
|
||||||
|
off_t (*f_seek)(struct fs_file *, off_t, int);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
17
lib/libfs/include/fs/inode.h
Normal file
17
lib/libfs/include/fs/inode.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef FS_INODE_H_
|
||||||
|
#define FS_INODE_H_
|
||||||
|
|
||||||
|
struct fs_inode;
|
||||||
|
struct fs_dentry;
|
||||||
|
struct fs_superblock;
|
||||||
|
|
||||||
|
struct fs_inode_ops {
|
||||||
|
int (*i_lookup)(struct fs_inode *, struct fs_dentry *);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fs_inode {
|
||||||
|
struct fs_superblock *i_sb;
|
||||||
|
const struct fs_inode_ops *i_ops;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
20
lib/libfs/include/fs/superblock.h
Normal file
20
lib/libfs/include/fs/superblock.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef FS_SUPERBLOCK_H_
|
||||||
|
#define FS_SUPERBLOCK_H_
|
||||||
|
|
||||||
|
struct fs_inode;
|
||||||
|
struct fs_dentry;
|
||||||
|
struct fs_superblock;
|
||||||
|
|
||||||
|
struct fs_superblock_ops {
|
||||||
|
struct fs_inode *(*s_alloc_inode)(struct fs_superblock *);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fs_superblock {
|
||||||
|
const struct fs_superblock_ops *s_ops;
|
||||||
|
|
||||||
|
struct fs_dentry *s_root;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct fs_inode *fs_superblock_alloc_inode(struct fs_superblock *sb);
|
||||||
|
|
||||||
|
#endif
|
||||||
21
lib/libfs/interface.h
Normal file
21
lib/libfs/interface.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef _FS_INTERFACE_H_
|
||||||
|
#define _FS_INTERFACE_H_
|
||||||
|
|
||||||
|
#include <mango/types.h>
|
||||||
|
|
||||||
|
struct msg_endpoint;
|
||||||
|
|
||||||
|
extern kern_status_t fs_msg_open(
|
||||||
|
const struct msg_endpoint *sender,
|
||||||
|
const char *path,
|
||||||
|
int flags,
|
||||||
|
int *out_err,
|
||||||
|
void *arg);
|
||||||
|
extern kern_status_t fs_msg_close(
|
||||||
|
const struct msg_endpoint *sender,
|
||||||
|
const char *path,
|
||||||
|
int flags,
|
||||||
|
int *out_err,
|
||||||
|
void *arg);
|
||||||
|
|
||||||
|
#endif
|
||||||
21
lib/libfs/interface/open.c
Normal file
21
lib/libfs/interface/open.c
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <fs/context.h>
|
||||||
|
|
||||||
|
extern kern_status_t fs_msg_open(
|
||||||
|
const struct msg_endpoint *sender,
|
||||||
|
const char *path,
|
||||||
|
int flags,
|
||||||
|
int *out_err,
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
struct fs_context *ctx = arg;
|
||||||
|
|
||||||
|
struct fs_dentry *dent = fs_context_resolve_path(ctx, path);
|
||||||
|
if (!dent) {
|
||||||
|
*out_err = ENOENT;
|
||||||
|
return KERN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_err = SUCCESS;
|
||||||
|
return KERN_OK;
|
||||||
|
}
|
||||||
11
lib/libfs/superblock.c
Normal file
11
lib/libfs/superblock.c
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#include <fs/superblock.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct fs_inode *fs_superblock_alloc_inode(struct fs_superblock *sb)
|
||||||
|
{
|
||||||
|
if (!sb->s_ops->s_alloc_inode) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb->s_ops->s_alloc_inode(sb);
|
||||||
|
}
|
||||||
@@ -18,4 +18,4 @@ sysroot_add_library(
|
|||||||
HEADER_DIR /usr/include
|
HEADER_DIR /usr/include
|
||||||
LIB_DIR /usr/lib)
|
LIB_DIR /usr/lib)
|
||||||
|
|
||||||
target_link_libraries(liblaunch libmango ulibc)
|
target_link_libraries(liblaunch librosetta libmango libc-core)
|
||||||
|
|||||||
@@ -300,8 +300,14 @@ static enum launch_status map_executable(struct elf_image *image)
|
|||||||
|
|
||||||
static elf_sym_t *get_dynsym(struct elf_image *image, size_t index)
|
static elf_sym_t *get_dynsym(struct elf_image *image, size_t index)
|
||||||
{
|
{
|
||||||
return (elf_sym_t *)(image->e_local_base + image->e_dynsym
|
elf_sym_t *sym = (elf_sym_t *)(image->e_local_base + image->e_dynsym
|
||||||
+ (index * image->e_dynsym_entsize));
|
+ (index * image->e_dynsym_entsize));
|
||||||
|
|
||||||
|
if (!sym->st_value) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum launch_status do_rela(struct elf_image *image, elf_rela_t *rela)
|
static enum launch_status do_rela(struct elf_image *image, elf_rela_t *rela)
|
||||||
@@ -312,6 +318,10 @@ static enum launch_status do_rela(struct elf_image *image, elf_rela_t *rela)
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case R_X86_64_JUMP_SLOT:
|
case R_X86_64_JUMP_SLOT:
|
||||||
sym = get_dynsym(image, ELF64_R_SYM(rela->r_info));
|
sym = get_dynsym(image, ELF64_R_SYM(rela->r_info));
|
||||||
|
if (!sym) {
|
||||||
|
return LAUNCH_ERR_MISSING_SYMBOL;
|
||||||
|
}
|
||||||
|
|
||||||
*(uint64_t *)(image->e_local_base + rela->r_offset)
|
*(uint64_t *)(image->e_local_base + rela->r_offset)
|
||||||
= image->e_remote_base + sym->st_value + rela->r_addend;
|
= image->e_remote_base + sym->st_value + rela->r_addend;
|
||||||
kern_tracef(
|
kern_tracef(
|
||||||
@@ -354,7 +364,7 @@ static enum launch_status do_rela_list(
|
|||||||
rela = (elf_rela_t *)((char *)rela + entsize);
|
rela = (elf_rela_t *)((char *)rela + entsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
return LAUNCH_OK;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum launch_status do_rel(
|
static enum launch_status do_rel(
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ enum launch_status {
|
|||||||
* version, etc).
|
* version, etc).
|
||||||
*/
|
*/
|
||||||
LAUNCH_ERR_UNSUPPORTED_EXECUTABLE,
|
LAUNCH_ERR_UNSUPPORTED_EXECUTABLE,
|
||||||
|
LAUNCH_ERR_MISSING_SYMBOL,
|
||||||
/* a particular dependency of the executable could not be resolved. */
|
/* a particular dependency of the executable could not be resolved. */
|
||||||
LAUNCH_ERR_CANNOT_RESOLVE_DEPENDENCY,
|
LAUNCH_ERR_CANNOT_RESOLVE_DEPENDENCY,
|
||||||
LAUNCH_ERR_MEMORY_MAP_FAILED,
|
LAUNCH_ERR_MEMORY_MAP_FAILED,
|
||||||
@@ -28,6 +29,8 @@ enum launch_flags {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct launch_ctx;
|
struct launch_ctx;
|
||||||
|
struct rosetta_bootstrap_handle;
|
||||||
|
struct rosetta_bootstrap_channel;
|
||||||
|
|
||||||
typedef enum launch_status (*launch_resolve_library_function)(
|
typedef enum launch_status (*launch_resolve_library_function)(
|
||||||
struct launch_ctx *,
|
struct launch_ctx *,
|
||||||
@@ -52,6 +55,12 @@ struct launch_parameters {
|
|||||||
int p_envc;
|
int p_envc;
|
||||||
const char **p_envp;
|
const char **p_envp;
|
||||||
|
|
||||||
|
const struct rosetta_bootstrap_handle *p_handles;
|
||||||
|
size_t p_handle_count;
|
||||||
|
|
||||||
|
const struct rosetta_bootstrap_channel *p_channels;
|
||||||
|
size_t p_channel_count;
|
||||||
|
|
||||||
void *p_resolver_arg;
|
void *p_resolver_arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
|
#include "stack.h"
|
||||||
|
|
||||||
#include <launch.h>
|
#include <launch.h>
|
||||||
#include <mango/handle.h>
|
#include <mango/handle.h>
|
||||||
#include <mango/log.h>
|
#include <mango/log.h>
|
||||||
#include <mango/task.h>
|
#include <mango/task.h>
|
||||||
#include <mango/vm.h>
|
#include <mango/vm.h>
|
||||||
|
#include <rosetta/bootstrap.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -34,6 +36,58 @@ static kern_handle_t get_library(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static virt_addr_t write_bootstrap_data(
|
||||||
|
struct stack_writer *stack,
|
||||||
|
const struct launch_parameters *params)
|
||||||
|
{
|
||||||
|
virt_addr_t bs_remote;
|
||||||
|
struct rosetta_bootstrap *bs
|
||||||
|
= stack_writer_put(stack, NULL, sizeof *bs, &bs_remote);
|
||||||
|
|
||||||
|
memset(bs, 0x0, sizeof *bs);
|
||||||
|
|
||||||
|
bs->bs_argc = params->p_argc;
|
||||||
|
bs->bs_envc = params->p_envc;
|
||||||
|
bs->bs_handles_count = params->p_handle_count;
|
||||||
|
bs->bs_channels_count = params->p_channel_count;
|
||||||
|
|
||||||
|
const char **argv, **envp;
|
||||||
|
|
||||||
|
if (bs->bs_argc > 0) {
|
||||||
|
virt_addr_t remote_argv;
|
||||||
|
argv = stack_writer_put(
|
||||||
|
stack,
|
||||||
|
NULL,
|
||||||
|
bs->bs_argc * sizeof(char *),
|
||||||
|
&remote_argv);
|
||||||
|
bs->bs_argv = (const char **)remote_argv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bs->bs_envc > 0) {
|
||||||
|
virt_addr_t remote_envp;
|
||||||
|
envp = stack_writer_put(
|
||||||
|
stack,
|
||||||
|
NULL,
|
||||||
|
bs->bs_envc * sizeof(char *),
|
||||||
|
&remote_envp);
|
||||||
|
bs->bs_envp = (const char **)remote_envp;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < params->p_argc; i++) {
|
||||||
|
virt_addr_t arg_ptr;
|
||||||
|
stack_writer_put_string(stack, params->p_argv[i], &arg_ptr);
|
||||||
|
argv[i] = (const char *)arg_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < params->p_envc; i++) {
|
||||||
|
virt_addr_t env_ptr;
|
||||||
|
stack_writer_put_string(stack, params->p_envp[i], &env_ptr);
|
||||||
|
envp[i] = (const char *)env_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bs_remote;
|
||||||
|
}
|
||||||
|
|
||||||
enum launch_status launch_ctx_execute(
|
enum launch_status launch_ctx_execute(
|
||||||
struct launch_ctx *ctx,
|
struct launch_ctx *ctx,
|
||||||
const struct launch_parameters *params,
|
const struct launch_parameters *params,
|
||||||
@@ -102,7 +156,7 @@ enum launch_status launch_ctx_execute(
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
virt_addr_t stack_buf;
|
virt_addr_t remote_stack_buf, local_stack_buf;
|
||||||
kstatus = vm_region_map_relative(
|
kstatus = vm_region_map_relative(
|
||||||
remote_address_space,
|
remote_address_space,
|
||||||
VM_REGION_ANY_OFFSET,
|
VM_REGION_ANY_OFFSET,
|
||||||
@@ -110,7 +164,15 @@ enum launch_status launch_ctx_execute(
|
|||||||
0,
|
0,
|
||||||
STACK_SIZE,
|
STACK_SIZE,
|
||||||
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
|
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
|
||||||
&stack_buf);
|
&remote_stack_buf);
|
||||||
|
kstatus = vm_region_map_relative(
|
||||||
|
params->p_local_address_space,
|
||||||
|
VM_REGION_ANY_OFFSET,
|
||||||
|
stack_vmo,
|
||||||
|
0,
|
||||||
|
STACK_SIZE,
|
||||||
|
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
|
||||||
|
&local_stack_buf);
|
||||||
kern_handle_close(stack_vmo);
|
kern_handle_close(stack_vmo);
|
||||||
|
|
||||||
if (kstatus != KERN_OK) {
|
if (kstatus != KERN_OK) {
|
||||||
@@ -120,11 +182,23 @@ enum launch_status launch_ctx_execute(
|
|||||||
return LAUNCH_ERR_MEMORY_MAP_FAILED;
|
return LAUNCH_ERR_MEMORY_MAP_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct stack_writer stack;
|
||||||
|
stack_writer_init(
|
||||||
|
&stack,
|
||||||
|
local_stack_buf + STACK_SIZE,
|
||||||
|
remote_stack_buf + STACK_SIZE);
|
||||||
|
virt_addr_t bsdata = write_bootstrap_data(&stack, params);
|
||||||
|
|
||||||
virt_addr_t ip = image.e_hdr.e_entry + image.e_remote_base;
|
virt_addr_t ip = image.e_hdr.e_entry + image.e_remote_base;
|
||||||
virt_addr_t sp = stack_buf + STACK_SIZE;
|
|
||||||
|
|
||||||
kern_handle_t thread;
|
kern_handle_t thread;
|
||||||
kstatus = task_create_thread(remote_task, ip, sp, NULL, 0, &thread);
|
kstatus = task_create_thread(
|
||||||
|
remote_task,
|
||||||
|
ip,
|
||||||
|
stack.w_remote_sp,
|
||||||
|
&bsdata,
|
||||||
|
1,
|
||||||
|
&thread);
|
||||||
if (kstatus != KERN_OK) {
|
if (kstatus != KERN_OK) {
|
||||||
elf_image_cleanup(&image);
|
elf_image_cleanup(&image);
|
||||||
kern_handle_close(remote_address_space);
|
kern_handle_close(remote_address_space);
|
||||||
|
|||||||
59
lib/liblaunch/stack.c
Normal file
59
lib/liblaunch/stack.c
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#include "stack.h"
|
||||||
|
|
||||||
|
#include <mango/log.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void stack_writer_init(
|
||||||
|
struct stack_writer *w,
|
||||||
|
virt_addr_t local_sp,
|
||||||
|
virt_addr_t remote_sp)
|
||||||
|
{
|
||||||
|
memset(w, 0x0, sizeof *w);
|
||||||
|
|
||||||
|
w->w_local_sp = local_sp;
|
||||||
|
w->w_remote_sp = remote_sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *stack_writer_put_string(
|
||||||
|
struct stack_writer *w,
|
||||||
|
const char *s,
|
||||||
|
virt_addr_t *out_remote)
|
||||||
|
{
|
||||||
|
size_t len = strlen(s);
|
||||||
|
|
||||||
|
w->w_local_sp -= (len + 1);
|
||||||
|
w->w_remote_sp -= (len + 1);
|
||||||
|
|
||||||
|
char *local_ptr = (char *)w->w_local_sp;
|
||||||
|
virt_addr_t remote_ptr = w->w_remote_sp;
|
||||||
|
|
||||||
|
memcpy(local_ptr, s, len);
|
||||||
|
local_ptr[len] = '\0';
|
||||||
|
|
||||||
|
if (out_remote) {
|
||||||
|
*out_remote = remote_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return local_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *stack_writer_put(
|
||||||
|
struct stack_writer *w,
|
||||||
|
const void *p,
|
||||||
|
size_t len,
|
||||||
|
virt_addr_t *out_remote)
|
||||||
|
{
|
||||||
|
w->w_local_sp -= len;
|
||||||
|
w->w_remote_sp -= len;
|
||||||
|
|
||||||
|
void *local_ptr = (char *)w->w_local_sp;
|
||||||
|
virt_addr_t remote_ptr = w->w_remote_sp;
|
||||||
|
|
||||||
|
memset(local_ptr, 0x0, len);
|
||||||
|
|
||||||
|
if (out_remote) {
|
||||||
|
*out_remote = remote_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return local_ptr;
|
||||||
|
}
|
||||||
26
lib/liblaunch/stack.h
Normal file
26
lib/liblaunch/stack.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef LIBLAUNCH_STACK_H_
|
||||||
|
#define LIBLAUNCH_STACK_H_
|
||||||
|
|
||||||
|
#include <mango/types.h>
|
||||||
|
|
||||||
|
struct stack_writer {
|
||||||
|
virt_addr_t w_local_sp;
|
||||||
|
virt_addr_t w_remote_sp;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void stack_writer_init(
|
||||||
|
struct stack_writer *w,
|
||||||
|
virt_addr_t local_sp,
|
||||||
|
virt_addr_t remote_sp);
|
||||||
|
|
||||||
|
extern void *stack_writer_put_string(
|
||||||
|
struct stack_writer *w,
|
||||||
|
const char *s,
|
||||||
|
virt_addr_t *out_remote);
|
||||||
|
extern void *stack_writer_put(
|
||||||
|
struct stack_writer *w,
|
||||||
|
const void *p,
|
||||||
|
size_t len,
|
||||||
|
virt_addr_t *out_remote);
|
||||||
|
|
||||||
|
#endif
|
||||||
15
lib/librosetta/CMakeLists.txt
Normal file
15
lib/librosetta/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
file(GLOB sources *.c)
|
||||||
|
file(GLOB headers include/rosetta/*.h)
|
||||||
|
|
||||||
|
rosetta_add_library(
|
||||||
|
NAME librosetta STATIC
|
||||||
|
PUBLIC_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
|
SOURCES ${sources}
|
||||||
|
HEADERS ${headers})
|
||||||
|
|
||||||
|
sysroot_add_library(
|
||||||
|
NAME librosetta
|
||||||
|
HEADER_DIR /usr/include
|
||||||
|
LIB_DIR /usr/lib)
|
||||||
|
|
||||||
|
target_link_libraries(librosetta libmango)
|
||||||
6
lib/librosetta/bootstrap.c
Normal file
6
lib/librosetta/bootstrap.c
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include <rosetta/bootstrap.h>
|
||||||
|
|
||||||
|
const struct rosetta_bootstrap_channel *rosetta_bootstrap_get_channel(void)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
45
lib/librosetta/include/rosetta/bootstrap.h
Normal file
45
lib/librosetta/include/rosetta/bootstrap.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#ifndef ROSETTA_BOOTSTRAP_H_
|
||||||
|
#define ROSETTA_BOOTSTRAP_H_
|
||||||
|
|
||||||
|
#include <mango/types.h>
|
||||||
|
|
||||||
|
enum rosetta_bootstrap_handle_type {
|
||||||
|
RSBS_HANDLE_NONE = 0,
|
||||||
|
RSBS_HANDLE_TASK,
|
||||||
|
RSBS_HANDLE_ADDRESS_SPACE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rosetta_bootstrap_channel_type {
|
||||||
|
RSBS_CHANNEL_NONE,
|
||||||
|
RSBS_CHANNEL_SYSTEM,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rosetta_bootstrap_handle {
|
||||||
|
enum rosetta_bootstrap_handle_type h_type;
|
||||||
|
kern_handle_t h_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rosetta_bootstrap_channel {
|
||||||
|
enum rosetta_bootstrap_channel_type c_type;
|
||||||
|
tid_t c_tid;
|
||||||
|
unsigned int c_cid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rosetta_bootstrap {
|
||||||
|
int bs_argc;
|
||||||
|
const char **bs_argv;
|
||||||
|
|
||||||
|
int bs_envc;
|
||||||
|
const char **bs_envp;
|
||||||
|
|
||||||
|
const struct rosetta_bootstrap_handle *bs_handles;
|
||||||
|
size_t bs_handles_count;
|
||||||
|
|
||||||
|
const struct rosetta_bootstrap_channel *bs_channels;
|
||||||
|
size_t bs_channels_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct rosetta_bootstrap_channel *rosetta_bootstrap_get_channel(
|
||||||
|
void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
file(GLOB sources *.c)
|
file(GLOB sources *.c)
|
||||||
add_executable(systemd ${sources})
|
add_executable(systemd ${sources})
|
||||||
target_link_libraries(systemd libc libc-rt liblaunch libmango)
|
target_link_libraries(systemd libc libc-runtime liblaunch libmango)
|
||||||
|
|
||||||
sysroot_add_program(
|
sysroot_add_program(
|
||||||
NAME systemd
|
NAME systemd
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
add_executable(test test.c)
|
add_executable(test test.c)
|
||||||
target_link_libraries(test libc libc-rt liblaunch)
|
target_link_libraries(test libc libc-runtime liblaunch)
|
||||||
|
|
||||||
sysroot_add_program(
|
sysroot_add_program(
|
||||||
NAME test
|
NAME test
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
file(GLOB sources *.c)
|
file(GLOB sources *.c)
|
||||||
add_executable(ldd ${sources})
|
add_executable(ldd ${sources})
|
||||||
target_link_libraries(ldd ulibc libc-rt libmango)
|
target_link_libraries(ldd libc-core libc-runtime libmango)
|
||||||
|
|
||||||
sysroot_add_program(
|
sysroot_add_program(
|
||||||
NAME ldd
|
NAME ldd
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ set_property(SOURCE ${arch_sources} PROPERTY LANGUAGE C)
|
|||||||
|
|
||||||
add_executable(bootstrap ${c_sources} ${arch_sources})
|
add_executable(bootstrap ${c_sources} ${arch_sources})
|
||||||
|
|
||||||
target_link_libraries(bootstrap libmango ulibc liblaunch interface::fs)
|
target_link_libraries(bootstrap
|
||||||
|
libmango libc-core libc-malloc libfs-static liblaunch
|
||||||
|
interface::fs)
|
||||||
|
|
||||||
target_compile_options(bootstrap PRIVATE
|
target_compile_options(bootstrap PRIVATE
|
||||||
-fPIC -pie -fno-stack-protector -nostdlib -ffreestanding)
|
-fno-stack-protector -nostdlib -ffreestanding)
|
||||||
target_link_options(bootstrap PRIVATE
|
target_link_options(bootstrap PRIVATE
|
||||||
-fPIC -static -pie -nostdlib -ffreestanding
|
-static -nostdlib -ffreestanding)
|
||||||
-T ${CMAKE_CURRENT_SOURCE_DIR}/arch/${TARGET_ARCH}/layout.ld)
|
#-T ${CMAKE_CURRENT_SOURCE_DIR}/arch/${TARGET_ARCH}/layout.ld)
|
||||||
|
|||||||
@@ -15,6 +15,5 @@ SECTIONS {
|
|||||||
|
|
||||||
/DISCARD/ : {
|
/DISCARD/ : {
|
||||||
*(.interp)
|
*(.interp)
|
||||||
*(.dynamic)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
#define MSG_IMPLEMENTATION
|
#define MSG_IMPLEMENTATION
|
||||||
#define MSG_NO_MALLOC
|
#define MSG_NO_MALLOC
|
||||||
|
|
||||||
#include "tar.h"
|
#include "tar.h"
|
||||||
|
|
||||||
|
#include <fs/allocator.h>
|
||||||
|
#include <fs/context.h>
|
||||||
|
#include <heap/heap.h>
|
||||||
#include <launch.h>
|
#include <launch.h>
|
||||||
#include <mango/log.h>
|
#include <mango/log.h>
|
||||||
#include <mango/msg.h>
|
#include <mango/msg.h>
|
||||||
#include <mango/task.h>
|
#include <mango/task.h>
|
||||||
#include <mango/types.h>
|
#include <mango/types.h>
|
||||||
|
#include <rosetta/bootstrap.h>
|
||||||
#include <rosetta/fs.h>
|
#include <rosetta/fs.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -47,29 +52,41 @@ static enum launch_status resolve_dependency(
|
|||||||
return LAUNCH_OK;
|
return LAUNCH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static kern_status_t open(const char *path, int flags, int *out_err)
|
static kern_status_t open(
|
||||||
|
const struct msg_endpoint *sender,
|
||||||
|
const char *path,
|
||||||
|
int flags,
|
||||||
|
int *out_err,
|
||||||
|
void *arg)
|
||||||
{
|
{
|
||||||
kern_logf("received msg: open(%s, %d)", path, flags);
|
kern_logf(
|
||||||
|
"received msg: [%u.%x] open(%s, %d)",
|
||||||
|
sender->e_task,
|
||||||
|
sender->e_port,
|
||||||
|
path,
|
||||||
|
flags);
|
||||||
*out_err = 13;
|
*out_err = 13;
|
||||||
return KERN_OK;
|
return KERN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static kern_status_t uppercase(const char *old, struct msg_string *new)
|
static void *_fs_alloc(struct fs_allocator *alloc, size_t count)
|
||||||
{
|
{
|
||||||
kern_logf("received msg: uppercase(%s)", old);
|
return heap_alloc(alloc->fs_arg, count);
|
||||||
size_t i;
|
|
||||||
for (i = 0; old[i] && i < new->str_max - 1; i++) {
|
|
||||||
char c = old[i];
|
|
||||||
if (c >= 'a' && c <= 'z') {
|
|
||||||
new->str_buf[i] = old[i] - 'a' + 'A';
|
|
||||||
} else {
|
|
||||||
new->str_buf[i] = old[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
new->str_len = i - 1;
|
static void *_fs_calloc(struct fs_allocator *alloc, size_t count, size_t sz)
|
||||||
new->str_buf[i] = 0;
|
{
|
||||||
return KERN_OK;
|
return heap_calloc(alloc->fs_arg, count, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *_fs_realloc(struct fs_allocator *alloc, void *p, size_t count)
|
||||||
|
{
|
||||||
|
return heap_realloc(alloc->fs_arg, p, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _fs_free(struct fs_allocator *alloc, void *p)
|
||||||
|
{
|
||||||
|
heap_free(alloc->fs_arg, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(
|
int main(
|
||||||
@@ -106,12 +123,36 @@ int main(
|
|||||||
|
|
||||||
struct launch_ctx launch;
|
struct launch_ctx launch;
|
||||||
struct launch_result result;
|
struct launch_result result;
|
||||||
|
const char *init_argv[] = {
|
||||||
|
"init",
|
||||||
|
"arg1",
|
||||||
|
"arg2",
|
||||||
|
"arg3",
|
||||||
|
};
|
||||||
|
const char *init_env[] = {
|
||||||
|
"TESTVAR=testvalue",
|
||||||
|
};
|
||||||
|
struct rosetta_bootstrap_channel init_channels[] = {
|
||||||
|
{
|
||||||
|
.c_type = RSBS_CHANNEL_SYSTEM,
|
||||||
|
.c_tid = 0,
|
||||||
|
.c_cid = 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
struct launch_parameters params = {
|
struct launch_parameters params = {
|
||||||
.p_executable = image,
|
.p_executable = image,
|
||||||
.p_parent_task = task,
|
.p_parent_task = task,
|
||||||
.p_task_name = "init",
|
.p_task_name = "init",
|
||||||
.p_local_address_space = address_space,
|
.p_local_address_space = address_space,
|
||||||
.p_resolver_arg = &bsp,
|
.p_resolver_arg = &bsp,
|
||||||
|
.p_argc = sizeof init_argv / sizeof init_argv[0],
|
||||||
|
.p_argv = init_argv,
|
||||||
|
.p_envc = sizeof init_env / sizeof init_env[0],
|
||||||
|
.p_envp = init_env,
|
||||||
|
.p_channel_count
|
||||||
|
= sizeof init_channels / sizeof init_channels[0],
|
||||||
|
.p_channels = init_channels,
|
||||||
};
|
};
|
||||||
|
|
||||||
kern_handle_t channel;
|
kern_handle_t channel;
|
||||||
@@ -122,33 +163,67 @@ int main(
|
|||||||
|
|
||||||
enum launch_status status
|
enum launch_status status
|
||||||
= launch_ctx_execute(&launch, ¶ms, LAUNCH_F_NONE, &result);
|
= launch_ctx_execute(&launch, ¶ms, LAUNCH_F_NONE, &result);
|
||||||
kern_logf("launch result: %d", status);
|
if (status != KERN_OK) {
|
||||||
|
kern_logf("failed to start init: %d", status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
const struct fs_vtable fs_vtable = {
|
heap_t heap = HEAP_INIT;
|
||||||
.open = open,
|
|
||||||
.uppercase = uppercase,
|
struct fs_allocator fs_allocator = {
|
||||||
|
.fs_alloc = _fs_alloc,
|
||||||
|
.fs_calloc = _fs_calloc,
|
||||||
|
.fs_realloc = _fs_realloc,
|
||||||
|
.fs_free = _fs_free,
|
||||||
|
.fs_arg = &heap,
|
||||||
};
|
};
|
||||||
#if 1
|
|
||||||
|
struct fs_context *fs = fs_context_create(&fs_allocator, NULL);
|
||||||
|
if (!fs) {
|
||||||
|
kern_logf("cannot initialise fs");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
msgid_t id;
|
struct msg_endpoint sender;
|
||||||
struct msg_header hdr;
|
struct msg_header hdr;
|
||||||
kern_status_t status = msg_recv_generic(channel, &id, &hdr);
|
kern_msg_handle_t handles[KERN_MSG_MAX_HANDLES] = {0};
|
||||||
|
kern_status_t status = msg_recv_generic(
|
||||||
|
channel,
|
||||||
|
&sender,
|
||||||
|
&hdr,
|
||||||
|
handles,
|
||||||
|
KERN_MSG_MAX_HANDLES);
|
||||||
if (status != KERN_OK) {
|
if (status != KERN_OK) {
|
||||||
kern_logf("message recv error %d", status);
|
kern_logf("message recv error %d", status);
|
||||||
|
msg_reply_generic(
|
||||||
|
channel,
|
||||||
|
&sender,
|
||||||
|
&hdr,
|
||||||
|
KERN_UNSUPPORTED);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hdr.hdr_protocol != PROTOCOL_FS) {
|
switch (hdr.hdr_protocol) {
|
||||||
|
case PROTOCOL_FS:
|
||||||
|
status = fs_context_dispatch_msg(
|
||||||
|
fs,
|
||||||
|
channel,
|
||||||
|
&sender,
|
||||||
|
&hdr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
kern_logf(
|
kern_logf(
|
||||||
"unknown message protocol %u",
|
"unknown message protocol %u",
|
||||||
hdr.hdr_protocol);
|
hdr.hdr_protocol);
|
||||||
continue;
|
msg_reply_generic(
|
||||||
|
channel,
|
||||||
|
&sender,
|
||||||
|
&hdr,
|
||||||
|
KERN_UNSUPPORTED);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status = fs_dispatch(channel, &fs_vtable, id, &hdr);
|
return 0;
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 102;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ set_target_properties(ld PROPERTIES
|
|||||||
OUTPUT_NAME "ld64"
|
OUTPUT_NAME "ld64"
|
||||||
SUFFIX ".so")
|
SUFFIX ".so")
|
||||||
|
|
||||||
target_link_libraries(ld ulibc libmango interface::fs)
|
target_link_libraries(ld
|
||||||
|
libc-core libc-malloc libmango librosetta
|
||||||
|
interface::fs)
|
||||||
|
|
||||||
target_compile_options(ld PRIVATE
|
target_compile_options(ld PRIVATE
|
||||||
-fPIC -fno-stack-protector -nostdlib -ffreestanding)
|
-fPIC -fno-stack-protector -nostdlib -ffreestanding)
|
||||||
|
|||||||
@@ -1,30 +1,27 @@
|
|||||||
#define MSG_IMPLEMENTATION
|
#define MSG_IMPLEMENTATION
|
||||||
|
#define MSG_NO_MALLOC
|
||||||
|
|
||||||
|
#include <heap/heap.h>
|
||||||
#include <mango/log.h>
|
#include <mango/log.h>
|
||||||
#include <mango/msg.h>
|
#include <mango/msg.h>
|
||||||
|
#include <mango/task.h>
|
||||||
#include <mango/types.h>
|
#include <mango/types.h>
|
||||||
|
#include <mango/vm.h>
|
||||||
|
#include <rosetta/bootstrap.h>
|
||||||
#include <rosetta/fs.h>
|
#include <rosetta/fs.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
int main(
|
int main(const struct rosetta_bootstrap *bs)
|
||||||
int argc,
|
|
||||||
const char **argv,
|
|
||||||
kern_handle_t task,
|
|
||||||
kern_handle_t address_space,
|
|
||||||
uintptr_t bsp_base)
|
|
||||||
{
|
{
|
||||||
void *brk = sbrk(0);
|
kern_handle_t task, address_space;
|
||||||
kern_logf("brk=%p", brk);
|
task_self(&task);
|
||||||
|
task_get_address_space(task, &address_space);
|
||||||
|
|
||||||
void *buf = malloc(64);
|
for (size_t i = 0; i < bs->bs_argc; i++) {
|
||||||
if (buf) {
|
kern_logf("argv[%zu]: %s", i, bs->bs_argv[i]);
|
||||||
memset(buf, 0x0, 64);
|
|
||||||
kern_logf("allocated 64 bytes at %p", buf);
|
|
||||||
} else {
|
|
||||||
kern_logf("malloc() failed");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kern_handle_t port;
|
kern_handle_t port;
|
||||||
@@ -34,16 +31,8 @@ int main(
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
|
||||||
port_connect(port, 0, 0);
|
port_connect(port, 0, 0);
|
||||||
|
|
||||||
const char *str = "hello";
|
|
||||||
char new_buf[512] = {0};
|
|
||||||
struct msg_string new = {.str_buf = new_buf, .str_max = sizeof new_buf};
|
|
||||||
kern_logf("sending msg: uppercase(%s)", str);
|
|
||||||
status = fs_uppercase(port, str, &new);
|
|
||||||
kern_logf("uppercase(%s) = %s", str, new_buf);
|
|
||||||
|
|
||||||
const char *path = "/usr/lib/libc.so";
|
const char *path = "/usr/lib/libc.so";
|
||||||
int flags = 4;
|
int flags = 4;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
@@ -54,9 +43,13 @@ int main(
|
|||||||
if (status != KERN_OK) {
|
if (status != KERN_OK) {
|
||||||
kern_logf("open call failed (status %d)", status);
|
kern_logf("open call failed (status %d)", status);
|
||||||
} else {
|
} else {
|
||||||
kern_logf("open(%s, %d) = %d", path, flags, err);
|
kern_logf(
|
||||||
|
"open(%s, %d) = %s (%s)",
|
||||||
|
path,
|
||||||
|
flags,
|
||||||
|
strerror_code(err),
|
||||||
|
strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
struct emit_ctx {
|
struct emit_ctx {
|
||||||
b_stream *ctx_out;
|
b_stream *ctx_out;
|
||||||
|
size_t ctx_max_handle_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void emit(struct emit_ctx *ctx, const char *format, ...)
|
static void emit(struct emit_ctx *ctx, const char *format, ...)
|
||||||
@@ -77,18 +78,24 @@ static int emit_header_lib_impl(struct emit_ctx *ctx)
|
|||||||
emit(ctx, "kern_status_t msg_recv_generic(\n");
|
emit(ctx, "kern_status_t msg_recv_generic(\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"kern_handle_t channel,\nmsgid_t *out_id,\nstruct msg_header "
|
"kern_handle_t channel,\nstruct msg_endpoint *out_sender,\nstruct "
|
||||||
"*out_hdr)\n");
|
"msg_header *out_hdr,\nkern_msg_handle_t *out_handles,\nsize_t "
|
||||||
|
"out_handles_max)\n");
|
||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
emit(ctx, "{\n");
|
emit(ctx, "{\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"struct iovec iov = IOVEC(out_hdr, sizeof *out_hdr);\n"
|
"kern_iovec_t iov = IOVEC(out_hdr, sizeof *out_hdr);\n"
|
||||||
"kern_status_t status = msg_recv(channel, out_id, &iov, 1);\n"
|
"kern_msg_t msg = { .msg_data = &iov, .msg_data_count = 1, "
|
||||||
|
".msg_handles = out_handles, .msg_handles_count = out_handles_max };\n"
|
||||||
|
"kern_status_t status = msg_recv(channel, &msg);\n"
|
||||||
"if (status != KERN_OK) return status;\n"
|
"if (status != KERN_OK) return status;\n"
|
||||||
"if (out_hdr->hdr_magic != MSG_MAGIC) return KERN_INVALID_ARGUMENT;\n"
|
"if (out_hdr->hdr_magic != MSG_MAGIC) return KERN_INVALID_ARGUMENT;\n"
|
||||||
|
"out_sender->e_task = msg.msg_sender;\n"
|
||||||
|
"out_sender->e_port = msg.msg_endpoint;\n"
|
||||||
|
"out_sender->e_msg = msg.msg_id;\n"
|
||||||
"return KERN_OK;\n");
|
"return KERN_OK;\n");
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
@@ -97,17 +104,17 @@ static int emit_header_lib_impl(struct emit_ctx *ctx)
|
|||||||
emit(ctx, "kern_status_t msg_read_generic(\n");
|
emit(ctx, "kern_status_t msg_read_generic(\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"kern_handle_t channel,\nmsgid_t id,\nstruct msg_header "
|
"kern_handle_t channel,\nconst struct msg_endpoint *sender,\n"
|
||||||
"*out_hdr)\n");
|
"struct msg_header *out_hdr)\n");
|
||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
emit(ctx, "{\n");
|
emit(ctx, "{\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"struct iovec iov = IOVEC(out_hdr, sizeof *out_hdr);\n"
|
"kern_iovec_t iov = IOVEC(out_hdr, sizeof *out_hdr);\n"
|
||||||
"size_t r = 0;\n"
|
"size_t r = 0;\n"
|
||||||
"kern_status_t status = msg_read(channel, id, 0, &iov, 1, &r);\n"
|
"kern_status_t status = msg_read(channel, sender->e_msg, 0, &iov, 1, &r);\n"
|
||||||
"if (status != KERN_OK) return status;\n"
|
"if (status != KERN_OK) return status;\n"
|
||||||
"if (r != sizeof *out_hdr) return KERN_INVALID_ARGUMENT;\n"
|
"if (r != sizeof *out_hdr) return KERN_INVALID_ARGUMENT;\n"
|
||||||
"if (out_hdr->hdr_magic != MSG_MAGIC) return KERN_INVALID_ARGUMENT;\n"
|
"if (out_hdr->hdr_magic != MSG_MAGIC) return KERN_INVALID_ARGUMENT;\n"
|
||||||
@@ -120,8 +127,8 @@ static int emit_header_lib_impl(struct emit_ctx *ctx)
|
|||||||
emit(ctx, "kern_status_t msg_reply_generic(\n");
|
emit(ctx, "kern_status_t msg_reply_generic(\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"kern_handle_t channel,\nmsgid_t id,\nconst struct msg_header "
|
"kern_handle_t channel,\nconst struct msg_endpoint *sender,\n"
|
||||||
"*msg, uint16_t status)\n");
|
"const struct msg_header *msg_data,\nuint16_t status)\n");
|
||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
emit(ctx, "{\n");
|
emit(ctx, "{\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
@@ -135,17 +142,18 @@ static int emit_header_lib_impl(struct emit_ctx *ctx)
|
|||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
emit(ctx, "};\n");
|
emit(ctx, "};\n");
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"if (msg) {\n");
|
"if (msg_data) {\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"resp_data.hdr_protocol = msg->hdr_protocol;\n"
|
"resp_data.hdr_protocol = msg_data->hdr_protocol;\n"
|
||||||
"resp_data.hdr_func = msg->hdr_func;\n");
|
"resp_data.hdr_func = msg_data->hdr_func;\n");
|
||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
emit(ctx, "}\n");
|
emit(ctx, "}\n");
|
||||||
|
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"struct iovec iov = IOVEC(&resp_data, sizeof resp_data);\n"
|
"kern_iovec_t iov = IOVEC(&resp_data, sizeof resp_data);\n"
|
||||||
"return msg_reply(channel, id, &iov, 1);\n");
|
"kern_msg_t reply = { .msg_data = &iov, .msg_data_count = 1 };\n"
|
||||||
|
"return msg_reply(channel, sender->e_msg, &reply);\n");
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
@@ -165,6 +173,16 @@ static int emit_header_lib_definitions(struct emit_ctx *ctx)
|
|||||||
|
|
||||||
emit(ctx, "#define MSG_MAGIC 0x9AB07D10U\n\n");
|
emit(ctx, "#define MSG_MAGIC 0x9AB07D10U\n\n");
|
||||||
|
|
||||||
|
emit(ctx, "struct msg_endpoint {\n");
|
||||||
|
emit_indent(ctx);
|
||||||
|
|
||||||
|
emit(ctx, "tid_t e_task;\n");
|
||||||
|
emit(ctx, "koid_t e_port;\n");
|
||||||
|
emit(ctx, "msgid_t e_msg;\n");
|
||||||
|
|
||||||
|
emit_unindent(ctx);
|
||||||
|
emit(ctx, "};\n\n");
|
||||||
|
|
||||||
emit(ctx, "struct msg_header {\n");
|
emit(ctx, "struct msg_header {\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
|
|
||||||
@@ -189,25 +207,23 @@ static int emit_header_lib_definitions(struct emit_ctx *ctx)
|
|||||||
emit(ctx, "extern kern_status_t msg_recv_generic(\n");
|
emit(ctx, "extern kern_status_t msg_recv_generic(\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"kern_handle_t channel,\nmsgid_t *out_id,\nstruct msg_header "
|
"kern_handle_t channel,\nstruct msg_endpoint *out_sender,\nstruct "
|
||||||
"*out_hdr);\n",
|
"msg_header *out_hdr,\nkern_msg_handle_t *out_handles,\nsize_t "
|
||||||
NULL);
|
"out_handles_max);\n");
|
||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
|
|
||||||
emit(ctx, "extern kern_status_t msg_read_generic(\n");
|
emit(ctx, "extern kern_status_t msg_read_generic(\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"kern_handle_t channel,\nmsgid_t id,\nstruct msg_header "
|
"kern_handle_t channel,\nconst struct msg_endpoint *sender,\n"
|
||||||
"*out_hdr);\n",
|
"struct msg_header *out_hdr);\n");
|
||||||
NULL);
|
|
||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
|
|
||||||
emit(ctx, "extern kern_status_t msg_reply_generic(\n");
|
emit(ctx, "extern kern_status_t msg_reply_generic(\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"kern_handle_t channel,\nmsgid_t id,\nconst struct msg_header "
|
"kern_handle_t channel,\nconst struct msg_endpoint *sender,\n"
|
||||||
"*msg, uint16_t status);\n",
|
"const struct msg_header *msg_data, uint16_t status);\n");
|
||||||
NULL);
|
|
||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
|
|
||||||
emit(ctx, "#if defined(MSG_IMPLEMENTATION)\n\n");
|
emit(ctx, "#if defined(MSG_IMPLEMENTATION)\n\n");
|
||||||
@@ -218,6 +234,42 @@ static int emit_header_lib_definitions(struct emit_ctx *ctx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t get_msg_handle_params(const struct msg_definition *msg)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
b_queue_entry *entry = b_queue_first(&msg->msg_params);
|
||||||
|
while (entry) {
|
||||||
|
const struct msg_parameter *param
|
||||||
|
= b_unbox(struct msg_parameter, entry, p_entry);
|
||||||
|
if (param->p_type->ty_id == TYPE_HANDLE) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = b_queue_next(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t get_max_handle_params(const struct interface_definition *iface)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
b_queue_entry *entry = b_queue_first(&iface->if_msg);
|
||||||
|
while (entry) {
|
||||||
|
const struct msg_definition *msg
|
||||||
|
= b_unbox(struct msg_definition, entry, msg_entry);
|
||||||
|
size_t msg_count = get_msg_handle_params(msg);
|
||||||
|
|
||||||
|
if (msg_count > count) {
|
||||||
|
count = msg_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = b_queue_next(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
static int emit_interface_id_macros(
|
static int emit_interface_id_macros(
|
||||||
struct emit_ctx *ctx,
|
struct emit_ctx *ctx,
|
||||||
const struct interface_definition *iface)
|
const struct interface_definition *iface)
|
||||||
@@ -279,6 +331,9 @@ static int emit_msg_struct_member(
|
|||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
emit(ctx, "uint32_t %s;\n", param->p_name);
|
emit(ctx, "uint32_t %s;\n", param->p_name);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HANDLE:
|
||||||
|
emit(ctx, "kern_handle_t %s;\n", param->p_name);
|
||||||
|
break;
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
emit(ctx, "uint16_t %s_offset;\n", param->p_name);
|
emit(ctx, "uint16_t %s_offset;\n", param->p_name);
|
||||||
emit(ctx, "uint16_t %s_len;\n", param->p_name);
|
emit(ctx, "uint16_t %s_len;\n", param->p_name);
|
||||||
@@ -405,22 +460,25 @@ static int emit_interface_msg_function_send_impl(
|
|||||||
b_string_toupper(msg_ucase);
|
b_string_toupper(msg_ucase);
|
||||||
|
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"struct msg_%s_%s msg = {0};\n",
|
"struct msg_%s_%s msg_data = {0};\n",
|
||||||
iface->if_name,
|
iface->if_name,
|
||||||
msg->msg_name);
|
msg->msg_name);
|
||||||
emit(ctx, "msg.msg_header.hdr_magic = MSG_MAGIC;\n");
|
emit(ctx, "msg_data.msg_header.hdr_magic = MSG_MAGIC;\n");
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"msg.msg_header.hdr_protocol = PROTOCOL_%s;\n",
|
"msg_data.msg_header.hdr_protocol = PROTOCOL_%s;\n",
|
||||||
b_string_ptr(iface_ucase));
|
b_string_ptr(iface_ucase));
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"msg.msg_header.hdr_func = MSG_%s_%s;\n\n",
|
"msg_data.msg_header.hdr_func = MSG_%s_%s;\n\n",
|
||||||
b_string_ptr(iface_ucase),
|
b_string_ptr(iface_ucase),
|
||||||
b_string_ptr(msg_ucase));
|
b_string_ptr(msg_ucase));
|
||||||
|
|
||||||
b_string_unref(iface_ucase);
|
b_string_unref(iface_ucase);
|
||||||
b_string_unref(msg_ucase);
|
b_string_unref(msg_ucase);
|
||||||
|
|
||||||
emit(ctx, "uint16_t offset = sizeof msg;\n\n");
|
emit(ctx, "uint16_t offset = sizeof msg_data;\n\n");
|
||||||
|
|
||||||
|
size_t nr_req_handles = 0;
|
||||||
|
size_t nr_resp_handles = 0;
|
||||||
|
|
||||||
b_queue_entry *entry = b_queue_first(&msg->msg_params);
|
b_queue_entry *entry = b_queue_first(&msg->msg_params);
|
||||||
while (entry) {
|
while (entry) {
|
||||||
@@ -429,20 +487,27 @@ static int emit_interface_msg_function_send_impl(
|
|||||||
switch (param->p_type->ty_id) {
|
switch (param->p_type->ty_id) {
|
||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"msg.msg_request.%s = %s;\n\n",
|
"msg_data.msg_request.%s = %s;\n\n",
|
||||||
param->p_name,
|
param->p_name,
|
||||||
param->p_name);
|
param->p_name);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HANDLE:
|
||||||
|
emit(ctx,
|
||||||
|
"msg_data.msg_request.%s = %zu;\n",
|
||||||
|
param->p_name,
|
||||||
|
nr_req_handles);
|
||||||
|
nr_req_handles++;
|
||||||
|
break;
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"msg.msg_request.%s_offset = offset;\n",
|
"msg_data.msg_request.%s_offset = offset;\n",
|
||||||
param->p_name);
|
param->p_name);
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"msg.msg_request.%s_len = strlen(%s);\n",
|
"msg_data.msg_request.%s_len = strlen(%s);\n",
|
||||||
param->p_name,
|
param->p_name,
|
||||||
param->p_name);
|
param->p_name);
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"offset += msg.msg_request.%s_len;\n",
|
"offset += msg_data.msg_request.%s_len;\n",
|
||||||
param->p_name);
|
param->p_name);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -459,10 +524,13 @@ static int emit_interface_msg_function_send_impl(
|
|||||||
switch (param->p_type->ty_id) {
|
switch (param->p_type->ty_id) {
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"msg.msg_request.%s_max = out_%s->str_max;\n",
|
"msg_data.msg_request.%s_max = out_%s->str_max;\n",
|
||||||
param->p_name,
|
param->p_name,
|
||||||
param->p_name);
|
param->p_name);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HANDLE:
|
||||||
|
nr_resp_handles++;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -470,9 +538,9 @@ static int emit_interface_msg_function_send_impl(
|
|||||||
entry = b_queue_next(entry);
|
entry = b_queue_next(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit(ctx, "struct iovec req_iov[] = {\n");
|
emit(ctx, "kern_iovec_t req_iov[] = {\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx, "IOVEC(&msg, sizeof msg),\n");
|
emit(ctx, "IOVEC(&msg_data, sizeof msg_data),\n");
|
||||||
size_t nr_req_iov = 1;
|
size_t nr_req_iov = 1;
|
||||||
|
|
||||||
entry = b_queue_first(&msg->msg_params);
|
entry = b_queue_first(&msg->msg_params);
|
||||||
@@ -485,7 +553,7 @@ static int emit_interface_msg_function_send_impl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"IOVEC(%s, msg.msg_request.%s_len),\n",
|
"IOVEC(%s, msg_data.msg_request.%s_len),\n",
|
||||||
param->p_name,
|
param->p_name,
|
||||||
param->p_name);
|
param->p_name);
|
||||||
|
|
||||||
@@ -496,9 +564,15 @@ static int emit_interface_msg_function_send_impl(
|
|||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
emit(ctx, "};\n\n");
|
emit(ctx, "};\n\n");
|
||||||
|
|
||||||
emit(ctx, "struct iovec resp_iov[] = {\n");
|
if (nr_req_handles) {
|
||||||
|
emit(ctx,
|
||||||
|
"kern_msg_handle_t req_handles[%zu] = {0};\n",
|
||||||
|
nr_req_handles);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(ctx, "kern_iovec_t resp_iov[] = {\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx, "IOVEC(&msg, sizeof msg),\n");
|
emit(ctx, "IOVEC(&msg_data, sizeof msg_data),\n");
|
||||||
size_t nr_resp_iov = 1;
|
size_t nr_resp_iov = 1;
|
||||||
|
|
||||||
entry = b_queue_first(&msg->msg_results);
|
entry = b_queue_first(&msg->msg_results);
|
||||||
@@ -522,8 +596,46 @@ static int emit_interface_msg_function_send_impl(
|
|||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
emit(ctx, "};\n\n");
|
emit(ctx, "};\n\n");
|
||||||
|
|
||||||
emit(ctx, "kern_status_t status = msg_send(port, req_iov, %zu, resp_iov, %zu);\n", nr_req_iov, nr_resp_iov);
|
if (nr_resp_handles) {
|
||||||
|
emit(ctx,
|
||||||
|
"kern_msg_handle_t resp_handles[%zu] = {0};\n",
|
||||||
|
nr_resp_handles);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(ctx, "kern_msg_t msg = {\n");
|
||||||
|
emit_indent(ctx);
|
||||||
|
emit(ctx, ".msg_data = req_iov,\n.msg_data_count = %zu,\n", nr_req_iov);
|
||||||
|
|
||||||
|
if (nr_req_handles) {
|
||||||
|
emit(ctx,
|
||||||
|
".msg_handles = req_handles,\n.msg_handles_count = %zu.",
|
||||||
|
nr_req_handles);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit_unindent(ctx);
|
||||||
|
emit(ctx, "};\n\n");
|
||||||
|
|
||||||
|
emit(ctx, "kern_msg_t reply = {\n");
|
||||||
|
emit_indent(ctx);
|
||||||
|
emit(ctx,
|
||||||
|
".msg_data = resp_iov,\n.msg_data_count = %zu,\n",
|
||||||
|
nr_resp_iov);
|
||||||
|
|
||||||
|
if (nr_resp_handles) {
|
||||||
|
emit(ctx,
|
||||||
|
".msg_handles = resp_handles,\n.msg_handles_count = "
|
||||||
|
"%zu,\n",
|
||||||
|
nr_resp_handles);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit_unindent(ctx);
|
||||||
|
emit(ctx, "};\n\n");
|
||||||
|
|
||||||
|
emit(ctx, "kern_status_t status = msg_send(port, &msg, &reply);\n");
|
||||||
emit(ctx, "if (status != KERN_OK) return status;\n\n");
|
emit(ctx, "if (status != KERN_OK) return status;\n\n");
|
||||||
|
emit(ctx,
|
||||||
|
"if (msg_data.msg_header.hdr_status != KERN_OK) return "
|
||||||
|
"msg_data.msg_header.hdr_status;\n\n");
|
||||||
|
|
||||||
entry = b_queue_first(&msg->msg_results);
|
entry = b_queue_first(&msg->msg_results);
|
||||||
while (entry) {
|
while (entry) {
|
||||||
@@ -532,7 +644,8 @@ static int emit_interface_msg_function_send_impl(
|
|||||||
switch (param->p_type->ty_id) {
|
switch (param->p_type->ty_id) {
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"out_%s->str_len = msg.msg_response.%s_len;\n",
|
"out_%s->str_len = "
|
||||||
|
"msg_data.msg_response.%s_len;\n",
|
||||||
param->p_name,
|
param->p_name,
|
||||||
param->p_name);
|
param->p_name);
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
@@ -545,12 +658,24 @@ static int emit_interface_msg_function_send_impl(
|
|||||||
param->p_name,
|
param->p_name,
|
||||||
param->p_name);
|
param->p_name);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HANDLE:
|
||||||
|
emit(ctx, "*out_%s = ", param->p_name);
|
||||||
|
emit(ctx,
|
||||||
|
"msg_data.msg_response.%s < %zu ",
|
||||||
|
param->p_name,
|
||||||
|
nr_resp_handles);
|
||||||
|
emit(ctx,
|
||||||
|
"? "
|
||||||
|
"resp_handles[msg_data.msg_response.%s].hnd_"
|
||||||
|
"value ",
|
||||||
|
param->p_name);
|
||||||
|
emit(ctx, ": KERN_HANDLE_INVALID;\n");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"*out_%s = msg.msg_response.%s;\n",
|
"*out_%s = msg_data.msg_response.%s;\n",
|
||||||
param->p_name,
|
param->p_name,
|
||||||
param->p_name);
|
param->p_name);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -566,16 +691,20 @@ static int emit_interface_msg_function_recv_impl(
|
|||||||
const struct interface_definition *iface,
|
const struct interface_definition *iface,
|
||||||
const struct msg_definition *msg)
|
const struct msg_definition *msg)
|
||||||
{
|
{
|
||||||
emit(ctx, "struct msg_%s_%s msg;\n", iface->if_name, msg->msg_name);
|
emit(ctx,
|
||||||
emit(ctx, "struct iovec iov = IOVEC(&msg, sizeof msg);\n");
|
"struct msg_%s_%s msg_data;\n",
|
||||||
|
iface->if_name,
|
||||||
|
msg->msg_name);
|
||||||
|
emit(ctx, "kern_iovec_t iov = IOVEC(&msg_data, sizeof msg_data);\n");
|
||||||
emit(ctx, "size_t r = 0;\n\n");
|
emit(ctx, "size_t r = 0;\n\n");
|
||||||
|
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"kern_status_t status = msg_read(channel, id, 0, &iov, 1, "
|
"kern_status_t status = msg_read(channel, sender->e_msg, 0, &iov, "
|
||||||
"&r);\n");
|
"1, &r);\n");
|
||||||
|
|
||||||
emit(ctx, "if (status != KERN_OK) return status;\n");
|
emit(ctx, "if (status != KERN_OK) return status;\n");
|
||||||
emit(ctx, "if (r != sizeof msg) return KERN_INVALID_ARGUMENT;\n\n");
|
emit(ctx,
|
||||||
|
"if (r != sizeof msg_data) return KERN_INVALID_ARGUMENT;\n\n");
|
||||||
|
|
||||||
b_queue_entry *entry = b_queue_first(&msg->msg_params);
|
b_queue_entry *entry = b_queue_first(&msg->msg_params);
|
||||||
while (entry) {
|
while (entry) {
|
||||||
@@ -584,13 +713,23 @@ static int emit_interface_msg_function_recv_impl(
|
|||||||
switch (param->p_type->ty_id) {
|
switch (param->p_type->ty_id) {
|
||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"*out_%s = msg.msg_request.%s;\n",
|
"*out_%s = msg_data.msg_request.%s;\n",
|
||||||
param->p_name,
|
param->p_name,
|
||||||
param->p_name);
|
param->p_name);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HANDLE:
|
||||||
|
emit(ctx, "*out_%s = ", param->p_name);
|
||||||
|
emit(ctx,
|
||||||
|
"msg_data.msg_request.%s < nr_handles ",
|
||||||
|
param->p_name);
|
||||||
|
emit(ctx,
|
||||||
|
"? handles[msg_data.msg_request.%s].hnd_value ",
|
||||||
|
param->p_name);
|
||||||
|
emit(ctx, ": KERN_HANDLE_INVALID;\n", param->p_name);
|
||||||
|
break;
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"out_%s->str_len = msg.msg_request.%s_len;\n",
|
"out_%s->str_len = msg_data.msg_request.%s_len;\n",
|
||||||
param->p_name,
|
param->p_name,
|
||||||
param->p_name);
|
param->p_name);
|
||||||
|
|
||||||
@@ -614,9 +753,9 @@ static int emit_interface_msg_function_recv_impl(
|
|||||||
emit(ctx, "status = msg_read(\n");
|
emit(ctx, "status = msg_read(\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx, "channel,\n");
|
emit(ctx, "channel,\n");
|
||||||
emit(ctx, "id,\n");
|
emit(ctx, "sender->e_msg,\n");
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"msg.msg_request.%s_offset,\n",
|
"msg_data.msg_request.%s_offset,\n",
|
||||||
param->p_name);
|
param->p_name);
|
||||||
emit(ctx, "&iov,\n");
|
emit(ctx, "&iov,\n");
|
||||||
emit(ctx, "1,\n");
|
emit(ctx, "1,\n");
|
||||||
@@ -662,21 +801,23 @@ static int emit_interface_msg_function_reply_impl(
|
|||||||
b_string_toupper(msg_ucase);
|
b_string_toupper(msg_ucase);
|
||||||
|
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"struct msg_%s_%s msg = {0};\n",
|
"struct msg_%s_%s msg_data = {0};\n",
|
||||||
iface->if_name,
|
iface->if_name,
|
||||||
msg->msg_name);
|
msg->msg_name);
|
||||||
emit(ctx, "msg.msg_header.hdr_magic = MSG_MAGIC;\n");
|
emit(ctx, "msg_data.msg_header.hdr_magic = MSG_MAGIC;\n");
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"msg.msg_header.hdr_protocol = PROTOCOL_%s;\n",
|
"msg_data.msg_header.hdr_protocol = PROTOCOL_%s;\n",
|
||||||
b_string_ptr(iface_ucase));
|
b_string_ptr(iface_ucase));
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"msg.msg_header.hdr_func = MSG_%s_%s;\n\n",
|
"msg_data.msg_header.hdr_func = MSG_%s_%s;\n\n",
|
||||||
b_string_ptr(iface_ucase),
|
b_string_ptr(iface_ucase),
|
||||||
b_string_ptr(msg_ucase));
|
b_string_ptr(msg_ucase));
|
||||||
|
|
||||||
b_string_unref(iface_ucase);
|
b_string_unref(iface_ucase);
|
||||||
b_string_unref(msg_ucase);
|
b_string_unref(msg_ucase);
|
||||||
|
|
||||||
|
size_t handle_index = 0;
|
||||||
|
|
||||||
b_queue_entry *entry = b_queue_first(&msg->msg_results);
|
b_queue_entry *entry = b_queue_first(&msg->msg_results);
|
||||||
while (entry) {
|
while (entry) {
|
||||||
struct msg_parameter *param
|
struct msg_parameter *param
|
||||||
@@ -684,13 +825,20 @@ static int emit_interface_msg_function_reply_impl(
|
|||||||
switch (param->p_type->ty_id) {
|
switch (param->p_type->ty_id) {
|
||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"msg.msg_response.%s = %s;\n\n",
|
"msg_data.msg_response.%s = %s;\n\n",
|
||||||
param->p_name,
|
param->p_name,
|
||||||
param->p_name);
|
param->p_name);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HANDLE:
|
||||||
|
emit(ctx,
|
||||||
|
"msg_data.msg_response.%s = %zu;\n\n",
|
||||||
|
param->p_name,
|
||||||
|
handle_index);
|
||||||
|
handle_index++;
|
||||||
|
break;
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"msg.msg_response.%s_len = strlen(%s);\n",
|
"msg_data.msg_response.%s_len = strlen(%s);\n",
|
||||||
param->p_name,
|
param->p_name,
|
||||||
param->p_name);
|
param->p_name);
|
||||||
break;
|
break;
|
||||||
@@ -701,9 +849,9 @@ static int emit_interface_msg_function_reply_impl(
|
|||||||
entry = b_queue_next(entry);
|
entry = b_queue_next(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit(ctx, "\nstruct iovec iov[] = {\n");
|
emit(ctx, "\nkern_iovec_t iov[] = {\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx, "IOVEC(&msg, sizeof msg),\n");
|
emit(ctx, "IOVEC(&msg_data, sizeof msg_data),\n");
|
||||||
size_t nr_iov = 1;
|
size_t nr_iov = 1;
|
||||||
|
|
||||||
entry = b_queue_first(&msg->msg_results);
|
entry = b_queue_first(&msg->msg_results);
|
||||||
@@ -713,7 +861,7 @@ static int emit_interface_msg_function_reply_impl(
|
|||||||
switch (param->p_type->ty_id) {
|
switch (param->p_type->ty_id) {
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"IOVEC(%s, msg.msg_response.%s_len),\n",
|
"IOVEC(%s, msg_data.msg_response.%s_len),\n",
|
||||||
param->p_name,
|
param->p_name,
|
||||||
param->p_name);
|
param->p_name);
|
||||||
nr_iov++;
|
nr_iov++;
|
||||||
@@ -728,7 +876,45 @@ static int emit_interface_msg_function_reply_impl(
|
|||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
emit(ctx, "};\n\n");
|
emit(ctx, "};\n\n");
|
||||||
|
|
||||||
emit(ctx, "return msg_reply(channel, id, iov, %zu);\n", nr_iov);
|
if (handle_index) {
|
||||||
|
emit(ctx, "kern_msg_handle_t handles[] = {\n");
|
||||||
|
emit_indent(ctx);
|
||||||
|
entry = b_queue_first(&msg->msg_results);
|
||||||
|
while (entry) {
|
||||||
|
struct msg_parameter *param
|
||||||
|
= b_unbox(struct msg_parameter, entry, p_entry);
|
||||||
|
switch (param->p_type->ty_id) {
|
||||||
|
case TYPE_HANDLE:
|
||||||
|
emit(ctx,
|
||||||
|
"{ .hnd_value = %s, .hnd_mode = "
|
||||||
|
"KERN_MSG_HANDLE_MOVE, },\n",
|
||||||
|
param->p_name);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = b_queue_next(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit_unindent(ctx);
|
||||||
|
emit(ctx, "};\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(ctx, "kern_msg_t reply = {\n");
|
||||||
|
emit_indent(ctx);
|
||||||
|
emit(ctx, ".msg_data = iov,\n.msg_data_count = %zu,\n", nr_iov);
|
||||||
|
|
||||||
|
if (handle_index) {
|
||||||
|
emit(ctx,
|
||||||
|
".msg_handles = handles,\n.msg_handles_count = %zu,\n",
|
||||||
|
handle_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit_unindent(ctx);
|
||||||
|
emit(ctx, "};\n\n");
|
||||||
|
|
||||||
|
emit(ctx, "return msg_reply(channel, sender->e_msg, &reply);\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -758,6 +944,9 @@ static int emit_interface_msg_function_send(
|
|||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
emit(ctx, "int %s", param->p_name);
|
emit(ctx, "int %s", param->p_name);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HANDLE:
|
||||||
|
emit(ctx, "kern_handle_t %s", param->p_name);
|
||||||
|
break;
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
emit(ctx, "const char *%s", param->p_name);
|
emit(ctx, "const char *%s", param->p_name);
|
||||||
break;
|
break;
|
||||||
@@ -776,6 +965,9 @@ static int emit_interface_msg_function_send(
|
|||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
emit(ctx, "int *out_%s", param->p_name);
|
emit(ctx, "int *out_%s", param->p_name);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HANDLE:
|
||||||
|
emit(ctx, "kern_handle_t *out_%s", param->p_name);
|
||||||
|
break;
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
emit(ctx, "struct msg_string *out_%s", param->p_name);
|
emit(ctx, "struct msg_string *out_%s", param->p_name);
|
||||||
break;
|
break;
|
||||||
@@ -818,7 +1010,9 @@ static int emit_interface_msg_function_recv(
|
|||||||
|
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
|
|
||||||
emit(ctx, "kern_handle_t channel,\nmsgid_t id");
|
emit(ctx,
|
||||||
|
"kern_handle_t channel,\nconst struct msg_endpoint *sender,\n"
|
||||||
|
"kern_msg_handle_t *handles,\nsize_t nr_handles");
|
||||||
|
|
||||||
b_queue_entry *entry = b_queue_first(&msg->msg_params);
|
b_queue_entry *entry = b_queue_first(&msg->msg_params);
|
||||||
while (entry) {
|
while (entry) {
|
||||||
@@ -829,6 +1023,9 @@ static int emit_interface_msg_function_recv(
|
|||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
emit(ctx, "int *out_%s", param->p_name);
|
emit(ctx, "int *out_%s", param->p_name);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HANDLE:
|
||||||
|
emit(ctx, "kern_handle_t *out_%s", param->p_name);
|
||||||
|
break;
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
emit(ctx, "struct msg_string *out_%s", param->p_name);
|
emit(ctx, "struct msg_string *out_%s", param->p_name);
|
||||||
break;
|
break;
|
||||||
@@ -874,7 +1071,7 @@ static int emit_interface_msg_function_reply(
|
|||||||
|
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
|
|
||||||
emit(ctx, "kern_handle_t channel,\nmsgid_t id");
|
emit(ctx, "kern_handle_t channel,\nconst struct msg_endpoint *sender");
|
||||||
|
|
||||||
b_queue_entry *entry = b_queue_first(&msg->msg_results);
|
b_queue_entry *entry = b_queue_first(&msg->msg_results);
|
||||||
while (entry) {
|
while (entry) {
|
||||||
@@ -885,6 +1082,9 @@ static int emit_interface_msg_function_reply(
|
|||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
emit(ctx, "int %s", param->p_name);
|
emit(ctx, "int %s", param->p_name);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HANDLE:
|
||||||
|
emit(ctx, "kern_handle_t %s", param->p_name);
|
||||||
|
break;
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
emit(ctx, "const char *%s", param->p_name);
|
emit(ctx, "const char *%s", param->p_name);
|
||||||
break;
|
break;
|
||||||
@@ -949,7 +1149,7 @@ static int emit_interface_dispatcher_impl_msg(
|
|||||||
const struct msg_definition *msg)
|
const struct msg_definition *msg)
|
||||||
{
|
{
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"if (!vtable->%s) return msg_reply_generic(channel, id, msg, "
|
"if (!vtable->%s) return msg_reply_generic(channel, sender, msg, "
|
||||||
"KERN_UNIMPLEMENTED);\n",
|
"KERN_UNIMPLEMENTED);\n",
|
||||||
msg->msg_name);
|
msg->msg_name);
|
||||||
b_queue_entry *entry = b_queue_first(&msg->msg_params);
|
b_queue_entry *entry = b_queue_first(&msg->msg_params);
|
||||||
@@ -997,6 +1197,9 @@ static int emit_interface_dispatcher_impl_msg(
|
|||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
emit(ctx, "int %s;\n", param->p_name);
|
emit(ctx, "int %s;\n", param->p_name);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HANDLE:
|
||||||
|
emit(ctx, "kern_handle_t %s;\n", param->p_name);
|
||||||
|
break;
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
emit(ctx,
|
emit(ctx,
|
||||||
"struct msg_string %s = {0};\n",
|
"struct msg_string %s = {0};\n",
|
||||||
@@ -1028,7 +1231,7 @@ static int emit_interface_dispatcher_impl_msg(
|
|||||||
|
|
||||||
emit(ctx, "status = %s_%s_recv(\n", iface->if_name, msg->msg_name);
|
emit(ctx, "status = %s_%s_recv(\n", iface->if_name, msg->msg_name);
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx, "channel,\nid");
|
emit(ctx, "channel,\nsender,\nhandles,\nnr_handles");
|
||||||
entry = b_queue_first(&msg->msg_params);
|
entry = b_queue_first(&msg->msg_params);
|
||||||
while (entry) {
|
while (entry) {
|
||||||
struct msg_parameter *param
|
struct msg_parameter *param
|
||||||
@@ -1043,7 +1246,7 @@ static int emit_interface_dispatcher_impl_msg(
|
|||||||
|
|
||||||
emit(ctx, "if (status != KERN_OK) {\n");
|
emit(ctx, "if (status != KERN_OK) {\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx, "msg_reply_generic(channel, id, msg, status);\n");
|
emit(ctx, "msg_reply_generic(channel, sender, msg, status);\n");
|
||||||
emit(ctx, "return status;\n");
|
emit(ctx, "return status;\n");
|
||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
emit(ctx, "}\n");
|
emit(ctx, "}\n");
|
||||||
@@ -1083,7 +1286,7 @@ static int emit_interface_dispatcher_impl_msg(
|
|||||||
|
|
||||||
emit(ctx, "status = %s_%s_recv(\n", iface->if_name, msg->msg_name);
|
emit(ctx, "status = %s_%s_recv(\n", iface->if_name, msg->msg_name);
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx, "channel,\nid");
|
emit(ctx, "channel,\nsender,\nhandles,\nnr_handles");
|
||||||
entry = b_queue_first(&msg->msg_params);
|
entry = b_queue_first(&msg->msg_params);
|
||||||
while (entry) {
|
while (entry) {
|
||||||
struct msg_parameter *param
|
struct msg_parameter *param
|
||||||
@@ -1098,7 +1301,7 @@ static int emit_interface_dispatcher_impl_msg(
|
|||||||
emit(ctx, "if (status != KERN_OK) {\n");
|
emit(ctx, "if (status != KERN_OK) {\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit_string_destructor_list(ctx, b_queue_last(&msg->msg_params));
|
emit_string_destructor_list(ctx, b_queue_last(&msg->msg_params));
|
||||||
emit(ctx, "msg_reply_generic(channel, id, msg, status);\n");
|
emit(ctx, "msg_reply_generic(channel, sender, msg, status);\n");
|
||||||
emit(ctx, "return status;\n");
|
emit(ctx, "return status;\n");
|
||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
emit(ctx, "}\n");
|
emit(ctx, "}\n");
|
||||||
@@ -1109,18 +1312,18 @@ static int emit_interface_dispatcher_impl_msg(
|
|||||||
|
|
||||||
emit(ctx, "status = vtable->%s(\n", msg->msg_name);
|
emit(ctx, "status = vtable->%s(\n", msg->msg_name);
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
|
emit(ctx, "sender");
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
entry = b_queue_first(&msg->msg_params);
|
entry = b_queue_first(&msg->msg_params);
|
||||||
while (entry) {
|
while (entry) {
|
||||||
struct msg_parameter *param
|
struct msg_parameter *param
|
||||||
= b_unbox(struct msg_parameter, entry, p_entry);
|
= b_unbox(struct msg_parameter, entry, p_entry);
|
||||||
if (i > 0) {
|
|
||||||
emit(ctx, ",\n");
|
emit(ctx, ",\n");
|
||||||
}
|
|
||||||
|
|
||||||
switch (param->p_type->ty_id) {
|
switch (param->p_type->ty_id) {
|
||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
|
case TYPE_HANDLE:
|
||||||
emit(ctx, "%s", param->p_name);
|
emit(ctx, "%s", param->p_name);
|
||||||
break;
|
break;
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
@@ -1138,9 +1341,7 @@ static int emit_interface_dispatcher_impl_msg(
|
|||||||
while (entry) {
|
while (entry) {
|
||||||
struct msg_parameter *param
|
struct msg_parameter *param
|
||||||
= b_unbox(struct msg_parameter, entry, p_entry);
|
= b_unbox(struct msg_parameter, entry, p_entry);
|
||||||
if (i > 0) {
|
|
||||||
emit(ctx, ",\n");
|
emit(ctx, ",\n");
|
||||||
}
|
|
||||||
|
|
||||||
emit(ctx, "&%s", param->p_name);
|
emit(ctx, "&%s", param->p_name);
|
||||||
|
|
||||||
@@ -1148,6 +1349,12 @@ static int emit_interface_dispatcher_impl_msg(
|
|||||||
entry = b_queue_next(entry);
|
entry = b_queue_next(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i > 0) {
|
||||||
|
emit(ctx, ",\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(ctx, "arg");
|
||||||
|
|
||||||
emit(ctx, ");\n");
|
emit(ctx, ");\n");
|
||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
|
|
||||||
@@ -1161,14 +1368,14 @@ static int emit_interface_dispatcher_impl_msg(
|
|||||||
|
|
||||||
emit(ctx, "if (status != KERN_OK) {\n");
|
emit(ctx, "if (status != KERN_OK) {\n");
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx, "msg_reply_generic(channel, id, msg, status);\n");
|
emit(ctx, "msg_reply_generic(channel, sender, msg, status);\n");
|
||||||
emit(ctx, "return status;\n");
|
emit(ctx, "return status;\n");
|
||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
emit(ctx, "}\n\n");
|
emit(ctx, "}\n\n");
|
||||||
|
|
||||||
emit(ctx, "status = %s_%s_reply(\n", iface->if_name, msg->msg_name);
|
emit(ctx, "status = %s_%s_reply(\n", iface->if_name, msg->msg_name);
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx, "channel,\nid");
|
emit(ctx, "channel,\nsender");
|
||||||
entry = b_queue_first(&msg->msg_results);
|
entry = b_queue_first(&msg->msg_results);
|
||||||
while (entry) {
|
while (entry) {
|
||||||
struct msg_parameter *param
|
struct msg_parameter *param
|
||||||
@@ -1176,6 +1383,7 @@ static int emit_interface_dispatcher_impl_msg(
|
|||||||
|
|
||||||
switch (param->p_type->ty_id) {
|
switch (param->p_type->ty_id) {
|
||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
|
case TYPE_HANDLE:
|
||||||
emit(ctx, ",\n%s", param->p_name);
|
emit(ctx, ",\n%s", param->p_name);
|
||||||
break;
|
break;
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
@@ -1258,8 +1466,11 @@ static int emit_interface_dispatcher(
|
|||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
emit(ctx, "kern_handle_t channel,\n");
|
emit(ctx, "kern_handle_t channel,\n");
|
||||||
emit(ctx, "const struct %s_vtable *vtable,\n", iface->if_name);
|
emit(ctx, "const struct %s_vtable *vtable,\n", iface->if_name);
|
||||||
emit(ctx, "msgid_t id,\n");
|
emit(ctx, "const struct msg_endpoint *sender,\n");
|
||||||
emit(ctx, "const struct msg_header *msg)", iface->if_name);
|
emit(ctx, "const struct msg_header *msg,\n");
|
||||||
|
emit(ctx, "kern_msg_handle_t *handles,\n");
|
||||||
|
emit(ctx, "size_t nr_handles,\n\n");
|
||||||
|
emit(ctx, "void *arg)\n\n");
|
||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
|
|
||||||
if (prototype_only) {
|
if (prototype_only) {
|
||||||
@@ -1303,7 +1514,9 @@ static int emit_interface_vtable_entry(
|
|||||||
const struct interface_definition *iface,
|
const struct interface_definition *iface,
|
||||||
const struct msg_definition *msg)
|
const struct msg_definition *msg)
|
||||||
{
|
{
|
||||||
emit(ctx, "kern_status_t(*%s)(\n", msg->msg_name);
|
emit(ctx,
|
||||||
|
"kern_status_t(*%s)(\nconst struct msg_endpoint *sender\n",
|
||||||
|
msg->msg_name);
|
||||||
emit_indent(ctx);
|
emit_indent(ctx);
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
@@ -1311,14 +1524,15 @@ static int emit_interface_vtable_entry(
|
|||||||
while (entry) {
|
while (entry) {
|
||||||
struct msg_parameter *param
|
struct msg_parameter *param
|
||||||
= b_unbox(struct msg_parameter, entry, p_entry);
|
= b_unbox(struct msg_parameter, entry, p_entry);
|
||||||
if (i > 0) {
|
|
||||||
emit(ctx, ",\n");
|
emit(ctx, ",\n");
|
||||||
}
|
|
||||||
|
|
||||||
switch (param->p_type->ty_id) {
|
switch (param->p_type->ty_id) {
|
||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
emit(ctx, "int %s", param->p_name);
|
emit(ctx, "int %s", param->p_name);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HANDLE:
|
||||||
|
emit(ctx, "kern_handle_t %s", param->p_name);
|
||||||
|
break;
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
emit(ctx, "const char *%s", param->p_name);
|
emit(ctx, "const char *%s", param->p_name);
|
||||||
break;
|
break;
|
||||||
@@ -1334,14 +1548,15 @@ static int emit_interface_vtable_entry(
|
|||||||
while (entry) {
|
while (entry) {
|
||||||
struct msg_parameter *param
|
struct msg_parameter *param
|
||||||
= b_unbox(struct msg_parameter, entry, p_entry);
|
= b_unbox(struct msg_parameter, entry, p_entry);
|
||||||
if (i > 0) {
|
|
||||||
emit(ctx, ",\n");
|
emit(ctx, ",\n");
|
||||||
}
|
|
||||||
|
|
||||||
switch (param->p_type->ty_id) {
|
switch (param->p_type->ty_id) {
|
||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
emit(ctx, "int *out_%s", param->p_name);
|
emit(ctx, "int *out_%s", param->p_name);
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HANDLE:
|
||||||
|
emit(ctx, "kern_handle_t *out_%s", param->p_name);
|
||||||
|
break;
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
emit(ctx, "struct msg_string *out_%s", param->p_name);
|
emit(ctx, "struct msg_string *out_%s", param->p_name);
|
||||||
break;
|
break;
|
||||||
@@ -1353,6 +1568,12 @@ static int emit_interface_vtable_entry(
|
|||||||
entry = b_queue_next(entry);
|
entry = b_queue_next(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i > 0) {
|
||||||
|
emit(ctx, ",\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
emit(ctx, "void *arg");
|
||||||
|
|
||||||
emit(ctx, ");\n", msg->msg_name);
|
emit(ctx, ");\n", msg->msg_name);
|
||||||
emit_unindent(ctx);
|
emit_unindent(ctx);
|
||||||
|
|
||||||
@@ -1393,6 +1614,7 @@ static int emit_header(
|
|||||||
emit_include(ctx, "stdlib.h", true);
|
emit_include(ctx, "stdlib.h", true);
|
||||||
emit(ctx, "#endif\n");
|
emit(ctx, "#endif\n");
|
||||||
emit_include(ctx, "mango/msg.h", true);
|
emit_include(ctx, "mango/msg.h", true);
|
||||||
|
emit_include(ctx, "mango/types.h", true);
|
||||||
emit(ctx, "\n");
|
emit(ctx, "\n");
|
||||||
|
|
||||||
emit_header_lib_definitions(ctx);
|
emit_header_lib_definitions(ctx);
|
||||||
@@ -1430,6 +1652,7 @@ static int emit_interface(const struct interface_definition *iface)
|
|||||||
|
|
||||||
struct emit_ctx ctx = {
|
struct emit_ctx ctx = {
|
||||||
.ctx_out = file,
|
.ctx_out = file,
|
||||||
|
.ctx_max_handle_params = get_max_handle_params(iface),
|
||||||
};
|
};
|
||||||
|
|
||||||
int err = emit_header(&ctx, iface);
|
int err = emit_header(&ctx, iface);
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ const struct type *ctx_get_type(struct ctx *ctx, const char *name)
|
|||||||
return ctx_get_builtin_type(ctx, TYPE_INT);
|
return ctx_get_builtin_type(ctx, TYPE_INT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strcmp(name, "handle")) {
|
||||||
|
return ctx_get_builtin_type(ctx, TYPE_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -195,6 +195,7 @@ struct msg_definition *parse_msg_definition(struct ctx *ctx, struct lex *lex)
|
|||||||
|
|
||||||
msg_definition_add_result(msg, type, result_name);
|
msg_definition_add_result(msg, type, result_name);
|
||||||
free(result_name);
|
free(result_name);
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parse_symbol(lex, SYM_SEMICOLON)) {
|
if (!parse_symbol(lex, SYM_SEMICOLON)) {
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ void type_print(const struct type *ty)
|
|||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
printf("string");
|
printf("string");
|
||||||
break;
|
break;
|
||||||
|
case TYPE_HANDLE:
|
||||||
|
printf("handle");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ enum type_id {
|
|||||||
TYPE_NONE,
|
TYPE_NONE,
|
||||||
TYPE_INT,
|
TYPE_INT,
|
||||||
TYPE_STRING,
|
TYPE_STRING,
|
||||||
|
TYPE_HANDLE,
|
||||||
TYPE_OTHER,
|
TYPE_OTHER,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user