Skip to content
Snippets Groups Projects
Commit 0390ca3c authored by Hoop77's avatar Hoop77
Browse files

added Busyable to Timer.h

parent 47a03f2a
Branches
No related merge requests found
......@@ -46,7 +46,8 @@ set(SOURCE_FILES
src/Time.cpp
src/Networking.cpp
src/Socket.cpp
src/Stream.cpp)
src/Stream.cpp
src/Busyable.cpp)
add_library(NetworkingLib STATIC ${SOURCE_FILES})
set(PUBLIC_HEADER_FILES
......
......@@ -23,8 +23,7 @@ public:
* @attention Returning false does not guarantee that a subsequent
* BusyLock instantiation with this object won't throw!
*/
bool isBusy() const noexcept
{ return busy; }
bool isBusy() const noexcept;
private:
std::mutex busyMutex;
......@@ -34,37 +33,22 @@ private:
class BusyLock
{
public:
BusyLock(Busyable & busyable)
: busyable(busyable)
{
if (!busyable.busyMutex.try_lock())
throw error::Busy{};
BusyLock(Busyable & busyable);
owns = true;
busyable.busy = true;
}
~BusyLock()
{
unlock();
}
~BusyLock();
BusyLock(const BusyLock &) = delete;
BusyLock & operator=(const BusyLock &) = delete;
void unlock()
{
if (owns)
{
busyable.busy = false;
busyable.busyMutex.unlock();
owns = false;
}
}
BusyLock(BusyLock && other) noexcept;
BusyLock & operator=(BusyLock && other) noexcept;
void unlock();
private:
Busyable & busyable;
Busyable * busyable{nullptr};
std::atomic<bool> owns{false};
};
......
......@@ -18,12 +18,32 @@ template<typename Closeable>
class Closer
{
public:
Closer(Closeable & closeable) : closeable(closeable)
Closer(Closeable & closeable)
: closeable(closeable)
{}
~Closer()
{
close(closeable);
if (alive)
close(closeable);
}
Closer(const Closer &) = delete;
Closer & operator=(const Closer &) = delete;
Closer(Closer && other)
: closeable(other.closeable)
{
other.alive = false;
}
Closer & operator=(Closer && other)
{
closeable = other.closeable;
alive = other.alive;
other.alive = false;
return *this;
}
static void close(Closeable & closeable)
......@@ -34,6 +54,7 @@ public:
private:
Closeable & closeable;
bool alive{true};
};
template<typename Closeable>
......
......@@ -182,7 +182,7 @@ private:
time::Duration timeout;
time::TimePoint startTime;
boost::asio::streambuf buffer;
closeable::Closer <Socket> closer;
closeable::Closer<Socket> closer;
};
};
......
......@@ -9,13 +9,16 @@
#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>
#include "Time.h"
#include "Busyable.h"
namespace networking
{
namespace time
{
class Timer : public std::enable_shared_from_this<Timer>
class Timer
: public std::enable_shared_from_this<Timer>
, private Busyable
{
private:
struct PrivateTag
......@@ -31,17 +34,27 @@ public:
static Ptr create(Networking & net);
void startTimeout(const time::Duration & duration, TimeoutHandler handler);
void startTimeout(const time::Duration & duration, const TimeoutHandler & handler);
void startPeriodicTimeout(const time::Duration & interval, TimeoutHandler handler);
void startPeriodicTimeout(const time::Duration & interval, const TimeoutHandler & handler);
void stop();
private:
struct AsyncState
{
AsyncState(Ptr self, const TimeoutHandler & handler, const time::Duration & duration);
BusyLock busyLock;
Ptr self;
TimeoutHandler handler;
time::Duration duration;
};
boost::asio::basic_waitable_timer<time::Clock> timer;
std::atomic<bool> enabled{true};
void nextPeriod(const time::Duration & interval, TimeoutHandler handler);
void nextPeriod(std::shared_ptr<AsyncState> & state);
};
}
......
//
// Created by philipp on 21.01.18.
//
#include "../include/Busyable.h"
namespace networking
{
bool Busyable::isBusy() const noexcept
{
return busy;
}
BusyLock::BusyLock(Busyable & busyable) : busyable(&busyable)
{
if (!busyable.busyMutex.try_lock())
throw error::Busy{};
owns = true;
busyable.busy = true;
}
BusyLock::~BusyLock()
{
if (owns)
unlock();
}
BusyLock::BusyLock(BusyLock && other) noexcept
: busyable(other.busyable)
, owns(other.owns.load())
{
other.busyable = nullptr;
other.owns = false;
}
BusyLock & BusyLock::operator=(BusyLock && other) noexcept
{
busyable = other.busyable;
owns = other.owns.load();
other.busyable = nullptr;
other.owns = false;
}
void BusyLock::unlock()
{
busyable->busy = false;
busyable->busyMutex.unlock();
owns = false;
}
}
\ No newline at end of file
......@@ -19,36 +19,41 @@ Timer::Ptr Timer::create(Networking & net)
return std::make_shared<Timer>(PrivateTag{}, net);
}
void Timer::startTimeout(const time::Duration & duration, TimeoutHandler handler)
void Timer::startTimeout(const time::Duration & duration, const TimeoutHandler & handler)
{
auto self = shared_from_this();
auto state = std::make_shared<AsyncState>(self, handler, duration);
enabled = true;
auto self = shared_from_this();
timer.expires_from_now(duration);
timer.async_wait(
[self, handler](const boost::system::error_code & error)
[state](const boost::system::error_code & error) mutable
{
if (error || !self->enabled)
if (error || !state->self->enabled)
return;
handler();
state->busyLock.unlock();
state->handler();
});
}
void Timer::startPeriodicTimeout(const time::Duration & interval, Timer::TimeoutHandler handler)
void Timer::startPeriodicTimeout(const time::Duration & interval, const TimeoutHandler & handler)
{
auto self = shared_from_this();
auto state = std::make_shared<AsyncState>(self, handler, interval);
enabled = true;
auto self = shared_from_this();
timer.expires_from_now(interval);
timer.async_wait(
[self, interval, handler](const boost::system::error_code & error)
[state = std::move(state)](const boost::system::error_code & error) mutable
{
if (error || !self->enabled)
if (error || !state->self->enabled)
return;
handler();
self->nextPeriod(interval, handler);
state->handler();
state->self->nextPeriod(state);
});
}
......@@ -62,23 +67,30 @@ void Timer::stop()
timer.cancel(ignoredError);
}
void Timer::nextPeriod(const time::Duration & interval, Timer::TimeoutHandler handler)
void Timer::nextPeriod(std::shared_ptr<AsyncState> & state)
{
if (!enabled)
if (!state->self->enabled)
return;
auto self = shared_from_this();
timer.expires_at(timer.expires_at() + interval);
timer.async_wait(
[self, interval, handler](const boost::system::error_code & error)
state->self->timer.expires_at(state->self->timer.expires_at() + state->duration);
state->self->timer.async_wait(
[state](const boost::system::error_code & error) mutable
{
if (error || !self->enabled)
if (error || !state->self->enabled)
return;
handler();
self->nextPeriod(interval, handler);
state->handler();
state->self->nextPeriod(state);
});
}
Timer::AsyncState::AsyncState(Timer::Ptr self, const Timer::TimeoutHandler & handler, const time::Duration & duration)
: busyLock(*self)
, self(self)
, handler(handler)
, duration(duration)
{
}
}
}
\ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment