Skip to content

[SYCL] no exceptions leaking from destructors #14273

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion sycl/include/sycl/buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,13 @@ class buffer : public detail::buffer_plain,

buffer &operator=(buffer &&rhs) = default;

~buffer() { buffer_plain::handleRelease(); }
~buffer() {
try {
buffer_plain::handleRelease();
} catch (std::exception &e) {
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~buffer", e);
}
}

bool operator==(const buffer &rhs) const { return impl == rhs.impl; }

Expand Down
11 changes: 11 additions & 0 deletions sycl/include/sycl/detail/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,17 @@ static constexpr std::array<T, N> RepeatValue(const T &Arg) {
return RepeatValueHelper(Arg, std::make_index_sequence<N>());
}

// to output exceptions caught in ~destructors
#ifndef NDEBUG
#define __SYCL_REPORT_EXCEPTION_TO_STREAM(str, e) \
{ \
std::cerr << str << " " << e.what() << std::endl; \
assert(false); \
}
#else
#define __SYCL_REPORT_EXCEPTION_TO_STREAM(str, e)
#endif

} // namespace detail
} // namespace _V1
} // namespace sycl
13 changes: 11 additions & 2 deletions sycl/include/sycl/image.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,12 @@ class unsampled_image
unsampled_image &operator=(unsampled_image &&rhs) = default;

~unsampled_image() {
common_base::unsampledImageDestructorNotification((void *)this->impl.get());
try {
common_base::unsampledImageDestructorNotification(
(void *)this->impl.get());
} catch (std::exception &e) {
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~unsampled_image", e);
}
}

