fix async redefined
This commit is contained in:
@ -22,226 +22,233 @@
|
||||
|
||||
// for pthread thread_local emulation
|
||||
#if defined(EMULATE_PTHREAD_THREAD_LOCAL)
|
||||
# include <pthread.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace async {
|
||||
namespace detail {
|
||||
|
||||
void* aligned_alloc(std::size_t size, std::size_t align)
|
||||
void *
|
||||
aligned_alloc(std::size_t size, std::size_t align)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
void* ptr = _aligned_malloc(size, align);
|
||||
if (!ptr)
|
||||
LIBASYNC_THROW(std::bad_alloc());
|
||||
return ptr;
|
||||
void *ptr = _aligned_malloc(size, align);
|
||||
if (!ptr) LIBASYNC_THROW(std::bad_alloc());
|
||||
return ptr;
|
||||
#else
|
||||
void* result;
|
||||
if (posix_memalign(&result, align, size))
|
||||
LIBASYNC_THROW(std::bad_alloc());
|
||||
else
|
||||
return result;
|
||||
void *result;
|
||||
if (posix_memalign(&result, align, size))
|
||||
LIBASYNC_THROW(std::bad_alloc());
|
||||
else
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
void aligned_free(void* addr) LIBASYNC_NOEXCEPT
|
||||
void
|
||||
aligned_free(void *addr) LIBASYNC_NOEXCEPT
|
||||
{
|
||||
#ifdef _WIN32
|
||||
_aligned_free(addr);
|
||||
_aligned_free(addr);
|
||||
#else
|
||||
free(addr);
|
||||
free(addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Wait for a task to complete (for threads outside thread pool)
|
||||
static void generic_wait_handler(task_wait_handle wait_task)
|
||||
static void
|
||||
generic_wait_handler(task_wait_handle wait_task)
|
||||
{
|
||||
// Create an event to wait on
|
||||
task_wait_event event;
|
||||
event.init();
|
||||
// Create an event to wait on
|
||||
task_wait_event event;
|
||||
event.init();
|
||||
|
||||
// Create a continuation for the task we are waiting for
|
||||
wait_task.on_finish([&event] {
|
||||
// Just signal the thread event
|
||||
event.signal(wait_type::task_finished);
|
||||
});
|
||||
// Create a continuation for the task we are waiting for
|
||||
wait_task.on_finish([&event] {
|
||||
// Just signal the thread event
|
||||
event.signal(wait_type::task_finished);
|
||||
});
|
||||
|
||||
// Wait for the event to be set
|
||||
event.wait();
|
||||
// Wait for the event to be set
|
||||
event.wait();
|
||||
}
|
||||
|
||||
#if defined(EMULATE_PTHREAD_THREAD_LOCAL)
|
||||
// Wait handler function, per-thread, defaults to generic version
|
||||
struct pthread_emulation_thread_wait_handler_key_initializer {
|
||||
pthread_key_t key;
|
||||
|
||||
pthread_emulation_thread_wait_handler_key_initializer()
|
||||
{
|
||||
pthread_key_create(&key, nullptr);
|
||||
}
|
||||
|
||||
~pthread_emulation_thread_wait_handler_key_initializer()
|
||||
{
|
||||
pthread_key_delete(key);
|
||||
}
|
||||
pthread_key_t key;
|
||||
|
||||
pthread_emulation_thread_wait_handler_key_initializer() { pthread_key_create(&key, nullptr); }
|
||||
|
||||
~pthread_emulation_thread_wait_handler_key_initializer() { pthread_key_delete(key); }
|
||||
};
|
||||
|
||||
static pthread_key_t get_thread_wait_handler_key()
|
||||
|
||||
static pthread_key_t
|
||||
get_thread_wait_handler_key()
|
||||
{
|
||||
static pthread_emulation_thread_wait_handler_key_initializer initializer;
|
||||
return initializer.key;
|
||||
static pthread_emulation_thread_wait_handler_key_initializer initializer;
|
||||
return initializer.key;
|
||||
}
|
||||
|
||||
#else
|
||||
static THREAD_LOCAL wait_handler thread_wait_handler = generic_wait_handler;
|
||||
#endif
|
||||
|
||||
static void set_thread_wait_handler(wait_handler handler)
|
||||
static void
|
||||
set_thread_wait_handler(wait_handler handler)
|
||||
{
|
||||
#if defined(EMULATE_PTHREAD_THREAD_LOCAL)
|
||||
// we need to call this here, because the pthread initializer is lazy,
|
||||
// this means the it could be null and we need to set it before trying to
|
||||
// get or set it
|
||||
pthread_setspecific(get_thread_wait_handler_key(), reinterpret_cast<void*>(handler));
|
||||
// we need to call this here, because the pthread initializer is lazy,
|
||||
// this means the it could be null and we need to set it before trying to
|
||||
// get or set it
|
||||
pthread_setspecific(get_thread_wait_handler_key(), reinterpret_cast<void *>(handler));
|
||||
#else
|
||||
thread_wait_handler = handler;
|
||||
thread_wait_handler = handler;
|
||||
#endif
|
||||
}
|
||||
|
||||
static wait_handler get_thread_wait_handler()
|
||||
|
||||
static wait_handler
|
||||
get_thread_wait_handler()
|
||||
{
|
||||
#if defined(EMULATE_PTHREAD_THREAD_LOCAL)
|
||||
// we need to call this here, because the pthread initializer is lazy,
|
||||
// this means the it could be null and we need to set it before trying to
|
||||
// get or set it
|
||||
wait_handler handler = (wait_handler) pthread_getspecific(get_thread_wait_handler_key());
|
||||
if(handler == nullptr) {
|
||||
return generic_wait_handler;
|
||||
}
|
||||
return handler;
|
||||
// we need to call this here, because the pthread initializer is lazy,
|
||||
// this means the it could be null and we need to set it before trying to
|
||||
// get or set it
|
||||
wait_handler handler = (wait_handler) pthread_getspecific(get_thread_wait_handler_key());
|
||||
if (handler == nullptr) { return generic_wait_handler; }
|
||||
return handler;
|
||||
#else
|
||||
return thread_wait_handler;
|
||||
return thread_wait_handler;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Wait for a task to complete
|
||||
void wait_for_task(task_base* wait_task)
|
||||
void
|
||||
generic_wait_for_task(task_base *wait_task)
|
||||
{
|
||||
// Dispatch to the current thread's wait handler
|
||||
wait_handler thread_wait_handler = get_thread_wait_handler();
|
||||
thread_wait_handler(task_wait_handle(wait_task));
|
||||
// Dispatch to the current thread's wait handler
|
||||
wait_handler thread_wait_handler = get_thread_wait_handler();
|
||||
thread_wait_handler(task_wait_handle(wait_task));
|
||||
}
|
||||
|
||||
// The default scheduler is just a thread pool which can be configured
|
||||
// using environment variables.
|
||||
class default_scheduler_impl: public threadpool_scheduler {
|
||||
static std::size_t get_num_threads()
|
||||
{
|
||||
// Get the requested number of threads from the environment
|
||||
// If that fails, use the number of CPUs in the system.
|
||||
std::size_t num_threads;
|
||||
class default_scheduler_impl : public threadpool_scheduler {
|
||||
static std::size_t get_num_threads()
|
||||
{
|
||||
// Get the requested number of threads from the environment
|
||||
// If that fails, use the number of CPUs in the system.
|
||||
std::size_t num_threads;
|
||||
#ifdef _MSC_VER
|
||||
char* s;
|
||||
# ifdef __cplusplus_winrt
|
||||
// Windows store applications do not support environment variables
|
||||
s = nullptr;
|
||||
# else
|
||||
// MSVC gives an error when trying to use getenv, work around this
|
||||
// by using _dupenv_s instead.
|
||||
_dupenv_s(&s, nullptr, "LIBASYNC_NUM_THREADS");
|
||||
# endif
|
||||
char *s;
|
||||
#ifdef __cplusplus_winrt
|
||||
// Windows store applications do not support environment variables
|
||||
s = nullptr;
|
||||
#else
|
||||
const char *s = std::getenv("LIBASYNC_NUM_THREADS");
|
||||
// MSVC gives an error when trying to use getenv, work around this
|
||||
// by using _dupenv_s instead.
|
||||
_dupenv_s(&s, nullptr, "LIBASYNC_NUM_THREADS");
|
||||
#endif
|
||||
if (s)
|
||||
num_threads = std::strtoul(s, nullptr, 10);
|
||||
else
|
||||
num_threads = hardware_concurrency();
|
||||
#else
|
||||
const char *s = std::getenv("LIBASYNC_NUM_THREADS");
|
||||
#endif
|
||||
if (s)
|
||||
num_threads = std::strtoul(s, nullptr, 10);
|
||||
else
|
||||
num_threads = hardware_concurrency();
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__cplusplus_winrt)
|
||||
// Free the string allocated by _dupenv_s
|
||||
free(s);
|
||||
// Free the string allocated by _dupenv_s
|
||||
free(s);
|
||||
#endif
|
||||
|
||||
// Make sure the thread count is reasonable
|
||||
if (num_threads < 1)
|
||||
num_threads = 1;
|
||||
return num_threads;
|
||||
}
|
||||
// Make sure the thread count is reasonable
|
||||
if (num_threads < 1) num_threads = 1;
|
||||
return num_threads;
|
||||
}
|
||||
|
||||
public:
|
||||
default_scheduler_impl()
|
||||
: threadpool_scheduler(get_num_threads()) {}
|
||||
default_scheduler_impl() : threadpool_scheduler(get_num_threads()) {}
|
||||
};
|
||||
|
||||
// Thread scheduler implementation
|
||||
void thread_scheduler_impl::schedule(task_run_handle t)
|
||||
void
|
||||
thread_scheduler_impl::schedule(task_run_handle t)
|
||||
{
|
||||
// A shared_ptr is used here because not all implementations of
|
||||
// std::thread support move-only objects.
|
||||
std::thread([](const std::shared_ptr<task_run_handle>& t) {
|
||||
t->run();
|
||||
}, std::make_shared<task_run_handle>(std::move(t))).detach();
|
||||
// A shared_ptr is used here because not all implementations of
|
||||
// std::thread support move-only objects.
|
||||
std::thread([](const std::shared_ptr<task_run_handle> &t) { t->run(); },
|
||||
std::make_shared<task_run_handle>(std::move(t)))
|
||||
.detach();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
}// namespace detail
|
||||
|
||||
threadpool_scheduler& default_threadpool_scheduler()
|
||||
threadpool_scheduler &
|
||||
default_threadpool_scheduler()
|
||||
{
|
||||
return detail::singleton<detail::default_scheduler_impl>::get_instance();
|
||||
return detail::singleton<detail::default_scheduler_impl>::get_instance();
|
||||
}
|
||||
|
||||
// FIFO scheduler implementation
|
||||
struct fifo_scheduler::internal_data {
|
||||
detail::fifo_queue queue;
|
||||
std::mutex lock;
|
||||
detail::fifo_queue queue;
|
||||
std::mutex lock;
|
||||
};
|
||||
fifo_scheduler::fifo_scheduler()
|
||||
: impl(new internal_data) {}
|
||||
|
||||
fifo_scheduler::fifo_scheduler() : impl(new internal_data) {}
|
||||
|
||||
fifo_scheduler::~fifo_scheduler() {}
|
||||
void fifo_scheduler::schedule(task_run_handle t)
|
||||
|
||||
void
|
||||
fifo_scheduler::schedule(task_run_handle t)
|
||||
{
|
||||
std::lock_guard<std::mutex> locked(impl->lock);
|
||||
impl->queue.push(std::move(t));
|
||||
}
|
||||
bool fifo_scheduler::try_run_one_task()
|
||||
{
|
||||
task_run_handle t;
|
||||
{
|
||||
std::lock_guard<std::mutex> locked(impl->lock);
|
||||
t = impl->queue.pop();
|
||||
}
|
||||
if (t) {
|
||||
t.run();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void fifo_scheduler::run_all_tasks()
|
||||
{
|
||||
while (try_run_one_task()) {}
|
||||
std::lock_guard<std::mutex> locked(impl->lock);
|
||||
impl->queue.push(std::move(t));
|
||||
}
|
||||
|
||||
std::size_t hardware_concurrency() LIBASYNC_NOEXCEPT
|
||||
bool
|
||||
fifo_scheduler::try_run_one_task()
|
||||
{
|
||||
// Cache the value because calculating it may be expensive
|
||||
static std::size_t value = std::thread::hardware_concurrency();
|
||||
|
||||
// Always return at least 1 core
|
||||
return value == 0 ? 1 : value;
|
||||
task_run_handle t;
|
||||
{
|
||||
std::lock_guard<std::mutex> locked(impl->lock);
|
||||
t = impl->queue.pop();
|
||||
}
|
||||
if (t) {
|
||||
t.run();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
wait_handler set_thread_wait_handler(wait_handler handler) LIBASYNC_NOEXCEPT
|
||||
void
|
||||
fifo_scheduler::run_all_tasks()
|
||||
{
|
||||
wait_handler old = detail::get_thread_wait_handler();
|
||||
detail::set_thread_wait_handler(handler);
|
||||
return old;
|
||||
while (try_run_one_task()) {}
|
||||
}
|
||||
|
||||
} // namespace async
|
||||
std::size_t
|
||||
hardware_concurrency() LIBASYNC_NOEXCEPT
|
||||
{
|
||||
// Cache the value because calculating it may be expensive
|
||||
static std::size_t value = std::thread::hardware_concurrency();
|
||||
|
||||
// Always return at least 1 core
|
||||
return value == 0 ? 1 : value;
|
||||
}
|
||||
|
||||
wait_handler
|
||||
set_thread_wait_handler(wait_handler handler) LIBASYNC_NOEXCEPT
|
||||
{
|
||||
wait_handler old = detail::get_thread_wait_handler();
|
||||
detail::set_thread_wait_handler(handler);
|
||||
return old;
|
||||
}
|
||||
|
||||
}// namespace async
|
||||
|
||||
#ifndef LIBASYNC_STATIC
|
||||
#if defined(__GNUC__) && !defined(_WIN32)
|
||||
# pragma GCC visibility pop
|
||||
#pragma GCC visibility pop
|
||||
#endif
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user