Compare commits

..

No commits in common. "5d62fa3f1038757d9de0742aa42165d45dc3a390" and "4af9699b22e68075df2d660bb29f322d67a691e1" have entirely different histories.

30 changed files with 1067 additions and 1414 deletions

View File

@ -221,7 +221,7 @@ namespace Kernel
ASSERT(!(pt[pte] & Flags::Present));
pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
invalidate(fast_page(), false);
}
void PageTable::unmap_fast_page()
@ -241,7 +241,7 @@ namespace Kernel
ASSERT(pt[pte] & Flags::Present);
pt[pte] = 0;
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
invalidate(fast_page(), false);
}
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
@ -314,8 +314,7 @@ namespace Kernel
.type = Processor::SMPMessage::Type::FlushTLB,
.flush_tlb = {
.vaddr = vaddr,
.page_count = 1,
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
.page_count = 1
}
});
}
@ -344,12 +343,8 @@ namespace Kernel
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
const paddr_t old_paddr = pt[pte] & PAGE_ADDR_MASK;
pt[pte] = 0;
if (old_paddr != 0)
invalidate(vaddr, send_smp_message);
invalidate(vaddr, send_smp_message);
}
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
@ -366,8 +361,7 @@ namespace Kernel
.type = Processor::SMPMessage::Type::FlushTLB,
.flush_tlb = {
.vaddr = vaddr,
.page_count = page_count,
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
.page_count = page_count
}
});
}
@ -423,13 +417,9 @@ namespace Kernel
uwr_flags &= ~Flags::Present;
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
const paddr_t old_paddr = pt[pte] & PAGE_ADDR_MASK;
pt[pte] = paddr | uwr_flags | extra_flags;
if (old_paddr != 0)
invalidate(vaddr, send_smp_message);
invalidate(vaddr, send_smp_message);
}
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
@ -448,8 +438,7 @@ namespace Kernel
.type = Processor::SMPMessage::Type::FlushTLB,
.flush_tlb = {
.vaddr = vaddr,
.page_count = page_count,
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
.page_count = page_count
}
});
}
@ -534,7 +523,6 @@ namespace Kernel
.flush_tlb = {
.vaddr = vaddr,
.page_count = bytes / PAGE_SIZE,
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
}
});
return true;

View File

@ -521,7 +521,7 @@ namespace Kernel
ASSERT(!(pt[pte] & Flags::Present));
pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
invalidate(fast_page(), false);
}
void PageTable::unmap_fast_page()
@ -544,7 +544,7 @@ namespace Kernel
ASSERT(pt[pte] & Flags::Present);
pt[pte] = 0;
asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
invalidate(fast_page(), false);
}
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
@ -623,8 +623,7 @@ namespace Kernel
.type = Processor::SMPMessage::Type::FlushTLB,
.flush_tlb = {
.vaddr = vaddr,
.page_count = 1,
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
.page_count = 1
}
});
}
@ -659,12 +658,8 @@ namespace Kernel
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
const paddr_t old_paddr = pt[pte] & PAGE_ADDR_MASK;
pt[pte] = 0;
if (old_paddr != 0)
invalidate(vaddr, send_smp_message);
invalidate(vaddr, send_smp_message);
}
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
@ -681,8 +676,7 @@ namespace Kernel
.type = Processor::SMPMessage::Type::FlushTLB,
.flush_tlb = {
.vaddr = vaddr,
.page_count = page_count,
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
.page_count = page_count
}
});
}
@ -748,12 +742,9 @@ namespace Kernel
if (!(flags & Flags::Present))
uwr_flags &= ~Flags::Present;
const paddr_t old_paddr = pt[pte] & PAGE_ADDR_MASK;
pt[pte] = paddr | uwr_flags | extra_flags;
if (old_paddr != 0)
invalidate(vaddr, send_smp_message);
invalidate(vaddr, send_smp_message);
}
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
@ -774,8 +765,7 @@ namespace Kernel
.type = Processor::SMPMessage::Type::FlushTLB,
.flush_tlb = {
.vaddr = vaddr,
.page_count = page_count,
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
.page_count = page_count
}
});
}
@ -850,7 +840,6 @@ namespace Kernel
.flush_tlb = {
.vaddr = vaddr,
.page_count = bytes / PAGE_SIZE,
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
}
});
return true;

View File

