Bläddra i källkod

* Implemented current thread executor (and executors in general)

* Refactored timer implementation
master
bergmann 4 år sedan
förälder
incheckning
222348dd4c
24 ändrade filer med 812 tillägg och 205 borttagningar
  1. +3
    -3
      include/asyncpp/core/misc.h
  2. +0
    -0
      include/asyncpp/core/misc.inl
  3. +26
    -11
      include/asyncpp/core/task.h
  4. +12
    -29
      include/asyncpp/core/task.inl
  5. +73
    -0
      include/asyncpp/executor/current_thread.h
  6. +136
    -0
      include/asyncpp/executor/current_thread.inl
  7. +44
    -0
      include/asyncpp/executor/executor.h
  8. +28
    -0
      include/asyncpp/executor/executor.inl
  9. +2
    -2
      include/asyncpp/timer.h
  10. +5
    -3
      include/asyncpp/timer/delay.h
  11. +4
    -4
      include/asyncpp/timer/delay.inl
  12. +8
    -0
      include/asyncpp/timer/delay.pre.h
  13. +40
    -0
      include/asyncpp/timer/impl/registration.h
  14. +23
    -0
      include/asyncpp/timer/impl/registration.inl
  15. +9
    -0
      include/asyncpp/timer/impl/registration.pre.h
  16. +86
    -0
      include/asyncpp/timer/impl/timer_base.h
  17. +95
    -0
      include/asyncpp/timer/impl/timer_base.inl
  18. +9
    -0
      include/asyncpp/timer/impl/timer_base.pre.h
  19. +33
    -72
      include/asyncpp/timer/timer.h
  20. +51
    -73
      include/asyncpp/timer/timer.inl
  21. +63
    -0
      test/asyncpp/executor/current_thread_tests.cpp
  22. +48
    -6
      test/asyncpp/timer/timer_tests.cpp
  23. +2
    -2
      test/helper/now_mock.h
  24. +12
    -0
      test/helper/runtime_mock.h

include/asyncpp/timer/misc.h → include/asyncpp/core/misc.h Visa fil

@@ -2,8 +2,8 @@

#include <chrono>

