Compare commits

..

No commits in common. "36d07065fb1fc07abc09d6a38aa99c558c5365ac" and "51bfe4252d416f4dc9806a776bd6ef05f6f3b3cc" have entirely different histories.

8 changed files with 85 additions and 273 deletions

View File

@ -60,7 +60,6 @@ namespace Kernel
static void wait_until_processors_ready(); static void wait_until_processors_ready();
static void toggle_should_print_cpu_load() { s_should_print_cpu_load = !s_should_print_cpu_load; } static void toggle_should_print_cpu_load() { s_should_print_cpu_load = !s_should_print_cpu_load; }
static bool get_should_print_cpu_load() { return s_should_print_cpu_load; }
static ProcessorID bsb_id() { return s_bsb_id; } static ProcessorID bsb_id() { return s_bsb_id; }
static bool current_is_bsb() { return current_id() == bsb_id(); } static bool current_is_bsb() { return current_id() == bsb_id(); }

View File

@ -3,14 +3,11 @@
#include <kernel/Device/FramebufferDevice.h> #include <kernel/Device/FramebufferDevice.h>
#include <kernel/FS/DevFS/FileSystem.h> #include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/Memory/Heap.h> #include <kernel/Memory/Heap.h>
#include <kernel/Terminal/TerminalDriver.h>
#include <sys/framebuffer.h> #include <sys/framebuffer.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/sysmacros.h> #include <sys/sysmacros.h>
extern Kernel::TerminalDriver* g_terminal_driver;
namespace Kernel namespace Kernel
{ {
@ -253,21 +250,16 @@ namespace Kernel
{ {
if (flags != MS_SYNC) if (flags != MS_SYNC)
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
if (vaddr % (BANAN_FB_BPP / 8))
return BAN::Error::from_errno(EINVAL);
if (auto rem = size % (BANAN_FB_BPP / 8)) if (vaddr < m_vaddr)
size += (BANAN_FB_BPP / 8) - rem; vaddr = m_vaddr;
if (vaddr + size > m_vaddr + m_size)
size = (vaddr - m_vaddr) + m_size;
const vaddr_t start = BAN::Math::max(vaddr, m_vaddr); m_framebuffer->sync_pixels_linear(
const size_t end = BAN::Math::min(vaddr + size, m_vaddr + m_size); (vaddr - m_vaddr) / (BANAN_FB_BPP / 8),
if (start < end) BAN::Math::div_round_up<uint32_t>((vaddr % (BANAN_FB_BPP / 8)) + size, (BANAN_FB_BPP / 8))
{
do_msync(
(start - m_vaddr) / (BANAN_FB_BPP / 8),
(end - start) / (BANAN_FB_BPP / 8)
); );
}
return {}; return {};
} }
@ -308,53 +300,6 @@ namespace Kernel
, m_framebuffer(framebuffer) , m_framebuffer(framebuffer)
{ } { }
void do_msync(uint32_t first_pixel, uint32_t pixel_count)
{
if (!Processor::get_should_print_cpu_load())
return m_framebuffer->sync_pixels_linear(first_pixel, pixel_count);
const uint32_t fb_width = m_framebuffer->width();
const auto& font = g_terminal_driver->font();
const uint32_t x = first_pixel % fb_width;
const uint32_t y = first_pixel / fb_width;
const uint32_t load_w = 16 * font.width();
const uint32_t load_h = Processor::count() * font.height();
if (y >= load_h || x + pixel_count <= fb_width - load_w)
return m_framebuffer->sync_pixels_linear(first_pixel, pixel_count);
if (x >= fb_width - load_w && x + pixel_count <= fb_width)
return;
if (x < fb_width - load_w)
m_framebuffer->sync_pixels_linear(first_pixel, fb_width - load_w - x);
if (x + pixel_count > fb_width)
{
const uint32_t past_last_pixel = first_pixel + pixel_count;
first_pixel = (y + 1) * fb_width;
pixel_count = past_last_pixel - first_pixel;
const uint32_t cpu_load_end = load_h * fb_width;
while (pixel_count && first_pixel < cpu_load_end)
{
m_framebuffer->sync_pixels_linear(first_pixel, BAN::Math::min(pixel_count, fb_width - load_w));
const uint32_t advance = BAN::Math::min(pixel_count, fb_width);
pixel_count -= advance;
first_pixel += advance;
}
if (pixel_count)
m_framebuffer->sync_pixels_linear(first_pixel, pixel_count);
}
}
private: private:
BAN::RefPtr<FramebufferDevice> m_framebuffer; BAN::RefPtr<FramebufferDevice> m_framebuffer;
}; };

