#include "pls/internal/scheduling/strain_local_resource.h" #include "pls/internal/base/error_handling.h" #include "pls/internal/scheduling/thread_state.h" #include "pls/internal/scheduling/scheduler.h" namespace pls::internal::scheduling { // Get item from locally owned items strain_local_resource::item_handle strain_local_resource::get_item(unsigned depth) { // Only change our resource usage when synced. // TODO: maybe relax this requirement scheduler::sync(); thread_state &my_state = thread_state::get(); auto *active_task = my_state.get_active_task(); // Find the item to use and acquire it from our local storage auto &local_resource = local_items_[my_state.get_thread_id()][depth]; strain_resource *result = local_resource.resource_; // Add it to the task used resources result->next_.store(active_task->attached_resources_.load(std::memory_order_relaxed), std::memory_order_relaxed); active_task->attached_resources_.store(result, std::memory_order_relaxed); // Wrap it for RAII usage on stack return strain_local_resource::item_handle{result}; } strain_local_resource::item_handle::item_handle(strain_resource *resource) : resource_{resource} { PLS_ASSERT(resource_->used_.fetch_add(1, std::memory_order_relaxed) == 0, "Must not create a handle of a already used resource!"); } // Return item to locally owned items strain_local_resource::item_handle::~item_handle() { // Only change our resource usage when synced. // TODO: maybe relax this requirement scheduler::sync(); thread_state &my_state = thread_state::get(); auto *active_task = my_state.get_active_task(); // Remove from task used resources strain_resource *previous_resource = nullptr; strain_resource *current_resource = active_task->attached_resources_.load(std::memory_order_relaxed); while (current_resource != resource_) { previous_resource = current_resource; current_resource = current_resource->next_.load(std::memory_order_relaxed); } auto *next_resource = current_resource->next_.load(std::memory_order_relaxed); if (previous_resource) { previous_resource->next_.store(next_resource, std::memory_order_relaxed); } else { active_task->attached_resources_.store(next_resource, std::memory_order_relaxed); } // Give the resource handle back to our local resource array auto &local_resource = resource_->strain_local_resource_->local_items_[my_state.get_thread_id()][resource_->depth_]; local_resource.resource_ = resource_; PLS_ASSERT(resource_->used_.fetch_sub(1, std::memory_order_relaxed) == 1, "Accidentally freed resource that was accessed multiple times!"); } strain_resource *strain_local_resource::get_local_copy(strain_resource *other_resources, unsigned thread_id) { strain_resource *result = nullptr; while (other_resources != nullptr) { local_item &local = other_resources->strain_local_resource_->local_items_[thread_id][other_resources->depth_]; local.resource_->next_.store(result, std::memory_order_relaxed); result = local.resource_; other_resources = other_resources->next_.load(std::memory_order_relaxed); } return result; } void strain_local_resource::acquire_locally(strain_resource *other_resources, unsigned thread_id) { while (other_resources != nullptr) { local_item &local = other_resources->strain_local_resource_->local_items_[thread_id][other_resources->depth_]; local.resource_ = other_resources; other_resources = other_resources->next_.load(std::memory_order_relaxed); } } }