namespace asyncpp {
namespace timer {
namespace asyncpp
{

using clock = std::chrono::steady_clock;

@@ -17,4 +17,4 @@ namespace timer {
*/
inline time_point now();

} }
}

include/asyncpp/timer/misc.inl → include/asyncpp/core/misc.inl Visa fil


+ 26
- 11
include/asyncpp/core/task.h Visa fil

@@ -1,41 +1,55 @@
#pragma once

#include <vector>
#include <memory>
#include <functional>

namespace asyncpp
{

struct task
{
public:
using notify_handler = std::function<void (task&)>;
using notify_handler_vector = std::vector<notify_handler>;

private:
bool _notified;
notify_handler_vector _notify_handlers;

public:
/**
* @brief Destructor.
*/
virtual ~task() = default;

/**
* @brief Check if the task is notified.
*/
inline bool notified() const;

/**
* @brief Notify the task that a resource that the task is interested in, is ready to be polled.
*/
inline void notify();

/**
* @brief Poll the future stored in the task.
*
* @return TRUE if the task is finished, FALSE otherwise.
*/
bool poll();
inline bool poll();

private:
/**
* @brief Actual implementation of the poll function.
* @brief Add a callback to execute when the task is notified.
*/
virtual bool poll_impl() = 0;
inline void add_notify_handler(notify_handler p_handler);

private:
struct storage
{
task* current { nullptr };
};

/**
* @brief Get the thread local storage.
* @brief Actual implementation of the poll function.
*/
static inline storage& local_storage();
virtual bool poll_impl() = 0;
};

template<typename T_future>
@@ -62,6 +76,7 @@ namespace asyncpp
inline bool poll_impl() override;
};

using task_ptr_w = std::weak_ptr<task>;
using task_ptr_s = std::shared_ptr<task>;

/**


+ 12
- 29
include/asyncpp/core/task.inl Visa fil

@@ -3,45 +3,28 @@
namespace asyncpp
{

namespace __impl
{

struct current_lock
{
task* owner;
task*& storage;

current_lock(
task* p_owner,
task*& p_storage)
: owner (p_owner)
, storage (p_storage)
{
if (storage)
throw std::runtime_error("Thread local task instance is already assigned!");
storage = owner;
}

~current_lock()
{ storage = nullptr; }
};

}

/* task */

bool task::poll()
{
__impl::current_lock l(this, local_storage().current);
_notified = false;
return poll_impl();
}

task::storage& task::local_storage()
bool task::notified() const
{ return _notified; }

void task::notify()
{
thread_local storage value;
return value;
_notified = true;

for (auto& h : _notify_handlers)
h(*this);
}

void task::add_notify_handler(notify_handler p_handler)
{ _notify_handlers.emplace_back(p_handler); }

/* task_tpl */

template<typename T_future>


+ 73
- 0
include/asyncpp/executor/current_thread.h Visa fil

@@ -0,0 +1,73 @@
#pragma once

#include <queue>

#include "executor.h"

namespace asyncpp {
namespace executor {

template<typename T_runtime>
struct current_thread
: public executor
{
public:
using runtime_type = T_runtime;
using task_map_type = std::map<task*, task_ptr_s>;
using task_queue_type = std::queue<task_ptr_s>;

private:
runtime_type _runtime; //!> Runtime to call when executor is idling
task_queue_type _pending_tasks; //!< Tasks ready for execution.
task_map_type _sleeping_tasks; //!< Tasks waiting for resource.

public:
/**
* @brief Constructor.
*/
template<typename X_runtime>
inline current_thread(X_runtime&& p_runtime);

/**
* @brief Run the executor.
*
* It will return if all tasks are finished.
*/
void run();

/**
* @brief Spawn the passed future and run the executor.
*
* It will return if all tasks are finished.
*/
template<typename X_future>
void run(X_future&& p_future);

private:
/**
* @brief Run the executor.
*
* It will return if all tasks are finished.
*/
void run_impl();

/**
* @brief Poll the passed task.
*/
void poll_task(task_ptr_s p_task);

/**
* @brief Callback to inform the executor about notified tasks.
*/
void task_notified(task& p_task);

private: /* executor */
/**
* @brief Actual implementation of the spawn method.
*/
void spawn_impl(task_ptr_s p_task) override;
};

} }

#include "current_thread.inl"

+ 136
- 0
include/asyncpp/executor/current_thread.inl Visa fil

@@ -0,0 +1,136 @@
#pragma once

#include "current_thread.h"

namespace asyncpp {
namespace executor {

namespace __impl
{

struct current_task_lock
{
private:
executor::storage& _storage;

public:
current_task_lock(
executor::storage& p_storage,
const task_ptr_s& p_task)
: _storage (p_storage)
{
_storage.current_task = p_task;
}

~current_task_lock()
{ _storage.current_task.reset(); }
};

struct current_executor_lock
{
private:
executor::storage& _storage;

public:
current_executor_lock(
executor::storage& p_storage,
executor& p_executor)
: _storage (p_storage)
{
_storage.current_executor = &p_executor;
}

~current_executor_lock()
{ _storage.current_executor = nullptr; }
};

}

/* current_thread */

template<typename T_runtime>
template<typename X_runtime>
current_thread<T_runtime>
::current_thread(X_runtime&& p_runtime)
: _runtime(std::forward<X_runtime>(p_runtime))
{ }

template<typename T_runtime>
void current_thread<T_runtime>
::run()
{
__impl::current_executor_lock l(executor::local_storage(), *this);

run_impl();
}

template<typename T_runtime>
template<typename X_future>
void current_thread<T_runtime>
::run(X_future&& p_future)
{
__impl::current_executor_lock l(executor::local_storage(), *this);

spawn(std::forward<X_future>(p_future));

run_impl();
}

template<typename T_runtime>
void current_thread<T_runtime>
::run_impl()
{
while (true)
{
while (!_pending_tasks.empty())
{
auto t = _pending_tasks.front();
_pending_tasks.pop();
poll_task(t);
}

if (_sleeping_tasks.empty())
return;

_runtime.idle(nullptr);
}
}

template<typename T_runtime>
void current_thread<T_runtime>
::poll_task(task_ptr_s p_task)
{
__impl::current_task_lock l(executor::local_storage(), p_task);

// TODO execption handling

if (!p_task->poll())
{
if (p_task->notified())
_pending_tasks.emplace(p_task);
else
_sleeping_tasks.emplace(p_task.get(), p_task);
}
}

template<typename T_runtime>
void current_thread<T_runtime>
::task_notified(task& p_task)
{
auto it = _sleeping_tasks.find(&p_task);
if (it != _sleeping_tasks.end())
{
_pending_tasks.emplace(it->second);
_sleeping_tasks.erase(it);
}
}

template<typename T_runtime>
void current_thread<T_runtime>
::spawn_impl(task_ptr_s p_task)
{
p_task->add_notify_handler(std::bind(&current_thread::task_notified, this, std::placeholders::_1));
_pending_tasks.push(p_task);
}

} }

+ 44
- 0
include/asyncpp/executor/executor.h Visa fil

@@ -0,0 +1,44 @@
#pragma once

#include <asyncpp/core/task.h>

namespace asyncpp {
namespace executor {

struct executor
{
public:
struct storage
{
task_ptr_w current_task;
executor * current_executor;
};

public:
/**
* @brief Get reference of the current task.
*/
static inline const task_ptr_w& current_task();

/**
* @brief Spawn a new task.
*/
template<typename X_future>
static inline void spawn(X_future&& p_future);

private:
/**
* @brief Actual implementation of the spawn method.
*/
virtual void spawn_impl(task_ptr_s p_task) = 0;

protected:
/**
* @brief Get the thread local storage.
*/
static inline storage& local_storage();
};

} }

#include "executor.inl"

+ 28
- 0
include/asyncpp/executor/executor.inl Visa fil

@@ -0,0 +1,28 @@
#pragma once

#include "executor.h"

namespace asyncpp {
namespace executor {

/* executor */

const task_ptr_w& executor::current_task()
{ return local_storage().current_task; }

template<typename X_future>
void executor::spawn(X_future&& p_future)
{
auto exec = local_storage().current_executor;
if (!exec)
throw std::runtime_error("Thread local executor instance is not assigned!");
exec->spawn_impl(make_task(std::forward<X_future>(p_future)));
}

executor::storage& executor::local_storage()
{
thread_local storage value;
return value;
}

} }

+ 2
- 2
include/asyncpp/timer.h Visa fil

@@ -1,7 +1,7 @@
#pragma once

#include "timer/delay.h"
#include "timer/misc.h"
#include "timer/timer.h"

#include "timer/delay.inl"
#include "timer/misc.inl"
#include "timer/timer.inl"

+ 5
- 3
include/asyncpp/timer/delay.h Visa fil

@@ -1,7 +1,9 @@
#pragma once

#include "misc.h"
#include <asyncpp/core/misc.h>

#include "timer.h"
#include "delay.pre.h"

namespace asyncpp {
namespace timer {
@@ -12,8 +14,8 @@ namespace timer {
friend struct future_trait<delay, void>;

private:
time_point _timeout;
registration _registration;
time_point _timeout;
__impl::registration _registration;

public:
/**


+ 4
- 4
include/asyncpp/timer/delay.inl Visa fil

@@ -24,21 +24,21 @@ namespace timer {
{ }

inline delay::~delay()
{ timer::unregister_resource(_registration); }
{ __impl::timer_base::unregister_resource(_registration); }

time_point delay::timeout() const
{ return _timeout; }

void delay::reset(const time_point& p_timeout)
{
timer::unregister_resource(_registration);
__impl::timer_base::unregister_resource(_registration);
_timeout = p_timeout;
}

template<typename T_base, typename T_ratio>
void delay::reset(const duration<T_base, T_ratio>& p_duration)
{
timer::unregister_resource(_registration);
__impl::timer_base::unregister_resource(_registration);
_timeout = now() + p_duration;
}

@@ -64,7 +64,7 @@ namespace asyncpp
if (self.ref._timeout <= now)
return result_type::ready();

timer::timer::register_resource(self.ref._registration);
timer::__impl::timer_base::register_resource(self.ref._registration);

return result_type::not_ready();
}


+ 8
- 0
include/asyncpp/timer/delay.pre.h Visa fil

@@ -0,0 +1,8 @@
#pragma once

namespace asyncpp {
namespace timer {

struct delay;

} }

+ 40
- 0
include/asyncpp/timer/impl/registration.h Visa fil

@@ -0,0 +1,40 @@
#pragma once

#include <memory>

#include <asyncpp/core/misc.h>

#include "timer_base.pre.h"
#include "../delay.pre.h"

namespace asyncpp {
namespace timer {
namespace __impl {

struct registration
{
public:
struct inner
{
timer_base& owner;
time_point timeout;

/**
* @brief Constructor.
*/
inline inner(timer_base& p_owner, time_point p_timeout);
};

using inner_ptr_w = std::weak_ptr<inner>;

public:
delay& owner;
inner_ptr_w ptr;

/**
* @brief Constructor.
*/
inline registration(delay& p_owner);
};

} } }

