Browse Source

Skeleton for channels and async programming

channel
Ludovic 'Archivist' Lagouardette 4 years ago
parent
commit
4fe3982d8a
12 changed files with 128 additions and 566 deletions
  1. +0
    -5
      include/gp/pointers.hpp
  2. +0
    -164
      include/gp/vfs/channel_fs.hpp
  3. +9
    -0
      include/gp/vfs/file_description.hpp
  4. +24
    -0
      include/gp/vfs/filesystem.hpp
  5. +0
    -306
      include/gp/vfs/fs_types.hpp
  6. +9
    -0
      include/gp/vfs/platforms/gcc-x86_64.hpp
  7. +21
    -0
      include/gp/vfs/platforms/platform_autopicker.hpp
  8. +28
    -0
      include/gp/vfs/process_data.hpp
  9. +14
    -0
      include/gp/vfs/scheduler.hpp
  10. +17
    -0
      include/gp/vfs/system.hpp
  11. +0
    -91
      include/gp/vfs/vfs.hpp
  12. +6
    -0
      include/gp_config.hpp

+ 0
- 5
include/gp/pointers.hpp View File

@ -184,9 +184,4 @@ public:
gp_config::assertion(alloc.deallocate(ptr), "freeing unique_ptr failed");
}
}
};
class unique_array_ptr {
gp::buffer<char> data;
};

+ 0
- 164
include/gp/vfs/channel_fs.hpp View File

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

+ 9
- 0
include/gp/vfs/file_description.hpp View File

@ -0,0 +1,9 @@
#pragma once
namespace gp {
class file_description {
};
}

+ 24
- 0
include/gp/vfs/filesystem.hpp View File

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

+ 0
- 306
include/gp/vfs/fs_types.hpp View File

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

+ 9
- 0
include/gp/vfs/platforms/gcc-x86_64.hpp View File

@ -0,0 +1,9 @@
#pragma once
namespace gp{
namespace specifics {
struct platform_data {
};
}
}

+ 21
- 0
include/gp/vfs/platforms/platform_autopicker.hpp View File

@ -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

+ 28
- 0
include/gp/vfs/process_data.hpp View File

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

+ 14
- 0
include/gp/vfs/scheduler.hpp View File

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

+ 17
- 0
include/gp/vfs/system.hpp View File

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

+ 0
- 91
include/gp/vfs/vfs.hpp View File

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

+ 6
- 0
include/gp_config.hpp View File

@ -21,6 +21,12 @@ namespace gp_config{
#define GP_CONFIG__RENDERING__COLOR_T vec4
}
namespace limits {
constexpr size_t max_processes = 4096;
constexpr size_t max_fd_per_process = 128;
constexpr size_t process_stack = 1024; // times 16
}
namespace memory_module{
#ifdef GP_TESTS
using default_allocator = static_mapper;

Loading…
Cancel
Save