/
githubmirror
/
julia
Обзор
Документация
Войти
/
githubmirror
/
julia
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
v1.12.5
src/engine.cpp
153 строки
5 KB
Keno Fischer
Add ABIOverride type for def field (#56555)
20 дек 2024, 06:45
Не верифицирован
20 дек 2024, 06:45
9bc27ad
Код
Авторство
О чём код?
// This file is a part of Julia. License is MIT: https://julialang.org/license #include <mutex> #include <condition_variable> #include <llvm/ADT/DenseMap.h> #include <llvm/ADT/DenseSet.h> #include <llvm/ADT/SmallVector.h> #include "julia.h" #include "julia_internal.h" #include "julia_assert.h" using namespace llvm; struct ReservationInfo { int16_t tid = 0; jl_code_instance_t *ci = nullptr; }; struct InferKey { jl_method_instance_t *mi = nullptr; jl_value_t *owner = nullptr; }; template<> struct llvm::DenseMapInfo<InferKey> { using FirstInfo = DenseMapInfo<jl_method_instance_t*>; using SecondInfo = DenseMapInfo<jl_value_t*>; static inline InferKey getEmptyKey() { return InferKey{FirstInfo::getEmptyKey(), SecondInfo::getEmptyKey()}; } static inline InferKey getTombstoneKey() { return InferKey{FirstInfo::getTombstoneKey(), SecondInfo::getTombstoneKey()}; } static unsigned getHashValue(const InferKey& PairVal) { return detail::combineHashValue(FirstInfo::getHashValue(PairVal.mi), SecondInfo::getHashValue(PairVal.owner)); } static bool isEqual(const InferKey &LHS, const InferKey &RHS) { return LHS.mi == RHS.mi && LHS.owner == RHS.owner; } }; static std::mutex engine_lock; // n.b. this lock is only ever held briefly static std::condition_variable engine_wait; // but it may be waiting a while in this state // map from MethodInstance to threadid that owns it currently for inference static DenseMap<InferKey, ReservationInfo> Reservations; // vector of which threads are blocked and which lease they need static SmallVector<InferKey, 0> Awaiting; // (this could be merged into ptls also) #ifdef __cplusplus extern "C" { #endif jl_code_instance_t *jl_engine_reserve(jl_method_instance_t *m, jl_value_t *owner) { jl_task_t *ct = jl_current_task; ct->ptls->engine_nqueued++; // disables finalizers until inference is finished on this method graph jl_code_instance_t *ci = jl_new_codeinst_uninit(m, owner); // allocate a placeholder JL_GC_PUSH1(&ci); auto tid = jl_atomic_load_relaxed(&ct->tid); if (([tid, m, owner, ci] () -> bool { // necessary scope block / lambda for unique_lock jl_unique_gcsafe_lock lock(engine_lock); InferKey key{m, owner}; if ((signed)Awaiting.size() < tid + 1) Awaiting.resize(tid + 1); while (1) { auto record = Reservations.find(key); if (record == Reservations.end()) { Reservations[key] = ReservationInfo{tid, ci}; return false; } // before waiting, need to run deadlock/cycle detection // there is a cycle if the thread holding our lease is blocked // and waiting for (transitively) any lease that is held by this thread auto wait_tid = record->second.tid; while (1) { if (wait_tid == tid) return true; if ((signed)Awaiting.size() <= wait_tid) break; // no cycle, since it is running (and this should be unreachable) auto key2 = Awaiting[wait_tid]; if (key2.mi == nullptr) break; // no cycle, since it is running auto record2 = Reservations.find(key2); if (record2 == Reservations.end()) break; // no cycle, since it is about to resume assert(wait_tid != record2->second.tid); wait_tid = record2->second.tid; } Awaiting[tid] = key; lock.wait(engine_wait); Awaiting[tid] = InferKey{}; } })()) ct->ptls->engine_nqueued--; JL_GC_POP(); return ci; } int jl_engine_hasreserved(jl_method_instance_t *m, jl_value_t *owner) { jl_task_t *ct = jl_current_task; InferKey key = {m, owner}; std::unique_lock lock(engine_lock); auto record = Reservations.find(key); return record != Reservations.end() && record->second.tid == jl_atomic_load_relaxed(&ct->tid); } STATIC_INLINE int gc_marked(uintptr_t bits) JL_NOTSAFEPOINT { return (bits & GC_MARKED) != 0; } void jl_engine_sweep(jl_ptls_t *gc_all_tls_states) { std::unique_lock lock(engine_lock); bool any = false; for (auto I = Reservations.begin(); I != Reservations.end(); ++I) { jl_code_instance_t *ci = I->second.ci; if (!gc_marked(jl_astaggedvalue(ci)->bits.gc)) { auto tid = I->second.tid; Reservations.erase(I); jl_ptls_t ptls2 = gc_all_tls_states[tid]; ptls2->engine_nqueued--; any = true; } } if (any) engine_wait.notify_all(); } void jl_engine_fulfill(jl_code_instance_t *ci, jl_code_info_t *src) { jl_task_t *ct = jl_current_task; std::unique_lock lock(engine_lock); auto record = Reservations.find(InferKey{jl_get_ci_mi(ci), ci->owner}); if (record == Reservations.end() || record->second.ci != ci) return; assert(jl_atomic_load_relaxed(&ct->tid) == record->second.tid); ct->ptls->engine_nqueued--; // re-enables finalizers, but doesn't immediately try to run them Reservations.erase(record); engine_wait.notify_all(); } #ifdef __cplusplus } #endif