Skip to content

Commit 1d13f84

Browse files
[SYCL] Fix segmentation fault that occurs when creating host accessors in parallel (#1597)
Signed-off-by: Dmitry Vodopyanov <[email protected]>
1 parent ec0846c commit 1d13f84

File tree

3 files changed

+30
-28
lines changed

3 files changed

+30
-28
lines changed

sycl/source/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,14 @@ function(add_sycl_rt_library LIB_NAME)
6060
"${sycl_inc_dir}"
6161
${OpenCL_INCLUDE_DIRS}
6262
)
63+
64+
find_package(Threads REQUIRED)
65+
6366
target_link_libraries(${LIB_NAME}
6467
PRIVATE
6568
${OpenCL_LIBRARIES}
6669
${CMAKE_DL_LIBS}
70+
${CMAKE_THREAD_LIBS_INIT}
6771
PUBLIC
6872
$<$<BOOL:${SYCL_BUILD_PI_CUDA}>:pi_cuda>
6973
)

sycl/source/detail/scheduler/scheduler.cpp

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,6 @@ __SYCL_INLINE_NAMESPACE(cl) {
2020
namespace sycl {
2121
namespace detail {
2222

23-
EventImplPtr addHostAccessorToSchedulerInstance(Requirement *Req,
24-
const bool destructor) {
25-
return cl::sycl::detail::Scheduler::getInstance().
26-
addHostAccessor(Req, destructor);
27-
}
28-
2923
void Scheduler::waitForRecordToFinish(MemObjRecord *Record) {
3024
#ifdef XPTI_ENABLE_INSTRUMENTATION
3125
// Will contain the list of dependencies for the Release Command
@@ -72,7 +66,7 @@ EventImplPtr Scheduler::addCG(std::unique_ptr<detail::CG> CommandGroup,
7266
Command *NewCmd = nullptr;
7367
const bool IsKernel = CommandGroup->getType() == CG::KERNEL;
7468
{
75-
std::lock_guard<std::mutex> Lock(MGraphLock);
69+
std::lock_guard<std::shared_timed_mutex> Lock(MGraphLock);
7670

7771
switch (CommandGroup->getType()) {
7872
case CG::UPDATE_HOST:
@@ -97,7 +91,7 @@ EventImplPtr Scheduler::addCG(std::unique_ptr<detail::CG> CommandGroup,
9791
}
9892

9993
EventImplPtr Scheduler::addCopyBack(Requirement *Req) {
100-
std::lock_guard<std::mutex> lock(MGraphLock);
94+
std::lock_guard<std::shared_timed_mutex> Lock(MGraphLock);
10195
Command *NewCmd = MGraphBuilder.addCopyBack(Req);
10296
// Command was not creted because there were no operations with
10397
// buffer.
@@ -121,35 +115,39 @@ EventImplPtr Scheduler::addCopyBack(Requirement *Req) {
121115
// else that has no priority set, or has a priority higher than 2000).
122116
Scheduler Scheduler::instance __attribute__((init_priority(2000)));
123117
#else
124-
#pragma warning(disable:4073)
118+
#pragma warning(disable : 4073)
125119
#pragma init_seg(lib)
126120
Scheduler Scheduler::instance;
127121
#endif
128122

129-
Scheduler &Scheduler::getInstance() {
130-
return instance;
131-
}
123+
Scheduler &Scheduler::getInstance() { return instance; }
132124

133125
std::vector<EventImplPtr> Scheduler::getWaitList(EventImplPtr Event) {
134-
std::lock_guard<std::mutex> lock(MGraphLock);
126+
std::shared_lock<std::shared_timed_mutex> Lock(MGraphLock);
135127
return GraphProcessor::getWaitList(std::move(Event));
136128
}
137129

138130
void Scheduler::waitForEvent(EventImplPtr Event) {
131+
std::shared_lock<std::shared_timed_mutex> Lock(MGraphLock);
139132
GraphProcessor::waitForEvent(std::move(Event));
140133
}
141134

142135
void Scheduler::cleanupFinishedCommands(EventImplPtr FinishedEvent) {
143-
std::lock_guard<std::mutex> lock(MGraphLock);
144-
Command *FinishedCmd = static_cast<Command *>(FinishedEvent->getCommand());
145-
// The command might have been cleaned up (and set to nullptr) by another
146-
// thread
147-
if (FinishedCmd)
148-
MGraphBuilder.cleanupFinishedCommands(FinishedCmd);
136+
// Avoiding deadlock situation, where one thread is in the process of
137+
// enqueueing (with a locked mutex) a currently blocked task that waits for
138+
// another thread which is stuck at attempting cleanup.
139+
std::unique_lock<std::shared_timed_mutex> Lock(MGraphLock, std::try_to_lock);
140+
if (Lock.owns_lock()) {
141+
Command *FinishedCmd = static_cast<Command *>(FinishedEvent->getCommand());
142+
// The command might have been cleaned up (and set to nullptr) by another
143+
// thread
144+
if (FinishedCmd)
145+
MGraphBuilder.cleanupFinishedCommands(FinishedCmd);
146+
}
149147
}
150148

151149
void Scheduler::removeMemoryObject(detail::SYCLMemObjI *MemObj) {
152-
std::lock_guard<std::mutex> lock(MGraphLock);
150+
std::lock_guard<std::shared_timed_mutex> Lock(MGraphLock);
153151

154152
MemObjRecord *Record = MGraphBuilder.getMemObjRecord(MemObj);
155153
if (!Record)
@@ -163,7 +161,7 @@ void Scheduler::removeMemoryObject(detail::SYCLMemObjI *MemObj) {
163161

164162
EventImplPtr Scheduler::addHostAccessor(Requirement *Req,
165163
const bool destructor) {
166-
std::lock_guard<std::mutex> lock(MGraphLock);
164+
std::lock_guard<std::shared_timed_mutex> Lock(MGraphLock);
167165

168166
Command *NewCmd = MGraphBuilder.addHostAccessor(Req, destructor);
169167

@@ -178,7 +176,8 @@ EventImplPtr Scheduler::addHostAccessor(Requirement *Req,
178176

179177
void Scheduler::releaseHostAccessor(Requirement *Req) {
180178
Req->MBlockedCmd->MEnqueueStatus = EnqueueResultT::SyclEnqueueReady;
181-
MemObjRecord* Record = Req->MSYCLMemObj->MRecord.get();
179+
std::shared_lock<std::shared_timed_mutex> Lock(MGraphLock);
180+
MemObjRecord *Record = Req->MSYCLMemObj->MRecord.get();
182181
auto EnqueueLeaves = [](CircularBuffer<Command *> &Leaves) {
183182
for (Command *Cmd : Leaves) {
184183
EnqueueResultT Res;
@@ -193,9 +192,9 @@ void Scheduler::releaseHostAccessor(Requirement *Req) {
193192

194193
Scheduler::Scheduler() {
195194
sycl::device HostDevice;
196-
DefaultHostQueue = QueueImplPtr(new queue_impl(
197-
detail::getSyclObjImpl(HostDevice), /*AsyncHandler=*/{},
198-
QueueOrder::Ordered, /*PropList=*/{}));
195+
DefaultHostQueue = QueueImplPtr(
196+
new queue_impl(detail::getSyclObjImpl(HostDevice), /*AsyncHandler=*/{},
197+
QueueOrder::Ordered, /*PropList=*/{}));
199198
}
200199

201200
} // namespace detail

sycl/source/detail/scheduler/scheduler.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
#include <cstddef>
1717
#include <memory>
18-
#include <mutex>
1918
#include <set>
19+
#include <shared_mutex>
2020
#include <vector>
2121

2222
/// \defgroup sycl_graph DPC++ Execution Graph
@@ -661,8 +661,7 @@ class Scheduler {
661661
void waitForRecordToFinish(MemObjRecord *Record);
662662

663663
GraphBuilder MGraphBuilder;
664-
// TODO Use read-write mutex in future.
665-
std::mutex MGraphLock;
664+
std::shared_timed_mutex MGraphLock;
666665

667666
QueueImplPtr DefaultHostQueue;
668667
};

0 commit comments

Comments
 (0)