Skip to content

Commit

Permalink
Prevent deadlock on process exit
Browse files Browse the repository at this point in the history
  • Loading branch information
stephen-webb committed Dec 20, 2024
1 parent 4e0bc97 commit e227b5c
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 15 deletions.
6 changes: 3 additions & 3 deletions src/main/cpp/aprinitializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,21 +103,21 @@ APRInitializer::~APRInitializer()
#endif
}

void APRInitializer::stopWatchDogs()
void APRInitializer::deleteWatchDogs()
{
std::lock_guard<std::mutex> lock(m_priv->mutex);

while (!m_priv->watchdogs.empty())
{
m_priv->watchdogs.back()->stop();
delete m_priv->watchdogs.back();
m_priv->watchdogs.pop_back();
}
}

void APRInitializer::unregisterAll()
{
getInstance().stopWatchDogs();
FileWatchdog::stopAll();
getInstance().deleteWatchDogs();
}

APRInitializer& APRInitializer::getInstance()
Expand Down
14 changes: 11 additions & 3 deletions src/main/cpp/filewatchdog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ long FileWatchdog::DEFAULT_DELAY = 60000;
struct FileWatchdog::FileWatchdogPrivate{
FileWatchdogPrivate(const File& file1) :
file(file1), delay(DEFAULT_DELAY), lastModif(0),
warnedAlready(false)
warnedAlready(false),
taskName{LOG4CXX_STR("WatchDog_") + file1.getName()}
{ }


Expand All @@ -57,7 +58,7 @@ struct FileWatchdog::FileWatchdogPrivate{
std::condition_variable interrupt;
std::mutex interrupt_mutex;
#endif
LogString taskName{LOG4CXX_STR("FileWatchdog")};
LogString taskName;
};

FileWatchdog::FileWatchdog(const File& file1)
Expand All @@ -67,7 +68,6 @@ FileWatchdog::FileWatchdog(const File& file1)

FileWatchdog::~FileWatchdog()
{
stop();
}


Expand All @@ -85,6 +85,14 @@ void FileWatchdog::stop()
}
}

/**
Stop all tasks that periodically checks for a file change.
*/
void FileWatchdog::stopAll()
{
ThreadUtility::instance()->removePeriodicTasksMatching(LOG4CXX_STR("WatchDog_"));
}

const File& FileWatchdog::file()
{
return m_priv->file;
Expand Down
20 changes: 19 additions & 1 deletion src/main/cpp/threadutility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ struct ThreadUtility::priv_data
{
priv_data()
#if LOG4CXX_EVENTS_AT_EXIT
: atExitRegistryRaii{ []{ stopThread(); } }
: atExitRegistryRaii{ [this]{ stopThread(); } }
#endif
{
}
Expand Down Expand Up @@ -298,6 +298,24 @@ void ThreadUtility::removePeriodicTask(const LogString& name)
m_priv->jobs.erase(pItem);
}

/**
* Remove any periodic task matching \c namePrefix
*/
void ThreadUtility::removePeriodicTasksMatching(const LogString& namePrefix)
{
while (1)
{
std::lock_guard<std::mutex> lock(m_priv->job_mutex);
auto pItem = std::find_if(m_priv->jobs.begin(), m_priv->jobs.end()
, [&namePrefix](const priv_data::NamedPeriodicFunction& item)
{ return namePrefix.size() <= item.name.size() && item.name.substr(0, namePrefix.size()) == namePrefix; }
);
if (m_priv->jobs.end() == pItem)
break;
m_priv->jobs.erase(pItem);
}
}

// Run ready tasks
void ThreadUtility::priv_data::doPeriodicTasks()
{
Expand Down
2 changes: 1 addition & 1 deletion src/main/include/log4cxx/helpers/aprinitializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class APRInitializer
private: // Modifiers
void addObject(size_t key, const ObjectPtr& pObject);
const ObjectPtr& findOrAddObject(size_t key, std::function<ObjectPtr()> creator);
void stopWatchDogs();
void deleteWatchDogs();
private: // Attributes
LOG4CXX_DECLARE_PRIVATE_MEMBER_PTR(APRInitializerPrivate, m_priv)
private: // Class methods
Expand Down
10 changes: 7 additions & 3 deletions src/main/include/log4cxx/helpers/filewatchdog.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,24 @@ class LOG4CXX_EXPORT FileWatchdog
void setDelay(long delay);

/**
Create a thread that periodically checks for a file change after first calling doOnChange() on the current thread.
Create an asynchronous task that periodically checks for a file change after first calling doOnChange().
*/
void start();

/**
Stop the thread that periodically checks for a file change.
Stop the task that periodically checks for a file change.
*/
void stop();

/**
Is the thread that periodically checks for a file change running?
Is the task that periodically checks for a file change running?
*/
bool is_active();

/**
Stop all tasks that periodically check for a file change.
*/
static void stopAll();
private:

FileWatchdog(const FileWatchdog&);
Expand Down
13 changes: 9 additions & 4 deletions src/main/include/log4cxx/helpers/threadutility.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,19 +159,24 @@ class LOG4CXX_EXPORT ThreadUtility
using Period = std::chrono::milliseconds;

/**
* Add a periodic task
* Add the \c taskName periodic task
*/
void addPeriodicTask(const LogString& name, std::function<void()> f, const Period& delay);
void addPeriodicTask(const LogString& taskName, std::function<void()> f, const Period& delay);

/**
* Has a \c taskName periodic task already been added?
*/
bool hasPeriodicTask(const LogString& name);
bool hasPeriodicTask(const LogString& taskName);

/**
* Remove the \c taskName periodic task
*/
void removePeriodicTask(const LogString& name);
void removePeriodicTask(const LogString& taskName);

/**
* Remove any periodic task matching \c namePrefix
*/
void removePeriodicTasksMatching(const LogString& namePrefix);
};

} /* namespace helpers */
Expand Down

0 comments on commit e227b5c

Please sign in to comment.