Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-30 08:33:58

0001 #ifndef LFHCAL_CHECKED_IO_H
0002 #define LFHCAL_CHECKED_IO_H
0003 
0004 #include "TError.h"
0005 #include "TFile.h"
0006 #include <atomic>
0007 #include <cstring>
0008 #include <exception>
0009 #include <initializer_list>
0010 #include <iostream>
0011 
0012 namespace lfhcal {
0013 
0014 // One guard per command-line process. Keep ROOT's diagnostics and fatal-error
0015 // behavior, while remembering I/O errors from APIs such as SaveAs that return void.
0016 class RootIOErrors {
0017  public:
0018   RootIOErrors() {
0019     failed().store(false);
0020     previous() = SetErrorHandler(Handle);
0021   }
0022   ~RootIOErrors() { SetErrorHandler(previous()); }
0023   RootIOErrors(const RootIOErrors&) = delete;
0024   RootIOErrors& operator=(const RootIOErrors&) = delete;
0025   bool ok() const { return !failed().load(); }
0026 
0027  private:
0028   static std::atomic<bool>& failed() {
0029     static std::atomic<bool> value{false};
0030     return value;
0031   }
0032   static ErrorHandlerFunc_t& previous() {
0033     static ErrorHandlerFunc_t value = nullptr;
0034     return value;
0035   }
0036   static bool IsIOError(int level, const char* location) {
0037     if (level < kError || !location) return false;
0038     const char* prefixes[] = {"TFile::", "TDirectory", "TBranch", "TTree::",
0039       "TBufferFile::", "TKey::", "TASImage::", "TImage::", "TCanvas::",
0040       "TPad::", "TPDF::", "TPostScript::", "TSVG::"};
0041     for (const char* prefix : prefixes)
0042       if (std::strncmp(location, prefix, std::strlen(prefix)) == 0) return true;
0043     return false;
0044   }
0045   static void Handle(int level, Bool_t abort, const char* location, const char* message) {
0046     if (IsIOError(level, location)) failed().store(true);
0047     ErrorHandlerFunc_t handler = previous();
0048     if (handler && handler != Handle) handler(level, abort, location, message);
0049     else DefaultErrorHandler(level, abort, location, message);
0050   }
0051 };
0052 
0053 inline bool CloseAndCheckOutputs(std::initializer_list<TFile*> outputs) {
0054   bool ok = true;
0055   for (TFile* output : outputs) {
0056     if (!output) continue;
0057     if (output->IsOpen()) {
0058       output->Flush();
0059       output->Close();
0060     }
0061     if (output->IsZombie() || output->TestBit(TFile::kWriteError)) {
0062       std::cerr << "ROOT output failed: " << output->GetName() << std::endl;
0063       ok = false;
0064     }
0065   }
0066   return ok;
0067 }
0068 
0069 // Shared exit-status handling for Convert and DataPrep. Do not short-circuit
0070 // the output check: Close can expose a buffered write failure after Process.
0071 template <class Analysis>
0072 int RunCheckedAnalysis(Analysis& analysis, const char* executable) {
0073   RootIOErrors io;
0074   try {
0075     if (!analysis.CheckAndOpenIO()) {
0076       std::cerr << executable << ": input/configuration check failed" << std::endl;
0077       return 1;
0078     }
0079     const bool processed = analysis.Process();
0080     const bool written = CloseAndCheckOutputs(
0081         {analysis.RootOutput, analysis.RootOutputHist, analysis.RootCalibOutput});
0082     if (!processed || !written || !io.ok()) {
0083       std::cerr << executable << ": processing or I/O failed" << std::endl;
0084       return 1;
0085     }
0086   } catch (const std::exception& error) {
0087     std::cerr << executable << ": processing or I/O failed: " << error.what() << std::endl;
0088     return 1;
0089   }
0090   std::cout << "Exiting" << std::endl;
0091   return 0;
0092 }
0093 
0094 } // namespace lfhcal
0095 #endif