Compare commits

..

67 Commits

Author SHA1 Message Date
4d6ac5cf30
wind: Handle ftruncate() and mmap() errors properly
Some checks failed
continuous-integration/drone/pr Build is failing
2023-08-17 20:16:39 +02:00
e954059c79
wind: Fix client references being out-of-date in windows when disconnecting other clients
Classic "keeping a pointer to an element inside a vector after the vector is updated" bug, ah yes.
2023-08-17 20:16:39 +02:00
3bc85b7929
taskbar: Wait for terminated child windows 2023-08-17 20:16:39 +02:00
3ce57443e2
wind: Add debug keybind 2023-08-17 20:16:39 +02:00
8e3535545c
wind+libos+libui: Handle interrupted reads properly 2023-08-17 20:16:38 +02:00
92c0cf0236
base: Actually add the start icon to source control 2023-08-17 20:16:38 +02:00
40ec7fd707
libui: Add Buttons 2023-08-17 20:16:38 +02:00
e311f9cb51
libui: Handle other mouse events 2023-08-17 20:16:38 +02:00
0f9ed8ae58
libui: Add aligned items using Containers, ImageWidget 2023-08-17 20:16:37 +02:00
141b212e88
libui: Add VerticalLayout 2023-08-17 20:16:37 +02:00
6b8fe49e5a
wind+libui+taskbar: Add GetScreenRect IPC, non-decorated windows, taskbar 2023-08-17 20:16:37 +02:00
e7ccfe1985
libui: Actually fill window backgrounds with the correct color 2023-08-17 20:16:37 +02:00
5862b32793
libui: Add basic widget and layout system =D 2023-08-17 20:16:37 +02:00
7c8e2d4da7
ui+wind: Send mouse move events through IPC 2023-08-17 20:16:36 +02:00
97994bfe6f
wind+libui: Add protocol for window close requests 2023-08-17 20:16:36 +02:00
e9423f3c39
libos+libui+wind: Use uppercase for static struct IDs to avoid confusion with fields 2023-08-17 20:16:36 +02:00
25053481f9
libui+gclient: Add basic OOP wrappers around the IPC protocol 2023-08-17 20:16:36 +02:00
b728c0d512
wind+gclient: Add SetWindowTitle and support shm buffers 2023-08-17 20:16:36 +02:00
a86d9ea2ac
gclient: Create two example windows 2023-08-17 20:16:35 +02:00
5984151a83
wind: Handle CreateWindow IPC messages 2023-08-17 20:16:35 +02:00
f9fa4bdd97
libui: Add CreateWindow IPC message definitions 2023-08-17 20:16:35 +02:00
974ad4dbd0
libos: Add basic IPC message framework 2023-08-17 20:16:35 +02:00
9a46033a9b
kernel: Fix poll syscall 2023-08-17 20:16:35 +02:00
6301138c14
wind: Monitor data on client connections 2023-08-17 20:16:34 +02:00
02593d4210
kernel: Add POLLHUP and store it when a polled socket's peer disconnects 2023-08-17 20:16:34 +02:00
00b7731281
libui: Add copyright/author text 2023-08-17 20:16:34 +02:00
87047127bd
libos: Add copyright/author comments to LocalServer and LocalClient 2023-08-17 20:16:34 +02:00
cd1342bc6a
wind: Use init --user and pledge() 2023-08-17 20:16:34 +02:00
768ab9882f
Update .gitignore 2023-08-17 20:16:33 +02:00
95f9a8ecb8
libos: Remove some shared pointers and change them to owned/live on the stack 2023-08-17 20:16:33 +02:00
95fe212e28
wind: Spawn a new client process after startup
Also, create the socket after dropping privileges.
2023-08-17 20:16:33 +02:00
0ccaaccb0d
apps: Add gclient 2023-08-17 20:16:33 +02:00
e6274b0dd2
libos: Add os::LocalClient 2023-08-17 20:16:18 +02:00
61a196dd42
libui: Change 'into' to 'onto' 2023-08-17 20:16:18 +02:00
c4f57b0c38
libui: Document ui::Font 2023-08-17 20:16:18 +02:00
83f898ff17
libui+wind: Move some static variables inside functions 2023-08-17 20:16:18 +02:00
f885831223
wind: Generate random windows on keypresses 2023-08-17 20:16:18 +02:00
6857d2cd5c
wind: Make sure windows have a minimum size to fit the titlebar 2023-08-17 20:16:18 +02:00
5c8bbc1b4b
libui: Properly cut off the last drawn character if necessary 2023-08-17 20:16:17 +02:00
af1ffa8459
libui: Add Rect::contains(Rect) 2023-08-17 20:16:17 +02:00
2646e6850f
libui: Render font characters properly with no spacing, matching the width calculations 2023-08-17 20:16:17 +02:00
f81f1a59e3
wind: Render an actual TGA mouse cursor 2023-08-17 20:16:17 +02:00
0ba0558585
wind: Add a close button to windows using a TGA icon 2023-08-17 20:16:17 +02:00
d1a9613607
libui: Add support for TGA image loading 2023-08-17 20:16:17 +02:00
214a3bb274
libui: Add an interface to fill a Canvas with an array of pixels 2023-08-17 20:16:17 +02:00
c6b4ad6ca1
wind: Add window titlebars using ui::Font 2023-08-17 20:16:16 +02:00
1f9344e727
libui: Add PSF font loading and rendering 2023-08-17 20:16:16 +02:00
01cb2fbd11
libui: Add Color::GRAY 2023-08-17 20:16:16 +02:00
ee2f3d0af3
libui: Rename Rect::absolute to normalized and add a new absolute function 2023-08-17 20:16:16 +02:00
907bdb8d68
libluna: Add assignment operators to Buffer 2023-08-17 20:16:16 +02:00
94ecefaac6
wind: Reorder drag sequence 2023-08-17 20:16:16 +02:00
e826538db1
libui: Add Rect::relative 2023-08-17 20:16:16 +02:00
a65c0a851b
libui: Remove redundant statement 2023-08-17 20:16:16 +02:00
1b414937da
libui: Add getters for separate color values 2023-08-17 20:16:15 +02:00
1db11bb0ac
libui: Remove unnecessary stuff 2023-08-17 20:16:15 +02:00
ded85b6b5c
base: Remove startup items not necessary for GUI startup 2023-08-17 20:16:15 +02:00
c6369f9132
libui+wind: (Draggable) windows 2023-08-17 20:16:15 +02:00
3546ed6de6
wind: Create a local server object 2023-08-17 20:16:15 +02:00
1b2c67fb50
libos: Add a new LocalServer class for local domain sockets 2023-08-17 20:16:15 +02:00
4614590cc7
kernel: Support listening sockets in poll() 2023-08-17 20:16:14 +02:00
41ab847ac9
base: Start wind on startup instead of the shell 2023-08-17 20:16:14 +02:00
1fd61f26be
wind: Add a simple display server skeleton using libui
No client functionality yet, but it's a start.
2023-08-17 20:16:14 +02:00
ab23c6103b
libui: Add a GUI and graphics library 2023-08-17 20:16:14 +02:00
d66aa31b2c
kernel: Fix negative movement in the PS/2 mouse driver 2023-08-17 20:16:14 +02:00
f2a5c9ad3f
apps: Add free
Some checks failed
continuous-integration/drone/push Build is failing
2023-08-17 20:15:39 +02:00
95a33c484e
kernel+libc: Add a memstat() syscall
We can finally show memory usage in userspace.

