@@ -110,22 +110,22 @@ DeviceImage &ProgramManager::getDeviceImage(OSModuleHandle M,
110110}
111111
112112template <typename ExceptionT, typename RetT>
113- RetT *
114- waitUntilBuilt (KernelProgramCache &Cache,
115- KernelProgramCache::EntityWithState<RetT> *WithBuildState) {
113+ RetT *waitUntilBuilt (KernelProgramCache &Cache,
114+ KernelProgramCache::BuildResult<RetT> *BuildResult) {
116115 // any thread which will find nullptr in cache will wait until the pointer
117116 // is not null anymore
118- Cache.waitUntilBuilt ([WithBuildState ]() {
119- int State = WithBuildState ->State .load ();
117+ Cache.waitUntilBuilt ([BuildResult ]() {
118+ int State = BuildResult ->State .load ();
120119
121120 return State == BS_Done || State == BS_Failed;
122121 });
123122
124- RetT *Result = WithBuildState->Ptr .load ();
123+ if (BuildResult->Error .FilledIn ) {
124+ const KernelProgramCache::BuildError &Error = BuildResult->Error ;
125+ throw ExceptionT (Error.Msg , Error.Code );
126+ }
125127
126- if (!Result)
127- throw ExceptionT (" The other thread tried to build the program/kernel but "
128- " did not succeed." );
128+ RetT *Result = BuildResult->Ptr .load ();
129129
130130 return Result;
131131}
@@ -152,7 +152,7 @@ template <typename RetT, typename ExceptionT, typename KeyT, typename AcquireFT,
152152RetT *getOrBuild (KernelProgramCache &KPCache, const KeyT &CacheKey,
153153 AcquireFT &&Acquire, GetCacheFT &&GetCache, BuildFT &&Build) {
154154 bool InsertionTookPlace;
155- KernelProgramCache::EntityWithState <RetT> *WithState ;
155+ KernelProgramCache::BuildResult <RetT> *BuildResult ;
156156
157157 {
158158 auto LockedCache = Acquire (KPCache);
@@ -162,36 +162,59 @@ RetT *getOrBuild(KernelProgramCache &KPCache, const KeyT &CacheKey,
162162 std::forward_as_tuple (nullptr , BS_InProgress));
163163
164164 InsertionTookPlace = Inserted.second ;
165- WithState = &Inserted.first ->second ;
165+ BuildResult = &Inserted.first ->second ;
166166 }
167167
168168 // no insertion took place, thus some other thread has already inserted smth
169169 // in the cache
170170 if (!InsertionTookPlace) {
171- return waitUntilBuilt<ExceptionT>(KPCache, WithState);
171+ for (;;) {
172+ RetT *Result = waitUntilBuilt<ExceptionT>(KPCache, BuildResult);
173+
174+ if (Result)
175+ return Result;
176+
177+ // Previous build is failed. There was no SYCL exception though.
178+ // We might try to build once more.
179+ int Expected = BS_Failed;
180+ int Desired = BS_InProgress;
181+
182+ if (BuildResult->State .compare_exchange_strong (Expected, Desired))
183+ break ; // this thread is the building thread now
184+ }
172185 }
173186
174- // only the building thread will run this, and only once.
187+ // only the building thread will run this
175188 try {
176189 RetT *Desired = Build ();
177190
178191#ifndef NDEBUG
179192 RetT *Expected = nullptr ;
180193
181- if (!WithState ->Ptr .compare_exchange_strong (Expected, Desired))
194+ if (!BuildResult ->Ptr .compare_exchange_strong (Expected, Desired))
182195 // We've got a funny story here
183196 assert (false && " We've build an entity that is already have been built." );
184197#else
185- WithState ->Ptr .store (Desired);
198+ BuildResult ->Ptr .store (Desired);
186199#endif
187200
188- WithState ->State .store (BS_Done);
201+ BuildResult ->State .store (BS_Done);
189202
190203 KPCache.notifyAllBuild ();
191204
192205 return Desired;
206+ } catch (const exception &Ex) {
207+ BuildResult->Error .Msg = Ex.what ();
208+ BuildResult->Error .Code = Ex.get_cl_code ();
209+ BuildResult->Error .FilledIn = true ;
210+
211+ BuildResult->State .store (BS_Failed);
212+
213+ KPCache.notifyAllBuild ();
214+
215+ std::rethrow_exception (std::current_exception ());
193216 } catch (...) {
194- WithState ->State .store (BS_Failed);
217+ BuildResult ->State .store (BS_Failed);
195218
196219 KPCache.notifyAllBuild ();
197220
0 commit comments