diff --git a/Makefile b/Makefile index f664f5e..f1e75f8 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,15 @@ CXX= clang++-10 CXXFLAGS= --std=c++20 -O0 -g -pthread -DGP_TESTS -DFUZZ_STRENGTH=500 -DNO_BENCH=1 -pedantic \ - -fprofile-instr-generate -fcoverage-mapping -Wno-unknown-attributes \ - -fsanitize=address -fno-omit-frame-pointer + -fprofile-instr-generate -fcoverage-mapping -Wno-unknown-attributes -fno-omit-frame-pointer \ + +# -fsanitize=address -fsanitize-blacklist=blacklist.txt all: tests tests: bin/tests LLVM_PROFILE_FILE="./bin/tests.profraw" ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer ./bin/tests @llvm-profdata merge -sparse ./bin/tests.profraw -o ./bin/tests.profdata - @llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata include/*.hpp include/gp/*.hpp include/gp/algorithm/*.hpp include/gp/enveloppe/*.hpp include/gp/allocator/*.hpp - @llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata include/*.hpp include/gp/*.hpp include/gp/algorithm/*.hpp include/gp/enveloppe/*.hpp include/gp/allocator/*.hpp | tail -n 1 | tr -s " " | sed -e 's/ /,/g' -- | awk -F "," '{print $$9}' | sed -e 's/^/Untested lines: /g' + @llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata include/*.hpp include/gp/*.hpp include/gp/algorithm/*.hpp include/gp/enveloppe/*.hpp include/gp/vfs/*.hpp include/gp/allocator/*.hpp + @llvm-cov report ./bin/tests -instr-profile=./bin/tests.profdata include/*.hpp include/gp/*.hpp include/gp/algorithm/*.hpp include/gp/enveloppe/*.hpp include/gp/vfs/*.hpp include/gp/allocator/*.hpp | tail -n 1 | tr -s " " | sed -e 's/ /,/g' -- | awk -F "," '{print $$9}' | sed -e 's/^/Untested lines: /g' bin/tests: tests.cpp $(wildcard tests/*.cpp) $(wildcard include/*.hpp) ./tests/test_scaffold.h @mkdir -p $(@D) diff --git a/blacklist.txt b/blacklist.txt new file mode 100644 index 0000000..6a86a7a --- /dev/null +++ b/blacklist.txt @@ -0,0 +1,3 @@ +src:gp/vfs/scheduler.hpp +src:gp/vfs/platforms/gcc-x86_64.hpp +fun:gp::specifics::platform_data::push(void*) \ No newline at end of file diff --git a/include/gp/indexed_array.hpp b/include/gp/indexed_array.hpp index 1c60214..1e54b34 100644 --- a/include/gp/indexed_array.hpp +++ b/include/gp/indexed_array.hpp @@ -55,7 +55,7 @@ namespace gp{ --data_top; if(v_idx < data_top) { size_t u_idx = reverse_translation_table[data_top]; - data_table.as_buffer().template cast()[v_idx] = gp::move(data_table[data_top]); + data_table.as_buffer().template cast()[v_idx] = gp::move(reinterpret_cast(data_table[data_top])); ::operator delete(&data_table.as_buffer().template cast()[data_top], &(data_table.as_buffer().template cast()[data_top])); data_table.as_buffer().template cast()[data_top].~T(); translation_table[u_idx] = v_idx; @@ -100,6 +100,13 @@ namespace gp{ return true; } + template + void foreach(fn_t function) { + for(size_t i = 0; i < data_top; ++i) { + function(reverse_translation_table[i], operator[](reverse_translation_table[i])); + } + } + pointer_iterator begin() { return data_table.as_buffer().template cast().begin(); diff --git a/include/gp/vfs/file_description.hpp b/include/gp/vfs/file_description.hpp index d0b067b..d24f92b 100644 --- a/include/gp/vfs/file_description.hpp +++ b/include/gp/vfs/file_description.hpp @@ -1,9 +1,26 @@ #pragma once +#include +#include + + + namespace gp { -class file_description { +template class buffer; +class file_description { + std::atomic_int64_t ref_counter; +public: + virtual void read() = 0; + virtual void write() = 0; + virtual void set_attr() = 0; + virtual void get_attr() = 0; + virtual void seek() = 0; + virtual void close() = 0; + static file_description* open(class system&, gp::buffer); + static file_description* create(class system&, gp::buffer); + static file_description* remove(class system&, gp::buffer); }; } \ No newline at end of file diff --git a/include/gp/vfs/filesystem.hpp b/include/gp/vfs/filesystem.hpp index 6374e22..31ee2ae 100644 --- a/include/gp/vfs/filesystem.hpp +++ b/include/gp/vfs/filesystem.hpp @@ -17,8 +17,8 @@ namespace gp{ }; class filesystem { - virtual file_description create(gp::buffer, fs_user_representation) = 0; - virtual file_description open(gp::buffer, fs_user_representation) = 0; - virtual file_description remove(gp::buffer, fs_user_representation) = 0; + virtual file_description create(gp::buffer, fs_user_representation&) = 0; + virtual file_description open(gp::buffer, fs_user_representation&) = 0; + virtual file_description remove(gp::buffer, fs_user_representation&) = 0; }; } \ No newline at end of file diff --git a/include/gp/vfs/platforms/gcc-x86_64.hpp b/include/gp/vfs/platforms/gcc-x86_64.hpp index 366c4cb..9e95b0f 100644 --- a/include/gp/vfs/platforms/gcc-x86_64.hpp +++ b/include/gp/vfs/platforms/gcc-x86_64.hpp @@ -1,12 +1,21 @@ #pragma once +#include "gp/buffer.hpp" + #include -#define no_inline_decl(a) [[gnu::noinline]] a +#define no_inline_decl(a) a __attribute__((noinline)) namespace gp{ namespace specifics { struct platform_data { + platform_data() = default; + + platform_data(gp::buffer stack_str) + : stack_ptr((stack_str.end()-16).data) + , base_ptr(stack_ptr) + {} + uint64_t rbx, r12, r13, r14, r15; void* stack_ptr; @@ -15,42 +24,44 @@ namespace gp{ void pull() __attribute__((always_inline)) { __asm__ __volatile__( - "movq %%rsp, %0\n" - "movq %%rbp, %1\n" - "movq %%rbx, %2\n" - "movq %%r12, %3\n" - "movq %%r13, %4\n" - "movq %%r14, %5\n" - "movq %%r15, %6\n" - : "=m"(stack_ptr) - , "=m"(base_ptr) - , "=m"(rbx) - , "=m"(r12) - , "=m"(r13) - , "=m"(r14) - , "=m"(r15)); + "movq %%rsp, %0\n" + "movq %%rbp, %1\n" + "movq %%rbx, %2\n" + "movq %%r12, %3\n" + "movq %%r13, %4\n" + "movq %%r14, %5\n" + "movq %%r15, %6\n" + : "=m"(stack_ptr) + , "=m"(base_ptr) + , "=m"(rbx) + , "=m"(r12) + , "=m"(r13) + , "=m"(r14) + , "=m"(r15) + ); } void* push(void* location) __attribute__((always_inline)) { - void* tmp = static_cast(stack_ptr) - sizeof(void*); - *static_cast(tmp) = location; + volatile void* volatile tmp = static_cast(stack_ptr) - sizeof(void*); + *static_cast(tmp) = location; __asm__ __volatile__( - "movq %1, %%rsp\n" - "movq %2, %%rbp\n" - "movq %3, %%r12\n" - "movq %4, %%r13\n" - "movq %5, %%r14\n" - "movq %6, %%r15\n" - "popq %0\n" - : "+r"(location) - : "m"(tmp) - , "m"(base_ptr) - , "m"(r12) - , "m"(r13) - , "m"(r14) - , "m"(r15) - : "memory"); + "movq %1, %%rsp\n" + "movq %2, %%rbp\n" + "movq %3, %%r12\n" + "movq %4, %%r13\n" + "movq %5, %%r14\n" + "movq %6, %%r15\n" + "popq %0\n" + : "+r"(location) + : "m"(tmp) + , "m"(base_ptr) + , "m"(r12) + , "m"(r13) + , "m"(r14) + , "m"(r15) + : "memory" + ); return location; } }; diff --git a/include/gp/vfs/process_data.hpp b/include/gp/vfs/process_data.hpp index 6db010c..de92254 100644 --- a/include/gp/vfs/process_data.hpp +++ b/include/gp/vfs/process_data.hpp @@ -7,20 +7,34 @@ #include "gp/vfs/file_description.hpp" #include "gp/vfs/platforms/platform_autopicker.hpp" +#include + namespace gp { enum class process_status { inactive = 0, running = 1, waiting = 2, - zombie = 3 + finished = 3, + zombie = 4 }; struct process_data{ - [[no_unique_address]] gp::specifics::platform_data specifics; - gp::function fn; + void* stack; + size_t stack_sz; + gp::process_status state; + std::atomic_bool is_running; + [[no_unique_address]] gp::specifics::platform_data specifics; gp::indexed_array fds; + + process_data(gp::function _fn, void* _stack, size_t _stack_sz) + : fn(_fn) + , stack(_stack) + , stack_sz(_stack_sz) + , state(gp::process_status::inactive) + , specifics(gp::buffer{(char*)stack, stack_sz}) + {} }; } \ No newline at end of file diff --git a/include/gp/vfs/scheduler.hpp b/include/gp/vfs/scheduler.hpp index 3cbe276..154fb6f 100644 --- a/include/gp/vfs/scheduler.hpp +++ b/include/gp/vfs/scheduler.hpp @@ -5,22 +5,35 @@ namespace gp{ +class system; + class scheduler { - gp::indexed_array processes; gp::specifics::platform_data root; - size_t current; + size_t current = 0; + system& sys; no_inline_decl( - void yield_impl(bool terminate) - ) { - - } + void yield_to(size_t target_pid) + ); + + public: - [[noreturn]] void run(); + scheduler(class system&); + + [[noreturn]] void run(allocator& alloc) { + again: + run_once(); + cleanup(alloc); + goto again; + } + + void cleanup(allocator& alloc); + + void run_once(); void yield(){ - yield_impl(false); + yield_to(0); } }; diff --git a/include/gp/vfs/system.hpp b/include/gp/vfs/system.hpp index 53a9bf1..8baa0ea 100644 --- a/include/gp/vfs/system.hpp +++ b/include/gp/vfs/system.hpp @@ -1,17 +1,106 @@ #pragma once +#include "gp/algorithm/foreach.hpp" #include "gp/algorithm/reference.hpp" #include "gp/allocator/allocator.hpp" #include "gp/vector.hpp" +#include "gp/vfs/file_description.hpp" #include "gp/vfs/filesystem.hpp" #include "gp/vfs/scheduler.hpp" namespace gp{ - +// TODO: thread safety class system { gp::reference_wrapper system_allocator; - gp::vector filesystems; - gp::scheduler process_manager; + gp::vector filesystems{system_allocator}; + gp::vector process_managers; + gp::indexed_array processes; + + friend class scheduler; +public: + system(allocator& v, size_t scheduler_count) + : system_allocator{v} + , process_managers{system_allocator} + { + gp_config::assertion(scheduler_count >= 1, "no scheduling in the system"); + process_managers.reserve(scheduler_count); + gp::repeat(scheduler_count,[&](){ + process_managers.emplace_back(*this); + }); + } + + size_t spawn(gp::function fn) { + constexpr size_t stack_sz = gp_config::limits::process_stack; + void* stack = system_allocator.get().allocate(stack_sz); + gp_config::assertion(stack != nullptr, "failed to allocate a stack"); + process_data* created_process = (process_data*)system_allocator.get().allocate(sizeof(process_data)); + gp_config::assertion(stack != nullptr, "failed to allocate a process data"); + new(created_process) process_data(fn, stack, stack_sz); + return processes.push(created_process); + } + + void run_once() { + (*process_managers.begin()).run_once(); + (*process_managers.begin()).cleanup(system_allocator); + } }; +scheduler::scheduler(class system& v) +: sys(v){} + +no_inline_decl( + void scheduler::yield_to(size_t target_pid) +) { + auto& cur = current ? sys.processes[current-1]->specifics : root; + auto& target = target_pid ? sys.processes[target_pid-1]->specifics : root; + current = target_pid; + cur.pull(); + if(target_pid) + { + no_inline_decl([&](scheduler* new_p)){ + auto& proc = *new_p->sys.processes[new_p->current-1]; + if(proc.state == gp::process_status::inactive) { + proc.state = gp::process_status::running; + proc.fn(); + proc.state = gp::process_status::finished; + new_p->yield_to(0); + } + }(static_cast(target.push(this))); + } else { + volatile scheduler* new_p = static_cast(target.push(this)); + } +} + + +void scheduler::cleanup(allocator& alloc) { + sys.processes.foreach( + [&] (size_t pid, process_data* process) { + if( + process->state == process_status::finished + ) { + process->fds.foreach([](size_t, file_description* fdes){ + fdes->close(); + }); + gp_config::assertion(alloc.deallocate(process->stack), "can't deallocate the stack"); + sys.processes.mark_for_removal(pid); + gp_config::assertion(alloc.deallocate(process), "can't deallocate the process data"); + } + } + ); + sys.processes.sweep_removed(); +} + +void scheduler::run_once() { + sys.processes.foreach( + [&] (size_t pid, process_data* process) { + if( + process->state == process_status::inactive + || process->state == process_status::running + ) { + yield_to(pid+1); + } + } + ); +} + } \ No newline at end of file diff --git a/include/gp_config.hpp b/include/gp_config.hpp index 37be1e0..6a357a1 100644 --- a/include/gp_config.hpp +++ b/include/gp_config.hpp @@ -28,12 +28,6 @@ namespace gp_config{ } namespace memory_module{ - #ifdef GP_TESTS - using default_allocator = static_mapper; - #else - using default_allocator = gp::c_allocator; - #endif - constexpr bool is_ok = true; } diff --git a/tests.cpp b/tests.cpp index 9d5732d..db34d72 100644 --- a/tests.cpp +++ b/tests.cpp @@ -3,6 +3,7 @@ #include "allocator.hpp" #include "bloomfilter.cpp" #include "cbor_test.cpp" +#include "channel_test.cpp" #include "gp_test.cpp" #include "math.cpp" #include "meta_test.cpp" diff --git a/tests/channel_test.cpp b/tests/channel_test.cpp new file mode 100644 index 0000000..3750384 --- /dev/null +++ b/tests/channel_test.cpp @@ -0,0 +1,35 @@ + +#include +#include +#include +#include +#include +#include "test_scaffold.h" + +#include + +struct channel_test : public test_scaffold { + channel_test() { + name = __FILE__ ":1"; + } + + virtual int run() { + auto store = std::make_unique>(); + gp::buddy<> alloc{&*store->begin(), store->size()}; + gp::system sys{alloc, 1}; + + std::atomic_int a = 0; + + sys.spawn(gp::function{[&](){ + a.fetch_add(1); + }, alloc}); + + sys.run_once(); + + gp_config::assertion(a.load(), "did not increment (aka run the fiber)"); + + return 0; + } +}; + +append_test dummy_hke41r43(new channel_test{}); \ No newline at end of file