Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle more generator problems in external generator #35201

Merged
merged 3 commits into from
Sep 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 41 additions & 5 deletions GeneratorInterface/Core/bin/externalGenerator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <iostream>
#include <string>
#include <thread>
#include <memory>

#include "FWCore/TestProcessor/interface/TestProcessor.h"

Expand Down Expand Up @@ -75,6 +76,18 @@ class Harness {
template <typename T>
using Serializer = ROOTSerializer<T, WriteBuffer>;

namespace {
//needed for atexit handling
boost::interprocess::scoped_lock<boost::interprocess::named_mutex>* s_sharedLock = nullptr;

void atexit_handler() {
if (s_sharedLock) {
std::cerr << "early exit called: unlock\n";
s_sharedLock->unlock();
}
}
} // namespace

int main(int argc, char* argv[]) {
std::string descString(argv[0]);
descString += " [--";
Expand All @@ -83,10 +96,9 @@ int main(int argc, char* argv[]) {
boost::program_options::options_description desc(descString);

desc.add_options()(kHelpCommandOpt, "produce help message")(
kMemoryNameCommandOpt,
boost::program_options::value<std::string>(),
"memory name")(kUniqueIDCommandOpt, boost::program_options::value<std::string>(), "unique id")(kVerboseCommandOpt,
"verbose output");
kMemoryNameCommandOpt, boost::program_options::value<std::string>(), "memory name")(
kUniqueIDCommandOpt, boost::program_options::value<std::string>(), "unique id")(kVerboseCommandOpt,
"verbose output");

boost::program_options::positional_options_description p;
p.add(kMemoryNameOpt, 1);
Expand Down Expand Up @@ -142,13 +154,36 @@ int main(int argc, char* argv[]) {

//The lock must be released if there is a catastrophic signal
auto lockPtr = communicationChannel.accessLock();

monitorThread.setAction([lockPtr]() {
if (lockPtr) {
std::cerr << "SIGNAL CAUGHT: unlock\n";
lockPtr->unlock();
}
});

//be sure to unset the address of the shared lock before the lock goes away
s_sharedLock = lockPtr;
auto unsetLockPtr = [](void*) { s_sharedLock = nullptr; };
std::unique_ptr<decltype(s_sharedLock), decltype(unsetLockPtr)> sharedLockGuard{&s_sharedLock, unsetLockPtr};
std::atexit(atexit_handler);
auto releaseLock = []() {
if (s_sharedLock) {
std::cerr << "terminate called: unlock\n";
s_sharedLock->unlock();
s_sharedLock = nullptr;
//deactivate the abort signal

struct sigaction act;
act.sa_sigaction = nullptr;
act.sa_flags = SA_SIGINFO;
sigemptyset(&act.sa_mask);
sigaction(SIGABRT, &act, nullptr);
std::abort();
}
};
std::set_terminate(releaseLock);

Serializer<ExternalGeneratorEventInfo> serializer(sm_buffer);
Serializer<ExternalGeneratorLumiInfo> bl_serializer(sm_buffer);
Serializer<GenLumiInfoProduct> el_serializer(sm_buffer);
Expand All @@ -175,8 +210,9 @@ int main(int argc, char* argv[]) {
edm::ServiceRegistry::createContaining(std::unique_ptr<edm::RandomNumberGenerator>(randomService));
Harness harness(configuration, serviceToken);

//Either ROOT or the Framework are overriding the signal handlers
//Some generator libraries override the signal handlers
monitorThread.setupSignalHandling();
std::set_terminate(releaseLock);

if (verbose) {
std::cerr << uniqueID << " process: done initializing" << std::endl;
Expand Down
2 changes: 1 addition & 1 deletion GeneratorInterface/Core/plugins/ExternalGeneratorFilter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ process = TestProcess()
config += "process."s + label + "=" + config_ + "\n";
config += "process.moduleToTest(process."s + label + ")\n";
config += R"_(
process.add_(cms.Service("InitRootHandlers", UnloadRootSigHandler=cms.untracked.bool(True)))
process.add_(cms.Service("InitRootHandlers", AbortOnSignal=cms.untracked.bool(False)))
)_";
if (not extraConfig_.empty()) {
config += "\n";
Expand Down
9 changes: 9 additions & 0 deletions GeneratorInterface/Core/test/BuildFile.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<environment>
<library file="FailingGeneratorFilter.cc" name="FailingGeneratorFilter">
<flags EDM_PLUGIN="1"/>
<use name="FWCore/Framework"/>
<use name="FWCore/ParameterSet"/>
<use name="GeneratorInterface/Core"/>
</library>
<test name="FailingGeneratorFilterTest" command="${LOCALTOP}/src/GeneratorInterface/Core/test/test_FailingGeneratorFilter.sh"/>
</environment>
128 changes: 128 additions & 0 deletions GeneratorInterface/Core/test/FailingGeneratorFilter.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// -*- C++ -*-
//
// Package: GeneratorInterface/Core
// Class : FailingGeneratorFilter
//
// Implementation:
// [Notes on implementation]
//
// Original Author: Christopher Jones
// Created: Wed, 08 Sep 2021 15:58:11 GMT
//

// system include files

// user include files
#include "GeneratorInterface/Core/interface/GeneratorFilter.h"
#include "FWCore/Framework/interface/MakerMacros.h"
#include "FWCore/Utilities/interface/Exception.h"

#include <csignal>
namespace test {
class FailingHad {
public:
FailingHad(const edm::ParameterSet& iPSet)
: failAt_(iPSet.getParameter<int>("failAt")), failureType_(iPSet.getParameter<int>("failureType")) {}

std::vector<std::string> sharedResources() const {
if (failAt_ == 0) {
fail("Constructor");
}
return {};
}

void setEDMEvent(edm::Event&) { event_ = std::make_unique<HepMC::GenEvent>(); }

bool generatePartonsAndHadronize() const {
if (failAt_ == 2) {
fail("Event");
}
return true;
}
bool decay() const { return true; }

std::unique_ptr<HepMC::GenEvent> getGenEvent() { return std::move(event_); }

bool select(HepMC::GenEvent*) const { return true; }
void resetEvent(std::unique_ptr<HepMC::GenEvent> iEvent) { event_ = std::move(iEvent); }
bool residualDecay() const { return true; }
void finalizeEvent() const {}
std::unique_ptr<GenEventInfoProduct> getGenEventInfo() const { return std::make_unique<GenEventInfoProduct>(); }

//caled at endRunProduce, endLumiProduce
void statistics() const {}
GenRunInfoProduct getGenRunInfo() const { return GenRunInfoProduct(); }

//called begin Lumi Produce
template <typename T>
void randomizeIndex(edm::LuminosityBlock const&, T&&) const {
if (failAt_ == 1) {
fail("BeginLumi");
}
}
template <typename T>
void generateLHE(edm::LuminosityBlock const&, T, unsigned int) const {}

bool readSettings(int) const { return true; }
std::string classname() const { return ""; }
template <typename T>
bool declareStableParticles(T&&) const {
return true;
}
template <typename T>
bool declareSpecialSettings(T&&) const {
return true;
}
bool initializeForInternalPartons() const { return true; }
std::unique_ptr<GenLumiInfoHeader> getGenLumiInfoHeader() const { return std::make_unique<GenLumiInfoHeader>(); }

//called end lumi
void cleanLHE() const {};

template <typename T>
void setRandomEngine(T&&) const {}

private:
void fail(std::string const& iName) const {
switch (failureType_) {
case 0: {
throw cms::Exception(iName);
}
case 1: {
std::raise(SIGSEGV);
break;
}
case 2: {
std::terminate();
break;
}
default: {
std::exit(-1);
}
}
}
std::unique_ptr<HepMC::GenEvent> event_;
int failAt_;
int failureType_;
};

class DummyDec {
public:
DummyDec(const edm::ParameterSet&) {}
std::vector<std::string> sharedResources() const { return {}; }

HepMC::GenEvent* decay(HepMC::GenEvent const*) { return nullptr; }
void statistics() const {}

void init(const edm::EventSetup&) const {}
bool operatesOnParticles() const { return false; }
bool specialSettings() const { return false; }

template <typename T>
void setRandomEngine(T&&) const {}
};
} // namespace test

using FailingGeneratorFilter = edm::GeneratorFilter<test::FailingHad, test::DummyDec>;

DEFINE_FWK_MODULE(FailingGeneratorFilter);
47 changes: 47 additions & 0 deletions GeneratorInterface/Core/test/test_FailingGeneratorFilter.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Pass in name and status
function die { echo $1: status $2 ; exit $2; }


echo "******************"
echo "Signal in constructor"
(cmsRun ${LOCALTOP}/src/GeneratorInterface/Core/test/test_FailingGeneratorFilter_cfg.py 0 1) && die "signal in constructor didn't fail" 1
echo "******************"
echo "Signal in beginLumi"
(cmsRun ${LOCALTOP}/src/GeneratorInterface/Core/test/test_FailingGeneratorFilter_cfg.py 1 1) && die "signal in begin lumi didn't fail" 1
echo "******************"
echo "Signal in event"
(cmsRun ${LOCALTOP}/src/GeneratorInterface/Core/test/test_FailingGeneratorFilter_cfg.py 2 1) && die "signal in event didn't fail" 1


echo "******************"
echo "Exception in constructor"
(cmsRun ${LOCALTOP}/src/GeneratorInterface/Core/test/test_FailingGeneratorFilter_cfg.py 0 0) && die "exception in constructor didn't fail" 1
echo "******************"
echo "Exception in beginLumi"
(cmsRun ${LOCALTOP}/src/GeneratorInterface/Core/test/test_FailingGeneratorFilter_cfg.py 1 0) && die "exception in begin lumi didn't fail" 1
echo "******************"
echo "Exception in event"
(cmsRun ${LOCALTOP}/src/GeneratorInterface/Core/test/test_FailingGeneratorFilter_cfg.py 2 0) && die "exception in event didn't fail" 1

echo "******************"
echo "terminate in constructor"
(cmsRun ${LOCALTOP}/src/GeneratorInterface/Core/test/test_FailingGeneratorFilter_cfg.py 0 2) && die "signal in constructor didn't fail" 1
echo "******************"
echo "terminate in beginLumi"
(cmsRun ${LOCALTOP}/src/GeneratorInterface/Core/test/test_FailingGeneratorFilter_cfg.py 1 2) && die "signal in begin lumi didn't fail" 1
echo "******************"
echo "terminate in event"
(cmsRun ${LOCALTOP}/src/GeneratorInterface/Core/test/test_FailingGeneratorFilter_cfg.py 2 2) && die "signal in event didn't fail" 1

echo "******************"
echo "exit in constructor"
(cmsRun ${LOCALTOP}/src/GeneratorInterface/Core/test/test_FailingGeneratorFilter_cfg.py 0 3) && die "signal in constructor didn't fail" 1
echo "******************"
echo "exit in beginLumi"
(cmsRun ${LOCALTOP}/src/GeneratorInterface/Core/test/test_FailingGeneratorFilter_cfg.py 1 3) && die "signal in begin lumi didn't fail" 1
echo "******************"
echo "exit in event"
(cmsRun ${LOCALTOP}/src/GeneratorInterface/Core/test/test_FailingGeneratorFilter_cfg.py 2 3) && die "signal in event didn't fail" 1


exit 0
27 changes: 27 additions & 0 deletions GeneratorInterface/Core/test/test_FailingGeneratorFilter_cfg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import FWCore.ParameterSet.Config as cms
import sys

process = cms.Process("TEST")

process.source = cms.Source("EmptySource")

process.maxEvents.input=10

from GeneratorInterface.Core.ExternalGeneratorFilter import *
process.generator = ExternalGeneratorFilter(
cms.EDFilter("FailingGeneratorFilter",
failAt=cms.int32(int(sys.argv[2])),
failureType = cms.int32(int(sys.argv[3]))),
_external_process_waitTime_ = cms.untracked.uint32(5),
_external_process_verbose_ = cms.untracked.bool(True),
_external_process_components_ =cms.vstring()
)

process.p = cms.Path(process.generator)

process.add_(cms.Service("RandomNumberGeneratorService",
generator = cms.PSet(
initialSeed = cms.untracked.uint32(123),
engineName = cms.untracked.string('HepJamesRandom')
)
))