@ -1,164 +0,0 @@ | |||||
#pragma once | |||||
#include "gp/algorithm/move.hpp" | |||||
#include "gp/allocator/aggregator.hpp" | |||||
#include "gp/array.hpp" | |||||
#include "gp/vfs/fs_types.hpp" | |||||
namespace gp { | |||||
template<typename error_function, typename pop_function> | |||||
class self_filling_channel{ | |||||
error_function on_error; | |||||
pop_function filler; | |||||
gp::buffer<char>::associated_iterator push(gp::buffer<char> input) { | |||||
return filler(input); | |||||
} | |||||
gp::buffer<char>::associated_iterator pop(gp::buffer<char> dest) { | |||||
on_error(); | |||||
return dest.begin(); | |||||
} | |||||
}; | |||||
template<typename error_function, typename push_function> | |||||
class input_channel{ | |||||
error_function on_error; | |||||
push_function filler; | |||||
gp::buffer<char>::associated_iterator push(gp::buffer<char> input) { | |||||
on_error(); | |||||
return input.begin(); | |||||
} | |||||
gp::buffer<char>::associated_iterator pop(gp::buffer<char> dest) { | |||||
return filler(dest); | |||||
} | |||||
}; | |||||
template<size_t size, size_t count = 1, bool whole_messages = true, bool zero_out = true> | |||||
class channel { | |||||
gp::array<size_t, count> message_sizes; | |||||
gp::array< | |||||
gp::array<char, size>, | |||||
count | |||||
> messages; | |||||
size_t r_offset = 0; | |||||
size_t w_offset = 0; | |||||
[[nodiscard]] size_t write_one(size_t loc, gp::buffer<char> message) { | |||||
auto cond = message.size(); | |||||
size_t idx = 0; | |||||
for(; idx < cond; ++idx) { | |||||
messages[loc][idx] = message[idx]; | |||||
} | |||||
message_sizes[loc] = message.size(); | |||||
w_offset += 1; | |||||
if constexpr (count != 1) w_offset %= size; | |||||
if constexpr (zero_out) { | |||||
auto ret = idx; | |||||
for(; idx < messages[loc].size(); ++idx) { | |||||
messages[loc] = 0; | |||||
} | |||||
return ret; | |||||
} | |||||
return idx; | |||||
} | |||||
[[nodiscard]] size_t read_one(size_t loc, gp::buffer<char> message) { | |||||
size_t ret; | |||||
size_t idx = 0; | |||||
size_t trailer = 0; | |||||
if(message_sizes[loc] < message.size()) | |||||
{ | |||||
for(; idx < message_sizes[loc]; ++idx) { | |||||
message[idx] = messages[loc][idx]; | |||||
} | |||||
r_offset += 1; | |||||
if constexpr (count != 1) w_offset %= size; | |||||
ret = idx; | |||||
} else { | |||||
for(; idx < message.size(); ++idx) { | |||||
message[idx] = messages[loc][idx]; | |||||
} | |||||
ret = idx; | |||||
for(; idx < message_sizes[loc]; ++idx, ++trailer) | |||||
{ | |||||
message[trailer] = message[idx]; | |||||
} | |||||
message_sizes[loc] = trailer; | |||||
} | |||||
if constexpr (zero_out) { | |||||
if(trailer == 0) { | |||||
message_sizes[loc] = 0; | |||||
} | |||||
for(; trailer < messages[loc].size(); ++trailer) | |||||
{ | |||||
messages[loc][trailer] = 0; | |||||
} | |||||
} | |||||
return ret; | |||||
} | |||||
public: | |||||
channel() {} | |||||
gp::buffer<char>::associated_iterator push(gp::buffer<char> input) { | |||||
if constexpr (whole_messages) { | |||||
if(input.size() > size) { | |||||
return input.begin(); | |||||
} | |||||
} | |||||
if constexpr (count == 1) { | |||||
if(w_offset == r_offset) { | |||||
auto to_write = gp::min(input.size(), size); | |||||
write_one( | |||||
0, | |||||
gp::buffer<char>(input.begin().data, to_write) | |||||
); | |||||
return input.begin()+to_write; | |||||
} else { | |||||
return input.begin(); | |||||
} | |||||
} else { | |||||
auto next_w = (w_offset+1)%count; | |||||
auto to_consume = input; | |||||
while(to_consume.size() && (next_w == r_offset)) { | |||||
auto to_write = gp::min(to_consume.size(), size); | |||||
to_write = write_one( | |||||
w_offset, | |||||
to_consume.trim_start(to_write) | |||||
); | |||||
to_consume = to_consume.trim_start(to_write); | |||||
next_w = (w_offset+1)%count; | |||||
} | |||||
return to_consume.begin(); | |||||
} | |||||
} | |||||
gp::buffer<char>::associated_iterator pop(gp::buffer<char> dest) { | |||||
if(r_offset == w_offset) { | |||||
return dest.begin(); | |||||
} | |||||
size_t idx; | |||||
if constexpr (count == 1) { | |||||
idx = 0; | |||||
} else { | |||||
idx = r_offset; | |||||
} | |||||
if constexpr (whole_messages) { | |||||
if(message_sizes[idx] > dest.size()) { | |||||
return dest.begin(); | |||||
} | |||||
auto sz = gp::min(message_sizes[idx], dest.size()); | |||||
read_one(idx, gp::buffer<char>(dest.begin(), sz)); | |||||
return dest.begin()+sz; | |||||
} | |||||
auto to_fill = dest; | |||||
do{ | |||||
auto to_read = gp::min(to_fill.size(), size); | |||||
to_read = read_one( | |||||
r_offset, | |||||
to_fill.trim_start(to_read) | |||||
); | |||||
to_fill = to_fill.trim_start(to_read); | |||||
}while(r_offset != w_offset && to_fill.size()); | |||||
return to_fill.begin(); | |||||
} | |||||
}; | |||||
} |
@ -0,0 +1,9 @@ | |||||
#pragma once | |||||
namespace gp { | |||||
class file_description { | |||||
}; | |||||
} |
@ -0,0 +1,24 @@ | |||||
#pragma once | |||||
#include "gp/buffer.hpp" | |||||
#include "gp/vector.hpp" | |||||
#include "gp/vfs/file_description.hpp" | |||||
namespace gp{ | |||||
struct file_char { | |||||
// v cannot contain '/' or 0 | |||||
char v; | |||||
}; | |||||
struct fs_user_representation { | |||||
virtual uint32_t to_posix() = 0; | |||||
virtual gp::vector<std::byte> to_sid() = 0; | |||||
}; | |||||
class filesystem { | |||||
virtual file_description create(gp::buffer<file_char>, fs_user_representation) = 0; | |||||
virtual file_description open(gp::buffer<file_char>, fs_user_representation) = 0; | |||||
virtual file_description remove(gp::buffer<file_char>, fs_user_representation) = 0; | |||||
}; | |||||
} |
@ -1,306 +0,0 @@ | |||||
#pragma once | |||||
#include "gp_config.hpp" | |||||
#include "gp/buffer.hpp" | |||||
#include "gp/variant.hpp" | |||||
namespace gp { | |||||
namespace fs { | |||||
struct bad_file final { | |||||
static constexpr auto _what = "bad_file"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct faulty_buffer final { | |||||
static constexpr auto _what = "faulty_buffer"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct interrupted final { | |||||
static constexpr auto _what = "interrupted"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct io_error final { | |||||
static constexpr auto _what = "io_error"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct is_directory final { | |||||
static constexpr auto _what = "is_directory"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct try_again final { | |||||
static constexpr auto _what = "try_again"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct not_connected final { | |||||
static constexpr auto _what = "not_connected"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct impossible_io final { | |||||
static constexpr auto _what = "impossible_io"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct negative_offset final { | |||||
static constexpr auto _what = "negative_offset"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct is_pipe final { | |||||
static constexpr auto _what = "is_pipe"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct buffer_too_big final { | |||||
static constexpr auto _what = "buffer_too_big"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct path_not_directory final { | |||||
static constexpr auto _what = "path_not_directory"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct name_too_long final { | |||||
static constexpr auto _what = "name_too_long"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct does_not_exist final { | |||||
static constexpr auto _what = "does_not_exist"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct may_loop final { | |||||
static constexpr auto _what = "may_loop"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct invalid_flags final { | |||||
static constexpr auto _what = "invalid_flags"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct is_read_only final { | |||||
static constexpr auto _what = "is_read_only"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct fd_limit_reached final { | |||||
static constexpr auto _what = "fd_limit_reached"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct file_limit_reached final { | |||||
static constexpr auto _what = "file_limit_reached"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct no_locking final { | |||||
static constexpr auto _what = "no_locking"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct would_block final { | |||||
static constexpr auto _what = "would_block"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct no_inodes final { | |||||
static constexpr auto _what = "no_inodes"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct no_space final { | |||||
static constexpr auto _what = "no_space"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct quota_reached final { | |||||
static constexpr auto _what = "quota_reached"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct cannot_write_shared_text final { | |||||
static constexpr auto _what = "cannot_write_shared_text"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct faulty_filename final { | |||||
static constexpr auto _what = "faulty_filename"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct exists_already final { | |||||
static constexpr auto _what = "exists_already"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct is_append_only final { | |||||
static constexpr auto _what = "is_append_only"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct unimplemented_operation final { | |||||
static constexpr auto _what = "unimplemented_operation"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct is_busy final { | |||||
static constexpr auto _what = "is_busy"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct bad_relative_path final { | |||||
static constexpr auto _what = "bad_relative_path"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct no_permissions final { | |||||
static constexpr auto _what = "no_permissions"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct success final { | |||||
static constexpr auto _what = "success"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct too_big final { | |||||
static constexpr auto _what = "too_big"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct network_down final { | |||||
static constexpr auto _what = "network_down"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct destination_not_available final { | |||||
static constexpr auto _what = "destination_not_available"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
struct insufficient_buffer_space final { | |||||
static constexpr auto _what = "insufficient_buffer_space"; | |||||
constexpr auto what() { | |||||
return _what; | |||||
} | |||||
}; | |||||
using read_return = gp::fixed_variant< | |||||
typename buffer<char>::associated_iterator, // iterator to last element read | |||||
bad_file, | |||||
faulty_buffer, | |||||
interrupted, | |||||
io_error, | |||||
is_directory, | |||||
try_again, | |||||
not_connected, | |||||
impossible_io, | |||||
negative_offset, | |||||
is_pipe, | |||||
buffer_too_big | |||||
>; | |||||
using open_return = gp::fixed_variant< | |||||
gp_config::file_descriptor_t, | |||||
path_not_directory, | |||||
name_too_long, | |||||
does_not_exist, | |||||
may_loop, | |||||
is_directory, | |||||
invalid_flags, | |||||
is_read_only, | |||||
fd_limit_reached, | |||||
file_limit_reached, | |||||
impossible_io, | |||||
interrupted, | |||||
no_locking, | |||||
would_block, | |||||
no_space, | |||||
no_inodes, | |||||
quota_reached, | |||||
io_error, | |||||
cannot_write_shared_text, | |||||
faulty_filename, | |||||
exists_already, | |||||
is_append_only, | |||||
unimplemented_operation, | |||||
is_busy, | |||||
bad_relative_path, | |||||
no_permissions | |||||
>; | |||||
using close_return = gp::fixed_variant< | |||||
success, | |||||
bad_file, | |||||
interrupted, | |||||
io_error | |||||
>; | |||||
using write_return = gp::fixed_variant< | |||||
typename buffer<char>::associated_iterator, | |||||
bad_file, | |||||
no_space, | |||||
quota_reached, | |||||
too_big, | |||||
interrupted, | |||||
io_error, | |||||
faulty_buffer, | |||||
is_pipe, | |||||
try_again, | |||||
network_down, | |||||
destination_not_available, | |||||
impossible_io, | |||||
buffer_too_big, | |||||
negative_offset, | |||||
insufficient_buffer_space | |||||
>; | |||||
class file_flags{}; | |||||
class file_permissions{}; | |||||
} | |||||
} |
@ -0,0 +1,9 @@ | |||||
#pragma once | |||||
namespace gp{ | |||||
namespace specifics { | |||||
struct platform_data { | |||||
}; | |||||
} | |||||
} |
@ -0,0 +1,21 @@ | |||||
#pragma once | |||||
#if defined(_M_IX86) or defined(__i386) | |||||
#if __clang__ | |||||
#elif __GNUG__ | |||||
#endif // __clang__ | |||||
#elif defined(_M_X64) or defined(__amd64) | |||||
#include "gp/vfs/platforms/gcc-x86_64.hpp" | |||||
#if __clang__ | |||||
#elif __GNUG__ | |||||
#endif // __clang__ | |||||
#endif // CPU ARCHITECTURE |
@ -0,0 +1,28 @@ | |||||
#pragma once | |||||
#include "gp_config.hpp" | |||||
#include "gp/function.hpp" | |||||
#include "gp/indexed_array.hpp" | |||||
#include "gp/pointers.hpp" | |||||
#include "gp/vfs/file_description.hpp" | |||||
#include "gp/vfs/platforms/platform_autopicker.hpp" | |||||
namespace gp { | |||||
enum class process_status { | |||||
inactive = 0, | |||||
running = 1, | |||||
waiting = 2, | |||||
zombie = 3 | |||||
}; | |||||
struct process_data{ | |||||
[[no_unique_address]] gp::specifics::platform_data specifics; | |||||
void* stack_ptr; | |||||
void* base_ptr; | |||||
gp::function<void()> fn; | |||||
gp::indexed_array<gp::file_description*, gp_config::limits::max_fd_per_process> fds; | |||||
}; | |||||
} |
@ -0,0 +1,14 @@ | |||||
#pragma once | |||||
#include "gp/indexed_array.hpp" | |||||
#include "gp/vfs/process_data.hpp" | |||||
namespace gp{ | |||||
class scheduler { | |||||
gp::indexed_array<gp::process_data*, gp_config::limits::max_processes> processes; | |||||
public: | |||||
[[noreturn]] void run(); | |||||
}; | |||||
} |
@ -0,0 +1,17 @@ | |||||
#pragma once | |||||
#include "gp/algorithm/reference.hpp" | |||||
#include "gp/allocator/allocator.hpp" | |||||
#include "gp/vector.hpp" | |||||
#include "gp/vfs/filesystem.hpp" | |||||
#include "gp/vfs/scheduler.hpp" | |||||
namespace gp{ | |||||
class system { | |||||
gp::reference_wrapper<gp::allocator> system_allocator; | |||||
gp::vector<gp::filesystem*> filesystems; | |||||
gp::scheduler process_manager; | |||||
}; | |||||
} |
@ -1,91 +0,0 @@ | |||||
#pragma once | |||||
#include "gp_config.hpp" | |||||
#include "gp/allocator/aggregator.hpp" | |||||
#include "gp/buffer.hpp" | |||||
#include "gp/optional.hpp" | |||||
#include "gp/variant.hpp" | |||||
#include "gp/vfs/fs_types.hpp" | |||||
#include <stddef.h> | |||||
namespace gp { | |||||
class vfs { | |||||
private: | |||||
struct virtual_fs | |||||
{ | |||||
virtual ~virtual_fs() = default; | |||||
virtual fs::open_return open(buffer<char>, fs::file_flags, fs::file_permissions) = 0; | |||||
virtual fs::read_return read(gp_config::file_descriptor_t, buffer<char>) = 0; | |||||
virtual fs::write_return write(gp_config::file_descriptor_t, buffer<char>, size_t) = 0; | |||||
virtual fs::close_return close(gp_config::file_descriptor_t) = 0; | |||||
}; | |||||
template<typename concrete> | |||||
class abstract_fs final : public virtual_fs{ | |||||
concrete internal_representation; | |||||
public: | |||||
abstract_fs(abstract_fs& v) = delete; | |||||
abstract_fs(abstract_fs&& v) | |||||
: internal_representation{v.internal_representation} | |||||
{} | |||||
abstract_fs(concrete& v) = delete; | |||||
abstract_fs(concrete&& v) | |||||
: internal_representation{v} | |||||
{} | |||||
virtual ~abstract_fs() override = default; | |||||
virtual fs::open_return open(buffer<char> path, fs::file_flags flags, fs::file_permissions perms) override { | |||||
return internal_representation.open(path, flags, perms); | |||||
} | |||||
virtual fs::read_return read(gp_config::file_descriptor_t fd, buffer<char> buff) override { | |||||
return internal_representation.read(fd, buff); | |||||
} | |||||
virtual fs::write_return write(gp_config::file_descriptor_t fd, buffer<char> buff, size_t offset) override { | |||||
return internal_representation.write(fd, buff, offset); | |||||
} | |||||
virtual fs::close_return close(gp_config::file_descriptor_t fd) override { | |||||
return internal_representation.close(fd); | |||||
} | |||||
}; | |||||
reference_wrapper<aggregator> allocator; | |||||
virtual_fs* file_system; | |||||
public: | |||||
template<typename T> | |||||
vfs(T&& v, reference_wrapper<aggregator> _ref) | |||||
: allocator{_ref} | |||||
, file_system{new(allocator.get().allocate(sizeof(T))) T(gp::move(v))} | |||||
{} | |||||
fs::open_return open(buffer<char> path, fs::file_flags flags, fs::file_permissions perms) { | |||||
return file_system->open(path, flags, perms); | |||||
} | |||||
fs::read_return read(gp_config::file_descriptor_t fd, buffer<char> buff) { | |||||
return file_system->read(fd, buff); | |||||
} | |||||
fs::write_return write(gp_config::file_descriptor_t fd, buffer<char> buff, size_t offset) { | |||||
return file_system->write(fd, buff, offset); | |||||
} | |||||
fs::close_return close(gp_config::file_descriptor_t fd) { | |||||
return file_system->close(fd); | |||||
} | |||||
~vfs() { | |||||
file_system->~virtual_fs(); | |||||
allocator.get().deallocate(file_system); | |||||
} | |||||
}; | |||||
} |