@ -76,7 +76,6 @@
namespace Debug
{
void dump_stack_trace();
void dump_stack_trace(uintptr_t ip, uintptr_t bp);
void dump_qr_code();
void putchar(char);

View File

@ -70,7 +70,6 @@ namespace Kernel
BAN::ErrorOr<void> cleanup_indirect_block(uint32_t block, uint32_t depth);
BAN::ErrorOr<void> cleanup_default_links();
BAN::ErrorOr<void> cleanup_data_blocks();
BAN::ErrorOr<void> cleanup_from_fs();
BAN::ErrorOr<void> sync();

View File

@ -133,7 +133,7 @@ namespace Kernel
void map_kernel_memory();
void prepare_fast_page();
void invalidate(vaddr_t, bool send_smp_message);
static void invalidate(vaddr_t, bool send_smp_message);
static void map_fast_page(paddr_t);
static void unmap_fast_page();

View File

@ -9,7 +9,6 @@
#include <kernel/ELF.h>
#include <kernel/FS/Inode.h>
#include <kernel/Lock/Mutex.h>
#include <kernel/Lock/RWLock.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/MemoryRegion.h>
#include <kernel/Memory/SharedMemoryObject.h>
@ -219,6 +218,8 @@ namespace Kernel
BAN::ErrorOr<long> sys_tcgetpgrp(int fd);
BAN::ErrorOr<long> sys_tcsetpgrp(int fd, pid_t pgid);
BAN::ErrorOr<long> sys_termid(char*);
BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*);
BAN::ErrorOr<long> sys_load_keymap(const char* path);
@ -273,20 +274,17 @@ namespace Kernel
};
// Adds new region to the sorted array of mapped regions
// You must hold writer end of m_mapped_region_lock when calling this.
BAN::ErrorOr<void> add_mapped_region(BAN::UniqPtr<MemoryRegion>&&);
// If address is contained by a region, returns the index of that.
// Otherwise returns the address of the first region after this address.
// You must hold reader end of m_mapped_region_lock when calling this.
size_t find_mapped_region(vaddr_t) const;
BAN::ErrorOr<VirtualFileSystem::File> find_file(int fd, const char* path, int flags) const;
BAN::ErrorOr<FileParent> find_parent_file(int fd, const char* path, int flags) const;
BAN::ErrorOr<VirtualFileSystem::File> find_relative_parent(int fd, const char* path) const;
BAN::ErrorOr<void> read_from_user(const void* user_addr, void* out, size_t size);
BAN::ErrorOr<void> read_string_from_user(const char* user_addr, char* out, size_t max_size);
BAN::ErrorOr<void> write_to_user(void* user_addr, const void* in, size_t size);
BAN::ErrorOr<void> validate_string_access(const char*);
BAN::ErrorOr<void> validate_pointer_access(const void*, size_t, bool needs_write);
BAN::ErrorOr<MemoryRegion*> validate_and_pin_pointer_access(const void*, size_t, bool needs_write);
uint64_t signal_pending_mask() const
@ -331,7 +329,6 @@ namespace Kernel
OpenFileDescriptorSet m_open_file_descriptors;
mutable RWLock m_memory_region_lock;
BAN::Vector<BAN::UniqPtr<MemoryRegion>> m_mapped_regions;
pid_t m_sid;
@ -351,7 +348,6 @@ namespace Kernel
struct futex_t
{
Mutex mutex;
ThreadBlocker blocker;
uint32_t waiters { 0 };
uint32_t to_wakeup { 0 };

View File

@ -46,7 +46,6 @@ namespace Kernel
{
uintptr_t vaddr;
size_t page_count;
void* page_table;
} flush_tlb;
SchedulerQueue::Node* new_thread;
SchedulerQueue::Node* unblock_thread;
@ -209,7 +208,7 @@ namespace Kernel
static vaddr_t s_shared_page_vaddr;
ProcessorID m_id { 0 };
uint8_t m_index { 0 };
uint8_t m_index { 0xFF };
vaddr_t m_thread_syscall_stack;

View File

@ -16,7 +16,6 @@
namespace Kernel
{
class MemoryBackedRegion;
class Process;
class Thread
@ -104,7 +103,9 @@ namespace Kernel
vaddr_t kernel_stack_top() const { return m_kernel_stack->vaddr() + m_kernel_stack->size(); }
VirtualRange& kernel_stack() { return *m_kernel_stack; }
MemoryBackedRegion& userspace_stack() { ASSERT(is_userspace() && m_userspace_stack); return *m_userspace_stack; }
vaddr_t userspace_stack_bottom() const { return is_userspace() ? m_userspace_stack->vaddr() : UINTPTR_MAX; }
vaddr_t userspace_stack_top() const { return is_userspace() ? m_userspace_stack->vaddr() + m_userspace_stack->size() : 0; }
VirtualRange& userspace_stack() { ASSERT(is_userspace()); return *m_userspace_stack; }
static Thread& current();
static pid_t current_tid();
@ -128,7 +129,7 @@ namespace Kernel
void set_gsbase(vaddr_t base) { m_gsbase = base; }
vaddr_t get_gsbase() const { return m_gsbase; }
size_t virtual_page_count() const { return m_kernel_stack ? (m_kernel_stack->size() / PAGE_SIZE) : 0; }
size_t virtual_page_count() const { return (m_kernel_stack ? (m_kernel_stack->size() / PAGE_SIZE) : 0) + (m_userspace_stack ? (m_userspace_stack->size() / PAGE_SIZE) : 0); }
size_t physical_page_count() const { return virtual_page_count(); }
YieldRegisters& yield_registers() { return m_yield_registers; }
@ -159,7 +160,7 @@ namespace Kernel
BAN::UniqPtr<PageTable> m_keep_alive_page_table;
BAN::UniqPtr<VirtualRange> m_kernel_stack;
MemoryBackedRegion* m_userspace_stack { nullptr };
BAN::UniqPtr<VirtualRange> m_userspace_stack;
const pid_t m_tid { 0 };
State m_state { State::NotStarted };
Process* m_process { nullptr };

View File

@ -29,33 +29,28 @@ namespace Debug
static uint8_t s_debug_ansi_state { 0 };
void dump_stack_trace()
{
dump_stack_trace(0, reinterpret_cast<uintptr_t>(__builtin_frame_address(0)));
}
void dump_stack_trace(uintptr_t ip, uintptr_t bp)
{
using namespace Kernel;
struct stackframe
{
stackframe* bp;
void* ip;
uintptr_t ip;
};
SpinLockGuard _(s_debug_lock);
const stackframe* frame = reinterpret_cast<const stackframe*>(bp);
void* first_ip = frame->ip;
void* last_ip = 0;
stackframe* frame = (stackframe*)__builtin_frame_address(0);
if (!frame)
{
dprintln("Could not get frame address");
return;
}
uintptr_t first_ip = frame->ip;
uintptr_t last_ip = 0;
bool first = true;
BAN::Formatter::print(Debug::putchar, "\e[36mStack trace:\r\n");
if (ip != 0)
BAN::Formatter::print(Debug::putchar, " {}\r\n", reinterpret_cast<void*>(ip));
while (frame)
{
if (!PageTable::is_valid_pointer((vaddr_t)frame))

View File

@ -128,18 +128,16 @@ namespace Kernel
{
auto& [inode, events] = *it;
#define REMOVE_IT() \
#define REMOVE_IT_AND_CONTINUE() \
({ \
m_processing_events.remove(it); \
if (event_count > 0) \
break; \
it = m_processing_events.begin(); \
continue; \
})
auto listen_it = m_listening_events.find(inode);
if (listen_it == m_listening_events.end())
REMOVE_IT();
REMOVE_IT_AND_CONTINUE();
auto& listen = listen_it->value;
{
@ -151,7 +149,7 @@ namespace Kernel
}
if (events == 0)
REMOVE_IT();
REMOVE_IT_AND_CONTINUE();
{
LockGuard inode_locker(inode->m_mutex);
@ -167,9 +165,9 @@ namespace Kernel
}
if (events == 0)
REMOVE_IT();
REMOVE_IT_AND_CONTINUE();
#undef REMOVE_IT
#undef REMOVE_IT_AND_CONTINUE
for (size_t fd = 0; fd < listen.events.size() && event_count < event_span.size(); fd++)
{

View File

@ -1,5 +1,4 @@
#include <BAN/ScopeGuard.h>
#include <BAN/Sort.h>
#include <kernel/FS/Ext2/FileSystem.h>
#include <kernel/Lock/LockGuard.h>
@ -128,7 +127,7 @@ namespace Kernel
{
auto block_buffer = TRY(m_buffer_manager.get_buffer());
if ((superblock().rev_level == Ext2::Enum::GOOD_OLD_REV) || !(m_superblock.feature_ro_compat & Ext2::Enum::FEATURE_RO_COMPAT_SPARSE_SUPER))
if (superblock().rev_level == Ext2::Enum::GOOD_OLD_REV)
{
// In revision 0 all blockgroups contain superblock backup
TRY(m_superblock_backups.reserve(number_of_block_groups - 1));
@ -149,8 +148,6 @@ namespace Kernel
// We don't really care if this succeeds or not
(void)m_superblock_backups.shrink_to_fit();
BAN::sort::sort(m_superblock_backups.begin(), m_superblock_backups.end());
}
for (uint32_t bg : m_superblock_backups)
@ -491,7 +488,14 @@ namespace Kernel
TRY(read_block(bgd_location.block, bgd_buffer));
const auto bgd = bgd_buffer.span().slice(bgd_location.offset).as<Ext2::BlockGroupDescriptor>();
auto& bgd = *(Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);
const uint32_t inode_byte_offset = inode_index * superblock().inode_size;
BlockLocation location
{
.block = inode_byte_offset / block_size + bgd.inode_table,
.offset = inode_byte_offset % block_size
};
#if EXT2_VERIFY_INODE
const uint32_t inode_bitmap_block = bgd.inode_bitmap;
@ -499,18 +503,14 @@ namespace Kernel
// NOTE: we can reuse the bgd_buffer since it is not needed anymore
auto& inode_bitmap = bgd_buffer;
TRY(read_block(inode_bitmap_block, inode_bitmap));
read_block(inode_bitmap_block, inode_bitmap.span());
const uint32_t byte = inode_index / 8;
const uint32_t bit = inode_index % 8;
ASSERT(inode_bitmap[byte] & (1 << bit));
#endif
const uint32_t inode_byte_offset = inode_index * superblock().inode_size;
return BlockLocation {
.block = inode_byte_offset / block_size + bgd.inode_table,
.offset = inode_byte_offset % block_size
};
return location;
}
Ext2FS::BlockLocation Ext2FS::locate_block_group_descriptior(uint32_t group_index)
@ -525,7 +525,8 @@ namespace Kernel
// Block Group Descriptor table is in the block after superblock
const uint32_t bgd_byte_offset = (superblock().first_data_block + 1) * block_size + sizeof(Ext2::BlockGroupDescriptor) * group_index;
return BlockLocation {
return
{
.block = bgd_byte_offset / block_size,
.offset = bgd_byte_offset % block_size
};

View File

@ -61,13 +61,13 @@ namespace Kernel
const uint32_t inode_blocks_per_fs_block = blksize() / 512;
const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t);
if (block == 0 && !allocate)
return BAN::Optional<uint32_t>();
if (depth == 0)
{
if (block == 0)
{
if (!allocate)
return BAN::Optional<uint32_t>();
block = TRY(m_fs.reserve_free_block(block_group()));
m_inode.blocks += inode_blocks_per_fs_block;
@ -87,6 +87,9 @@ namespace Kernel
TRY(m_fs.read_block(block, block_buffer));
else
{
if (!allocate)
return BAN::Optional<uint32_t>();
block = TRY(m_fs.reserve_free_block(block_group()));
m_inode.blocks += inode_blocks_per_fs_block;
@ -168,10 +171,8 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::set_link_target_impl(BAN::StringView target)
{
ASSERT(mode().iflnk());
if (target.size() < sizeof(m_inode.block))
if (m_inode.size < sizeof(m_inode.block) && target.size() < sizeof(m_inode.block))
{
if (m_inode.size >= sizeof(m_inode.block))
TRY(cleanup_data_blocks());
memset(m_inode.block, 0, sizeof(m_inode.block));
memcpy(m_inode.block, target.data(), target.size());
m_inode.size = target.size();
@ -411,8 +412,10 @@ namespace Kernel
return {};
}
BAN::ErrorOr<void> Ext2Inode::cleanup_data_blocks()
BAN::ErrorOr<void> Ext2Inode::cleanup_from_fs()
{
ASSERT(m_inode.links_count == 0);
if (mode().iflnk() && (size_t)size() < sizeof(m_inode.block))
goto done;
@ -433,16 +436,12 @@ done:
// mark blocks as deleted
memset(m_inode.block, 0x00, sizeof(m_inode.block));
// FIXME: this is only required since fs does not get
// deleting inode from its cache
TRY(sync());
return {};
}
BAN::ErrorOr<void> Ext2Inode::cleanup_from_fs()
{
ASSERT(m_inode.links_count == 0);
TRY(cleanup_data_blocks());
TRY(m_fs.delete_inode(ino()));
return {};
}

View File

@ -277,11 +277,7 @@ namespace Kernel
#endif
if (isr == ISR::PageFault)
PageTable::current().debug_dump();
#if ARCH(x86_64)
Debug::dump_stack_trace(interrupt_stack->ip, regs->rbp);
#elif ARCH(i686)
Debug::dump_stack_trace(interrupt_stack->ip, regs->ebp);
#endif
Debug::dump_stack_trace();
Debug::s_debug_lock.unlock(InterruptState::Disabled);

View File

@ -148,12 +148,12 @@ namespace Kernel
if (m_preallocated)
return false;
SpinLockGuard _(m_lock);
const size_t index = (vaddr - this->vaddr()) / PAGE_SIZE;
if (m_paddrs[index])
return false;
SpinLockGuard _(m_lock);
m_paddrs[index] = Heap::get().take_free_page();
if (m_paddrs[index] == 0)
return BAN::Error::from_errno(ENOMEM);

File diff suppressed because it is too large Load Diff

View File

@ -60,13 +60,8 @@ namespace Kernel
Kernel::panic("Trying to initialize invalid processor {}", id.m_id);
if (id == s_bsp_id)
{
for (auto& processor : s_processors)
{
processor.m_id = PROCESSOR_NONE;
processor.m_index = 0xFF;
}
}
auto& processor = s_processors[id.m_id];
@ -375,8 +370,6 @@ namespace Kernel
switch (message->type)
{
case SMPMessage::Type::FlushTLB:
if (message->flush_tlb.page_table && message->flush_tlb.page_table != processor.m_current_page_table)
break;
for (size_t i = 0; i < message->flush_tlb.page_count; i++)
asm volatile("invlpg (%0)" :: "r"(message->flush_tlb.vaddr + i * PAGE_SIZE) : "memory");
break;

View File

@ -256,16 +256,16 @@ namespace Kernel
fis_command.fis_type = FIS_TYPE_REGISTER_H2D;
fis_command.c = 1;
const bool needs_extended = lba >= (1 << 24) || sector_count > 0xFF;
ASSERT (!needs_extended || (m_command_set & ATA_COMMANDSET_LBA48_SUPPORTED));
bool need_extended = lba >= (1 << 28) || sector_count > 0xFF;
ASSERT (!need_extended || (m_command_set & ATA_COMMANDSET_LBA48_SUPPORTED));
switch (command)
{
case Command::Read:
fis_command.command = needs_extended ? ATA_COMMAND_READ_DMA_EXT : ATA_COMMAND_READ_DMA;
fis_command.command = need_extended ? ATA_COMMAND_READ_DMA_EXT : ATA_COMMAND_READ_DMA;
break;
case Command::Write:
fis_command.command = needs_extended ? ATA_COMMAND_WRITE_DMA_EXT : ATA_COMMAND_WRITE_DMA;
fis_command.command = need_extended ? ATA_COMMAND_WRITE_DMA_EXT : ATA_COMMAND_WRITE_DMA;
break;
default:
ASSERT_NOT_REACHED();

View File

@ -4,7 +4,6 @@
#include <kernel/InterruptController.h>
#include <kernel/InterruptStack.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Memory/MemoryBackedRegion.h>
#include <kernel/Process.h>
#include <kernel/Scheduler.h>
#include <kernel/Thread.h>
@ -219,16 +218,13 @@ namespace Kernel
true, true
));
auto userspace_stack = TRY(MemoryBackedRegion::create(
thread->m_userspace_stack = TRY(VirtualRange::create_to_vaddr_range(
page_table,
stack_addr_start, USERSPACE_END,
userspace_stack_size,
{ stack_addr_start, USERSPACE_END },
MemoryRegion::Type::PRIVATE,
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present,
O_RDWR
false, true
));
thread->m_userspace_stack = userspace_stack.ptr();
TRY(process->add_mapped_region(BAN::move(userspace_stack)));
thread_deleter.disable();
@ -323,18 +319,16 @@ namespace Kernel
{
auto* thread = TRY(create_userspace(m_process, m_process->page_table()));
if (Processor::get_current_sse_thread() == this)
save_sse();
save_sse();
memcpy(thread->m_sse_storage, m_sse_storage, sizeof(m_sse_storage));
TRY(thread->userspace_stack().copy_data_to_region(
thread->m_userspace_stack->size() - sizeof(void*),
reinterpret_cast<const uint8_t*>(&arg),
sizeof(void*)
));
TRY(thread->userspace_stack().allocate_page_for_demand_paging(thread->userspace_stack_top() - PAGE_SIZE));
PageTable::with_fast_page(thread->userspace_stack().paddr_of(thread->userspace_stack_top() - PAGE_SIZE), [=] {
PageTable::fast_page_as<void*>(PAGE_SIZE - sizeof(uintptr_t)) = arg;
});
const vaddr_t entry_addr = reinterpret_cast<vaddr_t>(entry);
thread->setup_exec(entry_addr, thread->userspace_stack().vaddr() + thread->userspace_stack().size() - sizeof(void*));
thread->setup_exec(entry_addr, thread->userspace_stack_top() - sizeof(uintptr_t));
return thread;
}
@ -352,18 +346,14 @@ namespace Kernel
thread->m_is_userspace = true;
thread->m_kernel_stack = TRY(m_kernel_stack->clone(new_process->page_table()));
const auto stack_index = new_process->find_mapped_region(m_userspace_stack->vaddr());
thread->m_userspace_stack = static_cast<MemoryBackedRegion*>(new_process->m_mapped_regions[stack_index].ptr());
ASSERT(thread->m_userspace_stack->vaddr() == m_userspace_stack->vaddr());
thread->m_userspace_stack = TRY(m_userspace_stack->clone(new_process->page_table()));
thread->m_fsbase = m_fsbase;
thread->m_gsbase = m_gsbase;
thread->m_state = State::NotStarted;
if (Processor::get_current_sse_thread() == this)
save_sse();
save_sse();
memcpy(thread->m_sse_storage, m_sse_storage, sizeof(m_sse_storage));
thread->m_yield_registers = {};
@ -407,18 +397,29 @@ namespace Kernel
if (needed_size > m_userspace_stack->size())
return BAN::Error::from_errno(ENOBUFS);
vaddr_t vaddr = userspace_stack().vaddr() + userspace_stack().size() - needed_size;
vaddr_t vaddr = userspace_stack_top() - needed_size;
const size_t page_count = BAN::Math::div_round_up<size_t>(needed_size, PAGE_SIZE);
for (size_t i = 0; i < page_count; i++)
TRY(m_userspace_stack->allocate_page_containing(vaddr + i * PAGE_SIZE, true));
TRY(m_userspace_stack->allocate_page_for_demand_paging(vaddr + i * PAGE_SIZE));
const auto stack_copy_buf =
[this](BAN::ConstByteSpan buffer, vaddr_t vaddr) -> void
{
ASSERT(vaddr >= m_userspace_stack->vaddr());
ASSERT(vaddr + buffer.size() <= m_userspace_stack->vaddr() + m_userspace_stack->size());
MUST(m_userspace_stack->copy_data_to_region(vaddr - m_userspace_stack->vaddr(), buffer.data(), buffer.size()));
ASSERT(vaddr + buffer.size() <= userspace_stack_top());
size_t bytes_copied = 0;
while (bytes_copied < buffer.size())
{
const size_t to_copy = BAN::Math::min<size_t>(buffer.size() - bytes_copied, PAGE_SIZE - (vaddr % PAGE_SIZE));
PageTable::with_fast_page(userspace_stack().paddr_of(vaddr & PAGE_ADDR_MASK), [=]() {
memcpy(PageTable::fast_page_as_ptr(vaddr % PAGE_SIZE), buffer.data() + bytes_copied, to_copy);
});
vaddr += to_copy;
bytes_copied += to_copy;
}
};
const auto stack_push_buf =
@ -470,7 +471,7 @@ namespace Kernel
stack_push_str(envp[i]);
}
setup_exec(entry, m_userspace_stack->vaddr() + m_userspace_stack->size() - needed_size);
setup_exec(entry, userspace_stack_top() - needed_size);
return {};
}

View File

@ -1,17 +1,17 @@
From 49d1ca61e6249c3bc3284a6b55578b4ddd7b13ac Mon Sep 17 00:00:00 2001
From 2b3a0198640c23a7f8f8247ed1edae309c11e15f Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <oskari.alaranta@bananymous.com>
Date: Tue, 13 Jan 2026 20:49:19 +0200
Subject: [PATCH] add support for banan-os
Date: Thu, 31 Jul 2025 22:15:43 +0300
Subject: [PATCH 1/2] add support for banan-os
---
engine/common/net_http.c | 4 +++-
engine/common/net_ws.c | 6 ++++++
engine/common/whereami.c | 2 +-
engine/platform/posix/net.h | 4 ++++
public/build.c | 2 ++
public/build.h | 3 +++
public/buildenums.h | 3 +++
7 files changed, 22 insertions(+), 2 deletions(-)
engine/common/net_http.c | 4 +++-
engine/common/net_ws.c | 17 +++++++++++++++++
engine/common/whereami.c | 16 ++++++++++++++++
engine/platform/posix/lib_posix.c | 2 ++
public/build.c | 2 ++
public/build.h | 3 +++
public/buildenums.h | 3 +++
7 files changed, 46 insertions(+), 1 deletion(-)
diff --git a/engine/common/net_http.c b/engine/common/net_http.c
index ff6fd41b..ebb5bbad 100644
@ -36,10 +36,23 @@ index ff6fd41b..ebb5bbad 100644
res = fcntl( file->socket, F_GETFL, 0 );
diff --git a/engine/common/net_ws.c b/engine/common/net_ws.c
index 7ee4cba0..b44d5cf1 100644
index 7ee4cba0..e93a2410 100644
--- a/engine/common/net_ws.c
+++ b/engine/common/net_ws.c
@@ -1617,7 +1617,11 @@ static int NET_IPSocket( const char *net_iface, int port, int family )
@@ -1364,7 +1364,12 @@ static qboolean NET_QueuePacket( netsrc_t sock, netadr_t *from, byte *data, size
byte buf[NET_MAX_FRAGMENT];
int ret, protocol;
int net_socket;
+#ifdef XASH_BANAN_OS
+ socklen_t addr_len;
+#else
WSAsize_t addr_len;
+#endif
+
struct sockaddr_storage addr = { 0 };
*length = 0;
@@ -1617,7 +1622,11 @@ static int NET_IPSocket( const char *net_iface, int port, int family )
if( family == AF_INET6 )
pfamily = PF_INET6;
@ -51,7 +64,7 @@ index 7ee4cba0..b44d5cf1 100644
{
err = WSAGetLastError();
if( err != WSAEAFNOSUPPORT )
@@ -1625,6 +1629,7 @@ static int NET_IPSocket( const char *net_iface, int port, int family )
@@ -1625,6 +1634,7 @@ static int NET_IPSocket( const char *net_iface, int port, int family )
return INVALID_SOCKET;
}
@ -59,7 +72,7 @@ index 7ee4cba0..b44d5cf1 100644
if( NET_IsSocketError( ioctlsocket( net_socket, FIONBIO, (void*)&_true )))
{
struct timeval timeout;
@@ -1634,6 +1639,7 @@ static int NET_IPSocket( const char *net_iface, int port, int family )
@@ -1634,6 +1644,7 @@ static int NET_IPSocket( const char *net_iface, int port, int family )
timeout.tv_sec = timeout.tv_usec = 0;
setsockopt( net_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
}
@ -67,34 +80,81 @@ index 7ee4cba0..b44d5cf1 100644
// make it broadcast capable
if( NET_IsSocketError( setsockopt( net_socket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof( _true ))))
@@ -1686,6 +1697,7 @@ static int NET_IPSocket( const char *net_iface, int port, int family )
optval = 0x10; // IPTOS_LOWDELAY
Con_Printf( "Enabling LOWDELAY TOS option\n" );
+#ifdef IP_TOS
if( NET_IsSocketError( setsockopt( net_socket, IPPROTO_IP, IP_TOS, (const char *)&optval, sizeof( optval ))))
{
err = WSAGetLastError();
@@ -1694,6 +1706,7 @@ static int NET_IPSocket( const char *net_iface, int port, int family )
closesocket( net_socket );
return INVALID_SOCKET;
}
+#endif
}
if( Sys_CheckParm( "-loopback" ))
@@ -1801,7 +1814,11 @@ static void NET_DetermineLocalAddress( void )
char hostname[512];
char buff[512];
struct sockaddr_storage address;
+#ifdef XASH_BANAN_OS
+ socklen_t namelen;
+#else
WSAsize_t namelen;
+#endif
const char *net_addr_string;
memset( &net_local, 0, sizeof( netadr_t ));
diff --git a/engine/common/whereami.c b/engine/common/whereami.c
index 31726774..69a6cb9f 100644
index 31726774..5b7ff504 100644
--- a/engine/common/whereami.c
+++ b/engine/common/whereami.c
@@ -175,7 +175,7 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
return length;
@@ -851,6 +851,22 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
return -1;
}
-#elif defined(__linux__) || defined(__CYGWIN__) || defined(__sun) || defined(__serenity__) || defined(WAI_USE_PROC_SELF_EXE)
+#elif defined(__linux__) || defined(__CYGWIN__) || defined(__sun) || defined(__serenity__) || defined(__banan_os__) || defined(WAI_USE_PROC_SELF_EXE)
+#elif defined(__banan_os__)
+
+/* Not possible on this platform */
+
+WAI_FUNCSPEC
+int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
+{
+ return -1;
+}
+
+WAI_FUNCSPEC
+int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
+{
+ return -1;
+}
+
#else
#include <stdio.h>
#include <stdlib.h>
diff --git a/engine/platform/posix/net.h b/engine/platform/posix/net.h
index 58532927..6ab3cd1f 100644
--- a/engine/platform/posix/net.h
+++ b/engine/platform/posix/net.h
@@ -90,6 +90,10 @@ static int ioctl_stub( int d, unsigned long r, ... )
#define closesocket close
#error unsupported platform
diff --git a/engine/platform/posix/lib_posix.c b/engine/platform/posix/lib_posix.c
index 23d1c3b1..a5a84fe1 100644
--- a/engine/platform/posix/lib_posix.c
+++ b/engine/platform/posix/lib_posix.c
@@ -208,6 +208,7 @@ const char *COM_NameForFunction( void *hInstance, void *function )
return Loader_GetFuncName_int(wm, function);
else
#endif
#define SOCKET int
+#if XASH_BANAN_OS
+typedef socklen_t WSAsize_t;
+#else
typedef int WSAsize_t;
+#ifndef XASH_BANAN_OS
// NOTE: dladdr() is a glibc extension
{
Dl_info info = {0};
@@ -215,6 +216,7 @@ const char *COM_NameForFunction( void *hInstance, void *function )
if( ret && info.dli_sname )
return COM_GetPlatformNeutralName( info.dli_sname );
}
+#endif
#endif // NET_H
#ifdef XASH_ALLOW_SAVERESTORE_OFFSETS
return COM_OffsetNameForFunction( function );
#else
diff --git a/public/build.c b/public/build.c
index 6c85bbaf..460b4040 100644
--- a/public/build.c
@ -151,5 +211,5 @@ index 4dc327d3..57585f73 100644
#error
#endif
--
2.52.0
2.50.1

View File

@ -0,0 +1,25 @@
From b8c6ea53b4a8119f299fb6b5e4684c30795037a7 Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <oskari.alaranta@bananymous.com>
Date: Thu, 31 Jul 2025 22:36:28 +0300
Subject: [PATCH] Don't export have libbacktrace
This doesnt work :)
---
3rdparty/libbacktrace/wscript | 1 -
1 file changed, 1 deletion(-)
diff --git a/3rdparty/libbacktrace/wscript b/3rdparty/libbacktrace/wscript
index 2e076a56..98aca8d5 100644
--- a/3rdparty/libbacktrace/wscript
+++ b/3rdparty/libbacktrace/wscript
@@ -180,7 +180,6 @@ def build(bld):
features = 'frandomseed' if bld.env.HAVE_FRANDOM_SEED else '',
use = 'EXTRAFLAGS lzma z zstd',
includes = '. libbacktrace/',
- export_defines = 'HAVE_LIBBACKTRACE=1',
export_includes = 'libbacktrace/'
)
--
2.50.1

View File

@ -0,0 +1,26 @@
From 1e1fb9caff45f0cb05e89bfe452a7ff2abb558ff Mon Sep 17 00:00:00 2001
From: Oskari Alaranta <oskari.alaranta@bananymous.com>
Date: Thu, 31 Jul 2025 22:17:48 +0300
Subject: [PATCH] include alloca on banan-os
This detection does not work :(
---
lib/os.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/os.h b/lib/os.h
index 9ded7358..66b56704 100644
--- a/lib/os.h
+++ b/lib/os.h
@@ -62,7 +62,7 @@ void *_alloca(size_t size);
#endif /* _V_IFDEFJAIL_H_ */
-#ifdef HAVE_ALLOCA_H
+#if defined(HAVE_ALLOCA_H) || defined(__banan_os__)
# include <alloca.h>
#endif
--
2.50.1

View File

@ -9,6 +9,7 @@ __BEGIN_DECLS
O(SYS_EXIT, exit) \
O(SYS_READ, read) \
O(SYS_WRITE, write) \
O(SYS_TERMID, termid) \
O(SYS_CLOSE, close) \
O(SYS_OPENAT, openat) \
O(SYS_SEEK, seek) \

View File

@ -138,7 +138,7 @@ char* ctermid(char* buffer)
{
static char s_buffer[L_ctermid];
char* target = buffer ? buffer : s_buffer;
strcpy(buffer, "/dev/tty");
syscall(SYS_TERMID, target);
return target;
}

View File

@ -62,7 +62,7 @@ int clock_gettime(clockid_t clock_id, struct timespec* tp)
if (clock_id == CLOCK_REALTIME)
tp->tv_sec += sgettime.realtime_seconds;
return 0;
return monotonic_ns;
}
}

View File

@ -5,8 +5,8 @@
#include <fcntl.h>
#include <stdlib.h>
#include <sys/banan-os.h>
#include <sys/epoll.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
@ -67,18 +67,6 @@ namespace LibGUI
return BAN::Error::from_errno(errno);
BAN::ScopeGuard server_closer([server_fd] { close(server_fd); });
int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd == -1)
return BAN::Error::from_errno(errno);
BAN::ScopeGuard epoll_closer([epoll_fd] { close(epoll_fd); });
epoll_event epoll_event {
.events = EPOLLIN,
.data = { .fd = server_fd },
};
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &epoll_event) == -1)
return BAN::Error::from_errno(errno);
if (fcntl(server_fd, F_SETFD, fcntl(server_fd, F_GETFD) | FD_CLOEXEC) == -1)
return BAN::Error::from_errno(errno);
@ -112,7 +100,7 @@ namespace LibGUI
TRY(create_packet.title.append(title));
TRY(create_packet.send_serialized(server_fd));
auto window = TRY(BAN::UniqPtr<Window>::create(server_fd, epoll_fd, attributes));
auto window = TRY(BAN::UniqPtr<Window>::create(server_fd, attributes));
bool resized = false;
window->set_resize_window_event_callback([&]() { resized = true; });
@ -121,7 +109,6 @@ namespace LibGUI
window->set_resize_window_event_callback({});
server_closer.disable();
epoll_closer.disable();
return window;
}
@ -274,7 +261,6 @@ namespace LibGUI
{
munmap(m_framebuffer_smo, m_width * m_height * 4);
close(m_server_fd);
close(m_epoll_fd);
}
BAN::ErrorOr<void> Window::handle_resize_event(const EventPacket::ResizeWindowEvent& event)
@ -303,8 +289,10 @@ namespace LibGUI
void Window::wait_events()
{
epoll_event dummy;
epoll_wait(m_epoll_fd, &dummy, 1, -1);
fd_set fds;
FD_ZERO(&fds);
FD_SET(m_server_fd, &fds);
select(m_server_fd + 1, &fds, nullptr, nullptr, nullptr);
}
void Window::poll_events()
@ -312,8 +300,13 @@ namespace LibGUI
#define TRY_OR_BREAK(...) ({ auto&& e = (__VA_ARGS__); if (e.is_error()) break; e.release_value(); })
for (;;)
{
epoll_event event;
if (epoll_wait(m_epoll_fd, &event, 1, 0) == 0)
fd_set fds;
FD_ZERO(&fds);
FD_SET(m_server_fd, &fds);
timeval timeout { .tv_sec = 0, .tv_usec = 0 };
select(m_server_fd + 1, &fds, nullptr, nullptr, &timeout);
if (!FD_ISSET(m_server_fd, &fds))
break;
auto packet_or_error = recv_packet(m_server_fd);

View File

@ -81,9 +81,8 @@ namespace LibGUI
int server_fd() const { return m_server_fd; }
private:
Window(int server_fd, int epoll_fd, Attributes attributes)
Window(int server_fd, Attributes attributes)
: m_server_fd(server_fd)
, m_epoll_fd(epoll_fd)
, m_attributes(attributes)
{ }
@ -94,7 +93,6 @@ namespace LibGUI
private:
const int m_server_fd;
const int m_epoll_fd;
bool m_handling_socket_error { false };

View File

@ -5,8 +5,8 @@
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
@ -119,24 +119,12 @@ int main()
if (server_fd == -1)
return 1;
const int epoll_fd = epoll_create1(0);
if (epoll_fd == -1)
struct ClientInfo
{
dwarnln("failed to create epoll: {}", strerror(errno));
return 1;
}
int fd;
};
{
epoll_event event {
.events = EPOLLIN,
.data = { .fd = server_fd },
};
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) == -1)
{
dwarnln("failed to add server socket to epoll: {}", strerror(errno));
return -1;
}
}
BAN::Vector<ClientInfo> clients;
dprintln("AudioServer started");
@ -144,70 +132,67 @@ int main()
for (;;)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(server_fd, &fds);
int max_fd = server_fd;
for (const auto& client : clients)
{
max_fd = BAN::Math::max(max_fd, client.fd);
FD_SET(client.fd, &fds);
}
const uint64_t current_ms = get_current_ms();
next_update_ms = current_ms + audio_server->update();
const uint64_t timeout_ms = next_update_ms - current_ms;
epoll_event events[16];
int event_count = epoll_wait(epoll_fd, events, 16, timeout_ms);
if (event_count == -1 && errno != EINTR)
timeval timeout {
.tv_sec = static_cast<time_t>(timeout_ms / 1000),
.tv_usec = static_cast<suseconds_t>((timeout_ms % 1000) * 1000)
};
if (select(max_fd + 1, &fds, nullptr, nullptr, &timeout) == -1)
{
dwarnln("epoll_wait: {}", strerror(errno));
dwarnln("select: {}", strerror(errno));
break;
}
for (int i = 0; i < event_count; i++)
if (FD_ISSET(server_fd, &fds))
{
if (events[i].data.fd == server_fd)
const int client_fd = accept(server_fd, nullptr, nullptr);
if (client_fd == -1)
{
ASSERT(events[i].events & EPOLLIN);
const int client_fd = accept(server_fd, nullptr, nullptr);
if (client_fd == -1)
{
dwarnln("accept: {}", strerror(errno));
continue;
}
epoll_event event {
.events = EPOLLIN,
.data = { .fd = client_fd },
};
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event) == -1)
{
dwarnln("Failed to add client to epoll: {}", strerror(errno));
close(client_fd);
continue;
}
if (auto ret = audio_server->on_new_client(client_fd); ret.is_error())
{
dwarnln("Failed to initialize client: {}", ret.error());
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
close(client_fd);
continue;
}
dwarnln("accept: {}", strerror(errno));
continue;
}
const int client_fd = events[i].data.fd;
if (events[i].events & EPOLLHUP)
if (auto ret = clients.emplace_back(client_fd); ret.is_error())
{
audio_server->on_client_disconnect(client_fd);
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
dwarnln("Failed to add client: {}", ret.error());
close(client_fd);
continue;
}
ASSERT(events[i].events & EPOLLIN);
if (auto ret = audio_server->on_new_client(client_fd); ret.is_error())
{
dwarnln("Failed to initialize client: {}", ret.error());
clients.pop_back();
close(client_fd);
continue;
}
}
for (size_t i = 0; i < clients.size(); i++)
{
auto& client = clients[i];
if (!FD_ISSET(client.fd, &fds))
continue;
LibAudio::Packet packet;
const ssize_t nrecv = recv(client_fd, &packet, sizeof(packet), 0);
const ssize_t nrecv = recv(client.fd, &packet, sizeof(packet), 0);
if (nrecv < static_cast<ssize_t>(sizeof(packet)) || !audio_server->on_client_packet(client_fd, packet))
if (nrecv < static_cast<ssize_t>(sizeof(packet)) || !audio_server->on_client_packet(client.fd, packet))
{
if (nrecv == 0)
;
@ -216,9 +201,10 @@ int main()
else if (nrecv < static_cast<ssize_t>(sizeof(packet)))
dwarnln("client sent only {} bytes, {} expected", nrecv, sizeof(packet));
audio_server->on_client_disconnect(client_fd);
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
close(client_fd);
audio_server->on_client_disconnect(client.fd);
close(client.fd);
clients.remove(i--);
continue;
}
}
}