+ 23
- 0
include/asyncpp/timer/impl/registration.inl Visa fil

@@ -0,0 +1,23 @@
#pragma once

#include "registration.h"

namespace asyncpp {
namespace timer {
namespace __impl {

/* registration::inner */

registration::inner::inner(timer_base& p_owner, time_point p_timeout)
: owner (p_owner)
, timeout (p_timeout)
{ }

/* registration */

registration::registration(delay& p_owner)
: owner(p_owner)
, ptr ()
{ }

} } }

+ 9
- 0
include/asyncpp/timer/impl/registration.pre.h Visa fil

@@ -0,0 +1,9 @@
#pragma once

namespace asyncpp {
namespace timer {
namespace __impl {

struct registration;

} } }

+ 86
- 0
include/asyncpp/timer/impl/timer_base.h Visa fil

@@ -0,0 +1,86 @@
#pragma once

#include <set>
#include <memory>

#include <cppcore/synchronization/locked.h>

#include <asyncpp/core/misc.h>

#include "timer_base.pre.h"
#include "registration.h"

namespace asyncpp {
namespace timer {
namespace __impl {

struct timer_base
{
private:
using inner_ptr_s = std::shared_ptr<registration::inner>;

struct inner_less_compare
{ constexpr bool operator()(const inner_ptr_s& lhs, const inner_ptr_s& rhs) const; };

using inner_set = std::set<inner_ptr_s, inner_less_compare>;

protected:
cppcore::locked<inner_set> _registrations;

public:
/**
* @brief Constructor.
*/
inline ~timer_base();

public:
/**
* @brief Get the number of resources assigned to this timer_base.
*/
inline size_t resource_count() const;

/**
* @brief Set the thread local current timer_base.
*/
inline void make_current();

/**
* @brief Set the thread local current timer_base.
*/
inline void clear_current();

public:
/**
* @brief Get the thread local timer_base instance.
*/
static inline timer_base* current();

/**
* @brief Register a new resource within this timer_base.
*/
static inline void register_resource(registration& p_value);

/**
* @brief Register a new resource within this timer_base.
*/
static inline void unregister_resource(registration& p_value);

private:
/**
* @brief Add a new resource to the timer_base.
*/
inline inner_ptr_s make_inner(registration& p_value);

private:
struct storage
{
timer_base* current { nullptr };
};

/**
* @brief Get the thread local storage.
*/
static inline storage& local_storage();
};

} } }