bool operator==(const unsampled_image &rhs) const {
Expand Down Expand Up @@ -1095,7 +1100,11 @@ class sampled_image
sampled_image &operator=(sampled_image &&rhs) = default;

~sampled_image() {
common_base::sampledImageDestructorNotification((void *)this->impl.get());
try {
common_base::sampledImageDestructorNotification((void *)this->impl.get());
} catch (std::exception &e) {
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~sampled_image", e);
}
}

bool operator==(const sampled_image &rhs) const {
Expand Down
10 changes: 7 additions & 3 deletions sycl/include/syclcompat/device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,9 +339,13 @@ class device_ext : public sycl::device {
public:
device_ext() : sycl::device(), _ctx(*this) {}
~device_ext() {
std::lock_guard<std::mutex> lock(m_mutex);
sycl::event::wait(_events);
_queues.clear();
try {
std::lock_guard<std::mutex> lock(m_mutex);
sycl::event::wait(_events);
_queues.clear();
} catch (std::exception &e) {
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~device_ext", e);
}
}
device_ext(const sycl::device &base, bool print_on_async_exceptions = false,
bool in_order = true)
Expand Down
38 changes: 21 additions & 17 deletions sycl/source/detail/context_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,23 +145,27 @@ cl_context context_impl::get() const {
bool context_impl::is_host() const { return MHostContext; }

context_impl::~context_impl() {
// Free all events associated with the initialization of device globals.
for (auto &DeviceGlobalInitializer : MDeviceGlobalInitializers)
DeviceGlobalInitializer.second.ClearEvents(getPlugin());
// Free all device_global USM allocations associated with this context.
for (const void *DeviceGlobal : MAssociatedDeviceGlobals) {
DeviceGlobalMapEntry *DGEntry =
detail::ProgramManager::getInstance().getDeviceGlobalEntry(
DeviceGlobal);
DGEntry->removeAssociatedResources(this);
}
for (auto LibProg : MCachedLibPrograms) {
assert(LibProg.second && "Null program must not be kept in the cache");
getPlugin()->call<PiApiKind::piProgramRelease>(LibProg.second);
}
if (!MHostContext) {
// TODO catch an exception and put it to list of asynchronous exceptions
getPlugin()->call_nocheck<PiApiKind::piContextRelease>(MContext);
try {
// Free all events associated with the initialization of device globals.
for (auto &DeviceGlobalInitializer : MDeviceGlobalInitializers)
DeviceGlobalInitializer.second.ClearEvents(getPlugin());
// Free all device_global USM allocations associated with this context.
for (const void *DeviceGlobal : MAssociatedDeviceGlobals) {
DeviceGlobalMapEntry *DGEntry =
detail::ProgramManager::getInstance().getDeviceGlobalEntry(
DeviceGlobal);
DGEntry->removeAssociatedResources(this);
}
for (auto LibProg : MCachedLibPrograms) {
assert(LibProg.second && "Null program must not be kept in the cache");
getPlugin()->call<PiApiKind::piProgramRelease>(LibProg.second);
}
if (!MHostContext) {
// TODO catch an exception and put it to list of asynchronous exceptions
getPlugin()->call<PiApiKind::piContextRelease>(MContext);
}
} catch (std::exception &e) {
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~context_impl", e);
}
}

Expand Down
21 changes: 12 additions & 9 deletions sycl/source/detail/device_image_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,15 +300,18 @@ class device_image_impl {
}

~device_image_impl() {

if (MProgram) {
const PluginPtr &Plugin = getSyclObjImpl(MContext)->getPlugin();
Plugin->call<PiApiKind::piProgramRelease>(MProgram);
}
if (MSpecConstsBuffer) {
std::lock_guard<std::mutex> Lock{MSpecConstAccessMtx};
const PluginPtr &Plugin = getSyclObjImpl(MContext)->getPlugin();
memReleaseHelper(Plugin, MSpecConstsBuffer);
try {
if (MProgram) {
const PluginPtr &Plugin = getSyclObjImpl(MContext)->getPlugin();
Plugin->call<PiApiKind::piProgramRelease>(MProgram);
}
if (MSpecConstsBuffer) {
std::lock_guard<std::mutex> Lock{MSpecConstAccessMtx};
const PluginPtr &Plugin = getSyclObjImpl(MContext)->getPlugin();
memReleaseHelper(Plugin, MSpecConstsBuffer);
}
} catch (std::exception &e) {
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~device_image_impl", e);
}
}

Expand Down
8 changes: 6 additions & 2 deletions sycl/source/detail/event_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,12 @@ bool event_impl::is_host() {
}

event_impl::~event_impl() {
if (MEvent)
getPlugin()->call<PiApiKind::piEventRelease>(MEvent);
try {
if (MEvent)
getPlugin()->call<PiApiKind::piEventRelease>(MEvent);
} catch (std::exception &e) {
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~event_impl", e);
}
}

void event_impl::waitInternal(bool *Success) {
Expand Down
31 changes: 20 additions & 11 deletions sycl/source/detail/global_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,18 @@ class ObjectUsageCounter {
MCounter++;
}
~ObjectUsageCounter() {
if (!MModifyCounter)
return;

LockGuard Guard(GlobalHandler::MSyclGlobalHandlerProtector);
MCounter--;
GlobalHandler *RTGlobalObjHandler = GlobalHandler::getInstancePtr();
if (RTGlobalObjHandler) {
RTGlobalObjHandler->prepareSchedulerToRelease(!MCounter);
try {
if (!MModifyCounter)
return;

LockGuard Guard(GlobalHandler::MSyclGlobalHandlerProtector);
MCounter--;
GlobalHandler *RTGlobalObjHandler = GlobalHandler::getInstancePtr();
if (RTGlobalObjHandler) {
RTGlobalObjHandler->prepareSchedulerToRelease(!MCounter);
}
} catch (std::exception &e) {
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~ObjectUsageCounter", e);
}
}

Expand Down Expand Up @@ -234,12 +238,17 @@ void GlobalHandler::releaseDefaultContexts() {

struct EarlyShutdownHandler {
~EarlyShutdownHandler() {
try {
#ifdef _WIN32
// on Windows we keep to the existing shutdown procedure
GlobalHandler::instance().releaseDefaultContexts();
// on Windows we keep to the existing shutdown procedure
GlobalHandler::instance().releaseDefaultContexts();
#else
shutdown_early();
shutdown_early();
#endif
} catch (std::exception &e) {
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~EarlyShutdownHandler",
e);
}
}
};

Expand Down
58 changes: 33 additions & 25 deletions sycl/source/detail/graph_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,9 +297,13 @@ void exec_graph_impl::makePartitions() {
}

graph_impl::~graph_impl() {
clearQueues();
for (auto &MemObj : MMemObjs) {
MemObj->markNoLongerBeingUsedInGraph();
try {
clearQueues();
for (auto &MemObj : MMemObjs) {
MemObj->markNoLongerBeingUsedInGraph();
}
} catch (std::exception &e) {
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~graph_impl", e);
}
}

Expand Down Expand Up @@ -782,34 +786,38 @@ exec_graph_impl::exec_graph_impl(sycl::context Context,
}

exec_graph_impl::~exec_graph_impl() {
const sycl::detail::PluginPtr &Plugin =
sycl::detail::getSyclObjImpl(MContext)->getPlugin();
MSchedule.clear();
// We need to wait on all command buffer executions before we can release
// them.
for (auto &Event : MExecutionEvents) {
Event->wait(Event);
}
try {
const sycl::detail::PluginPtr &Plugin =
sycl::detail::getSyclObjImpl(MContext)->getPlugin();
MSchedule.clear();
// We need to wait on all command buffer executions before we can release
// them.
for (auto &Event : MExecutionEvents) {
Event->wait(Event);
}

for (const auto &Partition : MPartitions) {
Partition->MSchedule.clear();
for (const auto &Iter : Partition->MPiCommandBuffers) {
if (auto CmdBuf = Iter.second; CmdBuf) {
for (const auto &Partition : MPartitions) {
Partition->MSchedule.clear();
for (const auto &Iter : Partition->MPiCommandBuffers) {
if (auto CmdBuf = Iter.second; CmdBuf) {
pi_result Res = Plugin->call_nocheck<
sycl::detail::PiApiKind::piextCommandBufferRelease>(CmdBuf);
(void)Res;
assert(Res == pi_result::PI_SUCCESS);
}
}
}

for (auto &Iter : MCommandMap) {
if (auto Command = Iter.second; Command) {
pi_result Res = Plugin->call_nocheck<
sycl::detail::PiApiKind::piextCommandBufferRelease>(CmdBuf);
sycl::detail::PiApiKind::piextCommandBufferReleaseCommand>(Command);
(void)Res;
assert(Res == pi_result::PI_SUCCESS);
}
}
}

for (auto &Iter : MCommandMap) {
if (auto Command = Iter.second; Command) {
pi_result Res = Plugin->call_nocheck<
sycl::detail::PiApiKind::piextCommandBufferReleaseCommand>(Command);
(void)Res;
assert(Res == pi_result::PI_SUCCESS);
}
} catch (std::exception &e) {
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~exec_graph_impl", e);
}
}

Expand Down
10 changes: 7 additions & 3 deletions sycl/source/detail/kernel_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,13 @@ kernel_impl::kernel_impl(ContextImplPtr Context, ProgramImplPtr ProgramImpl)
: MContext(Context), MProgram(ProgramImpl->getHandleRef()) {}

kernel_impl::~kernel_impl() {
// TODO catch an exception and put it to list of asynchronous exceptions
if (!is_host()) {
getPlugin()->call<PiApiKind::piKernelRelease>(MKernel);
try {
// TODO catch an exception and put it to list of asynchronous exceptions
if (!is_host()) {
getPlugin()->call<PiApiKind::piKernelRelease>(MKernel);
}
} catch (std::exception &e) {
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~kernel_impl", e);
}
}

Expand Down
11 changes: 8 additions & 3 deletions sycl/source/detail/pi_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,14 @@ struct OwnedPiEvent {
MPlugin->call<PiApiKind::piEventRetain>(*MEvent);
}
~OwnedPiEvent() {
// Release the event if the ownership was not transferred.
if (MEvent.has_value())
MPlugin->call<PiApiKind::piEventRelease>(*MEvent);
try {
// Release the event if the ownership was not transferred.
if (MEvent.has_value())
MPlugin->call<PiApiKind::piEventRelease>(*MEvent);

} catch (std::exception &e) {
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~OwnedPiEvent", e);
}
}

OwnedPiEvent(OwnedPiEvent &&Other)
Expand Down
12 changes: 8 additions & 4 deletions sycl/source/detail/program_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,14 @@ program_impl::program_impl(ContextImplPtr Context,
}

program_impl::~program_impl() {
// TODO catch an exception and put it to list of asynchronous exceptions
if (!is_host() && MProgram != nullptr) {
const PluginPtr &Plugin = getPlugin();
Plugin->call<PiApiKind::piProgramRelease>(MProgram);
try {
// TODO catch an exception and put it to list of asynchronous exceptions
if (!is_host() && MProgram != nullptr) {
const PluginPtr &Plugin = getPlugin();
Plugin->call<PiApiKind::piProgramRelease>(MProgram);
}
} catch (std::exception &e) {
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~program_impl", e);
}
}

Expand Down
38 changes: 21 additions & 17 deletions sycl/source/detail/queue_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,25 +320,29 @@ class queue_impl {
}

~queue_impl() {
// The trace event created in the constructor should be active through the
// lifetime of the queue object as member variables when ABI breakage is
// allowed. This example shows MTraceEvent as a member variable.
try {
// The trace event created in the constructor should be active through the
// lifetime of the queue object as member variables when ABI breakage is
// allowed. This example shows MTraceEvent as a member variable.
#if XPTI_ENABLE_INSTRUMENTATION
constexpr uint16_t NotificationTraceType =
static_cast<uint16_t>(xpti::trace_point_type_t::queue_destroy);
if (xptiCheckTraceEnabled(MStreamID, NotificationTraceType)) {
// Used cached information in member variables
xptiNotifySubscribers(MStreamID, NotificationTraceType, nullptr,
(xpti::trace_event_data_t *)MTraceEvent,
MInstanceID,
static_cast<const void *>("queue_destroy"));
xptiReleaseEvent((xpti::trace_event_data_t *)MTraceEvent);
}
constexpr uint16_t NotificationTraceType =
static_cast<uint16_t>(xpti::trace_point_type_t::queue_destroy);
if (xptiCheckTraceEnabled(MStreamID, NotificationTraceType)) {
// Used cached information in member variables
xptiNotifySubscribers(MStreamID, NotificationTraceType, nullptr,
(xpti::trace_event_data_t *)MTraceEvent,
MInstanceID,
static_cast<const void *>("queue_destroy"));
xptiReleaseEvent((xpti::trace_event_data_t *)MTraceEvent);
}
#endif
throw_asynchronous();
if (!MHostQueue) {
cleanup_fusion_cmd();
getPlugin()->call<PiApiKind::piQueueRelease>(MQueues[0]);
throw_asynchronous();
if (!MHostQueue) {
cleanup_fusion_cmd();
getPlugin()->call<PiApiKind::piQueueRelease>(MQueues[0]);
}
} catch (std::exception &e) {
__SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~queue_impl", e);
}
}

Expand Down
Loading
Loading