View File

@ -1460,17 +1460,28 @@ void WindowServer::remove_client_fd(int fd)
break;
}
}
m_deleted_window = true;
}
WindowServer::ClientData& WindowServer::get_client_data(int fd)
int WindowServer::get_client_fds(fd_set& fds) const
{
auto it = m_client_data.find(fd);
if (it != m_client_data.end())
return it->value;
dwarnln("could not find client {}", fd);
for (auto& [client_fd, _] : m_client_data)
dwarnln(" {}", client_fd);
ASSERT_NOT_REACHED();
int max_fd = 0;
for (const auto& [fd, _] : m_client_data)
{
FD_SET(fd, &fds);
max_fd = BAN::Math::max(max_fd, fd);
}
return max_fd;
}
void WindowServer::for_each_client_fd(const BAN::Function<BAN::Iteration(int, ClientData&)>& callback)
{
m_deleted_window = false;
for (auto& [fd, cliend_data] : m_client_data)
{
if (m_deleted_window)
break;
callback(fd, cliend_data);
}
}

View File

@ -15,6 +15,8 @@
#include <LibInput/KeyEvent.h>
#include <LibInput/MouseEvent.h>
#include <sys/select.h>
class WindowServer
{
public:
@ -56,7 +58,8 @@ public:
void add_client_fd(int fd);
void remove_client_fd(int fd);
ClientData& get_client_data(int fd);
int get_client_fds(fd_set& fds) const;
void for_each_client_fd(const BAN::Function<BAN::Iteration(int, ClientData&)>& callback);
bool is_stopped() const { return m_is_stopped; }
@ -111,6 +114,7 @@ private:
bool m_is_mouse_relative { false };
bool m_deleted_window { false };
bool m_is_stopped { false };
bool m_is_bouncing_window = false;

View File

@ -9,9 +9,9 @@
#include <fcntl.h>
#include <stdlib.h>
#include <sys/banan-os.h>
#include <sys/epoll.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>
@ -157,29 +157,10 @@ int main()
return 1;
}
int epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd == -1)
{
dwarnln("epoll_create1: {}", strerror(errno));
return 1;
}
{
epoll_event event {
.events = EPOLLIN,
.data = { .fd = server_fd },
};
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) == -1)
{
dwarnln("epoll_ctl server: {}", strerror(errno));
return 1;
}
}
if (tty_ctrl(STDIN_FILENO, TTY_CMD_UNSET, TTY_FLAG_ENABLE_INPUT) == -1)
{
dwarnln("tty_ctrl: {}", strerror(errno));
return 1;
perror("tty_ctrl");
exit(1);
}
atexit([]() { tty_ctrl(STDIN_FILENO, TTY_CMD_SET, TTY_FLAG_ENABLE_INPUT); });
@ -207,37 +188,11 @@ int main()
int keyboard_fd = open("/dev/keyboard", O_RDONLY | O_CLOEXEC);
if (keyboard_fd == -1)
dwarnln("open keyboard: {}", strerror(errno));
else
{
epoll_event event {
.events = EPOLLIN,
.data = { .fd = keyboard_fd },
};
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, keyboard_fd, &event) == -1)
{
dwarnln("epoll_ctl keyboard: {}", strerror(errno));
close(keyboard_fd);
keyboard_fd = -1;
}
}
perror("open");
int mouse_fd = open("/dev/mouse", O_RDONLY | O_CLOEXEC);
if (mouse_fd == -1)
dwarnln("open mouse: {}", strerror(errno));
else
{
epoll_event event {
.events = EPOLLIN,
.data = { .fd = mouse_fd },
};
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mouse_fd, &event) == -1)
{
dwarnln("epoll_ctl mouse: {}", strerror(errno));
close(mouse_fd);
mouse_fd = -1;
}
}
perror("open");
dprintln("Window server started");
@ -253,11 +208,11 @@ int main()
{
timespec current_ts;
clock_gettime(CLOCK_MONOTONIC, &current_ts);
return (current_ts.tv_sec * 1'000'000) + (current_ts.tv_nsec / 1000);
return (current_ts.tv_sec * 1'000'000) + (current_ts.tv_nsec / 1'000);
};
constexpr uint64_t sync_interval_us = 1'000'000 / 60;
uint64_t last_sync_us = get_current_us() - sync_interval_us;
uint64_t last_sync_us = 0;
while (!window_server.is_stopped())
{
const auto current_us = get_current_us();
@ -267,182 +222,168 @@ int main()
last_sync_us += sync_interval_us;
}
timespec timeout = {};
if (auto current_us = get_current_us(); current_us - last_sync_us < sync_interval_us)
timeout.tv_nsec = (sync_interval_us - (current_us - last_sync_us)) * 1000;
int max_fd = server_fd;
epoll_event events[16];
int epoll_events = epoll_pwait2(epoll_fd, events, 16, &timeout, nullptr);
if (epoll_events == -1 && errno != EINTR)
fd_set fds;
FD_ZERO(&fds);
FD_SET(server_fd, &fds);
if (keyboard_fd != -1)
{
dwarnln("epoll_pwait2: {}", strerror(errno));
FD_SET(keyboard_fd, &fds);
max_fd = BAN::Math::max(max_fd, keyboard_fd);
}
if (mouse_fd != -1)
{
FD_SET(mouse_fd, &fds);
max_fd = BAN::Math::max(max_fd, mouse_fd);
}
max_fd = BAN::Math::max(max_fd, window_server.get_client_fds(fds));
timeval select_timeout {};
if (auto current_us = get_current_us(); current_us - last_sync_us < sync_interval_us)
select_timeout.tv_usec = sync_interval_us - (current_us - last_sync_us);
int nselect = select(max_fd + 1, &fds, nullptr, nullptr, &select_timeout);
if (nselect == 0)
continue;
if (nselect == -1)
{
dwarnln("select: {}", strerror(errno));
break;
}
for (int i = 0; i < epoll_events; i++)
if (FD_ISSET(server_fd, &fds))
{
if (events[i].data.fd == server_fd)
int window_fd = accept4(server_fd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);
if (window_fd == -1)
{
ASSERT(events[i].events & EPOLLIN);
int window_fd = accept4(server_fd, nullptr, nullptr, SOCK_NONBLOCK | SOCK_CLOEXEC);
if (window_fd == -1)
{
dwarnln("accept: {}", strerror(errno));
continue;
}
epoll_event event {
.events = EPOLLIN,
.data = { .fd = window_fd },
};
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, window_fd, &event) == -1)
{
dwarnln("epoll_ctl: {}", strerror(errno));
close(window_fd);
continue;
}
window_server.add_client_fd(window_fd);
dwarnln("accept: {}", strerror(errno));
continue;
}
if (events[i].data.fd == keyboard_fd)
{
ASSERT(events[i].events & EPOLLIN);
LibInput::RawKeyEvent event;
if (read(keyboard_fd, &event, sizeof(event)) == -1)
{
dwarnln("read keyboard: {}", strerror(errno));
continue;
}
window_server.on_key_event(LibInput::KeyboardLayout::get().key_event_from_raw(event));
continue;
}
if (events[i].data.fd == mouse_fd)
{
ASSERT(events[i].events & EPOLLIN);
LibInput::MouseEvent event;
if (read(mouse_fd, &event, sizeof(event)) == -1)
{
dwarnln("read mouse: {}", strerror(errno));
continue;
}
switch (event.type)
{
case LibInput::MouseEventType::MouseButtonEvent:
window_server.on_mouse_button(event.button_event);
break;
case LibInput::MouseEventType::MouseMoveEvent:
window_server.on_mouse_move(event.move_event);
break;
case LibInput::MouseEventType::MouseMoveAbsEvent:
window_server.on_mouse_move_abs(event.move_abs_event);
break;
case LibInput::MouseEventType::MouseScrollEvent:
window_server.on_mouse_scroll(event.scroll_event);
break;
}
continue;
}
const int client_fd = events[i].data.fd;
if (events[i].events & EPOLLHUP)
{
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
window_server.remove_client_fd(client_fd);
continue;
}
ASSERT(events[i].events & EPOLLIN);
auto& client_data = window_server.get_client_data(client_fd);
if (client_data.packet_buffer.empty())
{
uint32_t packet_size;
const ssize_t nrecv = recv(client_fd, &packet_size, sizeof(uint32_t), 0);
if (nrecv < 0)
dwarnln("recv 1: {}", strerror(errno));
if (nrecv > 0 && nrecv != sizeof(uint32_t))
dwarnln("could not read packet size with a single recv call, closing connection...");
if (nrecv != sizeof(uint32_t))
{
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
window_server.remove_client_fd(client_fd);
break;
}
if (packet_size < 4)
{
dwarnln("client sent invalid packet, closing connection...");
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
window_server.remove_client_fd(client_fd);
break;
}
// this is a bit harsh, but i don't want to work on skipping streaming packets
if (client_data.packet_buffer.resize(packet_size).is_error())
{
dwarnln("could not allocate memory for client packet, closing connection...");
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
window_server.remove_client_fd(client_fd);
break;
}
client_data.packet_buffer_nread = 0;
continue;
}
const ssize_t nrecv = recv(
client_fd,
client_data.packet_buffer.data() + client_data.packet_buffer_nread,
client_data.packet_buffer.size() - client_data.packet_buffer_nread,
0
);
if (nrecv < 0)
dwarnln("recv 2: {}", strerror(errno));
if (nrecv <= 0)
{
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, nullptr);
window_server.remove_client_fd(client_fd);
break;
}
client_data.packet_buffer_nread += nrecv;
if (client_data.packet_buffer_nread < client_data.packet_buffer.size())
continue;
ASSERT(client_data.packet_buffer.size() >= sizeof(uint32_t));
switch (*reinterpret_cast<LibGUI::PacketType*>(client_data.packet_buffer.data()))
{
#define WINDOW_PACKET_CASE(enum, function) \
case LibGUI::PacketType::enum: \
if (auto ret = LibGUI::WindowPacket::enum::deserialize(client_data.packet_buffer.span()); !ret.is_error()) \
window_server.function(client_fd, ret.release_value()); \
break
WINDOW_PACKET_CASE(WindowCreate, on_window_create);
WINDOW_PACKET_CASE(WindowInvalidate, on_window_invalidate);
WINDOW_PACKET_CASE(WindowSetPosition, on_window_set_position);
WINDOW_PACKET_CASE(WindowSetAttributes, on_window_set_attributes);
WINDOW_PACKET_CASE(WindowSetMouseRelative, on_window_set_mouse_relative);
WINDOW_PACKET_CASE(WindowSetSize, on_window_set_size);
WINDOW_PACKET_CASE(WindowSetMinSize, on_window_set_min_size);
WINDOW_PACKET_CASE(WindowSetMaxSize, on_window_set_max_size);
WINDOW_PACKET_CASE(WindowSetFullscreen, on_window_set_fullscreen);
WINDOW_PACKET_CASE(WindowSetTitle, on_window_set_title);
WINDOW_PACKET_CASE(WindowSetCursor, on_window_set_cursor);
#undef WINDOW_PACKET_CASE
default:
dprintln("unhandled packet type: {}", *reinterpret_cast<uint32_t*>(client_data.packet_buffer.data()));
}
client_data.packet_buffer.clear();
client_data.packet_buffer_nread = 0;
window_server.add_client_fd(window_fd);
}
if (keyboard_fd != -1 && FD_ISSET(keyboard_fd, &fds))
{
LibInput::RawKeyEvent event;
if (read(keyboard_fd, &event, sizeof(event)) == -1)
{
perror("read");
continue;
}
window_server.on_key_event(LibInput::KeyboardLayout::get().key_event_from_raw(event));
}
if (mouse_fd != -1 && FD_ISSET(mouse_fd, &fds))
{
LibInput::MouseEvent event;
if (read(mouse_fd, &event, sizeof(event)) == -1)
{
perror("read");
continue;
}
switch (event.type)
{
case LibInput::MouseEventType::MouseButtonEvent:
window_server.on_mouse_button(event.button_event);
break;
case LibInput::MouseEventType::MouseMoveEvent:
window_server.on_mouse_move(event.move_event);
break;
case LibInput::MouseEventType::MouseMoveAbsEvent:
window_server.on_mouse_move_abs(event.move_abs_event);
break;
case LibInput::MouseEventType::MouseScrollEvent:
window_server.on_mouse_scroll(event.scroll_event);
break;
}
}
window_server.for_each_client_fd(
[&](int fd, WindowServer::ClientData& client_data) -> BAN::Iteration
{
if (!FD_ISSET(fd, &fds))
return BAN::Iteration::Continue;
if (client_data.packet_buffer.empty())
{
uint32_t packet_size;
const ssize_t nrecv = recv(fd, &packet_size, sizeof(uint32_t), 0);
if (nrecv < 0)
dwarnln("recv: {}", strerror(errno));
if (nrecv > 0 && nrecv != sizeof(uint32_t))
dwarnln("could not read packet size with a single recv call, closing connection...");
if (nrecv != sizeof(uint32_t))
{
window_server.remove_client_fd(fd);
return BAN::Iteration::Continue;
}
if (packet_size < 4)
{
dwarnln("client sent invalid packet, closing connection...");
return BAN::Iteration::Continue;
}
// this is a bit harsh, but i don't want to work on skipping streaming packets
if (client_data.packet_buffer.resize(packet_size).is_error())
{
dwarnln("could not allocate memory for client packet, closing connection...");
window_server.remove_client_fd(fd);
return BAN::Iteration::Continue;
}
client_data.packet_buffer_nread = 0;
return BAN::Iteration::Continue;
}
const ssize_t nrecv = recv(
fd,
client_data.packet_buffer.data() + client_data.packet_buffer_nread,
client_data.packet_buffer.size() - client_data.packet_buffer_nread,
0
);
if (nrecv < 0)
dwarnln("recv: {}", strerror(errno));
if (nrecv <= 0)
{
window_server.remove_client_fd(fd);
return BAN::Iteration::Continue;
}
client_data.packet_buffer_nread += nrecv;
if (client_data.packet_buffer_nread < client_data.packet_buffer.size())
return BAN::Iteration::Continue;
ASSERT(client_data.packet_buffer.size() >= sizeof(uint32_t));
switch (*reinterpret_cast<LibGUI::PacketType*>(client_data.packet_buffer.data()))
{
#define WINDOW_PACKET_CASE(enum, function) \
case LibGUI::PacketType::enum: \
if (auto ret = LibGUI::WindowPacket::enum::deserialize(client_data.packet_buffer.span()); !ret.is_error()) \
window_server.function(fd, ret.release_value()); \
break
WINDOW_PACKET_CASE(WindowCreate, on_window_create);
WINDOW_PACKET_CASE(WindowInvalidate, on_window_invalidate);
WINDOW_PACKET_CASE(WindowSetPosition, on_window_set_position);
WINDOW_PACKET_CASE(WindowSetAttributes, on_window_set_attributes);
WINDOW_PACKET_CASE(WindowSetMouseRelative, on_window_set_mouse_relative);
WINDOW_PACKET_CASE(WindowSetSize, on_window_set_size);
WINDOW_PACKET_CASE(WindowSetMinSize, on_window_set_min_size);
WINDOW_PACKET_CASE(WindowSetMaxSize, on_window_set_max_size);
WINDOW_PACKET_CASE(WindowSetFullscreen, on_window_set_fullscreen);
WINDOW_PACKET_CASE(WindowSetTitle, on_window_set_title);
WINDOW_PACKET_CASE(WindowSetCursor, on_window_set_cursor);
#undef WINDOW_PACKET_CASE
default:
dprintln("unhandled packet type: {}", *reinterpret_cast<uint32_t*>(client_data.packet_buffer.data()));
}
client_data.packet_buffer.clear();
client_data.packet_buffer_nread = 0;
return BAN::Iteration::Continue;
}
);
}
}