Files
llvm/lldb/source/Utility/TaskPool.cpp
Pavel Labath 7ef36b5c15 Work around a linux libc bug causing a crash in TaskPool
Summary:
Doing a pthread_detach while the thread is exiting can cause crashes or other mischief, so we
make sure the thread stays around long enough. The performance impact of the added
synchronization should be minimal, as the parent thread is already holding a mutex, so I am just
making sure it holds it for a little while longer. It's possible the new thread will block on
this mutex immediately after startup, but it should be unblocked really quickly and some
blocking is unavoidable if we actually want to have this synchronization.

Reviewers: tberghammer

Subscribers: lldb-commits

Differential Revision: http://reviews.llvm.org/D19153

llvm-svn: 266423
2016-04-15 10:49:07 +00:00

90 lines
2.1 KiB
C++

//===--------------------- TaskPool.cpp -------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Utility/TaskPool.h"
namespace
{
class TaskPoolImpl
{
public:
static TaskPoolImpl&
GetInstance();
void
AddTask(std::function<void()>&& task_fn);
private:
TaskPoolImpl();
static void
Worker(TaskPoolImpl* pool);
std::queue<std::function<void()>> m_tasks;
std::mutex m_tasks_mutex;
uint32_t m_thread_count;
};
} // end of anonymous namespace
TaskPoolImpl&
TaskPoolImpl::GetInstance()
{
static TaskPoolImpl g_task_pool_impl;
return g_task_pool_impl;
}
void
TaskPool::AddTaskImpl(std::function<void()>&& task_fn)
{
TaskPoolImpl::GetInstance().AddTask(std::move(task_fn));
}
TaskPoolImpl::TaskPoolImpl() :
m_thread_count(0)
{
}
void
TaskPoolImpl::AddTask(std::function<void()>&& task_fn)
{
static const uint32_t max_threads = std::thread::hardware_concurrency();
std::unique_lock<std::mutex> lock(m_tasks_mutex);
m_tasks.emplace(std::move(task_fn));
if (m_thread_count < max_threads)
{
m_thread_count++;
// Note that this detach call needs to happen with the m_tasks_mutex held. This prevents the thread
// from exiting prematurely and triggering a linux libc bug
// (https://sourceware.org/bugzilla/show_bug.cgi?id=19951).
std::thread (Worker, this).detach();
}
}
void
TaskPoolImpl::Worker(TaskPoolImpl* pool)
{
while (true)
{
std::unique_lock<std::mutex> lock(pool->m_tasks_mutex);
if (pool->m_tasks.empty())
{
pool->m_thread_count--;
break;
}
std::function<void()> f = pool->m_tasks.front();
pool->m_tasks.pop();
lock.unlock();
f();
}
}