+ 95
- 0
include/asyncpp/timer/impl/timer_base.inl Visa fil

@@ -0,0 +1,95 @@
#pragma once

#include "timer_base.h"

namespace asyncpp {
namespace timer {
namespace __impl {

/* timer_base::inner_less_compare */

constexpr bool timer_base::inner_less_compare::operator()(const inner_ptr_s& lhs, const inner_ptr_s& rhs) const
{
return (lhs->timeout < rhs->timeout)
? true
:
(lhs->timeout == rhs->timeout)
&& (lhs.get() < rhs.get())
? true
: false;
}

/* timer_base */

timer_base::~timer_base()
{
auto& s = local_storage();
if (s.current == this)
s.current = nullptr;
}

size_t timer_base::resource_count() const
{ return _registrations.lock()->size(); }

void timer_base::make_current()
{
auto& s = local_storage();
if (s.current)
throw std::runtime_error("Thread local timer_base instance is already assigned!");
s.current = this;
}

void timer_base::clear_current()
{
auto& s = local_storage();
if (s.current && s.current != this)
throw std::runtime_error("Thread local timer_base instance is not assigned to this instance!");
s.current = nullptr;
}

timer_base* timer_base::current()
{ return local_storage().current; }

void timer_base::register_resource(registration& p_value)
{
auto s = p_value.ptr.lock();

if (s && s->timeout != p_value.owner.timeout())
{
unregister_resource(p_value);
s.reset();
}

if (!s)
{
auto t = current();

if (!t)
throw std::runtime_error("Thread local timer_base instance is not assigned!");

p_value.ptr = t->make_inner(p_value);
}
}

void timer_base::unregister_resource(registration& p_value)
{
auto s = p_value.ptr.lock();
p_value.ptr.reset();
if (s)
s->owner._registrations.lock()->erase(s);
}

inline timer_base::inner_ptr_s timer_base::make_inner(registration& p_value)
{
auto s = std::make_shared<registration::inner>(*this, p_value.owner.timeout());
_registrations.lock()->insert(s);
return s;
}

timer_base::storage& timer_base::local_storage()
{
thread_local storage value;
return value;
}

} } }