View File

@ -179,8 +179,6 @@ namespace Kernel
const pid_t tid = Thread::current_tid(); const pid_t tid = Thread::current_tid();
const pid_t pid = (tid && Thread::current().has_process()) ? Process::current().pid() : 0; const pid_t pid = (tid && Thread::current().has_process()) ? Process::current().pid() : 0;
const char* process_name = "";
if (tid) if (tid)
{ {
auto& thread = Thread::current(); auto& thread = Thread::current();
@ -247,22 +245,15 @@ namespace Kernel
); );
} }
if (Thread::current().has_process() && Process::current().is_userspace())
{
const char* const* argv = Process::current().userspace_info().argv;
if (argv && *argv)
process_name = *argv;
}
#if ARCH(x86_64) #if ARCH(x86_64)
dwarnln( dwarnln(
"CPU {}: {} (error code: 0x{8H}), pid {}, tid {}: {}\r\n" "CPU {}: {} (error code: 0x{8H}), pid {}, tid {}\r\n"
"Register dump\r\n" "Register dump\r\n"
"rax=0x{16H}, rbx=0x{16H}, rcx=0x{16H}, rdx=0x{16H}\r\n" "rax=0x{16H}, rbx=0x{16H}, rcx=0x{16H}, rdx=0x{16H}\r\n"
"rsp=0x{16H}, rbp=0x{16H}, rdi=0x{16H}, rsi=0x{16H}\r\n" "rsp=0x{16H}, rbp=0x{16H}, rdi=0x{16H}, rsi=0x{16H}\r\n"
"rip=0x{16H}, rflags=0x{16H}\r\n" "rip=0x{16H}, rflags=0x{16H}\r\n"
"cr0=0x{16H}, cr2=0x{16H}, cr3=0x{16H}, cr4=0x{16H}", "cr0=0x{16H}, cr2=0x{16H}, cr3=0x{16H}, cr4=0x{16H}",
Processor::current_id(), isr_exceptions[isr], error, pid, tid, process_name, Processor::current_id(), isr_exceptions[isr], error, pid, tid,
regs->rax, regs->rbx, regs->rcx, regs->rdx, regs->rax, regs->rbx, regs->rcx, regs->rdx,
interrupt_stack->sp, regs->rbp, regs->rdi, regs->rsi, interrupt_stack->sp, regs->rbp, regs->rdi, regs->rsi,
interrupt_stack->ip, interrupt_stack->flags, interrupt_stack->ip, interrupt_stack->flags,
@ -270,13 +261,13 @@ namespace Kernel
); );
#elif ARCH(i686) #elif ARCH(i686)
dwarnln( dwarnln(
"CPU {}: {} (error code: 0x{8H}), pid {}, tid {}: {}\r\n" "CPU {}: {} (error code: 0x{8H}), pid {}, tid {}\r\n"
"Register dump\r\n" "Register dump\r\n"
"eax=0x{8H}, ebx=0x{8H}, ecx=0x{8H}, edx=0x{8H}\r\n" "eax=0x{8H}, ebx=0x{8H}, ecx=0x{8H}, edx=0x{8H}\r\n"
"esp=0x{8H}, ebp=0x{8H}, edi=0x{8H}, esi=0x{8H}\r\n" "esp=0x{8H}, ebp=0x{8H}, edi=0x{8H}, esi=0x{8H}\r\n"
"eip=0x{8H}, eflags=0x{8H}\r\n" "eip=0x{8H}, eflags=0x{8H}\r\n"
"cr0=0x{8H}, cr2=0x{8H}, cr3=0x{8H}, cr4=0x{8H}", "cr0=0x{8H}, cr2=0x{8H}, cr3=0x{8H}, cr4=0x{8H}",
Processor::current_id(), isr_exceptions[isr], error, pid, tid, process_name, Processor::current_id(), isr_exceptions[isr], error, pid, tid,
regs->eax, regs->ebx, regs->ecx, regs->edx, regs->eax, regs->ebx, regs->ecx, regs->edx,
interrupt_stack->sp, regs->ebp, regs->edi, regs->esi, interrupt_stack->sp, regs->ebp, regs->edi, regs->esi,
interrupt_stack->ip, interrupt_stack->flags, interrupt_stack->ip, interrupt_stack->flags,

View File

@ -1682,9 +1682,12 @@ namespace Kernel
if (flags != MS_SYNC && flags != MS_ASYNC && flags != MS_INVALIDATE) if (flags != MS_SYNC && flags != MS_ASYNC && flags != MS_INVALIDATE)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
vaddr_t vaddr = (vaddr_t)addr;
if (vaddr % PAGE_SIZE != 0)
return BAN::Error::from_errno(EINVAL);
LockGuard _(m_process_lock); LockGuard _(m_process_lock);
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(addr);
for (auto& mapped_region : m_mapped_regions) for (auto& mapped_region : m_mapped_regions)
if (mapped_region->overlaps(vaddr, len)) if (mapped_region->overlaps(vaddr, len))
TRY(mapped_region->msync(vaddr, len, flags)); TRY(mapped_region->msync(vaddr, len, flags));

View File

@ -80,32 +80,3 @@ struct Circle
} }
}; };
struct Range
{
uint32_t start { 0 };
uint32_t count { 0 };
bool is_continuous_with(const Range& range) const
{
return start <= range.start + range.count && range.start <= start + count;
}
uint32_t distance_between(const Range& range) const
{
if (is_continuous_with(range))
return 0;
if (start < range.start)
return range.start - (start + count);
return start - (range.start + range.count);
}
void merge_with(const Range& range)
{
const uint32_t new_start = BAN::Math::min(start, range.start);
const uint32_t new_end = BAN::Math::max(start + count, range.start + range.count);
start = new_start;
count = new_end - new_start;
}
};

