diff --git a/include/ur_api.h b/include/ur_api.h index 36e6c29e68..28569597c4 100644 --- a/include/ur_api.h +++ b/include/ur_api.h @@ -8562,6 +8562,7 @@ urCommandBufferReleaseExp( /// - ::UR_RESULT_ERROR_INVALID_NULL_HANDLE /// + `NULL == hCommandBuffer` /// - ::UR_RESULT_ERROR_INVALID_COMMAND_BUFFER_EXP +/// - ::UR_RESULT_ERROR_INVALID_OPERATION - "If `hCommandBuffer` has already been finalized" /// - ::UR_RESULT_ERROR_OUT_OF_HOST_MEMORY /// - ::UR_RESULT_ERROR_OUT_OF_RESOURCES UR_APIEXPORT ur_result_t UR_APICALL diff --git a/scripts/core/exp-command-buffer.yml b/scripts/core/exp-command-buffer.yml index 9708059b0a..7ca4c957d5 100644 --- a/scripts/core/exp-command-buffer.yml +++ b/scripts/core/exp-command-buffer.yml @@ -330,6 +330,8 @@ params: desc: "[in] Handle of the command-buffer object." returns: - $X_RESULT_ERROR_INVALID_COMMAND_BUFFER_EXP + - $X_RESULT_ERROR_INVALID_OPERATION + - "If `hCommandBuffer` has already been finalized" - $X_RESULT_ERROR_OUT_OF_HOST_MEMORY - $X_RESULT_ERROR_OUT_OF_RESOURCES --- #-------------------------------------------------------------------------- diff --git a/source/adapters/cuda/command_buffer.cpp b/source/adapters/cuda/command_buffer.cpp index dbaadbfbd0..9d54422981 100644 --- a/source/adapters/cuda/command_buffer.cpp +++ b/source/adapters/cuda/command_buffer.cpp @@ -404,6 +404,8 @@ urCommandBufferReleaseExp(ur_exp_command_buffer_handle_t hCommandBuffer) { UR_APIEXPORT ur_result_t UR_APICALL urCommandBufferFinalizeExp(ur_exp_command_buffer_handle_t hCommandBuffer) { + UR_ASSERT(hCommandBuffer->CudaGraphExec == nullptr, + UR_RESULT_ERROR_INVALID_OPERATION); try { const unsigned long long flags = 0; #if CUDA_VERSION >= 12000 diff --git a/source/adapters/cuda/command_buffer.hpp b/source/adapters/cuda/command_buffer.hpp index d2403a4ab3..67d725c3ad 100644 --- a/source/adapters/cuda/command_buffer.hpp +++ b/source/adapters/cuda/command_buffer.hpp @@ -355,7 +355,7 @@ struct ur_exp_command_buffer_handle_t_ { // Cuda Graph handle CUgraph CudaGraph; // Cuda Graph Exec handle - CUgraphExec CudaGraphExec; + CUgraphExec CudaGraphExec = nullptr; // Atomic variable counting the number of reference to this command_buffer // using std::atomic prevents data race when incrementing/decrementing. std::atomic_uint32_t RefCountInternal; diff --git a/source/adapters/hip/command_buffer.cpp b/source/adapters/hip/command_buffer.cpp index 86131a13ce..23f8a3087f 100644 --- a/source/adapters/hip/command_buffer.cpp +++ b/source/adapters/hip/command_buffer.cpp @@ -304,6 +304,8 @@ urCommandBufferReleaseExp(ur_exp_command_buffer_handle_t hCommandBuffer) { UR_APIEXPORT ur_result_t UR_APICALL urCommandBufferFinalizeExp(ur_exp_command_buffer_handle_t hCommandBuffer) { + UR_ASSERT(hCommandBuffer->HIPGraphExec == nullptr, + UR_RESULT_ERROR_INVALID_OPERATION); try { const unsigned long long flags = 0; UR_CHECK_ERROR(hipGraphInstantiateWithFlags( diff --git a/source/adapters/hip/command_buffer.hpp b/source/adapters/hip/command_buffer.hpp index e162b8e640..a236a32c24 100644 --- a/source/adapters/hip/command_buffer.hpp +++ b/source/adapters/hip/command_buffer.hpp @@ -175,7 +175,7 @@ struct ur_exp_command_buffer_handle_t_ { // HIP Graph handle hipGraph_t HIPGraph; // HIP Graph Exec handle - hipGraphExec_t HIPGraphExec; + hipGraphExec_t HIPGraphExec = nullptr; // Atomic variable counting the number of reference to this command_buffer // using std::atomic prevents data race when incrementing/decrementing. std::atomic_uint32_t RefCountInternal; diff --git a/source/adapters/level_zero/command_buffer.cpp b/source/adapters/level_zero/command_buffer.cpp index 5ae19092a6..01c682c770 100644 --- a/source/adapters/level_zero/command_buffer.cpp +++ b/source/adapters/level_zero/command_buffer.cpp @@ -865,6 +865,7 @@ finalizeWaitEventPath(ur_exp_command_buffer_handle_t CommandBuffer) { ur_result_t urCommandBufferFinalizeExp(ur_exp_command_buffer_handle_t CommandBuffer) { UR_ASSERT(CommandBuffer, UR_RESULT_ERROR_INVALID_NULL_POINTER); + UR_ASSERT(!CommandBuffer->IsFinalized, UR_RESULT_ERROR_INVALID_OPERATION); // It is not allowed to append to command list from multiple threads. std::scoped_lock Guard(CommandBuffer->Mutex); diff --git a/source/adapters/opencl/command_buffer.cpp b/source/adapters/opencl/command_buffer.cpp index a161a5b32b..ac23765f0f 100644 --- a/source/adapters/opencl/command_buffer.cpp +++ b/source/adapters/opencl/command_buffer.cpp @@ -124,6 +124,7 @@ urCommandBufferReleaseExp(ur_exp_command_buffer_handle_t hCommandBuffer) { UR_APIEXPORT ur_result_t UR_APICALL urCommandBufferFinalizeExp(ur_exp_command_buffer_handle_t hCommandBuffer) { + UR_ASSERT(!hCommandBuffer->IsFinalized, UR_RESULT_ERROR_INVALID_OPERATION); cl_context CLContext = cl_adapter::cast(hCommandBuffer->hContext); cl_ext::clFinalizeCommandBufferKHR_fn clFinalizeCommandBufferKHR = nullptr; UR_RETURN_ON_FAILURE( diff --git a/source/loader/ur_libapi.cpp b/source/loader/ur_libapi.cpp index bc7cfb7eec..e257366a7f 100644 --- a/source/loader/ur_libapi.cpp +++ b/source/loader/ur_libapi.cpp @@ -7584,6 +7584,7 @@ ur_result_t UR_APICALL urCommandBufferReleaseExp( /// - ::UR_RESULT_ERROR_INVALID_NULL_HANDLE /// + `NULL == hCommandBuffer` /// - ::UR_RESULT_ERROR_INVALID_COMMAND_BUFFER_EXP +/// - ::UR_RESULT_ERROR_INVALID_OPERATION - "If `hCommandBuffer` has already been finalized" /// - ::UR_RESULT_ERROR_OUT_OF_HOST_MEMORY /// - ::UR_RESULT_ERROR_OUT_OF_RESOURCES ur_result_t UR_APICALL urCommandBufferFinalizeExp( diff --git a/source/ur_api.cpp b/source/ur_api.cpp index 444170c71d..793045bcb4 100644 --- a/source/ur_api.cpp +++ b/source/ur_api.cpp @@ -6440,6 +6440,7 @@ ur_result_t UR_APICALL urCommandBufferReleaseExp( /// - ::UR_RESULT_ERROR_INVALID_NULL_HANDLE /// + `NULL == hCommandBuffer` /// - ::UR_RESULT_ERROR_INVALID_COMMAND_BUFFER_EXP +/// - ::UR_RESULT_ERROR_INVALID_OPERATION - "If `hCommandBuffer` has already been finalized" /// - ::UR_RESULT_ERROR_OUT_OF_HOST_MEMORY /// - ::UR_RESULT_ERROR_OUT_OF_RESOURCES ur_result_t UR_APICALL urCommandBufferFinalizeExp( diff --git a/test/conformance/exp_command_buffer/commands.cpp b/test/conformance/exp_command_buffer/commands.cpp index 49b2444176..5c4d4e7e4d 100644 --- a/test/conformance/exp_command_buffer/commands.cpp +++ b/test/conformance/exp_command_buffer/commands.cpp @@ -204,3 +204,14 @@ TEST_P(urCommandBufferAppendKernelLaunchExpTest, Basic) { ASSERT_EQ(result, ptrZ[i]); } } + +TEST_P(urCommandBufferAppendKernelLaunchExpTest, FinalizeTwice) { + ASSERT_SUCCESS(urCommandBufferAppendKernelLaunchExp( + cmd_buf_handle, kernel, n_dimensions, &global_offset, &global_size, + &local_size, 0, nullptr, 0, nullptr, 0, nullptr, nullptr, nullptr, + nullptr)); + + ASSERT_SUCCESS(urCommandBufferFinalizeExp(cmd_buf_handle)); + EXPECT_EQ_RESULT(urCommandBufferFinalizeExp(cmd_buf_handle), + UR_RESULT_ERROR_INVALID_OPERATION); +} diff --git a/test/conformance/exp_command_buffer/exp_command_buffer_adapter_level_zero_v2.match b/test/conformance/exp_command_buffer/exp_command_buffer_adapter_level_zero_v2.match index 5aa63f1cbc..5cd3d2a0ff 100644 --- a/test/conformance/exp_command_buffer/exp_command_buffer_adapter_level_zero_v2.match +++ b/test/conformance/exp_command_buffer/exp_command_buffer_adapter_level_zero_v2.match @@ -14,6 +14,7 @@ urCommandBufferCommandsTest.urCommandBufferAppendMemBufferFillExp/* urCommandBufferCommandsTest.urCommandBufferAppendUSMPrefetchExp/* urCommandBufferCommandsTest.urCommandBufferAppendUSMAdviseExp/* urCommandBufferAppendKernelLaunchExpTest.Basic/* +urCommandBufferAppendKernelLaunchExpTest.FinalizeTwice/* urCommandBufferFillCommandsTest.Buffer/* urCommandBufferFillCommandsTest.USM/* KernelCommandEventSyncTest.Basic/* diff --git a/test/conformance/exp_command_buffer/exp_command_buffer_adapter_native_cpu.match b/test/conformance/exp_command_buffer/exp_command_buffer_adapter_native_cpu.match index 3588eaea82..d6dc9a975c 100644 --- a/test/conformance/exp_command_buffer/exp_command_buffer_adapter_native_cpu.match +++ b/test/conformance/exp_command_buffer/exp_command_buffer_adapter_native_cpu.match @@ -5,6 +5,7 @@ {{OPT}}urCommandBufferRetainCommandExpTest.Success/* {{OPT}}urCommandBufferRetainCommandExpTest.InvalidNullHandle/* {{OPT}}urCommandBufferAppendKernelLaunchExpTest.Basic/* +{{OPT}}urCommandBufferAppendKernelLaunchExpTest.FinalizeTwice/* {{OPT}}BufferFillCommandTest.UpdateParameters/* {{OPT}}BufferFillCommandTest.UpdateGlobalSize/* {{OPT}}BufferFillCommandTest.SeparateUpdateCalls/*