// // Created by anton on 6/24/22. // #ifndef PMP_CALL_FRAME_H #define PMP_CALL_FRAME_H #include #include #include #include #include #include #include #include #include #include "helpers.h" namespace pmp::core { typedef void *call_frame_target(void * args, void * scope); typedef u64 frame_id_t; enum call_frame_state { initial = 0, running = 1, waiting = 2, completed = 3 }; class call_frame { public: call_frame(void *argument, void *scope, call_frame_target *target, frame_id_t id, const std::weak_ptr&parent) : state(initial), arguments(argument), scope(scope), result(nullptr), target_function(target), id(id), children(), children_lock(), parent(parent), evaluation_lock(), m_has_error(false) { } std::atomic state; void *arguments; void *scope; void* result; call_frame_target *target_function; frame_id_t id; bool evaluate(); private: void mark_completion() { // we can only be notified of child completion when we are waiting... assert(state == waiting); if (state == waiting && has_unfinished_children()) { state = completed; if (parent != nullptr) { parent->mark_completion(); } } } bool has_unfinished_children() { // make sure the list of children is not modified WITH_LOCK(children_lock); // return true as soon as any child is not complete return std::any_of(children.begin(), children.end(), [](auto child) { return child->state != completed; }); } std::list> children; std::mutex children_lock; const std::shared_ptr parent; // this lock is taken when the function is executed to prevent double-execution std::mutex evaluation_lock; std::atomic m_has_error; }; } #endif //PMP_CALL_FRAME_H