+ 9
- 0
include/asyncpp/timer/impl/timer_base.pre.h Visa fil

@@ -0,0 +1,9 @@
#pragma once

namespace asyncpp {
namespace timer {
namespace __impl {

struct timer_base;

} } }

+ 33
- 72
include/asyncpp/timer/timer.h Visa fil

@@ -5,107 +5,68 @@

#include <cppcore/synchronization/locked.h>

#include "misc.h"
#include "impl/timer_base.h"
#include "impl/registration.h"

namespace asyncpp {
namespace timer {

struct delay;
struct timer;

struct registration
namespace __impl
{
public:
struct inner

template<typename T_inner>
struct storage
{
timer& owner;
time_point timeout;
using inner_type = T_inner;

/**
* @brief Constructor.
*/
inline inner(timer& p_owner, time_point p_timeout);
};
inner_type inner;

using inner_ptr_w = std::weak_ptr<inner>;
template<typename... X_args>
inline storage(X_args&&... p_args);
};

public:
delay& owner;
inner_ptr_w ptr;

/**
* @brief Constructor.
*/
inline registration(delay& p_owner);
};
}

template<typename T_inner = void>
struct timer
: public __impl::timer_base
{
private:
using inner_ptr_s = std::shared_ptr<registration::inner>;

struct inner_less_compare
{ constexpr bool operator()(const inner_ptr_s& lhs, const inner_ptr_s& rhs) const; };

using inner_set = std::set<inner_ptr_s, inner_less_compare>;
public:
using inner_type = T_inner;
using storage_type = __impl::storage<inner_type>;

private:
cppcore::locked<inner_set> _registrations;
storage_type _storage;

public:
/**
* @brief Constructor.
*/
inline ~timer();

public:
/**
* @brief Get the number of resources assigned to this timer.
*/
inline size_t resource_count() const;

/**
* @brief Set the thread local current timer.
*/
inline void make_current();

/**
* @brief Set the thread local current timer.
*/
inline void clear_current();
template<typename... X_args>
inline timer(X_args&&... p_args);

public:
/**
* @brief Get the thread local timer instance.
* @brief Handle idle of the runtime.
*
* This method is called as soon as the runtime has nothing to do.
* The passed timeout is the timepoint the method should return (or null if not set).
*/
static inline timer* current();

/**
* @brief Register a new resource within this timer.
*/
static inline void register_resource(registration& p_value);

/**
* @brief Register a new resource within this timer.
*/
static inline void unregister_resource(registration& p_value);
inline void idle(asyncpp::time_point* p_timeout);

private:
/**
* @brief Add a new resource to the timer.
* @brief Call the idle method of the inner runtime.
*/
inline inner_ptr_s make_inner(registration& p_value);

private:
struct storage
{
timer* current { nullptr };
};
template<typename X = inner_type>
inline auto inner_idle(asyncpp::time_point* p_timeout)
-> std::enable_if_t<std::is_same_v<X, void>>;

/**
* @brief Get the thread local storage.
* @brief Call the idle method of the inner runtime.
*/
static inline storage& local_storage();
template<typename X = inner_type>
inline auto inner_idle(asyncpp::time_point* p_timeout)
-> std::enable_if_t<!std::is_same_v<X, void>>;
};

} }

+ 51
- 73
include/asyncpp/timer/timer.inl Visa fil

@@ -3,107 +3,85 @@
#include "timer.h"
#include "delay.inl"

#include "impl/timer_base.inl"
#include "impl/registration.inl"

