#include "fiko/cekirdek/gorev.hpp" #include #include "fiko/cekirdek/olay.hpp" #include "fiko/core/gunluk.hpp" // TESHIS: worker istisnalari sessizce kayboluyordu (bkz. isciDongusu) namespace fiko { // Worker thread basi kancasi (bkz. gorev.hpp). Atomik fn-pointer: main-thread set eder, // worker'lar okur. Uygulama init'te set edip is'ler cok sonra kuyruklandigi icin guvenli. namespace { std::atomic g_isciBaslatmaKanca{nullptr}; } void GorevSistemi::isciBaslatmaKancasiAyarla(void (*kanca)()) { g_isciBaslatmaKanca.store(kanca, std::memory_order_release); } // Is kaydinin ic durumu. Atomik alanlar worker↔main paylasimini kilitsiz tasir; // mesaj/hata metni kisa mutex ile korunur (dusuk frekans). struct GorevKayit { u64 kimlik = 0; std::string baslik; std::function is; std::function bitince; std::atomic oran{0.0f}; std::atomic durum{GorevDurum::Bekliyor}; std::atomic iptal{false}; bool basladiBildirildi = false; // yalniz main-thread (pompala) okur/yazar mutable std::mutex mesajKilit; std::string mesaj; std::string hata; }; // ---- GorevBaglam (worker tarafi) ---- void GorevBaglam::ilerlet(f32 oran, std::string_view mesaj) { if (!kayit_) return; kayit_->oran.store(oran < 0.0f ? 0.0f : (oran > 1.0f ? 1.0f : oran), std::memory_order_relaxed); if (!mesaj.empty()) { std::lock_guard k(kayit_->mesajKilit); kayit_->mesaj.assign(mesaj); } } bool GorevBaglam::iptalIstendi() const { return kayit_ && kayit_->iptal.load(std::memory_order_relaxed); } void GorevBaglam::hataAyarla(std::string_view mesaj) { if (!kayit_) return; std::lock_guard k(kayit_->mesajKilit); kayit_->hata.assign(mesaj); } // ---- GorevSistemi ---- GorevSistemi::GorevSistemi(unsigned isciSayisi) { if (isciSayisi == 0) { const unsigned h = std::thread::hardware_concurrency(); isciSayisi = h > 1 ? h - 1 : 1; } isciler_.reserve(isciSayisi); for (unsigned i = 0; i < isciSayisi; ++i) isciler_.emplace_back([this] { isciDongusu(); }); } GorevSistemi::~GorevSistemi() { dur_.store(true); kuyrukKosul_.notify_all(); for (auto& t : isciler_) if (t.joinable()) t.join(); } u64 GorevSistemi::kuyrukla(std::string baslik, std::function is, std::function bitince) { auto k = std::make_shared(); k->kimlik = sonrakiKimlik_++; k->baslik = std::move(baslik); k->is = std::move(is); k->bitince = std::move(bitince); kayitlar_.push_back(k); // main-thread: UI + finalize takibi { std::lock_guard kilit(kuyrukKilit_); kuyruk_.push_back(std::move(k)); } kuyrukKosul_.notify_one(); return kayitlar_.back()->kimlik; } void GorevSistemi::isciDongusu() { // Bu worker'da ilk is oncesi bir kez: OCCT thread-local sinyal korumasi (OSD::SetSignal). // Yoksa worker'daki OCCT AV'si Standard_Failure'a cevrilmez, catch(...) yakalayamaz → // bozuk STEP'te surec duser. Kanca uygulama katmaninda &occtSinyalKur'a baglanir. thread_local bool s_kancaKuruldu = false; for (;;) { std::shared_ptr k; { std::unique_lock kilit(kuyrukKilit_); kuyrukKosul_.wait(kilit, [this] { return dur_.load() || !kuyruk_.empty(); }); if (dur_.load() && kuyruk_.empty()) return; k = std::move(kuyruk_.front()); kuyruk_.pop_front(); } if (!s_kancaKuruldu) { if (auto kanca = g_isciBaslatmaKanca.load(std::memory_order_acquire)) kanca(); s_kancaKuruldu = true; } if (k->iptal.load()) { k->durum.store(GorevDurum::Iptal); continue; } k->durum.store(GorevDurum::Calisiyor); GorevBaglam baglam; baglam.kayit_ = k.get(); try { k->is(baglam); // hataAyarla cagirilmissa normal donus BILE Hata'dir (sozlesme: bitince // yalniz basarili bitiste). Eski kod Bitti ile eziyordu → bitince BAYAT/ // BOS sonucla kosuyordu (test_gorev yakaladi). bool hataVar = false; { std::lock_guard kilit(k->mesajKilit); hataVar = !k->hata.empty(); } if (k->iptal.load()) { k->durum.store(GorevDurum::Iptal); } else if (hataVar) { k->durum.store(GorevDurum::Hata); } else { k->oran.store(1.0f); k->durum.store(GorevDurum::Bitti); } } catch (const std::exception& e) { // TESHIS: bitince() Hata durumunda CAGRILMAZ (asagi bak) → bu istisna metni // olmadan is sessizce "kayboluyor" gibi gorunuyordu (bkz. "STEP acilmiyor" // sikayeti). Artik fikocad.log'a yaziliyor — kok neden orada gorunur. gunluk::hata("GOREV '{}' istisna ile basarisiz: {}", k->baslik, e.what()); baglam.hataAyarla(e.what()); k->durum.store(GorevDurum::Hata); } catch (...) { gunluk::hata("GOREV '{}' bilinmeyen (non-std::exception) istisna ile basarisiz — " "olasi SEH/OCCT donanim sinyali; occtSinyalKur bu thread'de kurulu mu " "kontrol edin", k->baslik); baglam.hataAyarla("bilinmeyen hata"); k->durum.store(GorevDurum::Hata); } } } void GorevSistemi::pompala(OlayGunlugu& olaylar) { for (size_t i = 0; i < kayitlar_.size();) { GorevKayit& k = *kayitlar_[i]; const GorevDurum d = k.durum.load(); // Baslama olayi: durum >= Calisiyor olunca bir kez (Bitti'ye atlasa da). if (!k.basladiBildirildi && d != GorevDurum::Bekliyor) { k.basladiBildirildi = true; olaylar.yayinla(GorevBasladi{k.kimlik}, k.baslik.c_str()); } if (d == GorevDurum::Bitti || d == GorevDurum::Hata || d == GorevDurum::Iptal) { if (d == GorevDurum::Bitti && k.bitince) k.bitince(); // main-thread finalize char ozet[48]; const char* durumAd = d == GorevDurum::Bitti ? "bitti" : d == GorevDurum::Hata ? "hata" : "iptal"; std::snprintf(ozet, sizeof(ozet), "%s (%s)", k.baslik.c_str(), durumAd); olaylar.yayinla(GorevBitti{k.kimlik, d != GorevDurum::Bitti}, ozet); kayitlar_.erase(kayitlar_.begin() + (long)i); continue; } ++i; } } void GorevSistemi::iptalEt(u64 kimlik) { for (auto& k : kayitlar_) if (k->kimlik == kimlik) { k->iptal.store(true); return; } } std::vector GorevSistemi::anlik() const { std::vector sonuc; sonuc.reserve(kayitlar_.size()); for (const auto& k : kayitlar_) { GorevGorunum g; g.kimlik = k->kimlik; g.baslik = k->baslik; g.oran = k->oran.load(std::memory_order_relaxed); g.durum = k->durum.load(std::memory_order_relaxed); { std::lock_guard kilit(k->mesajKilit); g.mesaj = k->mesaj; } sonuc.push_back(std::move(g)); } return sonuc; } } // namespace fiko