This could have been done using sysfs, but I'm lazy and don't want to implement that. Maybe in the next release?
2023-08-17 20:15:32 +02:00
4a654bf093
kernel: Handle OOMs better and without deadlocking
Use a separate task to do it.

Also fix a bug where the init thread would get no kernel stack ever since 5f698b477.
2023-08-17 20:14:33 +02:00
17 changed files with 199 additions and 10 deletions

View File

@ -47,6 +47,7 @@ luna_app(socket-client.cpp socket-client)
luna_app(input.cpp input) luna_app(input.cpp input)
luna_app(shmem-test.cpp shmem-test) luna_app(shmem-test.cpp shmem-test)
luna_app(touch.cpp touch) luna_app(touch.cpp touch)
luna_app(free.cpp free)
luna_app(gclient.cpp gclient) luna_app(gclient.cpp gclient)
target_link_libraries(gclient PUBLIC ui) target_link_libraries(gclient PUBLIC ui)
luna_app(taskbar.cpp taskbar) luna_app(taskbar.cpp taskbar)

50
apps/free.cpp Normal file
View File

@ -0,0 +1,50 @@
#include <luna/Units.h>
#include <os/ArgumentParser.h>
#include <os/File.h>
#include <sys/memstat.h>
Result<int> luna_main(int argc, char** argv)
{
bool reserved { false };
bool human_readable { false };
os::ArgumentParser parser;
parser.add_description("Query the amount of memory available and used in the system.");
parser.add_system_program_info("free"_sv);
parser.add_switch_argument(reserved, 'r', "show-reserved"_sv, "show reserved system memory"_sv);
parser.add_switch_argument(human_readable, 'h', "human-readable"_sv, "show output in human-readable units"_sv);
parser.parse(argc, argv);
struct membuf buf;
memstat(&buf);
if (human_readable)
{
auto total = TRY(to_dynamic_unit(buf.mem_total, 10, false, Unit::Binary, true));
auto free = TRY(to_dynamic_unit(buf.mem_free, 10, false, Unit::Binary, true));
auto used = TRY(to_dynamic_unit(buf.mem_used, 10, false, Unit::Binary, true));
os::println("%s total memory, out of which:", total.chars());
os::println("%s used", used.chars());
os::println("%s free", free.chars());
}
else
{
os::println("%lu total memory, out of which:", buf.mem_total);
os::println("%lu used", buf.mem_used);
os::println("%lu free", buf.mem_free);
}
if (reserved)
{
if (human_readable)
{
auto reserved_string = TRY(to_dynamic_unit(buf.mem_reserved, 10, false, Unit::Binary, true));
os::println("%s reserved", reserved_string.chars());
}
else { os::println("%lu reserved", buf.mem_reserved); }
}
return 0;
}