View File

@ -20,12 +20,7 @@ WindowServer::WindowServer(Framebuffer& framebuffer, int32_t corner_radius)
, m_cursor({ framebuffer.width / 2, framebuffer.height / 2 }) , m_cursor({ framebuffer.width / 2, framebuffer.height / 2 })
, m_font(MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"_sv))) , m_font(MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"_sv)))
{ {
BAN::Vector<LibImage::Image::Color> bitmap; MUST(m_pages_to_sync_bitmap.resize(BAN::Math::div_round_up<size_t>(m_framebuffer.width * m_framebuffer.height * sizeof(uint32_t), 4096 * 8), 0));
MUST(bitmap.resize(m_framebuffer.width * m_framebuffer.height, { 0x10, 0x10, 0x10, 0xFF }));
m_background_image = MUST(BAN::UniqPtr<LibImage::Image>::create(m_framebuffer.width, m_framebuffer.height, BAN::move(bitmap)));
MUST(m_pending_syncs.resize(m_framebuffer.height));
invalidate(m_framebuffer.area()); invalidate(m_framebuffer.area());
} }
@ -540,7 +535,6 @@ void WindowServer::on_mouse_scroll(LibInput::MouseScrollEvent event)
void WindowServer::set_focused_window(BAN::RefPtr<Window> window) void WindowServer::set_focused_window(BAN::RefPtr<Window> window)
{ {
ASSERT(window->get_attributes().focusable);
if (m_focused_window == window) if (m_focused_window == window)
return; return;
@ -580,9 +574,6 @@ static uint32_t alpha_blend(uint32_t color_a, uint32_t color_b)
void WindowServer::invalidate(Rectangle area) void WindowServer::invalidate(Rectangle area)
{ {
ASSERT(m_background_image->width() == (uint64_t)m_framebuffer.width);
ASSERT(m_background_image->height() == (uint64_t)m_framebuffer.height);
const auto get_cursor_pixel = const auto get_cursor_pixel =
[](int32_t rel_x, int32_t rel_y) -> BAN::Optional<uint32_t> [](int32_t rel_x, int32_t rel_y) -> BAN::Optional<uint32_t>
{ {
@ -614,28 +605,11 @@ void WindowServer::invalidate(Rectangle area)
return; return;
area = focused_overlap.release_value(); area = focused_overlap.release_value();
const bool should_alpha_blend = m_focused_window->get_attributes().alpha_channel;
if (client_area == m_framebuffer.area()) if (client_area == m_framebuffer.area())
{
if (!should_alpha_blend)
{ {
for (int32_t y = area.y; y < area.y + area.height; y++) for (int32_t y = area.y; y < area.y + area.height; y++)
for (int32_t x = area.x; x < area.x + area.width; x++) for (int32_t x = area.x; x < area.x + area.width; x++)
m_framebuffer.mmap[y * m_framebuffer.width + x] = m_focused_window->framebuffer()[y * m_focused_window->client_width() + x]; m_framebuffer.mmap[y * m_framebuffer.width + x] = m_focused_window->framebuffer()[y * m_focused_window->client_width() + x];
}
else
{
for (int32_t y = area.y; y < area.y + area.height; y++)
{
for (int32_t x = area.x; x < area.x + area.width; x++)
{
const uint32_t src_pixel = m_focused_window->framebuffer()[y * m_focused_window->client_width() + x];
const uint32_t bg_pixel = m_background_image->get_color(x, y).as_argb();
m_framebuffer.mmap[y * m_framebuffer.width + x] = alpha_blend(src_pixel, bg_pixel);
}
}
}
mark_pending_sync(area); mark_pending_sync(area);
} }
else else
@ -656,12 +630,7 @@ void WindowServer::invalidate(Rectangle area)
{ {
const int32_t src_x = BAN::Math::clamp<int32_t>(dst_x * m_focused_window->client_width() / m_framebuffer.width, 0, m_focused_window->client_width()); const int32_t src_x = BAN::Math::clamp<int32_t>(dst_x * m_focused_window->client_width() / m_framebuffer.width, 0, m_focused_window->client_width());
const int32_t src_y = BAN::Math::clamp<int32_t>(dst_y * m_focused_window->client_height() / m_framebuffer.height, 0, m_focused_window->client_height()); const int32_t src_y = BAN::Math::clamp<int32_t>(dst_y * m_focused_window->client_height() / m_framebuffer.height, 0, m_focused_window->client_height());
m_framebuffer.mmap[dst_y * m_framebuffer.width + dst_x] = m_focused_window->framebuffer()[src_y * m_focused_window->client_width() + src_x];
const uint32_t src_pixel = m_focused_window->framebuffer()[src_y * m_focused_window->client_width() + src_x];
const uint32_t bg_pixel = m_background_image->get_color(dst_x, dst_y).as_argb();
uint32_t& dst_pixel = m_framebuffer.mmap[dst_y * m_framebuffer.width + dst_x];
dst_pixel = should_alpha_blend ? alpha_blend(src_pixel, bg_pixel) : src_pixel;
} }
} }
@ -713,9 +682,20 @@ void WindowServer::invalidate(Rectangle area)
return; return;
area = fb_overlap.release_value(); area = fb_overlap.release_value();
if (m_background_image)
{
ASSERT(m_background_image->width() == (uint64_t)m_framebuffer.width);
ASSERT(m_background_image->height() == (uint64_t)m_framebuffer.height);
for (int32_t y = area.y; y < area.y + area.height; y++) for (int32_t y = area.y; y < area.y + area.height; y++)
for (int32_t x = area.x; x < area.x + area.width; x++) for (int32_t x = area.x; x < area.x + area.width; x++)
m_framebuffer.mmap[y * m_framebuffer.width + x] = m_background_image->get_color(x, y).as_argb(); m_framebuffer.mmap[y * m_framebuffer.width + x] = m_background_image->get_color(x, y).as_argb();
}
else
{
for (int32_t y = area.y; y < area.y + area.height; y++)
for (int32_t x = area.x; x < area.x + area.width; x++)
m_framebuffer.mmap[y * m_framebuffer.width + x] = 0xFF101010;
}
// FIXME: this loop should be inverse order and terminate // FIXME: this loop should be inverse order and terminate
// after window without alpha channel is found // after window without alpha channel is found
@ -912,71 +892,24 @@ void WindowServer::invalidate(Rectangle area)
mark_pending_sync(area); mark_pending_sync(area);
} }
void WindowServer::RangeList::add_range(const Range& range) void WindowServer::mark_pending_sync(Rectangle area)
{ {
if (range_count == 0) // FIXME: this marks too many pages
{
ranges[0] = range;
range_count++;
return;
}
size_t min_distance_value = SIZE_MAX; const uintptr_t mmap_start = reinterpret_cast<uintptr_t>(m_framebuffer.mmap) + area.y * m_framebuffer.width * 4;
size_t min_distance_index = 0; const uintptr_t mmap_end = mmap_start + (area.height + 1) * m_framebuffer.width * 4;
for (size_t i = 0; i < range_count; i++)
{
if (ranges[i].is_continuous_with(range))
{
ranges[i].merge_with(range);
size_t last_continuous = i; uintptr_t mmap_addr = mmap_start & ~(uintptr_t)0xFFF;
for (size_t j = i + 1; j < range_count; j++) while (mmap_addr < mmap_end)
{ {
if (!ranges[i].is_continuous_with(ranges[j])) size_t index = (mmap_addr - reinterpret_cast<uintptr_t>(m_framebuffer.mmap)) / 4096;
break; size_t byte = index / 8;
last_continuous = j; size_t bit = index % 8;
//dprintln("{}/{}", byte, m_pages_to_sync_bitmap.size());
if (byte < m_pages_to_sync_bitmap.size())
m_pages_to_sync_bitmap[byte] |= 1 << bit;
mmap_addr += 4096;
} }
if (last_continuous != i)
{
ranges[i].merge_with(ranges[last_continuous]);
for (size_t j = 1; last_continuous + j < range_count; j++)
ranges[i + j] = ranges[last_continuous + j];
range_count -= last_continuous - i;
}
return;
}
const auto distance = ranges[i].distance_between(range);
if (distance < min_distance_value)
{
min_distance_value = distance;
min_distance_index = i;
}
}
if (range_count >= ranges.size())
{
ranges[min_distance_index].merge_with(range);
return;
}
size_t insert_idx = 0;
for (; insert_idx < range_count; insert_idx++)
if (range.start < ranges[insert_idx].start)
break;
for (size_t i = range_count; i > insert_idx; i--)
ranges[i] = ranges[i - 1];
ranges[insert_idx] = range;
range_count++;
}
void WindowServer::mark_pending_sync(Rectangle to_sync)
{
ASSERT(to_sync == to_sync.get_overlap(m_framebuffer.area()).value());
for (int32_t y_off = 0; y_off < to_sync.height; y_off++)
m_pending_syncs[to_sync.y + y_off].add_range({ static_cast<uint32_t>(to_sync.x), static_cast<uint32_t>(to_sync.width) });
} }
void WindowServer::sync() void WindowServer::sync()
@ -1000,44 +933,33 @@ void WindowServer::sync()
dir_y = -dir_y; dir_y = -dir_y;
} }
size_t range_start = 0; for (size_t i = 0; i < m_pages_to_sync_bitmap.size() * 8; i++)
size_t range_count = 0;
for (int32_t y = 0; y < m_framebuffer.height; y++)
{ {
auto& range_list = m_pending_syncs[y]; size_t byte = i / 8;
size_t bit = i % 8;
if (!(m_pages_to_sync_bitmap[byte] & (1 << bit)))
continue;
for (size_t i = 0; i < range_list.range_count; i++) size_t len = 1;
while (i + len < m_pages_to_sync_bitmap.size() * 8)
{ {
const size_t cur_start = y * m_framebuffer.width + range_list.ranges[i].start; size_t byte = (i + len) / 8;
const size_t cur_count = range_list.ranges[i].count; size_t bit = (i + len) % 8;
if (!(m_pages_to_sync_bitmap[byte] & (1 << bit)))
if (range_count == 0) break;
{ len++;
range_start = cur_start;
range_count = cur_count;
}
else
{
const size_t distance = cur_start - (range_start + range_count);
// combine nearby ranges to reduce msync calls
// NOTE: value of 128 is an arbitary constant that *just* felt nice
if (distance <= 128)
range_count = (cur_start + cur_count) - range_start;
else
{
msync(m_framebuffer.mmap + range_start, range_count * 4, MS_SYNC);
range_start = cur_start;
range_count = cur_count;
}
}
} }
range_list.range_count = 0; msync(
reinterpret_cast<uint8_t*>(m_framebuffer.mmap) + i * 4096,
len * 4096,
MS_SYNC
);
i += len;
} }
if (range_count) memset(m_pages_to_sync_bitmap.data(), 0, m_pages_to_sync_bitmap.size());
msync(m_framebuffer.mmap + range_start, range_count * 4, MS_SYNC);
} }
Rectangle WindowServer::cursor_area() const Rectangle WindowServer::cursor_area() const
@ -1080,14 +1002,8 @@ void WindowServer::remove_client_fd(int fd)
if (window == m_focused_window) if (window == m_focused_window)
{ {
m_focused_window = nullptr; m_focused_window = nullptr;
for (size_t j = m_client_windows.size(); j > 0; j--) if (!m_client_windows.empty())
{ set_focused_window(m_client_windows.back());
auto& client_window = m_client_windows[j - 1];
if (!client_window->get_attributes().focusable)
continue;
set_focused_window(client_window);
break;
}
} }
break; break;

