Fix destructor race in Job

This commit is contained in:
Vinnie Falco
2016-02-19 19:08:24 -05:00
parent 92391332d7
commit 9ab5611c65
3 changed files with 40 additions and 30 deletions

View File

@@ -180,7 +180,7 @@ private:
//
// Invariants:
// <none>
void finishJob (Job const& job);
void finishJob (JobType type);
template <class Rep, class Period>
void on_dequeue (JobType type,

View File

@@ -80,6 +80,10 @@ void Job::doJob ()
m_loadEvent->reName (mName);
mJob (*this);
// Destroy the lambda, otherwise we won't include
// its duration in the time measurement
mJob = std::function<void(Job&)>();
}
void Job::rename (std::string const& newName)

View File

@@ -407,14 +407,11 @@ JobQueue::getNextJob (Job& job)
}
void
JobQueue::finishJob (Job const& job)
JobQueue::finishJob (JobType type)
{
JobType const type = job.getType ();
assert(type != jtINVALID);
assert (m_jobSet.find (job) == m_jobSet.end ());
assert (type != jtINVALID);
JobTypeData& data (getJobTypeData (type));
JobTypeData& data = getJobTypeData (type);
// Queue a deferred task if possible
if (data.deferred > 0)
@@ -457,40 +454,49 @@ void JobQueue::on_execute (JobType type,
void
JobQueue::processTask ()
{
Job job;
JobType type;
{
std::lock_guard <std::mutex> lock (m_mutex);
getNextJob (job);
++m_processCount;
}
Job job;
JobTypeData& data (getJobTypeData (job.getType ()));
{
std::lock_guard <std::mutex> lock (m_mutex);
getNextJob (job);
++m_processCount;
}
// Skip the job if we are stopping and the
// skipOnStop flag is set for the job type
//
if (!isStopping() || !data.info.skip ())
{
beast::Thread::setCurrentThreadName (data.name ());
JLOG(m_journal.trace) << "Doing " << data.name () << " job";
JobTypeData& data (getJobTypeData (job.getType ()));
Job::clock_type::time_point const start_time (
Job::clock_type::now());
// Skip the job if we are stopping and the
// skipOnStop flag is set for the job type
//
if (!isStopping() || !data.info.skip ())
{
beast::Thread::setCurrentThreadName (data.name ());
JLOG(m_journal.trace) << "Doing " << data.name () << " job";
on_dequeue (job.getType (), start_time - job.queue_time ());
job.doJob ();
on_execute (job.getType (), Job::clock_type::now() - start_time);
}
else
{
JLOG(m_journal.trace) << "Skipping processTask ('" << data.name () << "')";
Job::clock_type::time_point const start_time (
Job::clock_type::now());
on_dequeue (job.getType (), start_time - job.queue_time ());
job.doJob ();
on_execute (job.getType (), Job::clock_type::now() - start_time);
}
else
{
JLOG(m_journal.trace) << "Skipping processTask ('" << data.name () << "')";
}
type = job.getType();
}
{
std::lock_guard <std::mutex> lock (m_mutex);
finishJob (job);
finishJob (type);
--m_processCount;
// Job should be destroyed before calling checkStopped
// otherwise destructors with side effects can access
// parent objects that are already destroyed.
checkStopped (lock);
}