some work on compositor

This commit is contained in:
Benji Dial 2024-07-29 11:27:22 -04:00
parent 3636fd21e0
commit be691582ee
44 changed files with 1018 additions and 100 deletions

View file

@ -1,5 +1,5 @@
SOURCES = \
main.cpp
main.cpp renderer.cpp input.cpp socket.cpp
build/%.cpp.o: source/%.cpp
@mkdir -p $(@D)

View file

@ -0,0 +1,21 @@
#include "input.hpp"
#include "main.hpp"
[[noreturn]] void input_thread_main() {
euler::syscall::set_thread_name("input thread");
while (true) {
auto result = euler::syscall::get_input_packet();
if (std::holds_alternative<euler::syscall::mouse_packet>(result)) {
auto packet = std::get<euler::syscall::mouse_packet>(result);
r->lock();
r->bump_cursor(packet.x_changed, packet.y_changed);
r->unlock();
r->dispatch_render();
}
}
}

View file

@ -0,0 +1,3 @@
#pragma once
[[noreturn]] void input_thread_main();

View file

@ -1,79 +1,37 @@
#include <daguerre/framebuffer.hpp>
#include <daguerre/ppm.hpp>
#include "renderer.hpp"
#include "socket.hpp"
#include "input.hpp"
#include "main.hpp"
daguerre::hilbert_color trans_color;
//TODO: handle errors
void convert_pointer(
daguerre::hilbert_color &dest, const daguerre::hilbert_color &src) {
if (src != trans_color)
dest = src;
}
renderer *r;
int main(int, char **) {
trans_color = euler::syscall::encode_color(0xff, 0x00, 0xff);
euler::syscall::listener_handle listener;
euler::syscall::create_socket_listener("hilbert.compositor", listener);
daguerre::image<daguerre::hilbert_color> framebuffer =
daguerre::get_hilbert_framebuffer();
r = new renderer(
daguerre::get_hilbert_framebuffer(),
*daguerre::try_load_ppm("/assets/background.ppm"),
euler::syscall::encode_color(0x00, 0x00, 0x00),
*daguerre::try_load_ppm("/assets/pointer.ppm"),
euler::syscall::encode_color(0xff, 0x00, 0xff));
int fw = framebuffer.width;
int fh = framebuffer.height;
euler::syscall::start_thread([]() { r->render_thread_main(); });
euler::syscall::start_thread(input_thread_main);
daguerre::image<daguerre::hilbert_color> double_buffer(fw, fh);
r->dispatch_render();
std::optional<daguerre::image<daguerre::hilbert_color>>
background_original = daguerre::try_load_ppm("/assets/background.ppm");
daguerre::image<daguerre::hilbert_color> background;
if (background_original.has_value())
background = background_original->stretch(fw, fh);
else {
background = daguerre::image<daguerre::hilbert_color>(fw, fh);
background.fill(euler::syscall::encode_color(0, 0, 0));
}
std::optional<daguerre::image<daguerre::hilbert_color>>
pointer_original = daguerre::try_load_ppm("/assets/pointer.ppm");
if (!pointer_original.has_value())
//TODO
while (1)
;
daguerre::image<daguerre::hilbert_color>
pointer = std::move(*pointer_original);
int mouse_x = fw / 2;
int mouse_y = fh / 2;
euler::syscall::set_thread_name("socket listener thread");
while (true) {
double_buffer.copy_from(background, 0, 0);
double_buffer.convert_from(pointer, mouse_x, mouse_y, 0, 0,
std::min(pointer. width, double_buffer. width - mouse_x),
std::min(pointer.height, double_buffer.height - mouse_y),
&convert_pointer);
framebuffer.copy_from(double_buffer, 0, 0);
auto result = euler::syscall::get_input_packet();
if (std::holds_alternative<euler::syscall::mouse_packet>(result)) {
const auto &packet = std::get<euler::syscall::mouse_packet>(result);
mouse_x += packet.x_changed;
mouse_y += packet.y_changed;
if (mouse_x < 0)
mouse_x = 0;
else if (mouse_x >= fw)
mouse_x = fw - 1;
if (mouse_y < 0)
mouse_y = 0;
else if (mouse_y >= fh)
mouse_y = fh - 1;
}
euler::syscall::stream_handle socket;
euler::syscall::accept_socket_connection(listener, socket);
euler::syscall::start_thread(socket_thread_main, socket);
}
return 0;
}

View file

@ -0,0 +1,5 @@
#pragma once
#include "renderer.hpp"
extern renderer *r;

View file

@ -0,0 +1,102 @@
#include "renderer.hpp"
renderer::renderer(
daguerre::image<daguerre::hilbert_color> &&fb,
daguerre::image<daguerre::hilbert_color> &&bg,
daguerre::hilbert_color bgc,
daguerre::image<daguerre::hilbert_color> &&c,
daguerre::hilbert_color cbg)
: framebuffer(std::move(fb)),
double_buffer(framebuffer.width, framebuffer.height),
background(std::move(bg)), cursor(std::move(c)), cursor_background(cbg),
cursor_x(framebuffer.width / 2), cursor_y(framebuffer.height / 2) {
euler::syscall::create_private_socket(dispatcher_handle_1, dispatcher_handle_2);
if (background.width != framebuffer.width ||
background.height != framebuffer.height) {
daguerre::image<daguerre::hilbert_color>
new_background(framebuffer.width, framebuffer.height);
new_background.fill(bgc);
int from_x = 0;
int from_y = 0;
int to_x = framebuffer.width / 2 - background.width / 2;
int to_y = framebuffer.height / 2 - background.height / 2;
int width = background.width;
int height = background.height;
daguerre::make_safe(to_x, from_x, width, 0, framebuffer.width);
daguerre::make_safe(to_y, from_y, height, 0, framebuffer.height);
new_background.copy_from(background, to_x, to_y, from_x, from_y, width, height);
background = std::move(new_background);
}
}
template <class color_t>
void overlay_trans(color_t &to, const color_t &from, const color_t &param) {
if (from != param)
to = from;
}
void renderer::do_render() {
double_buffer.copy_from(background, 0, 0);
for (auto it = windows.begin(); it != windows.end(); ++it)
double_buffer.copy_from(
(*it)->contents, (*it)->x, (*it)->y, 0, 0,
std::min((*it)->contents.width, double_buffer.width - (*it)->x),
std::min((*it)->contents.height, double_buffer.height - (*it)->y));
double_buffer.convert_from(
cursor_background, cursor, cursor_x, cursor_y, 0, 0,
std::min(cursor.width, framebuffer.width - cursor_x),
std::min(cursor.height, framebuffer.height - cursor_y),
&overlay_trans);
}
[[noreturn]] void renderer::render_thread_main() {
euler::syscall::set_thread_name("render thread");
while (true) {
uint8_t byte;
euler::syscall::read_from_stream(dispatcher_handle_2, 1, &byte);
mut.lock();
euler::syscall::clear_socket_read_queue(dispatcher_handle_2);
do_render();
mut.unlock();
framebuffer.copy_from(double_buffer, 0, 0);
}
}
void renderer::bump_cursor(int x_offset, int y_offset) {
cursor_x += x_offset;
if (cursor_x < 0)
cursor_x = 0;
else if (cursor_x >= framebuffer.width)
cursor_x = framebuffer.width - 1;
cursor_y += y_offset;
if (cursor_y < 0)
cursor_y = 0;
else if (cursor_y >= framebuffer.height)
cursor_y = framebuffer.height - 1;
}
void renderer::add_window(const window *w) {
windows.push_back(w);
}
void renderer::remove_window(const window *w) {
windows.remove(w);
}

View file

@ -0,0 +1,61 @@
#pragma once
#include <daguerre/image.hpp>
#include "window.hpp"
#include <mutex>
#include <list>
class renderer {
daguerre::image<daguerre::hilbert_color> framebuffer;
daguerre::image<daguerre::hilbert_color> double_buffer;
daguerre::image<daguerre::hilbert_color> background;
daguerre::image<daguerre::hilbert_color> cursor;
daguerre::hilbert_color cursor_background;
int cursor_x;
int cursor_y;
//bottom to top
std::list<const window *> windows;
std::mutex mut;
euler::syscall::stream_handle
dispatcher_handle_1, dispatcher_handle_2;
void do_render();
public:
renderer(
daguerre::image<daguerre::hilbert_color> &&framebuffer,
daguerre::image<daguerre::hilbert_color> &&background,
daguerre::hilbert_color background_color,
daguerre::image<daguerre::hilbert_color> &&cursor,
daguerre::hilbert_color cursor_background);
inline ~renderer() {
euler::syscall::close_stream(dispatcher_handle_1);
euler::syscall::close_stream(dispatcher_handle_2);
}
renderer(const renderer &) = delete;
renderer &operator =(const renderer &) = delete;
[[noreturn]] void render_thread_main();
inline void lock() { mut.lock(); }
inline void unlock() { mut.unlock(); }
inline void dispatch_render() {
uint8_t byte = 0;
euler::syscall::write_to_stream(dispatcher_handle_1, 1, &byte);
}
void bump_cursor(int x_offset, int y_offset);
void add_window(const window *w);
void remove_window(const window *w);
};

View file

@ -0,0 +1,162 @@
#include <daguerre/image.hpp>
#include "socket.hpp"
#include "window.hpp"
#include "main.hpp"
#include <memory>
#include <vector>
struct socket_state {
euler::syscall::stream_handle socket;
std::vector<window *> windows;
daguerre::hilbert_color window_bg = euler::syscall::encode_color(0, 0, 0);
bool try_open_window() {
struct [[gnu::packed]] {
uint32_t width;
uint32_t height;
} body;
if (euler::syscall::read_from_stream(socket, sizeof(body), &body) !=
euler::syscall::stream_result::success)
return false;
window *w = new window(body.width, body.height);
w->contents.fill(window_bg);
uint16_t wid = 0;
while (wid < windows.size())
if (windows[wid] != 0)
++wid;
else
break;
if (wid == windows.size())
windows.push_back(w);
else
windows[wid] = w;
r->lock();
r->add_window(w);
r->unlock();
struct [[gnu::packed]] {
uint8_t type;
uint16_t the_window;
} response {
.type = 0x00,
.the_window = wid
};
return
euler::syscall::write_to_stream(socket, sizeof(response), &response) ==
euler::syscall::stream_result::success;
}
bool try_update_window_region() {
struct [[gnu::packed]] {
uint16_t window;
uint32_t start_x;
uint32_t start_y;
uint32_t width;
uint32_t height;
} body_head;
if (euler::syscall::read_from_stream(socket, sizeof(body_head), &body_head) !=
euler::syscall::stream_result::success)
return false;
std::vector<daguerre::hilbert_color> data(body_head.width * body_head.height);
if (euler::syscall::read_from_stream(socket, data.size() * 4, data.data()) !=
euler::syscall::stream_result::success)
return false;
daguerre::image<daguerre::hilbert_color>
data_as_image(body_head.width, body_head.height, data.data(), body_head.width, false);
if (body_head.window >= windows.size() || !windows[body_head.window])
return false;
window *w = windows[body_head.window];
r->lock();
if ((int)body_head.start_x + data_as_image.width > w->contents.width ||
(int)body_head.start_y + data_as_image.height > w->contents.height) {
r->unlock();
return false;
}
w->contents.copy_from(data_as_image, body_head.start_x, body_head.start_y);
r->unlock();
r->dispatch_render();
return true;
}
bool try_close_window() {
uint16_t wid;
if (euler::syscall::read_from_stream(socket, 2, &wid) !=
euler::syscall::stream_result::success)
return false;
if (wid >= windows.size() || !windows[wid])
return false;
r->lock();
r->remove_window(windows[wid]);
windows[wid] = 0;
r->unlock();
r->dispatch_render();
return true;
}
bool try_process_request() {
uint8_t type;
if (euler::syscall::read_from_stream(socket, 1, &type) !=
euler::syscall::stream_result::success)
return false;
switch (type) {
case 0x00: return try_open_window();
case 0x01: return try_update_window_region();
case 0x02: return try_close_window();
default: return false;
}
}
};
[[noreturn]] void socket_thread_main(euler::syscall::stream_handle socket) {
euler::syscall::set_thread_name("socket thread");
socket_state *state = new socket_state {
.socket = socket, .windows = {} };
while (state->try_process_request()) ;
r->lock();
for (unsigned i = 0; i < state->windows.size(); ++i) {
r->remove_window(state->windows[i]);
delete state->windows[i];
}
r->unlock();
delete state;
euler::syscall::close_stream(socket);
euler::syscall::end_this_thread(0);
}

View file

@ -0,0 +1,5 @@
#pragma once
#include <euler/syscall.hpp>
[[noreturn]] void socket_thread_main(euler::syscall::stream_handle socket);

View file

@ -0,0 +1,14 @@
#pragma once
#include <daguerre/image.hpp>
struct window {
daguerre::image<daguerre::hilbert_color> contents;
int x;
int y;
window(int width, int height) : contents(width, height), x(0), y(0) {}
};

View file

@ -0,0 +1,12 @@
SOURCES = \
main.cpp
build/%.cpp.o: source/%.cpp
@mkdir -p $(@D)
$(HILBERT_CC) -c $^ -o $@
build/hello.elf: $(SOURCES:%=build/%.o)
$(HILBERT_CC) $^ -ldaguerre -o $@
clean:
rm -rf build

View file

@ -0,0 +1,37 @@
#include <goldman/protocol.hpp>
#include <daguerre/psf.hpp>
template <class color_t>
void overlay(color_t &to, const bool &from, const color_t &param) {
if (from)
to = param;
}
int main(int, char **) {
auto bg = euler::syscall::encode_color(0xaa, 0xaa, 0xaa);
auto fg = euler::syscall::encode_color(0x00, 0x00, 0x00);
daguerre::image<daguerre::hilbert_color> image(300, 200);
image.fill(bg);
auto font = daguerre::try_load_psf("/assets/terminus-bold-18x10.psf");
image.render_text(*font, fg, 10, 10, "Hello, world!", &overlay);
euler::syscall::stream_handle s;
euler::syscall::connect_to_socket("hilbert.compositor", s);
goldman::protocol::send_open_window(s, 300, 200);
uint8_t byte;
euler::syscall::read_from_stream(s, 1, &byte);
auto w = goldman::protocol::get_window_opened_body(s);
goldman::protocol::send_update_window_region(
s, w, 0, 0, 300, 200, image.buffer, image.buffer_pitch);
euler::syscall::read_from_stream(s, 1, &byte);
__builtin_unreachable();
}

View file

@ -1,11 +1,11 @@
compositors listen on the socket id "hilbert.compositor".
when a window is opened by an application, that window can only be referred to
on that stream. the opaque value given in the "window opened" message refers to
that window in future messages on that stream. it is guaranteed to be distinct
for different windows on the same stream, and in no way guaranteed to be
distinct for different windows on different streams. the window is bound
just to the stream, not to the application. if the stream where a window
on that socket. the opaque value given in the "window opened" message refers to
that window in future messages on that socket. it is guaranteed to be distinct
for different windows on the same socket, and in no way guaranteed to be
distinct for different windows on different sockets. the window is bound
just to the socket, not to the application. if the socket where a window
was created is gifted to a new process, the new process has complete control
over the window, and the compositor does not need to be informed.
@ -37,8 +37,13 @@ messages from applications to compositor:
dword: height
color rectangle: the data
close window:
byte: 0x02
window: the window
messages from compositor to application:
window opened:
byte: 0x00
window: the window
these come in the order the open window requests were received

View file

@ -198,3 +198,8 @@ get environment variable value:
rdi in: pointer to variable name
rsi in: variable name length
rdx in: pointer to buffer for variable value
set thread name:
rax in: 24
rdi in: pointer to thread name
rsi in: thread name length

View file

@ -1,11 +1,11 @@
#pragma once
#include <std/fwd/string.hpp>
#include <std/fwd/vector.hpp>
#include <optional>
#include <cstdint>
#include <utility>
#include <variant>
#include <string>
#include <vector>
namespace euler::syscall {
@ -124,6 +124,30 @@ namespace euler::syscall {
//entry_point must not return
void start_thread(void (*entry_point)(uint64_t), uint64_t arg);
//entry_point must not return
template <class obj_t>
void start_thread(void (*entry_point)(obj_t *), obj_t *arg) {
start_thread((void (*)(uint64_t))entry_point, (uint64_t)arg);
}
//entry_point must not return
template <class obj_t>
void start_thread(void (*entry_point)(const obj_t *), const obj_t *arg) {
start_thread((void (*)(uint64_t))entry_point, (uint64_t)arg);
}
//entry_point must not return
template <class obj_t>
void start_thread(void (*entry_point)(obj_t &), obj_t &arg) {
start_thread((void (*)(uint64_t))entry_point, (uint64_t)&arg);
}
//entry_point must not return
template <class obj_t>
void start_thread(void (*entry_point)(const obj_t &), const obj_t &arg) {
start_thread((void (*)(uint64_t))entry_point, (uint64_t)&arg);
}
//entry_point must not return
void start_thread(void (*entry_point)());
@ -133,4 +157,9 @@ namespace euler::syscall {
std::optional<std::string> try_get_environment_variable(
const std::string &name);
void set_thread_name(const std::string &name);
}
#include <string>
#include <vector>

3
euler/include/list Normal file
View file

@ -0,0 +1,3 @@
#pragma once
#include <std/list.hpp>

4
euler/include/mutex Normal file
View file

@ -0,0 +1,4 @@
#pragma once
#include <std/unique_lock.hpp>
#include <std/mutex.hpp>

View file

@ -1,5 +1,7 @@
#pragma once
#include <std/fwd/allocator.hpp>
#include <euler/heap.hpp>
namespace std {

View file

@ -0,0 +1,6 @@
#pragma once
namespace std {
template <class T>
struct allocator;
}

View file

@ -0,0 +1,5 @@
#pragma once
namespace std {
class string;
}

View file

@ -0,0 +1,8 @@
#pragma once
#include <std/fwd/allocator.hpp>
namespace std {
template <class T, class Allocator = std::allocator<T>>
class vector;
}

157
euler/include/std/list.hpp Normal file
View file

@ -0,0 +1,157 @@
#pragma once
#include <memory>
namespace std {
template <class T, class Allocator = std::allocator<T>>
class list {
public:
struct node {
T value;
node *prev;
node *next;
};
template <class V>
struct generic_iterator {
node *the_node;
bool operator ==(const generic_iterator &other) {
return the_node == other.the_node;
}
bool operator !=(const generic_iterator &other) {
return the_node != other.the_node;
}
V &operator *() {
return the_node->value;
}
V *operator ->() {
return &the_node->value;
}
generic_iterator &operator ++() {
the_node = the_node->next;
return *this;
}
};
using iterator = generic_iterator<T>;
using const_iterator = generic_iterator<const T>;
private:
node *first_node;
node *last_node;
size_t count;
public:
void push_back(const T &value) {
node *n = new node { .value = value,
.prev = last_node, .next = 0 };
if (last_node) last_node->next = n;
else first_node = n;
last_node = n;
++count;
}
void push_back(T &&value) {
node *n = new node {
.value = std::move(value),
.prev = last_node, .next = 0 };
if (last_node) last_node->next = n;
else first_node = n;
last_node = n;
++count;
}
iterator erase(iterator pos) {
--count;
auto *n = pos.the_node;
auto *r = n->next;
if (n->prev) n->prev->next = n->next;
else first_node = n->next;
if (n->next) n->next->prev = n->prev;
else last_node = n->prev;
delete n;
return iterator { .the_node = r };
}
iterator begin() const noexcept {
return iterator { .the_node = first_node };
}
iterator end() const noexcept {
return iterator { .the_node = 0 };
}
size_t remove(const T &value) {
size_t removed = 0;
auto it = begin();
while (it != end())
if (*it == value) {
it = erase(it);
++removed;
}
else
++it;
count -= removed;
return removed;
}
list() : first_node(0), last_node(0), count(0) {}
list(const list &other) : first_node(0), last_node(0), count(0) {
for (node *n = other.first_node; n; n = n->next)
push_back(n->value);
}
list(list &&other) : first_node(other.first_node),
last_node(other.last_node), count(other.count) {
other.first_node = 0;
other.last_node = 0;
other.count = 0;
}
void clear() {
if (count == 0) return;
for (node *n = first_node->next; n; n = n->next)
delete n->prev;
delete last_node;
first_node = 0;
last_node = 0;
count = 0;
}
~list() {
clear();
}
list &operator =(const list &other) {
clear();
for (node *n = other.first_node; n; n = n->next)
push_back(n->value);
}
list &operator =(list &&other) {
clear();
first_node = other.first_node;
last_node = other.last_node;
count = other.count;
other.first_node = 0;
other.last_node = 0;
other.count = 0;
}
};
}

View file

@ -0,0 +1,40 @@
#pragma once
#include <euler/syscall.hpp>
namespace std {
class mutex {
euler::syscall::stream_handle in_handle;
euler::syscall::stream_handle out_handle;
public:
inline mutex() noexcept {
euler::syscall::create_private_socket(in_handle, out_handle);
uint8_t byte = 0;
euler::syscall::write_to_stream(in_handle, 1, &byte);
}
mutex(const mutex &) = delete;
inline ~mutex() {
euler::syscall::close_stream(in_handle);
euler::syscall::close_stream(out_handle);
}
mutex &operator =(const mutex &) = delete;
inline void lock() {
uint8_t byte;
euler::syscall::read_from_stream(out_handle, 1, &byte);
}
inline void unlock() {
uint8_t byte = 0;
euler::syscall::write_to_stream(in_handle, 1, &byte);
}
};
}

View file

@ -1,5 +1,7 @@
#pragma once
#include <std/fwd/string.hpp>
#include <cstddef>
#include <vector>
@ -16,9 +18,7 @@ namespace std {
: characters(other.characters) {}
constexpr string(string &&other) noexcept
: characters(std::move(other.characters)) {
other.characters.push_back('\0');
}
: characters(std::move(other.characters)) {}
constexpr string(const char *s) {
size_t count = 0;
@ -38,7 +38,6 @@ namespace std {
constexpr string &operator =(string &&str) noexcept {
characters = std::move(str.characters);
str.characters.push_back('\0');
return *this;
}

View file

@ -0,0 +1,53 @@
#pragma once
namespace std {
template <class Mutex>
class unique_lock {
Mutex *the_mutex;
bool has_locked;
public:
inline unique_lock() noexcept : the_mutex(0) {}
unique_lock(const unique_lock &other) = delete;
inline unique_lock(unique_lock &&other) noexcept
: the_mutex(other.the_mutex), has_locked(other.has_locked) {
other.the_mutex = 0;
}
inline explicit unique_lock(Mutex &m)
: the_mutex(&m), has_locked(true) {
the_mutex->lock();
}
inline ~unique_lock() {
if (the_mutex && has_locked)
the_mutex->unlock();
}
unique_lock &operator =(const unique_lock &other) = delete;
inline unique_lock &operator =(unique_lock &&other) {
if (the_mutex && has_locked)
the_mutex->unlock();
the_mutex = other.the_mutex;
has_locked = other.has_locked;
other.the_mutex = 0;
}
inline void lock() {
the_mutex->lock();
has_locked = true;
}
inline void unlock() {
the_mutex->unlock();
has_locked = false;
}
};
}

View file

@ -1,10 +1,12 @@
#pragma once
#include <std/fwd/vector.hpp>
#include <memory>
namespace std {
template <class T, class Allocator = std::allocator<T>>
template <class T, class Allocator>
class vector {
public:

View file

@ -6,6 +6,8 @@ int main(int argc, char **argv);
extern "C" [[noreturn]] void _start() {
//TODO: call static initializers
auto argc_raw = euler::syscall::try_get_environment_variable("ARGC");
int argc = argc_raw.has_value() ? std::stoi(argc_raw.value()) : 0;

View file

@ -1,4 +1,5 @@
#include <cstdio>
#include <string>
extern "C" FILE *fopen(const char *filename, const char *mode) {

View file

@ -44,6 +44,7 @@ namespace std {
value = value * base + c - 'A' + 10;
else
break;
++i;
}
if (pos != 0)
@ -75,10 +76,11 @@ namespace std {
}
std::string operator +(std::string &&lhs, std::string &&rhs) {
size_t og_lhs_s = lhs.size();
std::string s = std::move(lhs);
s.resize(lhs.size() + rhs.size());
s.resize(og_lhs_s + rhs.size());
for (size_t i = 0; i < rhs.size(); ++i)
s[lhs.size() + i] = rhs[i];
s[og_lhs_s + i] = rhs[i];
rhs.clear();
return s;
}

View file

@ -1,4 +1,5 @@
#include <euler/stream.hpp>
#include <algorithm>
#include <cstring>
namespace euler {

View file

@ -1,4 +1,6 @@
#include <euler/syscall.hpp>
#include <string>
#include <vector>
extern "C" void __euler_do_syscall(
uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx);
@ -394,4 +396,15 @@ namespace euler::syscall {
}
void set_thread_name(const std::string &name) {
uint64_t rax = 24;
uint64_t rdi = (uint64_t)name.data();
uint64_t rsi = name.size();
uint64_t rdx;
__euler_do_syscall(rax, rdi, rsi, rdx);
}
}

View file

@ -112,6 +112,8 @@ namespace hilbert::kernel::application {
utility::list<string_pair> environment_variables;
public:
utility::string name;
app_memory *memory;
//set in get_framebuffer syscall
@ -121,13 +123,16 @@ namespace hilbert::kernel::application {
uint64_t id;
//this class takes ownership of memory
process(app_memory *memory);
process(app_memory *memory, const utility::string &name);
~process();
//arguments are utility::move'd
void add_environment_variable(
utility::string &&name, utility::string &&value);
//null if unset
utility::string *get_environment_variable(const utility::string &name);
void add_thread(thread *t);
void notify_thread_ended(thread *t, int exit_code);
void on_end_process(int exit_code);
@ -180,6 +185,8 @@ namespace hilbert::kernel::application {
utility::maybe<unsigned> new_socket_stream_id;
public:
utility::string name;
process *owner;
//the cpu state is saved here when the thread is not running.

View file

@ -1,5 +1,6 @@
#pragma once
#include <hilbert/kernel/utility.hpp>
#include <stdint.h>
namespace hilbert::kernel {
@ -15,6 +16,11 @@ namespace hilbert::kernel {
}
}
static inline void serial_putstr(const utility::string &str) {
for (unsigned i = 0; i < str.count; ++i)
serial_putchar(str.buffer[i]);
}
template <int digits, int dot_every = 4>
static inline void serial_puthex(uint64_t n) {
for (int d = digits - 1; d >= 0; --d) {

View file

@ -107,6 +107,10 @@ namespace hilbert::kernel::utility {
n->value = value;
n->next = 0;
n->prev = last;
if (last)
last->next = n;
else
first = n;
last = n;
}
@ -115,12 +119,19 @@ namespace hilbert::kernel::utility {
n->value = value;
n->next = 0;
n->prev = last;
if (last)
last->next = n;
else
first = n;
last = n;
}
void clear() {
for (node *n = first; n; n = n->next)
delete n;
if (first) {
for (node *n = first->next; n; n = n->next)
delete n->prev;
delete last;
}
first = 0;
last = 0;
}

View file

@ -83,7 +83,8 @@ namespace hilbert::kernel::application {
resume_thread(t->saved_state);
}
process::process(app_memory *memory) : memory(memory) {}
process::process(app_memory *memory, const utility::string &name)
: name(name), memory(memory) {}
process::~process() {
delete memory; //:p
@ -94,6 +95,14 @@ namespace hilbert::kernel::application {
environment_variables.insert_end({.a = name, .b = value});
}
utility::string *process::get_environment_variable(
const utility::string &name) {
for (auto *i = environment_variables.first; i; i = i->next)
if (i->value.a == name)
return &i->value.b;
return 0;
}
void process::add_thread(thread *t) {
threads.insert_end(t);
}
@ -197,8 +206,8 @@ namespace hilbert::kernel::application {
thread::thread(process *owner, uint64_t entry)
: stack_top(owner->memory->map_new_stack()), waiting_for_socket_stream(0),
waiting_to_accept_from(0), waiting_to_connect_to(0),
waiting_for_input(false), owner(owner) {
waiting_to_accept_from(0), waiting_to_connect_to(0), waiting_for_input(false),
name(utility::string("main", 4)), owner(owner) {
saved_state.rax = 0;
saved_state.rbx = 0;

View file

@ -214,7 +214,8 @@ extern "C" [[noreturn]] void entry() {
if (load_init_result != load_app_result::success)
panic(0xc39db3);
application::process *init_process = new application::process(init_memory);
application::process *init_process =
new application::process(init_memory, utility::string("init", 4));
init_process->add_environment_variable(
utility::string("ARGC", 4), utility::string("1", 1));
init_process->add_environment_variable(

View file

@ -79,6 +79,11 @@ extern "C" [[noreturn]] void print_exception() {
print_reg("r14", exception_info.r14);
print_reg("r15", exception_info.r15);
if (application::running_thread != 0) {
serial_putstr("running app = ");
serial_putstr(application::running_thread->owner->name);
}
panic(0xba40bb);
}

View file

@ -183,7 +183,7 @@ namespace hilbert::kernel::syscall {
.waiting_to_read = utility::queue<application::thread *>(),
.is_other_side_open = true, .other_process = p2, .other_end = 0 };
se2_out = new application::socket_stream_end {
.the_socket = s, .read_queue = s->queue_2, .write_queue = s->queue_2,
.the_socket = s, .read_queue = s->queue_2, .write_queue = s->queue_1,
.waiting_to_read = utility::queue<application::thread *>(),
.is_other_side_open = true, .other_process = p1, .other_end = se1_out };
se1_out->other_end = se2_out;
@ -494,8 +494,12 @@ namespace hilbert::kernel::syscall {
rax = (uint64_t)application::stream_result::other_end_closed;
return;
}
for (uint64_t i = 0; i < count; ++i)
auto &wtr_queue = ss->other_end->waiting_to_read;
for (uint64_t i = 0; i < count; ++i) {
ss->write_queue.insert(buffer[i]);
if (wtr_queue.count > 0)
application::paused_threads->insert(wtr_queue.take());
}
rax = (uint64_t)application::stream_result::success;
}
@ -617,7 +621,8 @@ namespace hilbert::kernel::syscall {
break;
}
application::process *p = new application::process(memory);
application::process *p =
new application::process(memory, file.dir_entry.name);
for (uint64_t i = 0; i < psi->env_var_count; ++i)
p->add_environment_variable(
@ -735,6 +740,66 @@ namespace hilbert::kernel::syscall {
}
void get_environment_variable_length_syscall(
uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) {
const char *name = (const char *)rdi;
uint64_t name_len = rsi;
set_zero(rax, rdi, rsi, rdx);
auto *app = application::running_thread->owner;
if (!app->memory->valid_to_read(name, name + name_len, false))
return;
utility::string name_string(name, name_len);
utility::string *value = app->get_environment_variable(name_string);
rax = value == 0 ? (uint64_t)-1 : value->count;
}
void get_environment_variable_value_syscall(
uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) {
const char *name = (const char *)rdi;
uint64_t name_len = rsi;
char *buffer = (char *)rdx;
set_zero(rax, rdi, rsi, rdx);
auto *app = application::running_thread->owner;
if (!app->memory->valid_to_read(name, name + name_len, false))
return;
utility::string name_string(name, name_len);
utility::string *value = app->get_environment_variable(name_string);
if (value == 0)
return;
if (!app->memory->valid_to_read(buffer, buffer + value->count, true))
return;
for (unsigned i = 0; i < value->count; ++i)
buffer[i] = value->buffer[i];
}
void set_thread_name_syscall(
uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) {
const char *name = (const char *)rdi;
uint64_t name_len = rsi;
set_zero(rax, rdi, rsi, rdx);
auto *t = application::running_thread;
if (!t->owner->memory->valid_to_read(name, name + name_len, false))
return;
t->name = utility::string(name, name_len);
}
void (*handlers[])(
uint64_t &rax, uint64_t &rdi, uint64_t &rsi, uint64_t &rdx) = {
@ -759,11 +824,14 @@ namespace hilbert::kernel::syscall {
&set_stream_length_syscall,
&get_other_end_process_handle_syscall,
&start_thread_syscall,
&clear_socket_read_queue_syscall
&clear_socket_read_queue_syscall,
&get_environment_variable_length_syscall,
&get_environment_variable_value_syscall,
&set_thread_name_syscall
};
static constexpr int max_syscall_number = 20;
static constexpr int max_syscall_number = 24;
}

View file

@ -20,7 +20,7 @@ namespace daguerre {
template <class color_t>
fixed_font<color_t>::fixed_font(fixed_font<color_t> &&other)
: glyph_width(other.glyph_width), glyph_height(other.glyph_height) {
for (int i = 0; 0 < 128; ++i)
for (int i = 0; i < 128; ++i)
glyphs[i] = std::move(other.glyphs[i]);
other.glyph_width = 0;
other.glyph_height = 0;
@ -31,7 +31,7 @@ namespace daguerre {
fixed_font<color_t> &&other) {
glyph_width = other.glyph_width;
glyph_height = other.glyph_height;
for (int i = 0; 0 < 128; ++i)
for (int i = 0; i < 128; ++i)
glyphs[i] = std::move(other.glyphs[i]);
other.glyph_width = 0;
other.glyph_height = 0;

View file

@ -185,7 +185,7 @@ namespace daguerre {
const param_t &param, const image<other_color_t> &other, int to_x,
int to_y, param_converter_t<color_t, other_color_t, param_t> *conversion) {
convert_from(
param, other, to_x, to_y, 0, 0, other.width, other.y, conversion);
param, other, to_x, to_y, 0, 0, other.width, other.height, conversion);
}
template <class color_t>

View file

@ -0,0 +1,85 @@
#pragma once
#include <euler/syscall.hpp>
#include <memory>
//TODO: handle stream errors, make thread safe
namespace goldman::protocol {
typedef euler::syscall::encoded_color color;
typedef uint16_t window;
static inline void send_open_window(
euler::syscall::stream_handle socket, uint32_t width, uint32_t height) {
struct [[gnu::packed]] {
uint8_t type;
uint32_t width;
uint32_t height;
} packet {
.type = 0x00,
.width = width,
.height = height
};
euler::syscall::write_to_stream(socket, sizeof(packet), &packet);
}
void send_update_window_region(
euler::syscall::stream_handle socket, window the_window,
uint32_t start_x, uint32_t start_y, uint32_t width,
uint32_t height, const color *the_data, size_t data_pitch) {
struct [[gnu::packed]] {
uint8_t type;
window the_window;
uint32_t start_x;
uint32_t start_y;
uint32_t width;
uint32_t height;
} packet_head {
.type = 0x01,
.the_window = the_window,
.start_x = start_x,
.start_y = start_y,
.width = width,
.height = height
};
euler::syscall::write_to_stream(socket, sizeof(packet_head), &packet_head);
for (uint32_t y = 0; y < height; ++y)
euler::syscall::write_to_stream(
socket, width * sizeof(color), the_data + data_pitch * y);
}
void send_close_window(
euler::syscall::stream_handle socket, window the_window) {
struct [[gnu::packed]] {
uint8_t type;
window the_window;
} packet {
.type = 0x02,
.the_window = the_window
};
euler::syscall::write_to_stream(socket, sizeof(packet), &packet);
}
enum class response_id : uint8_t {
window_opened
};
window get_window_opened_body(euler::syscall::stream_handle socket) {
window w;
euler::syscall::read_from_stream(socket, sizeof(w), &w);
return w;
}
}

View file

@ -7,7 +7,8 @@ EXTRA_CC_ARGS = -Wall -Wextra -Og -ggdb -fno-exceptions
HILBERT_NASM = nasm -f elf64
HILBERT_CC = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-c++ -std=c++20 \
${EXTRA_CC_ARGS} -static -mno-sse -I include -I $(abspath euler/include) \
-I $(abspath libraries/daguerre/include) -I ${MINTSUKI_HEADERS_DIR}
-I $(abspath libraries/daguerre/include) -I ${MINTSUKI_HEADERS_DIR} \
-I $(abspath libraries/goldman/include)
HILBERT_AR = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-ar
HILBERT_LD = ${TOOLCHAIN_DIR}/usr/bin/x86_64-elf-ld -z noexecstack
@ -25,8 +26,8 @@ LIBSTDCPP_DEP = toolchain/.libstdcpp-done
EULER_DEP = toolchain/.euler-done
DAGUERRE_DEP = toolchain/.daguerre-done
APP_DEPS = ${GCC_DEP} ${LIBGCC_DEP} ${LIBSTDCPP_DEP} ${EULER_DEP}
LIBRARY_DEPS = ${GCC_DEP} ${LIBSTDCPP_DEP}
APP_DEPS = ${EULER_DEP}
LIBRARY_DEPS = ${LIBSTDCPP_DEP}
.PHONY: default run clean clean-dependencies
@ -41,6 +42,7 @@ clean:
make -C kernel clean
make -C applications/init clean
make -C applications/goldman clean
make -C applications/hello clean
make -C libraries/daguerre clean
clean-dependencies: clean
@ -90,7 +92,7 @@ ${LIBGCC_DEP}: ${GCC_DEP}
+make -C dependencies/gcc/build install-target-libgcc
touch $@
${LIBSTDCPP_DEP}: ${GCC_DEP}
${LIBSTDCPP_DEP}: ${LIBGCC_DEP}
+make -C dependencies/gcc/build all-target-libstdc++-v3
+make -C dependencies/gcc/build install-target-libstdc++-v3
patch toolchain/usr/x86_64-elf/include/c++/14.1.0/memory patches/gcc-memory.patch
@ -117,13 +119,18 @@ applications/init/build/init.elf: ${APP_DEPS}
applications/goldman/build/goldman.elf: ${APP_DEPS} ${DAGUERRE_DEP}
+make -C applications/goldman build/goldman.elf
applications/hello/build/hello.elf: ${APP_DEPS} ${DAGUERRE_DEP}
+make -C applications/hello build/hello.elf
build/initfs.tgz: applications/init/build/init.elf \
applications/goldman/build/goldman.elf
applications/goldman/build/goldman.elf \
applications/hello/build/hello.elf
@mkdir -p build
rm -rf build/initfs
cp -r skeleton build/initfs
cp applications/init/build/init.elf build/initfs/bin/init
cp applications/goldman/build/goldman.elf build/initfs/bin/goldman
cp applications/hello/build/hello.elf build/initfs/bin/hello
cd build/initfs && tar czf ../initfs.tgz .
build/disk.iso: kernel/build/kernel.elf build/initfs.tgz ${LIMINE_DEP}

View file

@ -1,6 +1,5 @@
target remote | qemu-system-x86_64 -gdb stdio -cdrom build/disk.iso -boot d
symbol-file kernel/build/kernel.elf
add-symbol-file applications/goldman/build/goldman.elf
set disassembly-flavor intel
set print asm-demangle on
layout src

View file

@ -67,7 +67,7 @@ the following directories and files are released under the text in cc0.txt
project structure:
- applications/goldman:
in the future, this will be the default compositor.
the default compositor, in a very early stage
- applications/init:
the initial program loaded by the kernel. currently it just
@ -87,6 +87,9 @@ project structure:
- libraries/daguerre:
an image loading / rendering library.
- libraries/goldman:
a library for interfacing with the goldman compositor
- patches:
a couple patches that are applied to dependencies