@ -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); | |||
} | |||
}; | |||
} |