diff --git a/runtime/hsa-runtime/core/inc/amd_aql_queue.h b/runtime/hsa-runtime/core/inc/amd_aql_queue.h index 5d551d4da8..4612ebbca9 100644 --- a/runtime/hsa-runtime/core/inc/amd_aql_queue.h +++ b/runtime/hsa-runtime/core/inc/amd_aql_queue.h @@ -379,7 +379,7 @@ class AqlQueue : public core::Queue, private core::LocalSignal, public core::Sig // Handle of scratch memory descriptor ScratchInfo queue_scratch_; - core::HsaEventCallback errors_callback_; + AMD::callback_t errors_callback_; void* errors_data_; diff --git a/runtime/hsa-runtime/core/inc/exceptions.h b/runtime/hsa-runtime/core/inc/exceptions.h index 4e4c97bbcf..52233f37d4 100644 --- a/runtime/hsa-runtime/core/inc/exceptions.h +++ b/runtime/hsa-runtime/core/inc/exceptions.h @@ -62,6 +62,36 @@ class hsa_exception : public std::exception { std::string desc_; }; +/// @brief Holds and invokes callbacks, capturing any execptions and forwarding those to the user +/// after unwinding the runtime stack. +template class callback_t; +template class callback_t { + public: + typedef R (*func_t)(Args...); + + callback_t() : function(nullptr) {} + + // Should not be marked explicit. + callback_t(func_t function_ptr) : function(function_ptr) {} + callback_t& operator=(func_t function_ptr) { function = function_ptr; } + + // Allows common function pointer idioms, such as if( func != nullptr )... + // without allowing silent reversion to the original function pointer type. + operator void*() { return reinterpret_cast(function); } + + R operator()(Args... args) { + try { + return function(args...); + } catch (...) { + throw std::nested_exception(); + return R(); + } + } + + private: + func_t function; +}; + } // namespace AMD #endif // HSA_RUNTIME_CORE_INC_EXCEPTIONS_H diff --git a/runtime/hsa-runtime/core/inc/intercept_queue.h b/runtime/hsa-runtime/core/inc/intercept_queue.h index bc51842434..762e888135 100644 --- a/runtime/hsa-runtime/core/inc/intercept_queue.h +++ b/runtime/hsa-runtime/core/inc/intercept_queue.h @@ -184,16 +184,11 @@ class QueueProxy : public QueueWrapper { // Device-side dispatches are processed as an asynchronous signal event. class InterceptQueue : public QueueProxy, private LocalSignal, public Signal { public: - // typedef void(*intercept_packet_writer)(const AqlPacket* pkts, uint64_t pkt_count); - // typedef void(*intercept_handler)(const AqlPacket* pkts, uint64_t pkt_count, uint64_t - // user_pkt_index, void* data, intercept_packet_writer writer); - - std::vector> interceptors; - explicit InterceptQueue(std::unique_ptr queue); ~InterceptQueue(); void AddInterceptor(hsa_amd_queue_intercept_handler interceptor, void* data) { + assert(interceptor != nullptr && "Packet intercept callback was nullptr."); interceptors.push_back(std::make_pair(interceptor, data)); } @@ -225,6 +220,9 @@ class InterceptQueue : public QueueProxy, private LocalSignal, public Signal { // Proxy packet buffer SharedArray buffer_; + // Packet transform callbacks + std::vector, void*>> interceptors; + static const hsa_signal_value_t DOORBELL_MAX = 0xFFFFFFFFFFFFFFFFull; static bool HandleAsyncDoorbell(hsa_signal_value_t value, void* arg); diff --git a/runtime/hsa-runtime/core/runtime/amd_gpu_agent.cpp b/runtime/hsa-runtime/core/runtime/amd_gpu_agent.cpp index 9379bd8aac..b3dc729798 100644 --- a/runtime/hsa-runtime/core/runtime/amd_gpu_agent.cpp +++ b/runtime/hsa-runtime/core/runtime/amd_gpu_agent.cpp @@ -451,8 +451,9 @@ hsa_status_t GpuAgent::IterateRegion( hsa_status_t GpuAgent::IterateCache(hsa_status_t (*callback)(hsa_cache_t cache, void* data), void* data) const { + AMD::callback_t call(callback); for (size_t i = 0; i < caches_.size(); i++) { - hsa_status_t stat = callback(core::Cache::Convert(caches_[i].get()), data); + hsa_status_t stat = call(core::Cache::Convert(caches_[i].get()), data); if (stat != HSA_STATUS_SUCCESS) return stat; } return HSA_STATUS_SUCCESS; @@ -493,6 +494,7 @@ hsa_status_t GpuAgent::VisitRegion( const std::vector& regions, hsa_status_t (*callback)(hsa_region_t region, void* data), void* data) const { + AMD::callback_t call(callback); for (const core::MemoryRegion* region : regions) { const amd::MemoryRegion* amd_region = reinterpret_cast(region); @@ -501,7 +503,7 @@ hsa_status_t GpuAgent::VisitRegion( if (amd_region->IsSystem() || amd_region->IsLocalMemory() || amd_region->IsLDS()) { hsa_region_t region_handle = core::MemoryRegion::Convert(region); - hsa_status_t status = callback(region_handle, data); + hsa_status_t status = call(region_handle, data); if (status != HSA_STATUS_SUCCESS) { return status; } diff --git a/runtime/hsa-runtime/core/runtime/hsa_ext_amd.cpp b/runtime/hsa-runtime/core/runtime/hsa_ext_amd.cpp index 9869451601..7e8458f295 100644 --- a/runtime/hsa-runtime/core/runtime/hsa_ext_amd.cpp +++ b/runtime/hsa-runtime/core/runtime/hsa_ext_amd.cpp @@ -128,17 +128,19 @@ hsa_status_t handleException() { try { throw; } catch (const std::bad_alloc& e) { + debug_print("HSA exception: BadAlloc\n"); return HSA_STATUS_ERROR_OUT_OF_RESOURCES; } catch (const hsa_exception& e) { debug_print("HSA exception: %s\n", e.what()); return e.error_code(); - // } catch (std::nested_exception& e) { // Rethrow exceptions from callbacks - // e.rethrow_nested(); - // return HSA_STATUS_ERROR; } catch (const std::exception& e) { debug_print("Unhandled exception: %s\n", e.what()); assert(false && "Unhandled exception."); return HSA_STATUS_ERROR; + } catch (const std::nested_exception& e) { + debug_print("Callback threw, forwarding.\n"); + e.rethrow_nested(); + return HSA_STATUS_ERROR; } catch (...) { assert(false && "Unhandled exception."); abort(); diff --git a/runtime/hsa-runtime/core/runtime/runtime.cpp b/runtime/hsa-runtime/core/runtime/runtime.cpp index c02c3a635c..949ef4a8d9 100644 --- a/runtime/hsa-runtime/core/runtime/runtime.cpp +++ b/runtime/hsa-runtime/core/runtime/runtime.cpp @@ -287,15 +287,13 @@ uint32_t Runtime::GetIndexLinkInfo(uint32_t node_id_from, uint32_t node_id_to) { hsa_status_t Runtime::IterateAgent(hsa_status_t (*callback)(hsa_agent_t agent, void* data), void* data) { - if (!IsOpen()) { - return HSA_STATUS_ERROR_NOT_INITIALIZED; - } + AMD::callback_t call(callback); std::vector* agent_lists[2] = {&cpu_agents_, &gpu_agents_}; for (std::vector* agent_list : agent_lists) { for (size_t i = 0; i < agent_list->size(); ++i) { hsa_agent_t agent = Agent::Convert(agent_list->at(i)); - hsa_status_t status = callback(agent, data); + hsa_status_t status = call(agent, data); if (status != HSA_STATUS_SUCCESS) { return status; @@ -768,7 +766,8 @@ hsa_status_t Runtime::PtrInfo(void* ptr, hsa_amd_pointer_info_t* info, void* (*a count += agents_by_node_[mappedNodes[i]].size(); } - *accessible = (hsa_agent_t*)alloc(sizeof(hsa_agent_t) * count); + AMD::callback_t Alloc(alloc); + *accessible = (hsa_agent_t*)Alloc(sizeof(hsa_agent_t) * count); if ((*accessible) == nullptr) return HSA_STATUS_ERROR_OUT_OF_RESOURCES; *num_agents_accessible = count;