namespace asyncpp {
namespace timer {

/* registration::inner */

registration::inner::inner(timer& p_owner, time_point p_timeout)
: owner (p_owner)
, timeout (p_timeout)
{ }

/* registration */

registration::registration(delay& p_owner)
: owner(p_owner)
, ptr ()
{ }

/* timer::inner_less_compare */

constexpr bool timer::inner_less_compare::operator()(const inner_ptr_s& lhs, const inner_ptr_s& rhs) const
namespace __impl
{
return (lhs->timeout < rhs->timeout)
? true
:
(lhs->timeout == rhs->timeout)
&& (lhs.get() < rhs.get())
? true
: false;
}

/* timer */
template<typename T_inner>
template<typename... X_args>
storage<T_inner>::storage(X_args&&... p_args)
: inner(std::forward<X_args>(p_args)...)
{ }

timer::~timer()
{
auto& s = local_storage();
if (s.current == this)
s.current = nullptr;
}
template<>
struct storage<void>
{
using inner_type = void;

size_t timer::resource_count() const
{ return _registrations.lock()->size(); }
inline storage() = default;
};

void timer::make_current()
{
auto& s = local_storage();
if (s.current)
throw std::runtime_error("Thread local timer instance is already assigned!");
s.current = this;
}

void timer::clear_current()
{
auto& s = local_storage();
if (s.current && s.current != this)
throw std::runtime_error("Thread local timer instance is not assigned to this instance!");
s.current = nullptr;
}
/* timer */

timer* timer::current()
{ return local_storage().current; }
template<typename T_inner>
template<typename... X_args>
timer<T_inner>::timer(X_args&&... p_args)
: _storage(std::forward<X_args>(p_args)...)
{ }

void timer::register_resource(registration& p_value)
template<typename T_inner>
void timer<T_inner>::idle(asyncpp::time_point* p_timeout)
{
auto s = p_value.ptr.lock();
bool has_timeout = false;
asyncpp::time_point timeout;

if (s && s->timeout != p_value.owner.timeout())
if (p_timeout)
{
unregister_resource(p_value);
s.reset();
timeout = *p_timeout;
has_timeout = true;
}

if (!s)
{
auto t = current();
auto r = _registrations.lock();
if (!r->empty())
{
auto t = (*r->begin())->timeout;

if (!t)
throw std::runtime_error("Thread local timer instance is not assigned!");
if (!has_timeout)
timeout = t;
else if (t < timeout)
timeout = t;

p_value.ptr = t->make_inner(p_value);
has_timeout = true;
}
}
}

void timer::unregister_resource(registration& p_value)
{
auto s = p_value.ptr.lock();
p_value.ptr.reset();
if (s)
s->owner._registrations.lock()->erase(s);
inner_idle(has_timeout
? &timeout
: nullptr);
}

inline timer::inner_ptr_s timer::make_inner(registration& p_value)
template<typename T_inner>
template<typename X>
auto timer<T_inner>::inner_idle(asyncpp::time_point* p_timeout)
-> std::enable_if_t<std::is_same_v<X, void>>
{
auto s = std::make_shared<registration::inner>(*this, p_value.owner.timeout());
_registrations.lock()->insert(s);
return s;
/* no-op */
}

timer::storage& timer::local_storage()
template<typename T_inner>
template<typename X>
auto timer<T_inner>::inner_idle(asyncpp::time_point* p_timeout)
-> std::enable_if_t<!std::is_same_v<X, void>>
{
thread_local storage value;
return value;
_storage.inner.idle(p_timeout);
}

} }

+ 63
- 0
test/asyncpp/executor/current_thread_tests.cpp Visa fil

@@ -0,0 +1,63 @@
#include <gtest/gtest.h>

#include "../../helper/runtime_mock.h"

#include <asyncpp.h>
#include <asyncpp/executor/current_thread.h>

using namespace ::testing;
using namespace ::asyncpp;

struct test
{
bool done { false };
task_ptr_w task;
};

namespace asyncpp
{

template<>
struct future_trait<test, void>
: public future_base<future<test, void>>
{
using value_type = void;
using result_type = future_result<value_type>;

template<typename X_future>
static inline auto poll(X_future& self)
{
self.ref.task = executor::executor::current_task();
return self.ref.done
? result_type::ready()
: result_type::not_ready();
}
};

}