View File

@ -47,6 +47,7 @@ set(SOURCES
src/sys/poll.cpp src/sys/poll.cpp
src/sys/alarm.cpp src/sys/alarm.cpp
src/sys/pledge.cpp src/sys/pledge.cpp
src/sys/memstat.cpp
src/fs/VFS.cpp src/fs/VFS.cpp
src/fs/Pipe.cpp src/fs/Pipe.cpp
src/fs/Mount.cpp src/fs/Mount.cpp

View File

@ -1,5 +1,6 @@
#include "fs/StorageCache.h" #include "fs/StorageCache.h"
#include "Log.h" #include "Log.h"
#include <luna/Heap.h>
#include <luna/ScopeGuard.h> #include <luna/ScopeGuard.h>
static LinkedList<StorageCache> g_storage_caches; static LinkedList<StorageCache> g_storage_caches;
@ -23,9 +24,13 @@ Result<StorageCache::CacheEntry*> StorageCache::fetch_entry(u64 block)
void StorageCache::clear() void StorageCache::clear()
{ {
ScopedKMutexLock<100> lock(m_mutex); m_mutex.lock();
kdbgln("cache: clearing %lu entries, out of %lu buckets", m_cache_entries.size(), m_cache_entries.capacity());
m_cache_entries.clear(); m_cache_entries.clear();
kdbgln("cache: done");
m_mutex.unlock();
} }
StorageCache::StorageCache() StorageCache::StorageCache()

View File

@ -31,6 +31,16 @@ void reap_thread()
} }
} }
void oom_thread()
{
while (true)
{
kernel_wait_for_event();
// OOM! Do everything we can to recover memory.
StorageCache::clear_caches();
}
}
[[noreturn]] void init() [[noreturn]] void init()
{ {
{ {
@ -58,6 +68,10 @@ void reap_thread()
"Failed to create the process reaper kernel thread"); "Failed to create the process reaper kernel thread");
Scheduler::set_reap_thread(reap); Scheduler::set_reap_thread(reap);
auto oom = mark_critical(Scheduler::new_kernel_thread(oom_thread, "[oom]"),
"Failed to create the out-of-memory kernel thread");
Scheduler::set_oom_thread(oom);
#ifdef ARCH_X86_64 #ifdef ARCH_X86_64
ATA::Controller::scan(); ATA::Controller::scan();
#endif #endif

View File

@ -146,9 +146,9 @@ namespace MemoryManager
bool ok = frame_bitmap->find_and_toggle(false, start_index).try_set_value(index); bool ok = frame_bitmap->find_and_toggle(false, start_index).try_set_value(index);
if (!ok) if (!ok)
{ {
kwarnln("OOM alert! Trying to free caches..."); kwarnln("OOM alert! Scheduling the OOM thread...");
StorageCache::clear_caches(); Scheduler::signal_oom_thread();
if (!frame_bitmap->find_and_toggle(false, start_index).try_set_value(index)) return err(ENOMEM); return err(ENOMEM);
} }
start_index = index + 1; start_index = index + 1;

View File

@ -0,0 +1,21 @@
#include "Pledge.h"
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include <bits/memstat.h>
Result<u64> sys_memstat(Registers*, SyscallArgs args)
{
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_stdio));
struct membuf buf;
buf.mem_total = MemoryManager::total();
buf.mem_used = MemoryManager::used();
buf.mem_free = MemoryManager::free();
buf.mem_reserved = MemoryManager::reserved();
if (!MemoryManager::copy_to_user_typed((struct membuf*)args[0], &buf)) return err(EFAULT);
return 0;
}

