Compare commits
20 Commits
2b48933f29
...
755d41ca4e
Author | SHA1 | Date |
---|---|---|
|
755d41ca4e | |
|
bbff9f89b0 | |
|
fdcb38ac1f | |
|
fac742c038 | |
|
5a6b43fc90 | |
|
317f413746 | |
|
895909b7fa | |
|
2ee8b6c8b4 | |
|
022bb69782 | |
|
be6da3e0db | |
|
1f07e02298 | |
|
7a645b8555 | |
|
c5b0d0235f | |
|
b7948551ff | |
|
e109b5cff6 | |
|
9883fb7bf6 | |
|
e9f8471a28 | |
|
4656b11256 | |
|
f2ccab2df7 | |
|
b2e3aefa72 |
|
@ -18,7 +18,7 @@ namespace BAN::UTF8
|
|||
return 3;
|
||||
if ((first_byte & 0xF8) == 0xF0)
|
||||
return 4;
|
||||
return 0;
|
||||
return UTF8::invalid;
|
||||
}
|
||||
|
||||
template<typename T> requires (sizeof(T) == 1)
|
||||
|
|
|
@ -98,7 +98,9 @@ namespace Kernel
|
|||
|
||||
private:
|
||||
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_processing_events;
|
||||
BAN::HashMap<BAN::RefPtr<Inode>, ListenEventList, InodeRefPtrHash> m_listening_events;
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ namespace Kernel
|
|||
FlushTLB,
|
||||
NewThread,
|
||||
UnblockThread,
|
||||
StackTrace,
|
||||
};
|
||||
SMPMessage* next { nullptr };
|
||||
Type type;
|
||||
|
@ -45,6 +46,7 @@ namespace Kernel
|
|||
} flush_tlb;
|
||||
SchedulerQueue::Node* new_thread;
|
||||
SchedulerQueue::Node* unblock_thread;
|
||||
bool dummy;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -29,18 +29,26 @@ namespace Kernel
|
|||
{
|
||||
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));
|
||||
if (it->value.has_fd(fd))
|
||||
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);
|
||||
|
||||
auto ready_it = m_ready_events.find(inode);
|
||||
if (ready_it == m_ready_events.end())
|
||||
ready_it = MUST(m_ready_events.insert(inode, 0));
|
||||
ready_it->value |= event.events;
|
||||
auto processing_it = m_processing_events.find(inode);
|
||||
if (processing_it == m_processing_events.end())
|
||||
processing_it = MUST(m_processing_events.insert(inode, 0));
|
||||
processing_it->value |= event.events;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -50,12 +58,13 @@ namespace Kernel
|
|||
return BAN::Error::from_errno(ENOENT);
|
||||
if (!it->value.has_fd(fd))
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
|
||||
it->value.events[fd] = event;
|
||||
|
||||
auto ready_it = m_ready_events.find(inode);
|
||||
if (ready_it == m_ready_events.end())
|
||||
ready_it = MUST(m_ready_events.insert(inode, 0));
|
||||
ready_it->value |= event.events;
|
||||
auto processing_it = m_processing_events.find(inode);
|
||||
if (processing_it == m_processing_events.end())
|
||||
processing_it = MUST(m_processing_events.insert(inode, 0));
|
||||
processing_it->value |= event.events;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
@ -68,7 +77,10 @@ namespace Kernel
|
|||
it->value.remove_fd(fd);
|
||||
if (it->value.empty())
|
||||
{
|
||||
inode->del_epoll(this);
|
||||
m_listening_events.remove(it);
|
||||
m_processing_events.remove(inode);
|
||||
SpinLockGuard _(m_ready_lock);
|
||||
m_ready_events.remove(inode);
|
||||
}
|
||||
return {};
|
||||
|
@ -83,53 +95,76 @@ namespace Kernel
|
|||
if (event_span.empty())
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
size_t count = 0;
|
||||
size_t event_count = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
bool failed_lock = false;
|
||||
|
||||
{
|
||||
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& 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;
|
||||
for (int fd = 0; fd < OPEN_MAX; fd++)
|
||||
if (listen.has_fd(fd))
|
||||
listen_mask |= listen.events[fd].events;
|
||||
events &= listen_mask;
|
||||
auto listen_it = m_listening_events.find(inode);
|
||||
if (listen_it == m_listening_events.end())
|
||||
REMOVE_IT_AND_CONTINUE();
|
||||
auto& listen = listen_it->value;
|
||||
|
||||
// This prevents a possible deadlock
|
||||
if (!inode->m_mutex.try_lock())
|
||||
{
|
||||
failed_lock = true;
|
||||
continue;
|
||||
uint32_t listen_mask = EPOLLERR | EPOLLHUP;
|
||||
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)
|
||||
REMOVE_IT_AND_CONTINUE();
|
||||
|
||||
{
|
||||
m_ready_events.remove(it);
|
||||
it = m_ready_events.begin();
|
||||
continue;
|
||||
LockGuard inode_locker(inode->m_mutex);
|
||||
|
||||
#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))
|
||||
continue;
|
||||
|
@ -139,7 +174,7 @@ namespace Kernel
|
|||
if (new_events == 0)
|
||||
continue;
|
||||
|
||||
event_span[count++] = {
|
||||
event_span[event_count++] = {
|
||||
.events = new_events,
|
||||
.data = listen_event.data,
|
||||
};
|
||||
|
@ -155,32 +190,29 @@ namespace Kernel
|
|||
}
|
||||
}
|
||||
|
||||
if (count)
|
||||
if (event_count > 0)
|
||||
break;
|
||||
|
||||
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
|
||||
if (current_ns >= waketime_ns)
|
||||
break;
|
||||
if (failed_lock)
|
||||
continue;
|
||||
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));
|
||||
}
|
||||
|
||||
return count;
|
||||
return event_count;
|
||||
}
|
||||
|
||||
void Epoll::notify(BAN::RefPtr<Inode> inode, uint32_t event)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
ASSERT(event);
|
||||
|
||||
if (!m_listening_events.contains(inode))
|
||||
return;
|
||||
SpinLockGuard _(m_ready_lock);
|
||||
|
||||
auto ready_it = m_ready_events.find(inode);
|
||||
if (ready_it == m_ready_events.end())
|
||||
ready_it = MUST(m_ready_events.insert(inode, 0));
|
||||
ready_it->value |= event;
|
||||
if (auto it = m_ready_events.find(inode); it != m_ready_events.end())
|
||||
it->value |= event;
|
||||
else
|
||||
MUST(m_ready_events.insert(inode, event));
|
||||
|
||||
m_thread_blocker.unblock();
|
||||
}
|
||||
|
|
|
@ -67,8 +67,6 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<size_t> Pipe::read_impl(off_t, BAN::ByteSpan buffer)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
while (m_buffer_size == 0)
|
||||
{
|
||||
if (m_writing_count == 0)
|
||||
|
@ -103,8 +101,6 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<size_t> Pipe::write_impl(off_t, BAN::ConstByteSpan buffer)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
while (m_buffer_size >= m_buffer.size())
|
||||
{
|
||||
if (m_reading_count == 0)
|
||||
|
|
|
@ -114,7 +114,37 @@ namespace Kernel
|
|||
auto& key_event = event.as<const LibInput::RawKeyEvent>();
|
||||
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):
|
||||
Processor::toggle_should_print_cpu_load();
|
||||
|
|
|
@ -244,6 +244,10 @@ namespace Kernel
|
|||
case SMPMessage::Type::UnblockThread:
|
||||
processor.m_scheduler->unblock_thread(message->unblock_thread);
|
||||
break;
|
||||
case SMPMessage::Type::StackTrace:
|
||||
dwarnln("Stack trace of CPU {}", current_id().as_u32());
|
||||
Debug::dump_stack_trace();
|
||||
break;
|
||||
}
|
||||
|
||||
last_handled = message;
|
||||
|
@ -275,7 +279,6 @@ namespace Kernel
|
|||
|
||||
void Processor::send_smp_message(ProcessorID processor_id, const SMPMessage& message, bool send_ipi)
|
||||
{
|
||||
ASSERT(processor_id != current_id());
|
||||
|
||||
auto state = get_interrupt_state();
|
||||
set_interrupt_state(InterruptState::Disabled);
|
||||
|
@ -307,7 +310,12 @@ namespace Kernel
|
|||
);
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -623,6 +623,9 @@ namespace Kernel
|
|||
{
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
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();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -37,8 +37,7 @@ build_target () {
|
|||
echo "No target provided"
|
||||
exit 1
|
||||
fi
|
||||
cd $BANAN_BUILD_DIR
|
||||
run_fakeroot ninja $1
|
||||
run_fakeroot $BANAN_CMAKE --build $BANAN_BUILD_DIR -- -j$(nproc) $1
|
||||
}
|
||||
|
||||
build_toolchain () {
|
||||
|
|
|
@ -19,7 +19,7 @@ endif ()
|
|||
set(TOOLCHAIN_PREFIX $ENV{BANAN_ROOT_DIR}/toolchain/local)
|
||||
|
||||
set(CMAKE_SYSTEM_NAME banan-os)
|
||||
set(CMAKE_SYSTEM_PROCESSOR AMD64)
|
||||
set(CMAKE_SYSTEM_PROCESSOR ${BANAN_ARCH})
|
||||
|
||||
set(CMAKE_SYSROOT ${BANAN_SYSROOT})
|
||||
|
||||
|
|
|
@ -118,6 +118,7 @@ build_gcc () {
|
|||
--prefix="$BANAN_TOOLCHAIN_PREFIX" \
|
||||
--with-sysroot="$BANAN_SYSROOT" \
|
||||
--enable-initfini-array \
|
||||
--enable-threads=posix \
|
||||
--enable-shared \
|
||||
--enable-lto \
|
||||
--disable-nls \
|
||||
|
|
|
@ -5,6 +5,8 @@ set(USERSPACE_LIBRARIES
|
|||
LibGUI
|
||||
LibImage
|
||||
LibInput
|
||||
LibMath
|
||||
LibPthread
|
||||
)
|
||||
|
||||
foreach(library ${USERSPACE_LIBRARIES})
|
||||
|
|
|
@ -27,28 +27,10 @@ uint16_t ntohs(uint16_t netshort)
|
|||
|
||||
in_addr_t inet_addr(const char* cp)
|
||||
{
|
||||
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')
|
||||
in_addr addr;
|
||||
if (inet_aton(cp, &addr) == 0)
|
||||
return INADDR_NONE;
|
||||
if (ret == 1 && (a > 0xFFFFFFFF))
|
||||
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);
|
||||
return addr.s_addr;
|
||||
}
|
||||
|
||||
char* inet_ntoa(struct in_addr in)
|
||||
|
@ -64,6 +46,33 @@ char* inet_ntoa(struct in_addr in)
|
|||
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)
|
||||
{
|
||||
if (af == AF_INET)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#define ATEXIT_MAX_FUNCS 128
|
||||
#include <limits.h>
|
||||
|
||||
struct atexit_func_entry_t
|
||||
{
|
||||
|
@ -9,12 +8,12 @@ struct atexit_func_entry_t
|
|||
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;
|
||||
|
||||
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;
|
||||
s_atexit_funcs[s_atexit_func_count++] = {
|
||||
.func = func,
|
||||
|
|
|
@ -11,6 +11,7 @@ __BEGIN_DECLS
|
|||
#include <bits/types/socklen_t.h>
|
||||
|
||||
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);
|
||||
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);
|
||||
|
|
|
@ -10,20 +10,54 @@ __BEGIN_DECLS
|
|||
#include <bits/inet_common.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#define IPPROTO_IP 1
|
||||
#define IPPROTO_IPV6 2
|
||||
#define IPPROTO_ICMP 3
|
||||
#define IPPROTO_RAW 4
|
||||
#define IPPROTO_TCP 5
|
||||
#define IPPROTO_UDP 6
|
||||
#define IPPROTO_IP 1
|
||||
#define IPPROTO_IPV6 2
|
||||
#define IPPROTO_ICMP 3
|
||||
#define IPPROTO_RAW 4
|
||||
#define IPPROTO_TCP 5
|
||||
#define IPPROTO_UDP 6
|
||||
|
||||
#define IPV6_JOIN_GROUP 1
|
||||
#define IPV6_LEAVE_GROUP 2
|
||||
#define IPV6_MULTICAST_HOPS 3
|
||||
#define IPV6_MULTICAST_IF 4
|
||||
#define IPV6_MULTICAST_LOOP 5
|
||||
#define IPV6_UNICAST_HOPS 6
|
||||
#define IPV6_V6ONLY 7
|
||||
enum
|
||||
{
|
||||
IP_ADD_MEMBERSHIP,
|
||||
#define IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP
|
||||
IP_ADD_SOURCE_MEMBERSHIP,
|
||||
#define IP_ADD_SOURCE_MEMBERSHIP IP_ADD_SOURCE_MEMBERSHIP
|
||||
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_NONE 0xFFFFFFFF
|
||||
|
@ -78,6 +112,19 @@ struct ipv6_mreq
|
|||
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
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,11 +14,13 @@ __BEGIN_DECLS
|
|||
|
||||
struct passwd
|
||||
{
|
||||
char* pw_name; /* User's login name. */
|
||||
uid_t pw_uid; /* Numerical user ID. */
|
||||
gid_t pw_gid; /* Numerical group ID. */
|
||||
char* pw_dir; /* Initial working directory. */
|
||||
char* pw_shell; /* Program to use as shell. */
|
||||
char* pw_name; /* User's login name. */
|
||||
char* pw_passwd; /* User's hashed password. */
|
||||
uid_t pw_uid; /* Numerical user ID. */
|
||||
gid_t pw_gid; /* Numerical group ID. */
|
||||
char* pw_gecos; /* User's information. */
|
||||
char* pw_dir; /* Initial working directory. */
|
||||
char* pw_shell; /* Program to use as shell. */
|
||||
};
|
||||
|
||||
void endpwent(void);
|
||||
|
|
|
@ -50,16 +50,33 @@ struct cmsghdr
|
|||
socklen_t cmsg_len; /* Data byte count, including the cmsghdr. */
|
||||
int cmsg_level; /* Originating protocol. */
|
||||
int cmsg_type; /* Protocol-specific type. */
|
||||
unsigned char __cmg_data[];
|
||||
};
|
||||
|
||||
// FIXME
|
||||
#if 0
|
||||
#define SCM_RIGHTS
|
||||
#define SCM_RIGHTS 1
|
||||
|
||||
#define CMSG_DATA(cmsg)
|
||||
#define CMSG_NXTHDR(mhdr, cmsg)
|
||||
#define CMSG_FIRSTHDR(mhdr)
|
||||
#endif
|
||||
#define CMSG_DATA(cmsg) ((cmsg)->__cmg_data)
|
||||
|
||||
#define __CMSG_NXTHDR_ADDR(cmsg) \
|
||||
((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
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <BAN/Debug.h>
|
||||
#include <BAN/Math.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
@ -95,6 +96,12 @@ static bool allocate_pool(size_t pool_index)
|
|||
node->prev_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;
|
||||
|
||||
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->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;
|
||||
|
||||
// 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)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -332,3 +368,27 @@ void* calloc(size_t nmemb, size_t size)
|
|||
memset(ptr, 0, total);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -147,11 +147,9 @@ error_close_socket:
|
|||
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)
|
||||
{
|
||||
printf("getnameinfo(%p, %p, %p, 0x%X)\n", sa, node, service, flags);
|
||||
(void)flags;
|
||||
|
||||
switch (sa->sa_family)
|
||||
{
|
||||
|
|
|
@ -71,12 +71,14 @@ struct passwd* getpwent(void)
|
|||
switch (i)
|
||||
{
|
||||
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)
|
||||
return nullptr;
|
||||
strcpy(s_pwent_struct.pw_name, ptr);
|
||||
break;
|
||||
case 1:
|
||||
s_pwent_struct.pw_passwd = strndup(ptr, field_len + 1);
|
||||
if (!s_pwent_struct.pw_passwd)
|
||||
return nullptr;
|
||||
break;
|
||||
case 2:
|
||||
ASSERT(1 <= field_len && field_len <= 9);
|
||||
|
@ -91,18 +93,19 @@ struct passwd* getpwent(void)
|
|||
s_pwent_struct.pw_gid = atoi(ptr);
|
||||
break;
|
||||
case 4:
|
||||
s_pwent_struct.pw_gecos = strndup(ptr, field_len + 1);
|
||||
if (!s_pwent_struct.pw_gecos)
|
||||
return nullptr;
|
||||
break;
|
||||
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)
|
||||
return nullptr;
|
||||
strcpy(s_pwent_struct.pw_dir, ptr);
|
||||
break;
|
||||
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)
|
||||
return nullptr;
|
||||
strcpy(s_pwent_struct.pw_shell, ptr);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -560,9 +560,12 @@ int mblen(const char* s, size_t n)
|
|||
case LOCALE_POSIX:
|
||||
return 1;
|
||||
case LOCALE_UTF8:
|
||||
if (const auto bytes = BAN::UTF8::byte_length(*s); n >= bytes)
|
||||
return bytes;
|
||||
return -1;
|
||||
const auto bytes = BAN::UTF8::byte_length(*s);
|
||||
if (bytes == BAN::UTF8::invalid)
|
||||
return -1;
|
||||
if (n < bytes)
|
||||
return -1;
|
||||
return bytes;
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@ namespace LibFont
|
|||
|
||||
uint32_t len = BAN::UTF8::byte_length(bytes[0]);
|
||||
|
||||
if (len == 0)
|
||||
if (len == BAN::UTF8::invalid)
|
||||
{
|
||||
invalid_utf = true;
|
||||
byte_index = 0;
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
|
@ -500,6 +500,7 @@ BAN::Optional<BAN::String> Input::get_input(BAN::Optional<BAN::StringView> custo
|
|||
fflush(stdout);
|
||||
break;
|
||||
case '\n':
|
||||
case '\r':
|
||||
{
|
||||
BAN::String input;
|
||||
MUST(input.append(m_buffers[m_buffer_index]));
|
||||
|
|
|
@ -748,7 +748,7 @@ Rectangle Terminal::putchar(uint8_t ch)
|
|||
m_utf8_bytes[m_utf8_index++] = ch;
|
||||
|
||||
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);
|
||||
m_utf8_index = 0;
|
||||
|
|
|
@ -39,6 +39,29 @@ bool is_sorted(BAN::Vector<T>& vec)
|
|||
} \
|
||||
} 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()
|
||||
{
|
||||
srand(time(0));
|
||||
|
@ -49,4 +72,5 @@ int main()
|
|||
TEST_ALGORITHM(100, BAN::sort::intro_sort);
|
||||
TEST_ALGORITHM(1000, BAN::sort::sort);
|
||||
TEST_ALGORITHM(1000, BAN::sort::radix_sort);
|
||||
TEST_ALGORITHM_QSORT(100);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue