some work on compositor
This commit is contained in:
parent
3636fd21e0
commit
be691582ee
44 changed files with 1018 additions and 100 deletions
|
@ -1,5 +1,5 @@
|
|||
SOURCES = \
|
||||
main.cpp
|
||||
main.cpp renderer.cpp input.cpp socket.cpp
|
||||
|
||||
build/%.cpp.o: source/%.cpp
|
||||
@mkdir -p $(@D)
|
||||
|
|
21
applications/goldman/source/input.cpp
Normal file
21
applications/goldman/source/input.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
3
applications/goldman/source/input.hpp
Normal file
3
applications/goldman/source/input.hpp
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
[[noreturn]] void input_thread_main();
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
5
applications/goldman/source/main.hpp
Normal file
5
applications/goldman/source/main.hpp
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "renderer.hpp"
|
||||
|
||||
extern renderer *r;
|
102
applications/goldman/source/renderer.cpp
Normal file
102
applications/goldman/source/renderer.cpp
Normal 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 ¶m) {
|
||||
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);
|
||||
}
|
61
applications/goldman/source/renderer.hpp
Normal file
61
applications/goldman/source/renderer.hpp
Normal 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);
|
||||
|
||||
};
|
162
applications/goldman/source/socket.cpp
Normal file
162
applications/goldman/source/socket.cpp
Normal 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);
|
||||
|
||||
}
|
5
applications/goldman/source/socket.hpp
Normal file
5
applications/goldman/source/socket.hpp
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <euler/syscall.hpp>
|
||||
|
||||
[[noreturn]] void socket_thread_main(euler::syscall::stream_handle socket);
|
14
applications/goldman/source/window.hpp
Normal file
14
applications/goldman/source/window.hpp
Normal 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) {}
|
||||
|
||||
};
|
12
applications/hello/makefile
Normal file
12
applications/hello/makefile
Normal 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
|
37
applications/hello/source/main.cpp
Normal file
37
applications/hello/source/main.cpp
Normal 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 ¶m) {
|
||||
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();
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
3
euler/include/list
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#include <std/list.hpp>
|
4
euler/include/mutex
Normal file
4
euler/include/mutex
Normal file
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
#include <std/unique_lock.hpp>
|
||||
#include <std/mutex.hpp>
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <std/fwd/allocator.hpp>
|
||||
|
||||
#include <euler/heap.hpp>
|
||||
|
||||
namespace std {
|
||||
|
|
6
euler/include/std/fwd/allocator.hpp
Normal file
6
euler/include/std/fwd/allocator.hpp
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
namespace std {
|
||||
template <class T>
|
||||
struct allocator;
|
||||
}
|
5
euler/include/std/fwd/string.hpp
Normal file
5
euler/include/std/fwd/string.hpp
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
namespace std {
|
||||
class string;
|
||||
}
|
8
euler/include/std/fwd/vector.hpp
Normal file
8
euler/include/std/fwd/vector.hpp
Normal 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
157
euler/include/std/list.hpp
Normal 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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
40
euler/include/std/mutex.hpp
Normal file
40
euler/include/std/mutex.hpp
Normal 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);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
53
euler/include/std/unique_lock.hpp
Normal file
53
euler/include/std/unique_lock.hpp
Normal 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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
extern "C" FILE *fopen(const char *filename, const char *mode) {
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <euler/stream.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace euler {
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -185,7 +185,7 @@ namespace daguerre {
|
|||
const param_t ¶m, 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>
|
||||
|
|
85
libraries/goldman/include/goldman/protocol.hpp
Normal file
85
libraries/goldman/include/goldman/protocol.hpp
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
}
|
17
makefile
17
makefile
|
@ -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}
|
||||
|
|
1
qemu.gdb
1
qemu.gdb
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Reference in a new issue