View File

@ -3,7 +3,6 @@
#include "Framebuffer.h" #include "Framebuffer.h"
#include "Window.h" #include "Window.h"
#include <BAN/Array.h>
#include <BAN/Function.h> #include <BAN/Function.h>
#include <BAN/Iteration.h> #include <BAN/Iteration.h>
#include <BAN/Vector.h> #include <BAN/Vector.h>
@ -60,14 +59,6 @@ public:
private: private:
void mark_pending_sync(Rectangle area); void mark_pending_sync(Rectangle area);
private:
struct RangeList
{
size_t range_count { 0 };
BAN::Array<Range, 32> ranges;
void add_range(const Range& range);
};
private: private:
Framebuffer& m_framebuffer; Framebuffer& m_framebuffer;
BAN::Vector<BAN::RefPtr<Window>> m_client_windows; BAN::Vector<BAN::RefPtr<Window>> m_client_windows;
@ -76,7 +67,7 @@ private:
const int32_t m_corner_radius; const int32_t m_corner_radius;
BAN::Vector<RangeList> m_pending_syncs; BAN::Vector<uint8_t> m_pages_to_sync_bitmap;
BAN::UniqPtr<LibImage::Image> m_background_image; BAN::UniqPtr<LibImage::Image> m_background_image;

View File