View File

@ -13,6 +13,7 @@ static Thread g_idle;
static Thread* g_current = nullptr; static Thread* g_current = nullptr;
static Thread* g_init = nullptr; static Thread* g_init = nullptr;
static Thread* g_reap = nullptr; static Thread* g_reap = nullptr;
static Thread* g_oom = nullptr;
static const usize TICKS_PER_TIMESLICE = 20; static const usize TICKS_PER_TIMESLICE = 20;
@ -70,6 +71,17 @@ namespace Scheduler
if (g_reap) g_reap->wake_up(); if (g_reap) g_reap->wake_up();
} }
void set_oom_thread(Thread* thread)
{
g_oom = thread;
g_oom->unrestricted_task = true;
}
void signal_oom_thread()
{
if (g_oom) g_oom->wake_up();
}
Result<Thread*> new_kernel_thread_impl(Thread* thread, const char* name) Result<Thread*> new_kernel_thread_impl(Thread* thread, const char* name)
{ {
// If anything fails, make sure to clean up. // If anything fails, make sure to clean up.
@ -154,8 +166,13 @@ namespace Scheduler
u64 argv = TRY(image->push_string_vector_on_stack(args)); u64 argv = TRY(image->push_string_vector_on_stack(args));
u64 envp = TRY(image->push_string_vector_on_stack(env)); u64 envp = TRY(image->push_string_vector_on_stack(env));
const u64 kernel_stack_base = TRY(MemoryManager::alloc_for_kernel(4, MMU::ReadWrite | MMU::NoExecute));
Stack kernel_stack { kernel_stack_base, 4 * ARCH_PAGE_SIZE };
guard.deactivate(); guard.deactivate();
thread->kernel_stack = kernel_stack;
image->apply(thread); image->apply(thread);
thread->set_arguments(args.size(), argv, env.size(), envp); thread->set_arguments(args.size(), argv, env.size(), envp);
@ -254,8 +271,12 @@ namespace Scheduler
new_thread->ticks_left = 1; // The idle task only runs for 1 tick so we can check for new runnable tasks new_thread->ticks_left = 1; // The idle task only runs for 1 tick so we can check for new runnable tasks
// as fast as possible. // as fast as possible.
} }
else else if (new_thread->unrestricted_task)
new_thread->ticks_left = TICKS_PER_TIMESLICE; {
check(new_thread->is_kernel);
new_thread->ticks_left = -1;
}
else { new_thread->ticks_left = TICKS_PER_TIMESLICE; }
} }
void switch_task(Registers* regs) void switch_task(Registers* regs)

View File

