Compare commits

...

20 Commits

Author SHA1 Message Date
Bananymous 755d41ca4e LibC: Add pw_passwd and pw_gecos to passwd structure
This information is available in /etc/passwd either way so why not
expose it to the user. Practically all UNIX-likes have these either way
2025-06-02 12:23:06 +03:00
Bananymous bbff9f89b0 BuildSystem: Don't invoke ninja directly, but use cmake --build 2025-06-02 11:45:06 +03:00
Bananymous fdcb38ac1f Shell: Accept '\r' as enter
This happens with some terminals and i don't want to bother with fixing
my termios :D
2025-06-02 11:42:06 +03:00
Bananymous fac742c038 test-sort: Add qsort test 2025-06-02 11:41:34 +03:00
Bananymous 5a6b43fc90 LibC: Remove debug printing from getnameinfo 2025-06-02 11:39:18 +03:00
Bananymous 317f413746 LibC: Implement very hacky posix_memalign
I did not even test this and i know the code is super hacky. I could not
bother with writing proper code for this xD
2025-06-02 11:39:18 +03:00
Bananymous 895909b7fa LibC: Add CMSG_* definitions to sys/socket.h 2025-06-02 11:39:18 +03:00
Bananymous 2ee8b6c8b4 LibC: Add more definitions to netinet/in.h
These are non-standard but a lot of UNIX-likes have them networking
software attempts to use them
2025-06-02 11:39:18 +03:00
Bananymous 022bb69782 LibC: Implement inet_aton
This is not POSIX but IMO it makes sense to have the counter part to
inet_ntoa
2025-06-02 11:39:18 +03:00
Bananymous be6da3e0db BuildSystem: Compile gcc with threading support 2025-06-02 11:39:18 +03:00
Bananymous 1f07e02298 BuildSystem: Fix cmake toolchain file processor 2025-06-02 11:39:18 +03:00
Bananymous 7a645b8555 Kernel: Add SMP message StackTrace
This event is sent when user presses ctrl+{F1-F12} and it will dump the
corresponding processor's stack trace. This is really helpful for
detecting deadlocks in the system
2025-06-02 11:39:18 +03:00
Bananymous c5b0d0235f Kenrel: Allow Processor::send_smp_message to send event to current CPU 2025-06-02 11:39:18 +03:00
Bananymous b7948551ff userspace: Add empty libm and libpthread
These making porting stuff easier. I could not find a way to tell CMake
that the system does not have threads library
2025-06-02 11:39:18 +03:00
Bananymous e109b5cff6 Kernel: Remove unnecessary locks from Pipe
Inode already locks its own mutex when read/write is called there is no
need to explicitly lock them in read_impl/write_impl
2025-06-02 11:39:18 +03:00
Bananymous 9883fb7bf6 Kernel: Rewrite epoll notifying system
This removes the need to lock epoll's mutex when notifying epoll. This
prevents a ton of deadlocks when epoll is notified from an interrupt
handler or otherwise with interrupts disabled
2025-06-02 11:39:18 +03:00
Bananymous e9f8471a28 BAN: Return UTF::invalid from byte_length instead of 0 2025-06-02 11:39:18 +03:00
Bananymous 4656b11256 LibC: actually use ATEXIT_MAX for atexit limit 2025-06-02 10:43:49 +03:00
Bananymous f2ccab2df7 ports/openssl: Fix openssl
New unistd.h definitions (or something) makes openssl think recvmsg is
available, disable it manually.
2025-06-01 19:51:33 +03:00
Bananymous b2e3aefa72 Kernel: Don't crash when terminating process with signal 2025-06-01 16:59:02 +03:00
31 changed files with 414 additions and 127 deletions

View File

@ -18,7 +18,7 @@ namespace BAN::UTF8
return 3; return 3;
if ((first_byte & 0xF8) == 0xF0) if ((first_byte & 0xF8) == 0xF0)
return 4; return 4;
return 0; return UTF8::invalid;
} }
template<typename T> requires (sizeof(T) == 1) template<typename T> requires (sizeof(T) == 1)

View File

@ -98,7 +98,9 @@ namespace Kernel
private: private:
ThreadBlocker m_thread_blocker; ThreadBlocker m_thread_blocker;
SpinLock m_ready_lock;
BAN::HashMap<BAN::RefPtr<Inode>, uint32_t, InodeRefPtrHash> m_ready_events; BAN::HashMap<BAN::RefPtr<Inode>, uint32_t, InodeRefPtrHash> m_ready_events;
BAN::HashMap<BAN::RefPtr<Inode>, uint32_t, InodeRefPtrHash> m_processing_events;
BAN::HashMap<BAN::RefPtr<Inode>, ListenEventList, InodeRefPtrHash> m_listening_events; BAN::HashMap<BAN::RefPtr<Inode>, ListenEventList, InodeRefPtrHash> m_listening_events;
}; };

View File

@ -33,6 +33,7 @@ namespace Kernel
FlushTLB, FlushTLB,
NewThread, NewThread,
UnblockThread, UnblockThread,
StackTrace,
}; };
SMPMessage* next { nullptr }; SMPMessage* next { nullptr };
Type type; Type type;
@ -45,6 +46,7 @@ namespace Kernel
} flush_tlb; } flush_tlb;
SchedulerQueue::Node* new_thread; SchedulerQueue::Node* new_thread;
SchedulerQueue::Node* unblock_thread; SchedulerQueue::Node* unblock_thread;
bool dummy;
}; };
}; };

View File

@ -29,18 +29,26 @@ namespace Kernel
{ {
case EPOLL_CTL_ADD: case EPOLL_CTL_ADD:
{ {
if (it == m_listening_events.end()) bool contains_inode = (it != m_listening_events.end());
if (!contains_inode)
it = TRY(m_listening_events.emplace(inode)); it = TRY(m_listening_events.emplace(inode));
if (it->value.has_fd(fd)) if (it->value.has_fd(fd))
return BAN::Error::from_errno(EEXIST); return BAN::Error::from_errno(EEXIST);
TRY(m_ready_events.reserve(m_listening_events.size()));
TRY(inode->add_epoll(this)); {
SpinLockGuard _(m_ready_lock);
TRY(m_ready_events.reserve(m_listening_events.size()));
}
TRY(m_processing_events.reserve(m_listening_events.size()));
if (!contains_inode)
TRY(inode->add_epoll(this));
it->value.add_fd(fd, event); it->value.add_fd(fd, event);
auto ready_it = m_ready_events.find(inode); auto processing_it = m_processing_events.find(inode);
if (ready_it == m_ready_events.end()) if (processing_it == m_processing_events.end())
ready_it = MUST(m_ready_events.insert(inode, 0)); processing_it = MUST(m_processing_events.insert(inode, 0));
ready_it->value |= event.events; processing_it->value |= event.events;
return {}; return {};
} }
@ -50,12 +58,13 @@ namespace Kernel
return BAN::Error::from_errno(ENOENT); return BAN::Error::from_errno(ENOENT);
if (!it->value.has_fd(fd)) if (!it->value.has_fd(fd))
return BAN::Error::from_errno(ENOENT); return BAN::Error::from_errno(ENOENT);
it->value.events[fd] = event; it->value.events[fd] = event;
auto ready_it = m_ready_events.find(inode); auto processing_it = m_processing_events.find(inode);
if (ready_it == m_ready_events.end()) if (processing_it == m_processing_events.end())
ready_it = MUST(m_ready_events.insert(inode, 0)); processing_it = MUST(m_processing_events.insert(inode, 0));
ready_it->value |= event.events; processing_it->value |= event.events;
return {}; return {};
} }
@ -68,7 +77,10 @@ namespace Kernel
it->value.remove_fd(fd); it->value.remove_fd(fd);
if (it->value.empty()) if (it->value.empty())
{ {
inode->del_epoll(this);
m_listening_events.remove(it); m_listening_events.remove(it);
m_processing_events.remove(inode);
SpinLockGuard _(m_ready_lock);
m_ready_events.remove(inode); m_ready_events.remove(inode);
} }
return {}; return {};
@ -83,53 +95,76 @@ namespace Kernel
if (event_span.empty()) if (event_span.empty())
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
size_t count = 0; size_t event_count = 0;
for (;;) for (;;)
{ {
bool failed_lock = false;
{ {
LockGuard _(m_mutex); LockGuard _(m_mutex);
for (auto it = m_ready_events.begin(); it != m_ready_events.end() && count < event_span.size();) {
SpinLockGuard _(m_ready_lock);
while (!m_ready_events.empty())
{
auto [inode, events] = *m_ready_events.begin();
m_ready_events.remove(m_ready_events.begin());
ASSERT(events);
if (auto it = m_processing_events.find(inode); it != m_processing_events.end())
it->value |= events;
else
MUST(m_processing_events.insert(inode, events));
}
}
for (auto it = m_processing_events.begin(); it != m_processing_events.end() && event_count < event_span.size();)
{ {
auto& [inode, events] = *it; auto& [inode, events] = *it;
auto& listen = m_listening_events[inode]; #define REMOVE_IT_AND_CONTINUE() \
({ \
m_processing_events.remove(it); \
it = m_processing_events.begin(); \
continue; \
})
uint32_t listen_mask = EPOLLERR | EPOLLHUP; auto listen_it = m_listening_events.find(inode);
for (int fd = 0; fd < OPEN_MAX; fd++) if (listen_it == m_listening_events.end())
if (listen.has_fd(fd)) REMOVE_IT_AND_CONTINUE();
listen_mask |= listen.events[fd].events; auto& listen = listen_it->value;
events &= listen_mask;
// This prevents a possible deadlock
if (!inode->m_mutex.try_lock())
{ {
failed_lock = true; uint32_t listen_mask = EPOLLERR | EPOLLHUP;
continue; for (size_t fd = 0; fd < listen.events.size(); fd++)
if (listen.has_fd(fd))
listen_mask |= listen.events[fd].events;
events &= listen_mask;
} }
#define CHECK_EVENT_BIT(mask, func) \
if ((events & mask) && !inode->func()) \
events &= ~mask;
CHECK_EVENT_BIT(EPOLLIN, can_read);
CHECK_EVENT_BIT(EPOLLOUT, can_write);
CHECK_EVENT_BIT(EPOLLERR, has_error);
CHECK_EVENT_BIT(EPOLLHUP, has_hungup);
#undef CHECK_EVENT_BIT
inode->m_mutex.unlock();
if (events == 0) if (events == 0)
REMOVE_IT_AND_CONTINUE();
{ {
m_ready_events.remove(it); LockGuard inode_locker(inode->m_mutex);
it = m_ready_events.begin();
continue; #define CHECK_EVENT_BIT(mask, func) \
if ((events & mask) && !inode->func()) \
events &= ~mask;
CHECK_EVENT_BIT(EPOLLIN, can_read);
CHECK_EVENT_BIT(EPOLLOUT, can_write);
CHECK_EVENT_BIT(EPOLLERR, has_error);
CHECK_EVENT_BIT(EPOLLHUP, has_hungup);
#undef CHECK_EVENT_BIT
} }
for (int fd = 0; fd < OPEN_MAX && count < event_span.size(); fd++) if (events == 0)
REMOVE_IT_AND_CONTINUE();
#undef REMOVE_IT_AND_CONTINUE
for (size_t fd = 0; fd < listen.events.size() && event_count < event_span.size(); fd++)
{ {
if (!listen.has_fd(fd)) if (!listen.has_fd(fd))
continue; continue;
@ -139,7 +174,7 @@ namespace Kernel
if (new_events == 0) if (new_events == 0)
continue; continue;
event_span[count++] = { event_span[event_count++] = {
.events = new_events, .events = new_events,
.data = listen_event.data, .data = listen_event.data,
}; };
@ -155,32 +190,29 @@ namespace Kernel
} }
} }
if (count) if (event_count > 0)
break; break;
const uint64_t current_ns = SystemTimer::get().ns_since_boot(); const uint64_t current_ns = SystemTimer::get().ns_since_boot();
if (current_ns >= waketime_ns) if (current_ns >= waketime_ns)
break; break;
if (failed_lock)
continue;
const uint64_t timeout_ns = BAN::Math::min<uint64_t>(100'000'000, waketime_ns - current_ns); const uint64_t timeout_ns = BAN::Math::min<uint64_t>(100'000'000, waketime_ns - current_ns);
TRY(Thread::current().block_or_eintr_or_timeout_ns(m_thread_blocker, timeout_ns, false)); TRY(Thread::current().block_or_eintr_or_timeout_ns(m_thread_blocker, timeout_ns, false));
} }
return count; return event_count;
} }
void Epoll::notify(BAN::RefPtr<Inode> inode, uint32_t event) void Epoll::notify(BAN::RefPtr<Inode> inode, uint32_t event)
{ {
LockGuard _(m_mutex); ASSERT(event);
if (!m_listening_events.contains(inode)) SpinLockGuard _(m_ready_lock);
return;
auto ready_it = m_ready_events.find(inode); if (auto it = m_ready_events.find(inode); it != m_ready_events.end())
if (ready_it == m_ready_events.end()) it->value |= event;
ready_it = MUST(m_ready_events.insert(inode, 0)); else
ready_it->value |= event; MUST(m_ready_events.insert(inode, event));
m_thread_blocker.unblock(); m_thread_blocker.unblock();
} }

