assertion failures.
Before this, it was possible for J2KEncoder::terminate_threads()
to finish without terminating all threads if the thread _running_
terminate_threads() was itself interrupt()ed.
This is because the thread_group::join_all() in terminate_threads()
is an interruption point, so it was possible it not to complete
but instead to throw interrupted_exception. Then the owning
J2KEncoder would be torn down but the threads would still be running,
causing use-after-frees.
This commit adds some boost::this_thread::disable_interruption
objects to ensure that the owning thread is not interrupted while
it is being destroyed.
Also tidy up code that does this stuff, assuming that it's safe
to not call thread::joinable but instead do
thread.interrupt();
try {
thread.join();
} catch (...) {}
12 files changed:
+ boost::this_thread::disable_interruption dis;
+
{
boost::mutex::scoped_lock lm (_mutex);
_stop_thread = true;
{
boost::mutex::scoped_lock lm (_mutex);
_stop_thread = true;
_thread.interrupt ();
try {
_thread.join ();
_thread.interrupt ();
try {
_thread.join ();
}
/** Caller must hold a lock on _mutex */
}
/** Caller must hold a lock on _mutex */
+ boost::this_thread::disable_interruption dis;
+
{
boost::mutex::scoped_lock lm (_mutex);
_terminate = true;
}
{
boost::mutex::scoped_lock lm (_mutex);
_terminate = true;
}
- if (_thread.joinable()) {
- _thread.interrupt ();
- try {
- _thread.join ();
- } catch (...) {
-
- }
- }
+ _thread.interrupt ();
+ try {
+ _thread.join ();
+ } catch (...) {}
EncodeServer::~EncodeServer ()
{
EncodeServer::~EncodeServer ()
{
+ boost::this_thread::disable_interruption dis;
+
{
boost::mutex::scoped_lock lm (_mutex);
_terminate = true;
{
boost::mutex::scoped_lock lm (_mutex);
_terminate = true;
}
_broadcast.io_service.stop ();
}
_broadcast.io_service.stop ();
- if (_broadcast.thread.joinable()) {
- try {
- _broadcast.thread.join ();
- } catch (...) {
-
- }
- }
+ try {
+ _broadcast.thread.join ();
+ } catch (...) {}
}
/** @param after_read Filled in with gettimeofday() after reading the input from the network.
}
/** @param after_read Filled in with gettimeofday() after reading the input from the network.
void
EncodeServerFinder::stop ()
{
void
EncodeServerFinder::stop ()
{
+ boost::this_thread::disable_interruption dis;
+
_stop = true;
_search_condition.notify_all ();
_stop = true;
_search_condition.notify_all ();
- if (_search_thread.joinable()) {
- try {
- _search_thread.join();
- } catch (...) {
-
- }
- }
+ try {
+ _search_thread.join();
+ } catch (...) {}
_listen_io_service.stop ();
_listen_io_service.stop ();
- if (_listen_thread.joinable()) {
- try {
- _listen_thread.join ();
- } catch (...) {
-
- }
- }
+ try {
+ _listen_thread.join ();
+ } catch (...) {}
boost::mutex::scoped_lock lm (_servers_mutex);
_servers.clear ();
boost::mutex::scoped_lock lm (_servers_mutex);
_servers.clear ();
- if (!_thread.joinable()) {
- return;
- }
+ boost::this_thread::disable_interruption dis;
try {
_stop = true;
_thread.interrupt ();
_thread.join ();
try {
_stop = true;
_thread.interrupt ();
_thread.join ();
J2KEncoder::~J2KEncoder ()
{
J2KEncoder::~J2KEncoder ()
{
- try {
- terminate_threads ();
- } catch (...) {
- /* Destructors must not throw exceptions; anything bad
- happening now is too late to worry about anyway,
- I think.
- */
- }
void
J2KEncoder::terminate_threads ()
{
void
J2KEncoder::terminate_threads ()
{
+ boost::this_thread::disable_interruption dis;
+
if (!_threads) {
return;
}
if (!_threads) {
return;
}
void
Job::stop_thread ()
{
void
Job::stop_thread ()
{
- if (!_thread.joinable()) {
- return;
- }
+ boost::this_thread::disable_interruption dis;
_thread.interrupt ();
try {
_thread.join ();
_thread.interrupt ();
try {
_thread.join ();
- } catch (...) {
- /* Too late to do anything about this */
- }
}
/** Start the job in a separate thread, returning immediately */
}
/** Start the job in a separate thread, returning immediately */
JobManager::~JobManager ()
{
JobManager::~JobManager ()
{
+ boost::this_thread::disable_interruption dis;
+
BOOST_FOREACH (boost::signals2::connection& i, _connections) {
i.disconnect ();
}
BOOST_FOREACH (boost::signals2::connection& i, _connections) {
i.disconnect ();
}
_empty_condition.notify_all ();
}
_empty_condition.notify_all ();
}
- if (_scheduler.joinable()) {
- try {
- _scheduler.join();
- } catch (...) {
-
- }
- }
+ try {
+ _scheduler.join();
+ } catch (...) {}
UpdateChecker::~UpdateChecker ()
{
UpdateChecker::~UpdateChecker ()
{
+ boost::this_thread::disable_interruption dis;
+
{
boost::mutex::scoped_lock lm (_process_mutex);
_terminate = true;
}
_condition.notify_all ();
{
boost::mutex::scoped_lock lm (_process_mutex);
_terminate = true;
}
_condition.notify_all ();
- if (_thread.joinable()) {
- try {
- _thread.join ();
- } catch (...) {
-
- }
- }
+ try {
+ _thread.join ();
+ } catch (...) {}
curl_easy_cleanup (_curl);
delete[] _buffer;
curl_easy_cleanup (_curl);
delete[] _buffer;
void
Writer::terminate_thread (bool can_throw)
{
void
Writer::terminate_thread (bool can_throw)
{
+ boost::this_thread::disable_interruption dis;
+
boost::mutex::scoped_lock lock (_state_mutex);
boost::mutex::scoped_lock lock (_state_mutex);
- if (!_thread.joinable()) {
- return;
- }
_finish = true;
_empty_condition.notify_all ();
_full_condition.notify_all ();
lock.unlock ();
_finish = true;
_empty_condition.notify_all ();
_full_condition.notify_all ();
lock.unlock ();
+ try {
+ _thread.join ();
+ } catch (...) {}
if (can_throw) {
rethrow ();
if (can_throw) {
rethrow ();
GLVideoView::~GLVideoView ()
{
GLVideoView::~GLVideoView ()
{
+ boost::this_thread::disable_interruption dis;
+
try {
_thread.interrupt ();
_thread.join ();
try {
_thread.interrupt ();
_thread.join ();
glDeleteTextures (1, &_id);
}
glDeleteTextures (1, &_id);
}
+ boost::this_thread::disable_interruption dis;
+ try {
+ _thread.join ();
+ } catch (...) {}