0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-09-29 20:28:52 +02:00

ircd: Add scope 'life_guard' util for references in reentrant contexts.

This commit is contained in:
Jason Volk 2016-09-13 12:39:13 -07:00
parent 8f9a4bd6db
commit d8d2fe1564
6 changed files with 112 additions and 4 deletions

View file

@ -33,7 +33,9 @@ namespace ircd {
struct sock;
struct client;
std::shared_ptr<const client> shared_from(const client &);
std::shared_ptr<client> shared_from(client &);
std::weak_ptr<const client> weak_from(const client &);
std::weak_ptr<client> weak_from(client &);
// Client socket addressing

93
include/ircd/life_guard.h Normal file
View file

@ -0,0 +1,93 @@
/*
* Copyright (C) 2016 Charybdis Development Team
* Copyright (C) 2016 Jason Volk <jason@zemos.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#define HAVE_IRCD_LIFE_GUARD_H
#ifdef __cplusplus
namespace ircd {
// Tests if type inherits from std::enable_shared_from_this<>
template<class T>
constexpr typename std::enable_if<is_complete<T>::value, bool>::type
is_shared_from_this()
{
return std::is_base_of<std::enable_shared_from_this<T>, T>();
}
// Unconditional failure for fwd-declared incomplete types, which
// obviously don't inherit from std::enable_shared_from_this<>
template<class T>
constexpr typename std::enable_if<!is_complete<T>::value, bool>::type
is_shared_from_this()
{
return false;
}
/* Use the life_guard to keep an object alive within a function running in a context.
*
* Example:
*
void foo(client &c)
{
const life_guard<client> lg(c);
c.call(); // This call was always safe with or w/o life_guard.
ctx::wait(); // The context has now yielded and another context might destroy client &c
c.call(); // The context continues and this would have made a call on a dead c.
}
*/
template<class T>
struct life_guard
:std::shared_ptr<T>
{
// This constructor is used when the templated type inherits from std::enable_shared_from_this<>
template<class SFINAE = T>
life_guard(T &t,
typename std::enable_if<is_shared_from_this<SFINAE>(), void>::type * = 0)
:std::shared_ptr<T>(t.shared_from_this())
{
}
// This constructor uses our convention for forward declaring objects that internally
// inherit from std::enable_shared_from_this<>. Our convention is to provide:
//
// std::shared_ptr<T> shared_from(T &c);
//
template<class SFINAE = T>
life_guard(T &t,
typename std::enable_if<!is_shared_from_this<SFINAE>(), void>::type * = 0)
:std::shared_ptr<T>(shared_from(t))
{
}
// This constructor is used with a weak_ptr of the type. This throws an exception
// to abort the scope when the object already died before being able to guard at all.
life_guard(const std::weak_ptr<T> &wp)
:std::shared_ptr<T>(wp.lock())
{
if(wp.expired())
throw std::bad_weak_ptr();
}
};
} // namespace ircd
#endif // __cplusplus

View file

@ -70,6 +70,7 @@ namespace ircd
#include "util.h"
#include "util_timer.h"
#include "life_guard.h"
#include "defaults.h"
#include "exception.h"
#include "getopt.h"

View file

@ -325,8 +325,20 @@ ircd::weak_from(client &client)
return shared_from(client);
}
std::weak_ptr<const client>
ircd::weak_from(const client &client)
{
return shared_from(client);
}
std::shared_ptr<client>
ircd::shared_from(client &client)
{
return client.shared_from_this();
}
std::shared_ptr<const client>
ircd::shared_from(const client &client)
{
return client.shared_from_this();
}

View file

@ -45,10 +45,8 @@ ircd::vm::execute(client &client,
{
context([wp(weak_from(client)), &client, &reel]
{
auto cp(wp.lock()); // Hold the client for the lifetime of this context
if(!cp) // client already gone though
return;
// Hold the client for the lifetime of this context
const lifeguard<struct client> lg(wp);
while(!reel.empty()) try
{

View file

@ -60,6 +60,8 @@ m_host::operator()(client &client,
line line)
try
{
const lifeguard<struct client> lg(client);
const auto &host(line[0]);
const auto &port(has(line, 1)? line[1] : std::string{});
const ip::tcp::resolver::query query(host, port);