Commit 181823d4 authored by tqcq's avatar tqcq
Browse files

fix async deadlock

parent fd46ca62
Loading
Loading
Loading
Loading
+49 −42
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ template<typename T, typename = decltype(std::declval<T>().schedule(std::declval
two &is_scheduler_helper(int);
template<typename T>
one &is_scheduler_helper(...);

template<typename T>
struct is_scheduler : public std::integral_constant<bool, sizeof(is_scheduler_helper<T>(0)) - 1> {};

@@ -48,6 +49,7 @@ class thread_scheduler_impl {
public:
    LIBASYNC_EXPORT static void schedule(task_run_handle t);
};

class inline_scheduler_impl {
public:
    static void schedule(task_run_handle t);
@@ -63,7 +65,9 @@ void schedule_task(Sched& sched, task_ptr t);

// 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);
#endif

// Forward-declaration for data used by threadpool_scheduler
struct threadpool_data;
@@ -71,7 +75,8 @@ struct threadpool_data;
}// namespace detail

// Run a task in the current thread as soon as it is scheduled
inline detail::inline_scheduler_impl& inline_scheduler()
inline detail::inline_scheduler_impl &
inline_scheduler()
{
    static detail::inline_scheduler_impl instance;
    return instance;
@@ -80,7 +85,8 @@ inline detail::inline_scheduler_impl& inline_scheduler()
// Run a task in a separate thread. Note that this scheduler does not wait for
// threads to finish at process exit. You must ensure that all threads finish
// before ending the process.
inline detail::thread_scheduler_impl& thread_scheduler()
inline detail::thread_scheduler_impl &
thread_scheduler()
{
    static detail::thread_scheduler_impl instance;
    return instance;
@@ -96,8 +102,10 @@ LIBASYNC_EXPORT threadpool_scheduler& default_threadpool_scheduler();
// LIBASYNC_CUSTOM_DEFAULT_SCHEDULER before including async++.h. Keep in mind
// that in that case async::default_scheduler should be declared before
// including async++.h.

#ifndef LIBASYNC_CUSTOM_DEFAULT_SCHEDULER
inline threadpool_scheduler& default_scheduler()
inline threadpool_scheduler &
default_scheduler()
{
    return default_threadpool_scheduler();
}
@@ -137,9 +145,8 @@ public:

    // Create a thread pool with the given number of threads. Call `prerun`
    // function before execution loop and `postrun` after.
	LIBASYNC_EXPORT threadpool_scheduler(std::size_t num_threads,
                                         std::function<void()>&& prerun_,
                                         std::function<void()>&& postrun_);
    LIBASYNC_EXPORT
    threadpool_scheduler(std::size_t num_threads, std::function<void()> &&prerun_, std::function<void()> &&postrun_);

    // Destroy the thread pool, tasks that haven't been started are dropped
    LIBASYNC_EXPORT ~threadpool_scheduler();
+3 −0
Original line number Diff line number Diff line
@@ -141,6 +141,9 @@ if(SLED_BUILD_TESTS)
    src/system/thread_pool_test.cc
    src/rx_test.cc
    src/uri_test.cc)
    if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
        target_compile_options(sled_tests PRIVATE -Wthread-safety)
    endif()
    target_link_libraries(sled_tests PRIVATE sled GTest::gtest GTest::gtest_main)
    add_test(NAME sled_tests COMMAND sled_tests)
endif(SLED_BUILD_TESTS)
+10 −0
Original line number Diff line number Diff line
@@ -3,18 +3,28 @@

namespace sled {
class FiberScheduler;

}

namespace async {
sled::FiberScheduler &default_scheduler();
class task_base;

namespace detail {
void wait_for_task(task_base *wait_task);
}
}// namespace async

#define LIBASYNC_CUSTON_EVENT
#define LIBASYNC_CUSTOM_DEFAULT_SCHEDULER
#include <async++.h>

namespace sled {
void SleepWaitHandler(async::task_wait_handle t);

class FiberScheduler {
public:
    FiberScheduler();
    void schedule(async::task_run_handle t);
};

+32 −34
Original line number Diff line number Diff line
@@ -33,28 +33,29 @@ struct HasLockAndUnlock {
};
}// namespace internal

using Mutex = marl::mutex;
// using Mutex = marl::mutex;

// class Mutex final {
// public:
//     Mutex() = default;
//     Mutex(const Mutex &) = delete;
//     Mutex &operator=(const Mutex &) = delete;
//
//     inline void Lock() { impl_.lock(); };
//
//     inline bool TryLock() { return impl_.try_lock(); }
//
//     inline void AssertHeld() {}
//
//     inline void Unlock() { impl_.unlock(); }
//
// private:
//     std::mutex impl_;
//     friend class ConditionVariable;
// };
class SLED_LOCKABLE Mutex final {
public:
    Mutex()                         = default;
    Mutex(const Mutex &)            = delete;
    Mutex &operator=(const Mutex &) = delete;

class RecursiveMutex final {
    inline void Lock() SLED_EXCLUSIVE_LOCK_FUNCTION(impl_) { impl_.lock(); };

    inline bool TryLock() SLED_EXCLUSIVE_TRYLOCK_FUNCTION(true) { return impl_.try_lock(); }

    inline void AssertHeld() SLED_ASSERT_EXCLUSIVE_LOCK(impl_) {}

    inline void Unlock() SLED_UNLOCK_FUNCTION(impl_) { impl_.unlock(); }

private:
    marl::mutex impl_;
    friend class ConditionVariable;
    friend class MutexLock;
};

class SLED_LOCKABLE RecursiveMutex final {
public:
    RecursiveMutex()                                  = default;
    RecursiveMutex(const RecursiveMutex &)            = delete;
@@ -72,17 +73,14 @@ private:
    std::recursive_mutex impl_;
};

class RecursiveMutexLock final {
class SLED_SCOPED_CAPABILITY RecursiveMutexLock final {
public:
    RecursiveMutexLock(const RecursiveMutexLock &)            = delete;
    RecursiveMutexLock &operator=(const RecursiveMutexLock &) = delete;

    explicit RecursiveMutexLock(RecursiveMutex *mutex) SLED_EXCLUSIVE_LOCK_FUNCTION(mutex) : mutex_(mutex)
    {
        mutex->Lock();
    }
    explicit RecursiveMutexLock(RecursiveMutex *mutex) SLED_ACQUIRE_SHARED(mutex) : mutex_(mutex) { mutex->Lock(); }

    ~RecursiveMutexLock() SLED_UNLOCK_FUNCTION() { mutex_->Unlock(); }
    ~RecursiveMutexLock() SLED_RELEASE_SHARED(mutex_) { mutex_->Unlock(); }

private:
    RecursiveMutex *mutex_;
@@ -101,11 +99,11 @@ private:
//     friend class ConditionVariable;
// };
//
class MutexLock final {
class SLED_SCOPED_CAPABILITY MutexLock final {
public:
    MutexLock(Mutex *mutex) SLED_EXCLUSIVE_LOCK_FUNCTION(mutex) : lock_(*mutex) {}
    MutexLock(Mutex *mutex) SLED_ACQUIRE(mutex) : lock_(mutex->impl_) {}

    ~MutexLock() SLED_UNLOCK_FUNCTION() = default;
    ~MutexLock() SLED_RELEASE() = default;

    MutexLock(const MutexLock &)            = delete;
    MutexLock &operator=(const MutexLock &) = delete;
+21 −10
Original line number Diff line number Diff line
@@ -5,15 +5,6 @@
// clang-format off
#include <async++.h>

// clang-format on
namespace async {
sled::FiberScheduler &
default_scheduler()
{
    static sled::FiberScheduler scheduler;
    return scheduler;
}
}// namespace async

namespace sled {

@@ -25,13 +16,33 @@ SleepWaitHandler(async::task_wait_handle t)
    event.Wait(sled::Event::kForever);
}

FiberScheduler::FiberScheduler()
{
}

void
FiberScheduler::schedule(async::task_run_handle t)
{
    static ThreadPool thread_pool;
    auto move_on_copy = sled::MakeMoveOnCopy(t);
    // thread_pool.PostTask([move_on_copy] { move_on_copy.value.run_with_wait_handler(SleepWaitHandler); });
    thread_pool.submit([move_on_copy] { move_on_copy.value.run_with_wait_handler(SleepWaitHandler); });
    // thread_pool.submit([move_on_copy] { move_on_copy.value.run(); });
}

}// namespace sled

// clang-format on
namespace async {
sled::FiberScheduler &
default_scheduler()
{
    static sled::FiberScheduler scheduler;
    return scheduler;
}

void
detail::wait_for_task(task_base *wait_task)
{
    sled::SleepWaitHandler(task_wait_handle(wait_task));
}
}// namespace async
Loading