From 0f54f72dc83fc3200dbc5748a227e34c4335a307 Mon Sep 17 00:00:00 2001 From: Marcin Hajder Date: Mon, 3 Jun 2024 18:49:43 +0200 Subject: [PATCH] Added tests to verify negative results of -clReleaseSemaphoreKHR -clRetainSemaphoreKHR --- .../cl_khr_semaphore/CMakeLists.txt | 2 + .../extensions/cl_khr_semaphore/main.cpp | 2 + .../extensions/cl_khr_semaphore/procs.h | 8 + .../cl_khr_semaphore/semaphore_base.h | 202 ++++++++++++++++++ ...est_semaphores_negative_release_retain.cpp | 79 +++++++ 5 files changed, 293 insertions(+) create mode 100644 test_conformance/extensions/cl_khr_semaphore/semaphore_base.h create mode 100644 test_conformance/extensions/cl_khr_semaphore/test_semaphores_negative_release_retain.cpp diff --git a/test_conformance/extensions/cl_khr_semaphore/CMakeLists.txt b/test_conformance/extensions/cl_khr_semaphore/CMakeLists.txt index 824784a135..f2ab96c652 100644 --- a/test_conformance/extensions/cl_khr_semaphore/CMakeLists.txt +++ b/test_conformance/extensions/cl_khr_semaphore/CMakeLists.txt @@ -3,6 +3,8 @@ set(MODULE_NAME CL_KHR_SEMAPHORE) set(${MODULE_NAME}_SOURCES main.cpp test_semaphores.cpp + test_semaphores_negative_release_retain.cpp + semaphore_base.h ) include(../../CMakeCommon.txt) diff --git a/test_conformance/extensions/cl_khr_semaphore/main.cpp b/test_conformance/extensions/cl_khr_semaphore/main.cpp index 0ae7206a0d..bc23cb886b 100644 --- a/test_conformance/extensions/cl_khr_semaphore/main.cpp +++ b/test_conformance/extensions/cl_khr_semaphore/main.cpp @@ -35,6 +35,8 @@ test_definition test_list[] = { ADD_TEST_VERSION(semaphores_multi_wait, Version(1, 2)), ADD_TEST_VERSION(semaphores_queries, Version(1, 2)), ADD_TEST_VERSION(semaphores_import_export_fd, Version(1, 2)), + ADD_TEST_VERSION(semaphores_negative_release, Version(1, 2)), + ADD_TEST_VERSION(semaphores_negative_retain, Version(1, 2)), }; const int test_num = ARRAY_SIZE(test_list); diff --git a/test_conformance/extensions/cl_khr_semaphore/procs.h b/test_conformance/extensions/cl_khr_semaphore/procs.h index f7c1aaa301..552c42a3cd 100644 --- a/test_conformance/extensions/cl_khr_semaphore/procs.h +++ b/test_conformance/extensions/cl_khr_semaphore/procs.h @@ -45,3 +45,11 @@ extern int test_semaphores_import_export_fd(cl_device_id deviceID, cl_context context, cl_command_queue queue, int num_elements); +extern int test_semaphores_negative_release(cl_device_id device, + cl_context context, + cl_command_queue queue, + int num_elements); +extern int test_semaphores_negative_retain(cl_device_id device, + cl_context context, + cl_command_queue queue, + int num_elements); diff --git a/test_conformance/extensions/cl_khr_semaphore/semaphore_base.h b/test_conformance/extensions/cl_khr_semaphore/semaphore_base.h new file mode 100644 index 0000000000..e50f33aedd --- /dev/null +++ b/test_conformance/extensions/cl_khr_semaphore/semaphore_base.h @@ -0,0 +1,202 @@ +// +// Copyright (c) 2024 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef CL_KHR_SEMAPHORE_BASE_H +#define CL_KHR_SEMAPHORE_BASE_H + +#include +#include "harness/deviceInfo.h" +#include "harness/testHarness.h" + +#include "harness/typeWrappers.h" + +struct SemaphoreBase +{ + SemaphoreBase(cl_device_id device): device(device) {} + + cl_int init_extension_functions() + { + cl_platform_id platform; + cl_int error = + clGetDeviceInfo(device, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), + &platform, nullptr); + test_error(error, "clGetDeviceInfo for CL_DEVICE_PLATFORM failed"); + + // If it is supported get the addresses of all the APIs here. + // clang-format off +#define GET_EXTENSION_ADDRESS(FUNC) \ + FUNC = reinterpret_cast( \ + clGetExtensionFunctionAddressForPlatform(platform, #FUNC)); \ + if (FUNC == nullptr) \ + { \ + log_error("ERROR: clGetExtensionFunctionAddressForPlatform failed" \ + " with " #FUNC "\n"); \ + return TEST_FAIL; \ + } + // clang-format on + + GET_EXTENSION_ADDRESS(clCreateSemaphoreWithPropertiesKHR); + GET_EXTENSION_ADDRESS(clEnqueueSignalSemaphoresKHR); + GET_EXTENSION_ADDRESS(clEnqueueWaitSemaphoresKHR); + GET_EXTENSION_ADDRESS(clReleaseSemaphoreKHR); + GET_EXTENSION_ADDRESS(clGetSemaphoreInfoKHR); + GET_EXTENSION_ADDRESS(clRetainSemaphoreKHR); + GET_EXTENSION_ADDRESS(clGetSemaphoreHandleForTypeKHR); + +#undef GET_EXTENSION_ADDRESS + return CL_SUCCESS; + } + + clCreateSemaphoreWithPropertiesKHR_fn clCreateSemaphoreWithPropertiesKHR = + nullptr; + clEnqueueSignalSemaphoresKHR_fn clEnqueueSignalSemaphoresKHR = nullptr; + clEnqueueWaitSemaphoresKHR_fn clEnqueueWaitSemaphoresKHR = nullptr; + clReleaseSemaphoreKHR_fn clReleaseSemaphoreKHR = nullptr; + clGetSemaphoreInfoKHR_fn clGetSemaphoreInfoKHR = nullptr; + clRetainSemaphoreKHR_fn clRetainSemaphoreKHR = nullptr; + clGetSemaphoreHandleForTypeKHR_fn clGetSemaphoreHandleForTypeKHR = nullptr; + + cl_device_id device = nullptr; +}; + +// Wrapper class based off generic typeWrappers.h wrappers. However, because +// the release/retain functions are queried at runtime from the platform, +// rather than known at compile time we cannot link the instantiated template. +// Instead, pass an instance of `SemaphoreTestBase` on wrapper construction +// to access the release/retain functions. +class clSemaphoreWrapper { + cl_semaphore_khr object = nullptr; + + void retain() + { + if (!object) return; + + auto err = base->clRetainSemaphoreKHR(object); + if (err != CL_SUCCESS) + { + print_error(err, "clRetainCommandBufferKHR() failed"); + std::abort(); + } + } + + void release() + { + if (!object) return; + + auto err = base->clReleaseSemaphoreKHR(object); + if (err != CL_SUCCESS) + { + print_error(err, "clReleaseCommandBufferKHR() failed"); + std::abort(); + } + } + + // Used to access release/retain functions + SemaphoreBase *base; + +public: + // We always want to have base available to dereference + clSemaphoreWrapper() = delete; + + clSemaphoreWrapper(SemaphoreBase *base): base(base) {} + + // On assignment, assume the object has a refcount of one. + clSemaphoreWrapper &operator=(cl_semaphore_khr rhs) + { + reset(rhs); + return *this; + } + + // Copy semantics, increase retain count. + clSemaphoreWrapper(clSemaphoreWrapper const &w) { *this = w; } + clSemaphoreWrapper &operator=(clSemaphoreWrapper const &w) + { + reset(w.object); + retain(); + return *this; + } + + // Move semantics, directly take ownership. + clSemaphoreWrapper(clSemaphoreWrapper &&w) { *this = std::move(w); } + clSemaphoreWrapper &operator=(clSemaphoreWrapper &&w) + { + reset(w.object); + w.object = nullptr; + return *this; + } + + ~clSemaphoreWrapper() { reset(); } + + // Release the existing object, if any, and own the new one, if any. + void reset(cl_semaphore_khr new_object = nullptr) + { + release(); + object = new_object; + } + + operator cl_semaphore_khr() const { return object; } + operator const cl_semaphore_khr *() { return &object; } +}; + +struct SemaphoreTestBase : public SemaphoreBase +{ + SemaphoreTestBase(cl_device_id device, cl_context context, + cl_command_queue queue) + : SemaphoreBase(device), context(context), semaphore(this) + { + cl_int error = init_extension_functions(); + if (error != CL_SUCCESS) + throw std::runtime_error("init_extension_functions failed\n"); + + error = clRetainCommandQueue(queue); + if (error != CL_SUCCESS) + throw std::runtime_error("clRetainCommandQueue failed\n"); + this->queue = queue; + } + + virtual cl_int Run() = 0; + +protected: + cl_context context = nullptr; + clCommandQueueWrapper queue = nullptr; + clSemaphoreWrapper semaphore = nullptr; +}; + +template +int MakeAndRunTest(cl_device_id device, cl_context context, + cl_command_queue queue) +{ + if (!is_extension_available(device, "cl_khr_semaphore")) + { + log_info( + "Device does not support 'cl_khr_semaphore'. Skipping the test.\n"); + return TEST_SKIPPED_ITSELF; + } + + cl_int status = TEST_PASS; + try + { + auto test_fixture = T(device, context, queue); + status = test_fixture.Run(); + } catch (const std::runtime_error &e) + { + log_error("%s", e.what()); + return TEST_FAIL; + } + + return status; +} + +#endif // CL_KHR_SEMAPHORE_BASE_H diff --git a/test_conformance/extensions/cl_khr_semaphore/test_semaphores_negative_release_retain.cpp b/test_conformance/extensions/cl_khr_semaphore/test_semaphores_negative_release_retain.cpp new file mode 100644 index 0000000000..f7056c53bf --- /dev/null +++ b/test_conformance/extensions/cl_khr_semaphore/test_semaphores_negative_release_retain.cpp @@ -0,0 +1,79 @@ +// +// Copyright (c) 2024 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "semaphore_base.h" + +#include "harness/errorHelpers.h" +#include +#include +#include +#include + +namespace { + +// sema_object is not a valid semaphore object + +struct ReleaseInvalidSemaphore : public SemaphoreTestBase +{ + ReleaseInvalidSemaphore(cl_device_id device, cl_context context, + cl_command_queue queue) + : SemaphoreTestBase(device, context, queue) + {} + + cl_int Run() override + { + // Release invalid semaphore + cl_int err = CL_SUCCESS; + err = clReleaseSemaphoreKHR(nullptr); + test_failure_error(err, CL_INVALID_SEMAPHORE_KHR, + "Unexpected clReleaseSemaphoreKHR return"); + + return CL_SUCCESS; + } +}; + +struct RetainInvalidSemaphore : public SemaphoreTestBase +{ + RetainInvalidSemaphore(cl_device_id device, cl_context context, + cl_command_queue queue) + : SemaphoreTestBase(device, context, queue) + {} + + cl_int Run() override + { + // Release invalid semaphore + cl_int err = CL_SUCCESS; + err = clRetainSemaphoreKHR(nullptr); + test_failure_error(err, CL_INVALID_SEMAPHORE_KHR, + "Unexpected clRetainSemaphoreKHR return"); + + return CL_SUCCESS; + } +}; + +} + +int test_semaphores_negative_release(cl_device_id device, cl_context context, + cl_command_queue queue, int num_elements) +{ + return MakeAndRunTest(device, context, queue); +} + +int test_semaphores_negative_retain(cl_device_id device, cl_context context, + cl_command_queue queue, int num_elements) +{ + return MakeAndRunTest(device, context, queue); +}