@ -198,23 +198,19 @@ int main()
if (auto ret = window_server.set_background_image(BAN::move(config.background_image)); ret.is_error()) if (auto ret = window_server.set_background_image(BAN::move(config.background_image)); ret.is_error())
dwarnln("Could not set background image: {}", ret.error()); dwarnln("Could not set background image: {}", ret.error());
const auto get_current_us = constexpr uint64_t sync_interval_us = 1'000'000 / 60;
[]() -> uint64_t timespec last_sync { .tv_sec = 0, .tv_nsec = 0 };
while (!window_server.is_stopped())
{ {
timespec current_ts; timespec current_ts;
clock_gettime(CLOCK_MONOTONIC, &current_ts); clock_gettime(CLOCK_MONOTONIC, &current_ts);
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 us_since_last_sync = (current_ts.tv_sec - last_sync.tv_sec) * 1'000'000 + (current_ts.tv_nsec - last_sync.tv_nsec) / 1000;
uint64_t last_sync_us = 0; if (us_since_last_sync > sync_interval_us)
while (!window_server.is_stopped())
{
const auto current_us = get_current_us();
if (current_us - last_sync_us > sync_interval_us)
{ {
window_server.sync(); window_server.sync();
last_sync_us += sync_interval_us; us_since_last_sync = 0;
last_sync = current_ts;
} }
int max_fd = server_fd; int max_fd = server_fd;
@ -234,10 +230,10 @@ int main()
} }
max_fd = BAN::Math::max(max_fd, window_server.get_client_fds(fds)); max_fd = BAN::Math::max(max_fd, window_server.get_client_fds(fds));
timeval select_timeout {}; timeval select_timeout {
if (auto current_us = get_current_us(); current_us - last_sync_us < sync_interval_us) .tv_sec = 0,
select_timeout.tv_usec = sync_interval_us - (current_us - last_sync_us); .tv_usec = static_cast<long>(sync_interval_us - us_since_last_sync)
};
int nselect = select(max_fd + 1, &fds, nullptr, nullptr, &select_timeout); int nselect = select(max_fd + 1, &fds, nullptr, nullptr, &select_timeout);
if (nselect == 0) if (nselect == 0)
continue; continue;