Skip to content

Commit a4d7ee2

Browse files
DinoVmeta-codesync[bot]
authored andcommitted
Fix thread-safely issue in IsolatedManagers
Summary: There's a thread safety issue here: Thread 1 swaps in it's map and swaps out the global one. Thread 2 swaps in it's map and swaps out thread's 1. Thread 1 completes and swaps the global one back in. Thread 2 completes and swap's back in thread 1's - the value is stack allocated so now we have garbage. Claude's solution is to use a thread-local to store the preload manager on the stack and then clear it out when done. Reviewed By: jbower-fb Differential Revision: D92114066 fbshipit-source-id: 59ce532c4b8c32fc1b5104dade9b1d909d1665b9
1 parent 973be8a commit a4d7ee2

3 files changed

Lines changed: 25 additions & 22 deletions

File tree

cinderx/Jit/hir/preload.cpp

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ static std::unique_ptr<NativeTarget> resolve_native_target(
119119
}
120120

121121
PreloaderManager s_manager;
122+
thread_local PreloaderManager* tls_manager = nullptr;
122123

123124
} // namespace
124125

@@ -535,33 +536,31 @@ bool PreloaderManager::empty() const {
535536
return preloaders_.empty();
536537
}
537538

539+
size_t PreloaderManager::size() const {
540+
return preloaders_.size();
541+
}
542+
538543
void PreloaderManager::clear() {
539544
preloaders_.clear();
540545
}
541546

542-
void PreloaderManager::swap(PreloaderMap& replacement) {
543-
// Should never be called from within the actual multi-threaded compile;
544-
// it's not safe to mess with the global preloaders map in that context.
545-
JIT_CHECK(
546-
!getThreadedCompileContext().compileRunning(),
547-
"cannot preload single func from within multi-threaded compile");
548-
preloaders_.swap(replacement);
547+
bool PreloaderManager::isGlobalManager() const {
548+
return tls_manager == nullptr;
549549
}
550550

551551
PreloaderManager& preloaderManager() {
552+
if (tls_manager != nullptr) {
553+
return *tls_manager;
554+
}
552555
return s_manager;
553556
}
554557

555-
IsolatedPreloaders::IsolatedPreloaders() {
556-
swap();
558+
IsolatedPreloaders::IsolatedPreloaders() : prev_manager_(tls_manager) {
559+
tls_manager = &local_manager_;
557560
}
558561

559562
IsolatedPreloaders::~IsolatedPreloaders() {
560-
swap();
561-
}
562-
563-
void IsolatedPreloaders::swap() {
564-
s_manager.swap(orig_preloaders_);
563+
tls_manager = prev_manager_;
565564
}
566565

567566
} // namespace jit::hir

cinderx/Jit/hir/preload.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -269,13 +269,13 @@ class PreloaderManager {
269269
// Check if there are any preloaders registered.
270270
bool empty() const;
271271

272+
size_t size() const;
273+
274+
bool isGlobalManager() const;
275+
272276
// Clear out all preloaders.
273277
void clear();
274278

275-
// Swap the inner map with the one passed as an argument. Needed by
276-
// IsolatedPreloaders.
277-
void swap(PreloaderMap& replacement);
278-
279279
private:
280280
PreloaderMap preloaders_;
281281
};
@@ -284,15 +284,16 @@ class PreloaderManager {
284284
PreloaderManager& preloaderManager();
285285

286286
// RAII device for isolating preloaders state.
287+
// Uses thread-local storage to give each thread its own PreloaderManager
288+
// while isolation is active, avoiding race conditions between threads.
287289
class IsolatedPreloaders {
288290
public:
289291
IsolatedPreloaders();
290292
~IsolatedPreloaders();
291293

292294
private:
293-
void swap();
294-
295-
PreloaderMap orig_preloaders_;
295+
PreloaderManager local_manager_;
296+
PreloaderManager* prev_manager_;
296297
};
297298

298299
} // namespace jit::hir

cinderx/Jit/pyjit.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3420,7 +3420,10 @@ void finalize() {
34203420
jit_reg_units.clear();
34213421
JIT_CHECK(
34223422
hir::preloaderManager().empty(),
3423-
"JIT cannot be finalized while batch compilation is active");
3423+
"JIT cannot be finalized while batch compilation is active size:{} "
3424+
"is_global:{}",
3425+
hir::preloaderManager().size(),
3426+
hir::preloaderManager().isGlobalManager());
34243427

34253428
for (auto func : jitCtx()->compiledFuncs()) {
34263429
deoptFuncImpl(func);

0 commit comments

Comments
 (0)