@ -13,6 +13,9 @@ namespace Scheduler
void set_reap_thread(Thread*); void set_reap_thread(Thread*);
void signal_reap_thread(); void signal_reap_thread();
void set_oom_thread(Thread*);
void signal_oom_thread();
Result<Thread*> new_kernel_thread(u64 address, const char* name); Result<Thread*> new_kernel_thread(u64 address, const char* name);
Result<Thread*> new_kernel_thread(void (*func)(void), const char* name); Result<Thread*> new_kernel_thread(void (*func)(void), const char* name);
Result<Thread*> new_kernel_thread(void (*func)(void*), void* arg, const char* name); Result<Thread*> new_kernel_thread(void (*func)(void*), void* arg, const char* name);

View File

@ -109,6 +109,8 @@ struct Thread : public LinkedListNode<Thread>
sigset_t pending_signals { 0 }; sigset_t pending_signals { 0 };
bool interrupted { false }; bool interrupted { false };
bool unrestricted_task { false };
FPData fp_data; FPData fp_data;
ThreadState state = ThreadState::Runnable; ThreadState state = ThreadState::Runnable;

View File

@ -33,6 +33,7 @@ set(SOURCES
src/sys/utsname.cpp src/sys/utsname.cpp
src/sys/mount.cpp src/sys/mount.cpp
src/sys/pstat.cpp src/sys/pstat.cpp
src/sys/memstat.cpp
src/sys/resource.cpp src/sys/resource.cpp
src/sys/socket.cpp src/sys/socket.cpp
src/sys/poll.cpp src/sys/poll.cpp

View File

@ -0,0 +1,14 @@
/* bits/memstat.h: The membuf structure for memstat(). */
#ifndef _BITS_MEMSTAT_H
#define _BITS_MEMSTAT_H
struct membuf
{
unsigned long mem_total;
unsigned long mem_used;
unsigned long mem_free;
unsigned long mem_reserved;
};
#endif

View File

@ -0,0 +1,20 @@
/* sys/memstat.h: Memory usage querying. */
#ifndef _SYS_MEMSTAT_H
#define _SYS_MEMSTAT_H
#include <bits/memstat.h>
#ifdef __cplusplus
extern "C"
{
#endif
/* Query system memory usage. */
int memstat(struct membuf* mem);
#ifdef __cplusplus
}
#endif
#endif

13
libc/src/sys/memstat.cpp Normal file
View File

@ -0,0 +1,13 @@
#include <bits/errno-return.h>
#include <sys/memstat.h>
#include <sys/syscall.h>
#include <unistd.h>
extern "C"
{
int memstat(struct membuf* buf)
{
long rc = syscall(SYS_memstat, buf);
__errno_return(rc, int);
}
}

View File

@ -49,6 +49,16 @@ template <typename K, typename V> struct HashMap
return m_table.try_remove(HashPair<K, V> { key, {} }); return m_table.try_remove(HashPair<K, V> { key, {} });
} }
usize capacity() const
{
return m_table.capacity();
}
usize size() const
{
return m_table.size();
}
void clear() void clear()
{ {
m_table.clear(); m_table.clear();

View File

@ -101,10 +101,23 @@ template <typename T> class HashTable
void clear() void clear()
{ {
for (usize i = 0; i < m_capacity; i++) m_buckets[i].~Option(); if (m_capacity)
{
for (usize i = 0; i < m_capacity; i++) m_buckets[i].~Option();
free_impl(m_buckets); free_impl(m_buckets);
m_capacity = m_size = 0; m_capacity = m_size = 0;
}
}
usize capacity() const
{
return m_capacity;
}
usize size() const
{
return m_size;
} }
~HashTable() ~HashTable()

View File

@ -8,7 +8,7 @@
_e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask) _e(linkat) _e(faccessat) \ _e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask) _e(linkat) _e(faccessat) \
_e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \ _e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \
_e(getpgid) _e(socket) _e(bind) _e(connect) _e(listen) _e(accept) _e(poll) _e(msync) \ _e(getpgid) _e(socket) _e(bind) _e(connect) _e(listen) _e(accept) _e(poll) _e(msync) \
_e(truncate) _e(ftruncate) _e(utimensat) _e(alarm) _e(pledge) _e(truncate) _e(ftruncate) _e(utimensat) _e(alarm) _e(pledge) _e(memstat)
enum Syscalls enum Syscalls
{ {