View File

@ -67,8 +67,6 @@ namespace Kernel
BAN::ErrorOr<size_t> Pipe::read_impl(off_t, BAN::ByteSpan buffer) BAN::ErrorOr<size_t> Pipe::read_impl(off_t, BAN::ByteSpan buffer)
{ {
LockGuard _(m_mutex);
while (m_buffer_size == 0) while (m_buffer_size == 0)
{ {
if (m_writing_count == 0) if (m_writing_count == 0)
@ -103,8 +101,6 @@ namespace Kernel
BAN::ErrorOr<size_t> Pipe::write_impl(off_t, BAN::ConstByteSpan buffer) BAN::ErrorOr<size_t> Pipe::write_impl(off_t, BAN::ConstByteSpan buffer)
{ {
LockGuard _(m_mutex);
while (m_buffer_size >= m_buffer.size()) while (m_buffer_size >= m_buffer.size())
{ {
if (m_reading_count == 0) if (m_reading_count == 0)

View File

@ -114,7 +114,37 @@ namespace Kernel
auto& key_event = event.as<const LibInput::RawKeyEvent>(); auto& key_event = event.as<const LibInput::RawKeyEvent>();
if (key_event.modifier & LibInput::KeyEvent::Modifier::Pressed) if (key_event.modifier & LibInput::KeyEvent::Modifier::Pressed)
{ {
switch (key_event.keycode) if (key_event.modifier & LibInput::KeyEvent::Modifier::LCtrl)
{
const auto processor_count = Processor::count();
switch (key_event.keycode)
{
#define DUMP_CPU_STACK_TRACE(idx) \
case LibInput::keycode_function(idx + 1): \
if (idx >= processor_count) \
break; \
Processor::send_smp_message(Processor::id_from_index(idx), { \
.type = Processor::SMPMessage::Type::StackTrace, \
.dummy = false, \
}); \
break
// F1-F12
DUMP_CPU_STACK_TRACE(0);
DUMP_CPU_STACK_TRACE(1);
DUMP_CPU_STACK_TRACE(2);
DUMP_CPU_STACK_TRACE(3);
DUMP_CPU_STACK_TRACE(4);
DUMP_CPU_STACK_TRACE(5);
DUMP_CPU_STACK_TRACE(6);
DUMP_CPU_STACK_TRACE(7);
DUMP_CPU_STACK_TRACE(8);
DUMP_CPU_STACK_TRACE(9);
DUMP_CPU_STACK_TRACE(10);
DUMP_CPU_STACK_TRACE(11);
#undef DUMP_CPU_STACK_TRACE
}
}
else switch (key_event.keycode)
{ {
case LibInput::keycode_function(1): case LibInput::keycode_function(1):
Processor::toggle_should_print_cpu_load(); Processor::toggle_should_print_cpu_load();

View File

@ -244,6 +244,10 @@ namespace Kernel
case SMPMessage::Type::UnblockThread: case SMPMessage::Type::UnblockThread:
processor.m_scheduler->unblock_thread(message->unblock_thread); processor.m_scheduler->unblock_thread(message->unblock_thread);
break; break;
case SMPMessage::Type::StackTrace:
dwarnln("Stack trace of CPU {}", current_id().as_u32());
Debug::dump_stack_trace();
break;
} }
last_handled = message; last_handled = message;
@ -275,7 +279,6 @@ namespace Kernel
void Processor::send_smp_message(ProcessorID processor_id, const SMPMessage& message, bool send_ipi) void Processor::send_smp_message(ProcessorID processor_id, const SMPMessage& message, bool send_ipi)
{ {
ASSERT(processor_id != current_id());
auto state = get_interrupt_state(); auto state = get_interrupt_state();
set_interrupt_state(InterruptState::Disabled); set_interrupt_state(InterruptState::Disabled);
@ -307,7 +310,12 @@ namespace Kernel
); );
if (send_ipi) if (send_ipi)
InterruptController::get().send_ipi(processor_id); {
if (processor_id == current_id())
handle_smp_messages();
else
InterruptController::get().send_ipi(processor_id);
}
set_interrupt_state(state); set_interrupt_state(state);
} }

View File

@ -623,6 +623,9 @@ namespace Kernel
{ {
Processor::set_interrupt_state(InterruptState::Disabled); Processor::set_interrupt_state(InterruptState::Disabled);
setup_process_cleanup(); setup_process_cleanup();
// This is super hacky but prevents a crash in yield :D
if (m_signal_lock.current_processor_has_lock())
m_signal_lock.unlock(InterruptState::Disabled);
Processor::yield(); Processor::yield();
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }

View File

@ -0,0 +1,12 @@
diff -ruN openssl-3.3.1/crypto/bio/bss_dgram.c openssl-3.3.1-banan_os/crypto/bio/bss_dgram.c
--- openssl-3.3.1/crypto/bio/bss_dgram.c 2024-06-04 15:53:04.000000000 +0300
+++ openssl-3.3.1-banan_os/crypto/bio/bss_dgram.c 2025-06-01 19:48:55.088806701 +0300
@@ -61,7 +61,7 @@
# define NO_RECVMMSG
# endif
# endif
-# if defined(__GNU__)
+# if defined(__GNU__) || defined(__banan_os__)
/* GNU/Hurd does not have IP_PKTINFO yet */
#undef NO_RECVMSG
#define NO_RECVMSG

View File

@ -37,8 +37,7 @@ build_target () {
echo "No target provided" echo "No target provided"
exit 1 exit 1
fi fi
cd $BANAN_BUILD_DIR run_fakeroot $BANAN_CMAKE --build $BANAN_BUILD_DIR -- -j$(nproc) $1
run_fakeroot ninja $1
} }
build_toolchain () { build_toolchain () {

View File

@ -19,7 +19,7 @@ endif ()
set(TOOLCHAIN_PREFIX $ENV{BANAN_ROOT_DIR}/toolchain/local) set(TOOLCHAIN_PREFIX $ENV{BANAN_ROOT_DIR}/toolchain/local)
set(CMAKE_SYSTEM_NAME banan-os) set(CMAKE_SYSTEM_NAME banan-os)
set(CMAKE_SYSTEM_PROCESSOR AMD64) set(CMAKE_SYSTEM_PROCESSOR ${BANAN_ARCH})
set(CMAKE_SYSROOT ${BANAN_SYSROOT}) set(CMAKE_SYSROOT ${BANAN_SYSROOT})

View File

@ -118,6 +118,7 @@ build_gcc () {
--prefix="$BANAN_TOOLCHAIN_PREFIX" \ --prefix="$BANAN_TOOLCHAIN_PREFIX" \
--with-sysroot="$BANAN_SYSROOT" \ --with-sysroot="$BANAN_SYSROOT" \
--enable-initfini-array \ --enable-initfini-array \
--enable-threads=posix \
--enable-shared \ --enable-shared \
--enable-lto \ --enable-lto \
--disable-nls \ --disable-nls \

View File

@ -5,6 +5,8 @@ set(USERSPACE_LIBRARIES
LibGUI LibGUI
LibImage LibImage
LibInput LibInput
LibMath
LibPthread
) )
foreach(library ${USERSPACE_LIBRARIES}) foreach(library ${USERSPACE_LIBRARIES})

View File

@ -27,28 +27,10 @@ uint16_t ntohs(uint16_t netshort)
in_addr_t inet_addr(const char* cp) in_addr_t inet_addr(const char* cp)
{ {
uint32_t a, b, c, d, n; in_addr addr;
const int ret = sscanf(cp, "%i%n.%i%n.%i%n.%i%n", if (inet_aton(cp, &addr) == 0)
&a, &n, &b, &n, &c, &n, &d, &n
);
if (ret < 1 || ret > 4 || cp[n] != '\0')
return INADDR_NONE; return INADDR_NONE;
if (ret == 1 && (a > 0xFFFFFFFF)) return addr.s_addr;
return INADDR_NONE;
if (ret == 2 && (a > 0xFF || b > 0xFFFFFF))
return INADDR_NONE;
if (ret == 3 && (a > 0xFF || b > 0xFF || c > 0xFFFF))
return INADDR_NONE;
if (ret == 4 && (a > 0xFF || b > 0xFF || c > 0xFF || d > 0xFF))
return INADDR_NONE;
uint32_t result = 0;
result |= (ret == 1) ? a : a << 24;
result |= (ret == 2) ? b : b << 16;
result |= (ret == 3) ? c : c << 8;
result |= (ret == 4) ? d : d << 0;
return htonl(result);
} }
char* inet_ntoa(struct in_addr in) char* inet_ntoa(struct in_addr in)
@ -64,6 +46,33 @@ char* inet_ntoa(struct in_addr in)
return buffer; return buffer;
} }
int inet_aton(const char* cp, struct in_addr* inp)
{
uint32_t a, b, c, d, n;
const int ret = sscanf(cp, "%i%n.%i%n.%i%n.%i%n",
&a, &n, &b, &n, &c, &n, &d, &n
);
if (ret < 1 || ret > 4 || cp[n] != '\0')
return 0;
if (ret == 1 && (a > 0xFFFFFFFF))
return 0;
if (ret == 2 && (a > 0xFF || b > 0xFFFFFF))
return 0;
if (ret == 3 && (a > 0xFF || b > 0xFF || c > 0xFFFF))
return 0;
if (ret == 4 && (a > 0xFF || b > 0xFF || c > 0xFF || d > 0xFF))
return 0;
uint32_t result = 0;
result |= (ret == 1) ? a : a << 24;
result |= (ret == 2) ? b : b << 16;
result |= (ret == 3) ? c : c << 8;
result |= (ret == 4) ? d : d << 0;
inp->s_addr = htonl(result);
return 1;
}
const char* inet_ntop(int af, const void* __restrict src, char* __restrict dst, socklen_t size) const char* inet_ntop(int af, const void* __restrict src, char* __restrict dst, socklen_t size)
{ {
if (af == AF_INET) if (af == AF_INET)

View File

@ -1,6 +1,5 @@
#include <stddef.h> #include <stddef.h>
#include <limits.h>
#define ATEXIT_MAX_FUNCS 128
struct atexit_func_entry_t struct atexit_func_entry_t
{ {
@ -9,12 +8,12 @@ struct atexit_func_entry_t
void* dso_handle; void* dso_handle;
}; };
static atexit_func_entry_t s_atexit_funcs[ATEXIT_MAX_FUNCS]; static atexit_func_entry_t s_atexit_funcs[ATEXIT_MAX];
static size_t s_atexit_func_count = 0; static size_t s_atexit_func_count = 0;
extern "C" int __cxa_atexit(void(*func)(void*), void* arg, void* dso_handle) extern "C" int __cxa_atexit(void(*func)(void*), void* arg, void* dso_handle)
{ {
if (s_atexit_func_count >= ATEXIT_MAX_FUNCS) if (s_atexit_func_count >= ATEXIT_MAX)
return -1; return -1;
s_atexit_funcs[s_atexit_func_count++] = { s_atexit_funcs[s_atexit_func_count++] = {
.func = func, .func = func,

View File

@ -11,6 +11,7 @@ __BEGIN_DECLS
#include <bits/types/socklen_t.h> #include <bits/types/socklen_t.h>
in_addr_t inet_addr(const char* cp); in_addr_t inet_addr(const char* cp);
int inet_aton(const char* cp, struct in_addr* inp);
char* inet_ntoa(struct in_addr in); char* inet_ntoa(struct in_addr in);
const char* inet_ntop(int af, const void* __restrict src, char* __restrict dst, socklen_t size); const char* inet_ntop(int af, const void* __restrict src, char* __restrict dst, socklen_t size);
int inet_pton(int af, const char* __restrict src, void* __restrict dst); int inet_pton(int af, const char* __restrict src, void* __restrict dst);

View File

@ -10,20 +10,54 @@ __BEGIN_DECLS
#include <bits/inet_common.h> #include <bits/inet_common.h>
#include <sys/socket.h> #include <sys/socket.h>
#define IPPROTO_IP 1 #define IPPROTO_IP 1
#define IPPROTO_IPV6 2 #define IPPROTO_IPV6 2
#define IPPROTO_ICMP 3 #define IPPROTO_ICMP 3
#define IPPROTO_RAW 4 #define IPPROTO_RAW 4
#define IPPROTO_TCP 5 #define IPPROTO_TCP 5
#define IPPROTO_UDP 6 #define IPPROTO_UDP 6
#define IPV6_JOIN_GROUP 1 enum
#define IPV6_LEAVE_GROUP 2 {
#define IPV6_MULTICAST_HOPS 3 IP_ADD_MEMBERSHIP,
#define IPV6_MULTICAST_IF 4 #define IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP
#define IPV6_MULTICAST_LOOP 5 IP_ADD_SOURCE_MEMBERSHIP,
#define IPV6_UNICAST_HOPS 6 #define IP_ADD_SOURCE_MEMBERSHIP IP_ADD_SOURCE_MEMBERSHIP
#define IPV6_V6ONLY 7 IP_DROP_MEMBERSHIP,
#define IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP
IP_DROP_SOURCE_MEMBERSHIP,
#define IP_DROP_SOURCE_MEMBERSHIP IP_DROP_SOURCE_MEMBERSHIP
IP_MULTICAST_IF,
#define IP_MULTICAST_IF IP_MULTICAST_IF
IP_MULTICAST_LOOP,
#define IP_MULTICAST_LOOP IP_MULTICAST_LOOP
IP_MULTICAST_TTL,
#define IP_MULTICAST_TTL IP_MULTICAST_TTL
IP_TTL,
#define IP_TTL IP_TTL
};
enum
{
IPV6_ADD_MEMBERSHIP,
#define IPV6_ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP
IPV6_DROP_MEMBERSHIP,
#define IPV6_DROP_MEMBERSHIP IPV6_DROP_MEMBERSHIP
IPV6_JOIN_GROUP,
#define IPV6_JOIN_GROUP IPV6_JOIN_GROUP
IPV6_LEAVE_GROUP,
#define IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP
IPV6_MULTICAST_HOPS,
#define IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS
IPV6_MULTICAST_IF,
#define IPV6_MULTICAST_IF IPV6_MULTICAST_IF
IPV6_MULTICAST_LOOP,
#define IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP
IPV6_UNICAST_HOPS,
#define IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS
IPV6_V6ONLY,
#define IPV6_V6ONLY IPV6_V6ONLY
};
#define INADDR_ANY 0 #define INADDR_ANY 0
#define INADDR_NONE 0xFFFFFFFF #define INADDR_NONE 0xFFFFFFFF
@ -78,6 +112,19 @@ struct ipv6_mreq
unsigned ipv6mr_interface; /* Interface index. */ unsigned ipv6mr_interface; /* Interface index. */
}; };
struct ip_mreq
{
struct in_addr imr_multiaddr; /* IP multicast group address. */
struct in_addr imr_interface; /* IP address of local interface. */
};
struct ip_mreq_source
{
struct in_addr imr_multiaddr; /* IP multicast group address. */
struct in_addr imr_interface; /* IP address of local interface. */
struct in_addr imr_sourceaddr; /* IP address of multicast source. */
};
__END_DECLS __END_DECLS
#endif #endif

View File

@ -14,11 +14,13 @@ __BEGIN_DECLS
struct passwd struct passwd
{ {
char* pw_name; /* User's login name. */ char* pw_name; /* User's login name. */
uid_t pw_uid; /* Numerical user ID. */ char* pw_passwd; /* User's hashed password. */
gid_t pw_gid; /* Numerical group ID. */ uid_t pw_uid; /* Numerical user ID. */
char* pw_dir; /* Initial working directory. */ gid_t pw_gid; /* Numerical group ID. */
char* pw_shell; /* Program to use as shell. */ char* pw_gecos; /* User's information. */
char* pw_dir; /* Initial working directory. */
char* pw_shell; /* Program to use as shell. */
}; };
void endpwent(void); void endpwent(void);

View File

@ -50,16 +50,33 @@ struct cmsghdr
socklen_t cmsg_len; /* Data byte count, including the cmsghdr. */ socklen_t cmsg_len; /* Data byte count, including the cmsghdr. */
int cmsg_level; /* Originating protocol. */ int cmsg_level; /* Originating protocol. */
int cmsg_type; /* Protocol-specific type. */ int cmsg_type; /* Protocol-specific type. */
unsigned char __cmg_data[];
}; };
// FIXME #define SCM_RIGHTS 1
#if 0
#define SCM_RIGHTS
#define CMSG_DATA(cmsg) #define CMSG_DATA(cmsg) ((cmsg)->__cmg_data)
#define CMSG_NXTHDR(mhdr, cmsg)
#define CMSG_FIRSTHDR(mhdr) #define __CMSG_NXTHDR_ADDR(cmsg) \
#endif ((unsigned char*)(cmsg) + (cmsg)->cmsg_len)
#define __CMSG_NXTHDR_OFFSET(mhdr, cmsg) \
(__CMSG_NXTHDR_ADDR(cmsg) - (unsigned char*)(mhdr)->msg_control)
#define CMSG_NXTHDR(mhdr, cmsg) \
((size_t)(mhdr)->msg_controllen \
>= __CMSG_NXTHDR_OFFSET(mhdr, cmsg) + sizeof(struct cmsghdr) \
? (struct cmsghdr*)__CMSG_NXTHDR_ADDR(cmsg) \
: (struct cmsghdr*)0)
#define CMSG_FIRSTHDR(mhdr) \
((size_t)(mhdr)->msg_controllen >= sizeof(struct cmsghdr) \
? (struct cmsghdr*)((mhdr)->msg_control) \
: (struct cmsghdr*)0)
#define CMSG_SPACE(length) \
(socklen_t)((length) + sizeof(struct cmsghdr))
#define CMSG_LEN(length) \
(socklen_t)((length) + sizeof(struct cmsghdr))
struct linger struct linger
{ {

View File

@ -1,4 +1,5 @@
#include <BAN/Debug.h> #include <BAN/Debug.h>
#include <BAN/Math.h>
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
@ -95,6 +96,12 @@ static bool allocate_pool(size_t pool_index)
node->prev_free = nullptr; node->prev_free = nullptr;
node->next_free = nullptr; node->next_free = nullptr;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#pragma GCC diagnostic ignored "-Wstringop-overflow"
node->data[-1] = 0;
#pragma GCC diagnostic pop
pool.free_list = node; pool.free_list = node;
return true; return true;
@ -143,6 +150,12 @@ static void shrink_node_if_needed(malloc_pool_t& pool, malloc_node_t* node, size
next->size = node_end - (uint8_t*)next; next->size = node_end - (uint8_t*)next;
next->last = node->last; next->last = node->last;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#pragma GCC diagnostic ignored "-Wstringop-overflow"
next->data[-1] = 0;
#pragma GCC diagnostic pop
node->last = false; node->last = false;
// insert excess node to free list // insert excess node to free list
@ -183,6 +196,29 @@ static void* allocate_from_pool(size_t pool_index, size_t size)
static malloc_node_t* node_from_data_pointer(void* data_pointer) static malloc_node_t* node_from_data_pointer(void* data_pointer)
{ {
if (((uint8_t*)data_pointer)[-1])
{
malloc_pool_t* pool = nullptr;
for (size_t i = 0; i < s_malloc_pool_count; i++)
{
if (!s_malloc_pools[i].start)
continue;
if (data_pointer < s_malloc_pools[i].start)
continue;
if (data_pointer > s_malloc_pools[i].end())
continue;
pool = &s_malloc_pools[i];
break;
}
assert(pool);
auto* node = (malloc_node_t*)pool->start;
for (; (uint8_t*)node < pool->end(); node = node->next())
if (node->data < data_pointer && data_pointer < node->next())
return node;
assert(false);
}
return (malloc_node_t*)((uint8_t*)data_pointer - sizeof(malloc_node_t)); return (malloc_node_t*)((uint8_t*)data_pointer - sizeof(malloc_node_t));
} }
@ -332,3 +368,27 @@ void* calloc(size_t nmemb, size_t size)
memset(ptr, 0, total); memset(ptr, 0, total);
return ptr; return ptr;
} }
int posix_memalign(void** memptr, size_t alignment, size_t size)
{
dprintln_if(DEBUG_MALLOC, "posix_memalign({}, {})", alignment, size);
if (alignment < sizeof(void*) || alignment % sizeof(void*) || !BAN::Math::is_power_of_two(alignment / sizeof(void*)))
{
errno = EINVAL;
return -1;
}
uint8_t* unaligned = (uint8_t*)malloc(size + alignment);
if (unaligned == nullptr)
return -1;
if (auto rem = (uintptr_t)unaligned % alignment)
{
unaligned += alignment - rem;
unaligned[-1] = 1;
}
*memptr = unaligned;
return 0;
}

View File

@ -147,11 +147,9 @@ error_close_socket:
return EAI_FAIL; return EAI_FAIL;
} }
#include <BAN/Debug.h>
int getnameinfo(const struct sockaddr* __restrict sa, socklen_t salen, char* __restrict node, socklen_t nodelen, char* __restrict service, socklen_t servicelen, int flags) int getnameinfo(const struct sockaddr* __restrict sa, socklen_t salen, char* __restrict node, socklen_t nodelen, char* __restrict service, socklen_t servicelen, int flags)
{ {
printf("getnameinfo(%p, %p, %p, 0x%X)\n", sa, node, service, flags); (void)flags;
switch (sa->sa_family) switch (sa->sa_family)
{ {

View File

@ -71,12 +71,14 @@ struct passwd* getpwent(void)
switch (i) switch (i)
{ {
case 0: case 0:
s_pwent_struct.pw_name = (char*)malloc(field_len + 1); s_pwent_struct.pw_name = strndup(ptr, field_len + 1);
if (!s_pwent_struct.pw_name) if (!s_pwent_struct.pw_name)
return nullptr; return nullptr;
strcpy(s_pwent_struct.pw_name, ptr);
break; break;
case 1: case 1:
s_pwent_struct.pw_passwd = strndup(ptr, field_len + 1);
if (!s_pwent_struct.pw_passwd)
return nullptr;
break; break;
case 2: case 2:
ASSERT(1 <= field_len && field_len <= 9); ASSERT(1 <= field_len && field_len <= 9);
@ -91,18 +93,19 @@ struct passwd* getpwent(void)
s_pwent_struct.pw_gid = atoi(ptr); s_pwent_struct.pw_gid = atoi(ptr);
break; break;
case 4: case 4:
s_pwent_struct.pw_gecos = strndup(ptr, field_len + 1);
if (!s_pwent_struct.pw_gecos)
return nullptr;
break; break;
case 5: case 5:
s_pwent_struct.pw_dir = (char*)malloc(field_len + 1); s_pwent_struct.pw_dir = strndup(ptr, field_len + 1);
if (!s_pwent_struct.pw_dir) if (!s_pwent_struct.pw_dir)
return nullptr; return nullptr;
strcpy(s_pwent_struct.pw_dir, ptr);
break; break;
case 6: case 6:
s_pwent_struct.pw_shell = (char*)malloc(field_len + 1); s_pwent_struct.pw_shell = strndup(ptr, field_len + 1);
if (!s_pwent_struct.pw_shell) if (!s_pwent_struct.pw_shell)
return nullptr; return nullptr;
strcpy(s_pwent_struct.pw_shell, ptr);
break; break;
} }

View File

@ -560,9 +560,12 @@ int mblen(const char* s, size_t n)
case LOCALE_POSIX: case LOCALE_POSIX:
return 1; return 1;
case LOCALE_UTF8: case LOCALE_UTF8:
if (const auto bytes = BAN::UTF8::byte_length(*s); n >= bytes) const auto bytes = BAN::UTF8::byte_length(*s);
return bytes; if (bytes == BAN::UTF8::invalid)
return -1; return -1;
if (n < bytes)
return -1;
return bytes;
} }
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }

View File

@ -176,7 +176,7 @@ namespace LibFont
uint32_t len = BAN::UTF8::byte_length(bytes[0]); uint32_t len = BAN::UTF8::byte_length(bytes[0]);
if (len == 0) if (len == BAN::UTF8::invalid)
{ {
invalid_utf = true; invalid_utf = true;
byte_index = 0; byte_index = 0;

View File

@ -0,0 +1,18 @@
set(SOURCES
dummy.cpp
)
add_library(libmath-static STATIC ${SOURCES})
add_library(libmath-shared SHARED ${SOURCES})
target_link_options(libmath-static PRIVATE -nolibc)
target_link_options(libmath-shared PRIVATE -nolibc)
banan_link_library(libmath-static libc)
banan_link_library(libmath-shared libc)
set_target_properties(libmath-static PROPERTIES OUTPUT_NAME libm)
set_target_properties(libmath-shared PROPERTIES OUTPUT_NAME libm)
install(TARGETS libmath-static OPTIONAL)
install(TARGETS libmath-shared OPTIONAL)

View File

View File

@ -0,0 +1,18 @@
set(SOURCES
dummy.cpp
)
add_library(libpthread-static STATIC ${SOURCES})
add_library(libpthread-shared SHARED ${SOURCES})
target_link_options(libpthread-static PRIVATE -nolibc)
target_link_options(libpthread-shared PRIVATE -nolibc)
banan_link_library(libpthread-static libc)
banan_link_library(libpthread-shared libc)
set_target_properties(libpthread-static PROPERTIES OUTPUT_NAME libpthread)
set_target_properties(libpthread-shared PROPERTIES OUTPUT_NAME libpthread)
install(TARGETS libpthread-static OPTIONAL)
install(TARGETS libpthread-shared OPTIONAL)

View File

View File

@ -500,6 +500,7 @@ BAN::Optional<BAN::String> Input::get_input(BAN::Optional<BAN::StringView> custo
fflush(stdout); fflush(stdout);
break; break;
case '\n': case '\n':
case '\r':
{ {
BAN::String input; BAN::String input;
MUST(input.append(m_buffers[m_buffer_index])); MUST(input.append(m_buffers[m_buffer_index]));

View File

@ -748,7 +748,7 @@ Rectangle Terminal::putchar(uint8_t ch)
m_utf8_bytes[m_utf8_index++] = ch; m_utf8_bytes[m_utf8_index++] = ch;
const size_t utf8_len = BAN::UTF8::byte_length(m_utf8_bytes[0]); const size_t utf8_len = BAN::UTF8::byte_length(m_utf8_bytes[0]);
if (utf8_len == 0) if (utf8_len == BAN::UTF8::invalid)
{ {
dwarnln("invalid utf8 leading byte 0x{2H}", ch); dwarnln("invalid utf8 leading byte 0x{2H}", ch);
m_utf8_index = 0; m_utf8_index = 0;

View File

@ -39,6 +39,29 @@ bool is_sorted(BAN::Vector<T>& vec)
} \ } \
} while (0) } while (0)
#define TEST_ALGORITHM_QSORT(ms) do { \
uint64_t duration_us = 0; \
printf("qsort\n"); \
for (size_t size = 100; duration_us < ms * 1000; size *= 10) { \
BAN::Vector<unsigned> data(size, 0); \
for (auto& val : data) \
val = rand() % 100; \
uint64_t start_ns = CURRENT_NS(); \
qsort(data.data(), data.size(), sizeof(unsigned), [](const void* a, const void* b) -> int { return *(unsigned*)a - *(unsigned*)b; }); \
uint64_t stop_ns = CURRENT_NS(); \
if (!is_sorted(data)) { \
printf(" \e[31mFAILED!\e[m\n"); \
break; \
} \
duration_us = (stop_ns - start_ns) / 1'000; \
printf(" %5d.%03d ms (%zu)\n", \
(int)(duration_us / 1000), \
(int)(duration_us % 1000), \
size \
); \
} \
} while (0)
int main() int main()
{ {
srand(time(0)); srand(time(0));
@ -49,4 +72,5 @@ int main()
TEST_ALGORITHM(100, BAN::sort::intro_sort); TEST_ALGORITHM(100, BAN::sort::intro_sort);
TEST_ALGORITHM(1000, BAN::sort::sort); TEST_ALGORITHM(1000, BAN::sort::sort);
TEST_ALGORITHM(1000, BAN::sort::radix_sort); TEST_ALGORITHM(1000, BAN::sort::radix_sort);
TEST_ALGORITHM_QSORT(100);
} }