From cf8ee4a243658f87e79f2a930dec05605dcfdb8d Mon Sep 17 00:00:00 2001 From: tqcq <99722391+tqcq@users.noreply.github.com> Date: Fri, 29 Mar 2024 10:26:51 +0800 Subject: [PATCH] fix async redefined --- .../asyncplusplus/include/async++/scheduler.h | 190 ++++++------ .../include/async++/scheduler_fwd.h | 7 +- 3party/asyncplusplus/src/scheduler.cpp | 277 +++++++++--------- include/sled/async/async.h | 6 +- src/uri.cc | 2 +- src/uri_test.cc | 2 +- 6 files changed, 245 insertions(+), 239 deletions(-) diff --git a/3party/asyncplusplus/include/async++/scheduler.h b/3party/asyncplusplus/include/async++/scheduler.h index 6718095..774b691 100644 --- a/3party/asyncplusplus/include/async++/scheduler.h +++ b/3party/asyncplusplus/include/async++/scheduler.h @@ -19,7 +19,7 @@ // THE SOFTWARE. #ifndef ASYNCXX_H_ -# error "Do not include this header directly, include instead." +#error "Do not include this header directly, include instead." #endif namespace async { @@ -31,54 +31,51 @@ LIBASYNC_EXPORT std::size_t hardware_concurrency() LIBASYNC_NOEXCEPT; // Task handle used by a wait handler class task_wait_handle { - detail::task_base* handle; + detail::task_base *handle; - // Allow construction in wait_for_task() - friend LIBASYNC_EXPORT void detail::wait_for_task(detail::task_base* t); - task_wait_handle(detail::task_base* t) - : handle(t) {} + // Allow construction in wait_for_task() + friend void detail::wait_for_task(detail::task_base *t); + friend void detail::generic_wait_for_task(detail::task_base *wait_task); - // Execution function for use by wait handlers - template - struct wait_exec_func: private detail::func_base { - template - explicit wait_exec_func(F&& f) - : detail::func_base(std::forward(f)) {} - void operator()(detail::task_base*) - { - // Just call the function directly, all this wrapper does is remove - // the task_base* parameter. - this->get_func()(); - } - }; + task_wait_handle(detail::task_base *t) : handle(t) {} + + // Execution function for use by wait handlers + template + struct wait_exec_func : private detail::func_base { + template + explicit wait_exec_func(F &&f) : detail::func_base(std::forward(f)) + {} + + void operator()(detail::task_base *) + { + // Just call the function directly, all this wrapper does is remove + // the task_base* parameter. + this->get_func()(); + } + }; public: - task_wait_handle() - : handle(nullptr) {} + task_wait_handle() : handle(nullptr) {} - // Check if the handle is valid - explicit operator bool() const - { - return handle != nullptr; - } + // Check if the handle is valid + explicit operator bool() const { return handle != nullptr; } - // Check if the task has finished executing - bool ready() const - { - return detail::is_finished(handle->state.load(std::memory_order_acquire)); - } + // Check if the task has finished executing + bool ready() const { return detail::is_finished(handle->state.load(std::memory_order_acquire)); } - // Queue a function to be executed when the task has finished executing. - template - void on_finish(Func&& func) - { - // Make sure the function type is callable - static_assert(detail::is_callable::value, "Invalid function type passed to on_finish()"); + // Queue a function to be executed when the task has finished executing. + template + void on_finish(Func &&func) + { + // Make sure the function type is callable + static_assert(detail::is_callable::value, "Invalid function type passed to on_finish()"); - auto cont = new detail::task_func::type, wait_exec_func::type>, detail::fake_void>(std::forward(func)); - cont->sched = std::addressof(inline_scheduler()); - handle->add_continuation(inline_scheduler(), detail::task_ptr(cont)); - } + auto cont = new detail::task_func::type, + wait_exec_func::type>, + detail::fake_void>(std::forward(func)); + cont->sched = std::addressof(inline_scheduler()); + handle->add_continuation(inline_scheduler(), detail::task_ptr(cont)); + } }; // Wait handler function prototype @@ -95,81 +92,78 @@ struct LIBASYNC_EXPORT_EXCEPTION task_not_executed {}; // Task handle used in scheduler, acts as a unique_ptr to a task object class task_run_handle { - detail::task_ptr handle; + detail::task_ptr handle; - // Allow construction in schedule_task() - template - friend void detail::schedule_task(Sched& sched, detail::task_ptr t); - explicit task_run_handle(detail::task_ptr t) - : handle(std::move(t)) {} + // Allow construction in schedule_task() + template + friend void detail::schedule_task(Sched &sched, detail::task_ptr t); + + explicit task_run_handle(detail::task_ptr t) : handle(std::move(t)) {} public: - // Movable but not copyable - task_run_handle() = default; - task_run_handle(task_run_handle&& other) LIBASYNC_NOEXCEPT - : handle(std::move(other.handle)) {} - task_run_handle& operator=(task_run_handle&& other) LIBASYNC_NOEXCEPT - { - handle = std::move(other.handle); - return *this; - } + // Movable but not copyable + task_run_handle() = default; - // If the task is not executed, cancel it with an exception - ~task_run_handle() - { - if (handle) - handle->vtable->cancel(handle.get(), std::make_exception_ptr(task_not_executed())); - } + task_run_handle(task_run_handle &&other) LIBASYNC_NOEXCEPT : handle(std::move(other.handle)) {} - // Check if the handle is valid - explicit operator bool() const - { - return handle != nullptr; - } + task_run_handle &operator=(task_run_handle &&other) LIBASYNC_NOEXCEPT + { + handle = std::move(other.handle); + return *this; + } - // Run the task and release the handle - void run() - { - handle->vtable->run(handle.get()); - handle = nullptr; - } + // If the task is not executed, cancel it with an exception + ~task_run_handle() + { + if (handle) handle->vtable->cancel(handle.get(), std::make_exception_ptr(task_not_executed())); + } - // Run the task but run the given wait handler when waiting for a task, - // instead of just sleeping. - void run_with_wait_handler(wait_handler handler) - { - wait_handler old = set_thread_wait_handler(handler); - run(); - set_thread_wait_handler(old); - } + // Check if the handle is valid + explicit operator bool() const { return handle != nullptr; } - // Conversion to and from void pointer. This allows the task handle to be - // sent through C APIs which don't preserve types. - void* to_void_ptr() - { - return handle.release(); - } - static task_run_handle from_void_ptr(void* ptr) - { - return task_run_handle(detail::task_ptr(static_cast(ptr))); - } + // Run the task and release the handle + void run() + { + handle->vtable->run(handle.get()); + handle = nullptr; + } + + // Run the task but run the given wait handler when waiting for a task, + // instead of just sleeping. + void run_with_wait_handler(wait_handler handler) + { + wait_handler old = set_thread_wait_handler(handler); + run(); + set_thread_wait_handler(old); + } + + // Conversion to and from void pointer. This allows the task handle to be + // sent through C APIs which don't preserve types. + void *to_void_ptr() { return handle.release(); } + + static task_run_handle from_void_ptr(void *ptr) + { + return task_run_handle(detail::task_ptr(static_cast(ptr))); + } }; namespace detail { // Schedule a task for execution using its scheduler template -void schedule_task(Sched& sched, task_ptr t) +void +schedule_task(Sched &sched, task_ptr t) { - static_assert(is_scheduler::value, "Type is not a valid scheduler"); - sched.schedule(task_run_handle(std::move(t))); + static_assert(is_scheduler::value, "Type is not a valid scheduler"); + sched.schedule(task_run_handle(std::move(t))); } // Inline scheduler implementation -inline void inline_scheduler_impl::schedule(task_run_handle t) +inline void +inline_scheduler_impl::schedule(task_run_handle t) { - t.run(); + t.run(); } -} // namespace detail -} // namespace async +}// namespace detail +}// namespace async diff --git a/3party/asyncplusplus/include/async++/scheduler_fwd.h b/3party/asyncplusplus/include/async++/scheduler_fwd.h index 8b41c58..4f5b010 100644 --- a/3party/asyncplusplus/include/async++/scheduler_fwd.h +++ b/3party/asyncplusplus/include/async++/scheduler_fwd.h @@ -63,10 +63,15 @@ typedef ref_count_ptr task_ptr; template void schedule_task(Sched &sched, task_ptr t); +void generic_wait_for_task(task_base *wait_task); // Wait for the given task to finish. This will call the wait handler currently // active for this thread, which causes the thread to sleep by default. #ifndef LIBASYNC_CUSTOM_WAIT_FOR_TASK -LIBASYNC_EXPORT void wait_for_task(task_base *wait_task); +inline void +wait_for_task(task_base *wait_task) +{ + generic_wait_for_task(wait_task); +} #endif // Forward-declaration for data used by threadpool_scheduler diff --git a/3party/asyncplusplus/src/scheduler.cpp b/3party/asyncplusplus/src/scheduler.cpp index 9afb0cc..f4d56a3 100644 --- a/3party/asyncplusplus/src/scheduler.cpp +++ b/3party/asyncplusplus/src/scheduler.cpp @@ -22,226 +22,233 @@ // for pthread thread_local emulation #if defined(EMULATE_PTHREAD_THREAD_LOCAL) -# include +#include #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(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(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& t) { - t->run(); - }, std::make_shared(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 &t) { t->run(); }, + std::make_shared(std::move(t))) + .detach(); } -} // namespace detail +}// namespace detail -threadpool_scheduler& default_threadpool_scheduler() +threadpool_scheduler & +default_threadpool_scheduler() { - return detail::singleton::get_instance(); + return detail::singleton::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 locked(impl->lock); - impl->queue.push(std::move(t)); -} -bool fifo_scheduler::try_run_one_task() -{ - task_run_handle t; - { - std::lock_guard 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 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 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 diff --git a/include/sled/async/async.h b/include/sled/async/async.h index d566fe6..bb81dc8 100644 --- a/include/sled/async/async.h +++ b/include/sled/async/async.h @@ -8,14 +8,14 @@ class FiberScheduler; namespace async { sled::FiberScheduler &default_scheduler(); -class task_base; namespace detail { +class task_base; void wait_for_task(task_base *wait_task); -} +}// namespace detail }// namespace async -#define LIBASYNC_CUSTON_EVENT +#define LIBASYNC_CUSTOM_WAIT_FOR_TASK #define LIBASYNC_CUSTOM_DEFAULT_SCHEDULER #include diff --git a/src/uri.cc b/src/uri.cc index aa9265a..0109ac2 100644 --- a/src/uri.cc +++ b/src/uri.cc @@ -532,7 +532,7 @@ URI::href() const { std::stringstream ss; if (!scheme().empty()) { ss << scheme() << ":"; } - if (!user_info.empty()) { ss << user_info() << "@"; } + if (!user_info().empty()) { ss << user_info() << "@"; } if (!authority().empty()) { ss << authority(); } ss << path(); ss << "?" << query_string(); diff --git a/src/uri_test.cc b/src/uri_test.cc index 42d9ef3..26cc84f 100644 --- a/src/uri_test.cc +++ b/src/uri_test.cc @@ -7,7 +7,7 @@ TEST(URI, Absolute) EXPECT_EQ(uri.scheme(), "http"); EXPECT_EQ(uri.host(), "example.com"); EXPECT_EQ(uri.port(), 1234); - EXPECT_EQ(uri.path(), "dir1/dir2/file"); + EXPECT_EQ(uri.path(), "/dir1/dir2/file"); EXPECT_EQ(uri.query().size(), 1); EXPECT_EQ(uri.query()["a"], "1"); EXPECT_EQ(uri.anchor(), "anchor");