TEST(current_thread_tests, run)
{
Sequence s;
StrictMock<runtime_mock> m;
executor::current_thread<StrictMock<runtime_mock>&> e(m);

test t;
auto f = as_future(t);

EXPECT_CALL(m, idle(nullptr))
.InSequence(s)
.WillOnce(Invoke([&t](auto){
auto s = t.task.lock();
ASSERT_TRUE(s);
s->notify();
}))
.WillOnce(Invoke([&t](auto){
t.done = true;
auto s = t.task.lock();
ASSERT_TRUE(s);
s->notify();
}));;

e.run(f);
}

+ 48
- 6
test/asyncpp/timer/timer_tests.cpp Visa fil

@@ -1,6 +1,7 @@
#include <gtest/gtest.h>

#include "../../helper/now_mock.h"
#include "../../helper/runtime_mock.h"

#include <asyncpp.h>
#include <asyncpp/timer.h>
@@ -13,29 +14,29 @@ TEST(timer_tests, current)
{
timer::timer t;

EXPECT_EQ(nullptr, timer::timer::current());
EXPECT_EQ(nullptr, timer::__impl::timer_base::current());

t.make_current();

EXPECT_EQ(&t, timer::timer::current());
EXPECT_EQ(&t, timer::__impl::timer_base::current());

t.clear_current();

EXPECT_EQ(nullptr, timer::timer::current());
EXPECT_EQ(nullptr, timer::__impl::timer_base::current());

t.make_current();

EXPECT_EQ(&t, timer::timer::current());
EXPECT_EQ(&t, timer::__impl::timer_base::current());
}

EXPECT_EQ(nullptr, timer::timer::current());
EXPECT_EQ(nullptr, timer::__impl::timer_base::current());
}

TEST(timer_tests, resource_registration)
{
StrictMock<now_mock> m;
EXPECT_CALL(m, now)
.WillRepeatedly(Return(timer::time_point(std::chrono::seconds(0))));
.WillRepeatedly(Return(time_point(std::chrono::seconds(0))));

using delay_future_type = decltype(as_future(timer::delay(std::chrono::seconds(10))));

@@ -76,3 +77,44 @@ TEST(timer_tests, resource_registration)

EXPECT_EQ(0, t.resource_count());
}

TEST(timer_tests, idle)
{
using delay_future_type = decltype(as_future(std::declval<timer::delay>()));

time_point x;
InSequence seq;
StrictMock<now_mock> nm;
StrictMock<runtime_mock> rm;
timer::timer<StrictMock<runtime_mock>&> t(rm);
t.make_current();

EXPECT_CALL(rm, idle(nullptr));

t.idle(nullptr);

EXPECT_CALL(rm, idle(Pointee(time_point(std::chrono::seconds(5)))));

x = time_point(std::chrono::seconds(5));
t.idle(&x);

EXPECT_CALL(nm, now)
.WillOnce(Return(time_point(std::chrono::seconds(0))));

auto f = std::make_unique<delay_future_type>(timer::delay(time_point(std::chrono::seconds(10))));
f->poll();

EXPECT_CALL(rm, idle(Pointee(time_point(std::chrono::seconds(10)))));

t.idle(nullptr);

EXPECT_CALL(rm, idle(Pointee(time_point(std::chrono::seconds(5)))));

x = time_point(std::chrono::seconds(5));
t.idle(&x);

EXPECT_CALL(rm, idle(Pointee(time_point(std::chrono::seconds(10)))));

x = time_point(std::chrono::seconds(15));
t.idle(&x);
}

+ 2
- 2
test/helper/now_mock.h Visa fil

@@ -5,7 +5,7 @@

#define __asyncpp_has_impl_timer_now

#include <asyncpp/timer/misc.h>
#include <asyncpp/core/misc.h>

struct now_mock;

@@ -24,7 +24,7 @@ public:
}

public:
MOCK_METHOD0(now, asyncpp::timer::time_point());
MOCK_METHOD0(now, asyncpp::time_point());
};

namespace asyncpp {


+ 12
- 0
test/helper/runtime_mock.h Visa fil

@@ -0,0 +1,12 @@
#pragma once

#include <gtest/gtest.h>
#include <gmock/gmock.h>

#include <asyncpp/core/misc.h>

struct runtime_mock
{
public:
MOCK_METHOD1(idle, void (asyncpp::time_point* p_timeout));
};

Laddar…
Avbryt
Spara