Skip to content

Commit

Permalink
[WIP] server
Browse files Browse the repository at this point in the history
  • Loading branch information
vinniefalco committed Oct 6, 2016
1 parent 92e81bf commit 37b361b
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 0 deletions.
232 changes: 232 additions & 0 deletions extras/beast/server/io_list.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
//
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef BEAST_SERVER_IO_LIST_HPP
#define BEAST_SERVER_IO_LIST_HPP

#include <boost/container/flat_map.hpp>
#include <condition_variable>
#include <functional>
#include <mutex>

namespace beast {

class io_object
{
public:
virtual ~io_object() = default;
virtual void close() = 0;
};

/** Manages a set of objects performing asynchronous I/O.
*/
class io_list final
{
private:
template<class = void>
void destroy();

std::mutex m_;
std::size_t n_ = 0;
bool closed_ = false;
std::condition_variable cv_;
boost::container::flat_map<io_object*,
std::weak_ptr<io_object>> map_;
std::function<void(void)> f_;

public:
io_list() = default;

/** Destroy the list.
Effects:
Closes the io_list if it was not previously
closed. No finisher is invoked in this case.
Blocks until all work is destroyed.
*/
~io_list()
{
destroy();
}

/** Return `true` if the list is closed.
Thread Safety:
Undefined result if called concurrently
with close().
*/
bool
closed() const
{
return closed_;
}

/** Create associated work if not closed.
Requirements:
`std::is_base_of_v<work, T> == true`
Thread Safety:
May be called concurrently.
Effects:
Atomically creates, inserts, and returns new
work T, or returns nullptr if the io_list is
closed,
If the call succeeds and returns a new object,
it is guaranteed that a subsequent call to close
will invoke work::close on the object.
*/
template <class T, class... Args>
std::shared_ptr<T>
emplace(Args&&... args);

/** Cancel active I/O.
Thread Safety:
May not be called concurrently.
Effects:
Associated work is closed.
Finisher if provided, will be called when
all associated work is destroyed. The finisher
may be called from a foreign thread, or within
the call to this function.
Only the first call to close will set the
finisher.
No effect after the first call.
*/
template<class Finisher>
void
close(Finisher&& f);

void
close()
{
close([]{});
}

/** Block until the io_list stops.
Effects:
The caller is blocked until the io_list is
closed and all associated work is destroyed.
Thread safety:
May be called concurrently.
Preconditions:
No call to io_service::run on any io_service
used by work objects associated with this io_list
exists in the caller's call stack.
*/
template<class = void>
void
join();
};

//------------------------------------------------------------------------------

template<class>
void
io_list::work::destroy()
{
if(! ios_)
return;
std::function<void(void)> f;
{
std::lock_guard<
std::mutex> lock(ios_->m_);
ios_->map_.erase(this);
if(--ios_->n_ == 0 &&
ios_->closed_)
{
std::swap(f, ios_->f_);
ios_->cv_.notify_all();
}
}
if(f)
f();
}

template<class>
void
io_list::destroy()
{
close();
join();
}

template <class T, class... Args>
std::shared_ptr<T>
io_list::emplace(Args&&... args)
{
static_assert(std::is_base_of<work, T>::value,
"T must derive from io_list::work");
if(closed_)
return nullptr;
auto sp = std::make_shared<T>(
std::forward<Args>(args)...);
decltype(sp) dead;

std::lock_guard<std::mutex> lock(m_);
if(! closed_)
{
++n_;
sp->work::ios_ = this;
map_.emplace(sp.get(), sp);
}
else
{
std::swap(sp, dead);
}
return sp;
}

template<class Finisher>
void
io_list::close(Finisher&& f)
{
std::unique_lock<std::mutex> lock(m_);
if(closed_)
return;
closed_ = true;
auto map = std::move(map_);
if(! map.empty())
{
f_ = std::forward<Finisher>(f);
lock.unlock();
for(auto const& p : map)
if(auto sp = p.second.lock())
sp->close();
}
else
{
lock.unlock();
f();
}
}

template<class>
void
io_list::join()
{
std::unique_lock<std::mutex> lock(m_);
cv_.wait(lock,
[&]
{
return closed_ && n_ == 0;
});
}


} // beast

#endif
1 change: 1 addition & 0 deletions test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ unit-test core-tests :
core/handler_concepts.cpp
core/placeholders.cpp
core/prepare_buffers.cpp
core/server.cpp
core/static_streambuf.cpp
core/static_string.cpp
core/stream_concepts.cpp
Expand Down
1 change: 1 addition & 0 deletions test/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ add_executable (core-tests
handler_concepts.cpp
placeholders.cpp
prepare_buffers.cpp
server.cpp
static_streambuf.cpp
static_string.cpp
stream_concepts.cpp
Expand Down
57 changes: 57 additions & 0 deletions test/core/server.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include <beast/unit_test/suite.hpp>

#include <boost/asio.hpp>

namespace beast {

template<class Derived>
class basic_listener
{
boost::asio::ip::tcp::socket sock_;
boost::asio::ip::tcp::acceptor acceptor_;

public:
basic_listener(boost::asio::io_service& ios)
: sock_(ios)
, acceptor_(ios)
{
}
};

template<class Derived>
class basic_server
{
boost::asio::io_service& ios_;

public:
basic_server(boost::asio::io_service& ios)
: ios_(ios)
{
}

boost::asio::io_service&
get_io_service()
{
return ios_;
}
};

class server_test : public unit_test::suite
{
public:
void run() override
{
pass();
}
};

BEAST_DEFINE_TESTSUITE(server,core,beast);

} // beast

0 comments on commit 37b361b

Please sign in to comment.