mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-28 23:15:52 +00:00
Remove obsolete classes:
Legacy workarounds for Visual Studio non thread-safe initialization of function local objects with static storage duration are removed: * Remove LeakChecked * Remove StaticObject * Remove SharedSingleton
This commit is contained in:
committed by
Tom Ritchford
parent
11c472d701
commit
df89999891
@@ -52,9 +52,7 @@
|
|||||||
#include <beast/utility/Debug.h>
|
#include <beast/utility/Debug.h>
|
||||||
#include <beast/utility/Error.h>
|
#include <beast/utility/Error.h>
|
||||||
#include <beast/utility/Journal.h>
|
#include <beast/utility/Journal.h>
|
||||||
#include <beast/utility/LeakChecked.h>
|
|
||||||
#include <beast/utility/PropertyStream.h>
|
#include <beast/utility/PropertyStream.h>
|
||||||
#include <beast/utility/StaticObject.h>
|
|
||||||
|
|
||||||
#include <beast/module/core/system/StandardIncludes.h>
|
#include <beast/module/core/system/StandardIncludes.h>
|
||||||
|
|
||||||
@@ -144,7 +142,6 @@ class FileOutputStream;
|
|||||||
#include <beast/module/core/streams/FileInputSource.h>
|
#include <beast/module/core/streams/FileInputSource.h>
|
||||||
#include <beast/module/core/streams/OutputStream.h>
|
#include <beast/module/core/streams/OutputStream.h>
|
||||||
#include <beast/module/core/files/FileOutputStream.h>
|
#include <beast/module/core/files/FileOutputStream.h>
|
||||||
#include <beast/module/core/memory/SharedSingleton.h>
|
|
||||||
#include <beast/module/core/streams/MemoryOutputStream.h>
|
#include <beast/module/core/streams/MemoryOutputStream.h>
|
||||||
|
|
||||||
#include <beast/module/core/system/SystemStats.h>
|
#include <beast/module/core/system/SystemStats.h>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ namespace beast {
|
|||||||
|
|
||||||
It can also guess how far it's got using a wildly inaccurate algorithm.
|
It can also guess how far it's got using a wildly inaccurate algorithm.
|
||||||
*/
|
*/
|
||||||
class DirectoryIterator : LeakChecked <DirectoryIterator>
|
class DirectoryIterator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
@@ -119,7 +119,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
class NativeIterator : LeakChecked <NativeIterator>
|
class NativeIterator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NativeIterator (const File& directory, const String& wildCard);
|
NativeIterator (const File& directory, const String& wildCard);
|
||||||
|
|||||||
@@ -22,29 +22,16 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <beast/unit_test/suite.h>
|
#include <beast/unit_test/suite.h>
|
||||||
|
#include <beast/utility/static_initializer.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
// We need to make a shared singleton or else there are
|
File const& File::nonexistent()
|
||||||
// issues with the leak detector and order of detruction.
|
|
||||||
//
|
|
||||||
class NonexistentHolder
|
|
||||||
{
|
{
|
||||||
public:
|
static beast::static_initializer<File> instance;
|
||||||
static NonexistentHolder* getInstance()
|
return *instance;
|
||||||
{
|
|
||||||
return SharedSingleton <NonexistentHolder>::getInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
File file;
|
|
||||||
};
|
|
||||||
|
|
||||||
File const& File::nonexistent ()
|
|
||||||
{
|
|
||||||
return NonexistentHolder::getInstance ()->file;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ namespace beast
|
|||||||
*/
|
*/
|
||||||
class FileInputStream
|
class FileInputStream
|
||||||
: public InputStream
|
: public InputStream
|
||||||
, LeakChecked <FileInputStream>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ namespace beast
|
|||||||
*/
|
*/
|
||||||
class FileOutputStream
|
class FileOutputStream
|
||||||
: public OutputStream
|
: public OutputStream
|
||||||
, LeakChecked <FileOutputStream>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#define BEAST_MODULE_CORE_MEMORY_MEMORYBLOCK_H_INCLUDED
|
#define BEAST_MODULE_CORE_MEMORY_MEMORYBLOCK_H_INCLUDED
|
||||||
|
|
||||||
#include <beast/HeapBlock.h>
|
#include <beast/HeapBlock.h>
|
||||||
#include <beast/utility/LeakChecked.h>
|
|
||||||
#include <beast/strings/String.h>
|
#include <beast/strings/String.h>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
@@ -35,7 +34,7 @@ namespace beast {
|
|||||||
A class to hold a resizable block of raw data.
|
A class to hold a resizable block of raw data.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
class MemoryBlock : LeakChecked <MemoryBlock>
|
class MemoryBlock
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|||||||
@@ -1,205 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
|
||||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
|
||||||
|
|
||||||
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 appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#ifndef BEAST_MODULE_CORE_MEMORY_SHAREDSINGLETON_H_INCLUDED
|
|
||||||
#define BEAST_MODULE_CORE_MEMORY_SHAREDSINGLETON_H_INCLUDED
|
|
||||||
|
|
||||||
#include <beast/threads/SpinLock.h>
|
|
||||||
#include <beast/smart_ptr/SharedPtr.h>
|
|
||||||
#include <beast/module/core/time/AtExitHook.h>
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
namespace beast
|
|
||||||
{
|
|
||||||
|
|
||||||
/** Thread-safe singleton which comes into existence on first use. Use this
|
|
||||||
instead of creating objects with static storage duration. These singletons
|
|
||||||
are automatically reference counted, so if you hold a pointer to it in every
|
|
||||||
object that depends on it, the order of destruction of objects is assured
|
|
||||||
to be correct.
|
|
||||||
|
|
||||||
Object Requirements:
|
|
||||||
DefaultConstructible
|
|
||||||
TriviallyDestructible (when lifetime == neverDestroyed)
|
|
||||||
Destructible
|
|
||||||
|
|
||||||
@class SharedSingleton
|
|
||||||
@ingroup beast_core
|
|
||||||
*/
|
|
||||||
/** @{ */
|
|
||||||
class SingletonLifetime
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// It would be nice if we didn't have to qualify the enumeration but
|
|
||||||
// Argument Dependent Lookup is inapplicable here because:
|
|
||||||
//
|
|
||||||
// "Base classes dependent on a template parameter aren't part of lookup."
|
|
||||||
// - ville
|
|
||||||
//
|
|
||||||
|
|
||||||
/** Construction options for SharedSingleton
|
|
||||||
|
|
||||||
@ingroup beast_core
|
|
||||||
*/
|
|
||||||
enum Lifetime
|
|
||||||
{
|
|
||||||
/** Created on first use, destroyed when the last reference is removed.
|
|
||||||
*/
|
|
||||||
createOnDemand,
|
|
||||||
|
|
||||||
/** The singleton is created on first use and persists until program exit.
|
|
||||||
*/
|
|
||||||
persistAfterCreation,
|
|
||||||
|
|
||||||
/** The singleton is created when needed and never destroyed.
|
|
||||||
|
|
||||||
This is useful for applications which do not have a clean exit.
|
|
||||||
*/
|
|
||||||
neverDestroyed
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Wraps object to produce a reference counted singleton. */
|
|
||||||
template <class Object>
|
|
||||||
class SharedSingleton
|
|
||||||
: public Object
|
|
||||||
, private SharedObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef SharedPtr <SharedSingleton <Object> > Ptr;
|
|
||||||
|
|
||||||
static Ptr get (SingletonLifetime::Lifetime lifetime
|
|
||||||
= SingletonLifetime::persistAfterCreation)
|
|
||||||
{
|
|
||||||
StaticData& staticData (getStaticData ());
|
|
||||||
SharedSingleton* instance = staticData.instance;
|
|
||||||
if (instance == nullptr)
|
|
||||||
{
|
|
||||||
std::lock_guard <LockType> lock (staticData.mutex);
|
|
||||||
instance = staticData.instance;
|
|
||||||
if (instance == nullptr)
|
|
||||||
{
|
|
||||||
bassert (lifetime == SingletonLifetime::createOnDemand || ! staticData.destructorCalled);
|
|
||||||
staticData.instance = &staticData.object;
|
|
||||||
new (staticData.instance) SharedSingleton (lifetime);
|
|
||||||
std::atomic_thread_fence (std::memory_order_seq_cst);
|
|
||||||
instance = staticData.instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEPRECATED LEGACY FUNCTION NAME
|
|
||||||
static Ptr getInstance (SingletonLifetime::Lifetime lifetime
|
|
||||||
= SingletonLifetime::persistAfterCreation)
|
|
||||||
{
|
|
||||||
return get (lifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
explicit SharedSingleton (SingletonLifetime::Lifetime lifetime)
|
|
||||||
: m_lifetime (lifetime)
|
|
||||||
, m_exitHook (this)
|
|
||||||
{
|
|
||||||
if (m_lifetime == SingletonLifetime::persistAfterCreation ||
|
|
||||||
m_lifetime == SingletonLifetime::neverDestroyed)
|
|
||||||
this->incReferenceCount ();
|
|
||||||
}
|
|
||||||
|
|
||||||
~SharedSingleton ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void onExit ()
|
|
||||||
{
|
|
||||||
if (m_lifetime == SingletonLifetime::persistAfterCreation)
|
|
||||||
this->decReferenceCount ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy () const
|
|
||||||
{
|
|
||||||
bool callDestructor;
|
|
||||||
|
|
||||||
// Handle the condition where one thread is releasing the last
|
|
||||||
// reference just as another thread is trying to acquire it.
|
|
||||||
//
|
|
||||||
{
|
|
||||||
StaticData& staticData (getStaticData ());
|
|
||||||
std::lock_guard <LockType> lock (staticData.mutex);
|
|
||||||
|
|
||||||
if (this->getReferenceCount() != 0)
|
|
||||||
{
|
|
||||||
callDestructor = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
callDestructor = true;
|
|
||||||
staticData.instance = nullptr;
|
|
||||||
staticData.destructorCalled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callDestructor)
|
|
||||||
{
|
|
||||||
bassert (m_lifetime != SingletonLifetime::neverDestroyed);
|
|
||||||
|
|
||||||
this->~SharedSingleton();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef SpinLock LockType;
|
|
||||||
|
|
||||||
// This structure gets zero-filled at static initialization time.
|
|
||||||
// No constructors are called.
|
|
||||||
//
|
|
||||||
class StaticData
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LockType mutex;
|
|
||||||
SharedSingleton* instance;
|
|
||||||
SharedSingleton object;
|
|
||||||
bool destructorCalled;
|
|
||||||
|
|
||||||
StaticData() = delete;
|
|
||||||
StaticData(StaticData const&) = delete;
|
|
||||||
StaticData& operator= (StaticData const&) = delete;
|
|
||||||
~StaticData() = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
static StaticData& getStaticData ()
|
|
||||||
{
|
|
||||||
static std::uint8_t storage [sizeof (StaticData)];
|
|
||||||
return *(reinterpret_cast <StaticData*> (&storage [0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
friend class SharedPtr <SharedSingleton>;
|
|
||||||
friend class AtExitMemberHook <SharedSingleton>;
|
|
||||||
|
|
||||||
SingletonLifetime::Lifetime m_lifetime;
|
|
||||||
AtExitMemberHook <SharedSingleton> m_exitHook;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
} // beast
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -399,7 +399,6 @@ bool File::setAsCurrentWorkingDirectory() const
|
|||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
class DirectoryIterator::NativeIterator::Pimpl
|
class DirectoryIterator::NativeIterator::Pimpl
|
||||||
: LeakChecked <DirectoryIterator::NativeIterator::Pimpl>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Pimpl (const File& directory, const String& wildCard)
|
Pimpl (const File& directory, const String& wildCard)
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ namespace beast
|
|||||||
*/
|
*/
|
||||||
class FileInputSource
|
class FileInputSource
|
||||||
: public InputSource
|
: public InputSource
|
||||||
, LeakChecked <FileInputSource>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace beast
|
|||||||
|
|
||||||
@see FileInputSource
|
@see FileInputSource
|
||||||
*/
|
*/
|
||||||
class InputSource : LeakChecked <InputSource>
|
class InputSource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ class MemoryBlock;
|
|||||||
@see OutputStream, FileInputStream
|
@see OutputStream, FileInputStream
|
||||||
*/
|
*/
|
||||||
class InputStream
|
class InputStream
|
||||||
: LeakChecked <InputStream>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/** Destructor. */
|
/** Destructor. */
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ namespace beast
|
|||||||
*/
|
*/
|
||||||
class MemoryOutputStream
|
class MemoryOutputStream
|
||||||
: public OutputStream
|
: public OutputStream
|
||||||
, LeakChecked <MemoryOutputStream>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|||||||
@@ -17,12 +17,13 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <beast/utility/static_initializer.h>
|
||||||
|
|
||||||
namespace beast
|
namespace beast
|
||||||
{
|
{
|
||||||
|
|
||||||
class DeadlineTimer::Manager
|
class DeadlineTimer::Manager
|
||||||
: public LeakChecked <Manager>
|
: protected Thread
|
||||||
, protected Thread
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
typedef CriticalSection LockType;
|
typedef CriticalSection LockType;
|
||||||
@@ -42,6 +43,14 @@ public:
|
|||||||
bassert (m_items.empty ());
|
bassert (m_items.empty ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Manager&
|
||||||
|
instance()
|
||||||
|
{
|
||||||
|
static beast::static_initializer<Manager> m;
|
||||||
|
return *m;
|
||||||
|
}
|
||||||
|
|
||||||
// Okay to call on an active timer.
|
// Okay to call on an active timer.
|
||||||
// However, an extra notification may still happen due to concurrency.
|
// However, an extra notification may still happen due to concurrency.
|
||||||
//
|
//
|
||||||
@@ -210,19 +219,18 @@ private:
|
|||||||
|
|
||||||
DeadlineTimer::DeadlineTimer (Listener* listener)
|
DeadlineTimer::DeadlineTimer (Listener* listener)
|
||||||
: m_listener (listener)
|
: m_listener (listener)
|
||||||
, m_manager (SharedSingleton <Manager>::getInstance ())
|
|
||||||
, m_isActive (false)
|
, m_isActive (false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
DeadlineTimer::~DeadlineTimer ()
|
DeadlineTimer::~DeadlineTimer ()
|
||||||
{
|
{
|
||||||
m_manager->deactivate (*this);
|
Manager::instance().deactivate (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeadlineTimer::cancel ()
|
void DeadlineTimer::cancel ()
|
||||||
{
|
{
|
||||||
m_manager->deactivate (*this);
|
Manager::instance().deactivate (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeadlineTimer::setExpiration (double secondsUntilDeadline)
|
void DeadlineTimer::setExpiration (double secondsUntilDeadline)
|
||||||
@@ -232,7 +240,7 @@ void DeadlineTimer::setExpiration (double secondsUntilDeadline)
|
|||||||
RelativeTime const when (
|
RelativeTime const when (
|
||||||
RelativeTime::fromStartup() + secondsUntilDeadline);
|
RelativeTime::fromStartup() + secondsUntilDeadline);
|
||||||
|
|
||||||
m_manager->activate (*this, 0, when);
|
Manager::instance().activate (*this, 0, when);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeadlineTimer::setRecurringExpiration (double secondsUntilDeadline)
|
void DeadlineTimer::setRecurringExpiration (double secondsUntilDeadline)
|
||||||
@@ -242,7 +250,7 @@ void DeadlineTimer::setRecurringExpiration (double secondsUntilDeadline)
|
|||||||
RelativeTime const when (
|
RelativeTime const when (
|
||||||
RelativeTime::fromStartup() + secondsUntilDeadline);
|
RelativeTime::fromStartup() + secondsUntilDeadline);
|
||||||
|
|
||||||
m_manager->activate (*this, secondsUntilDeadline, when);
|
Manager::instance().activate (*this, secondsUntilDeadline, when);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
|
|||||||
@@ -20,8 +20,6 @@
|
|||||||
#ifndef BEAST_MODULE_CORE_THREAD_DEADLINETIMER_H_INCLUDED
|
#ifndef BEAST_MODULE_CORE_THREAD_DEADLINETIMER_H_INCLUDED
|
||||||
#define BEAST_MODULE_CORE_THREAD_DEADLINETIMER_H_INCLUDED
|
#define BEAST_MODULE_CORE_THREAD_DEADLINETIMER_H_INCLUDED
|
||||||
|
|
||||||
#include <beast/module/core/memory/SharedSingleton.h>
|
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
/** Provides periodic or one time notifications at a specified time interval.
|
/** Provides periodic or one time notifications at a specified time interval.
|
||||||
@@ -108,7 +106,6 @@ private:
|
|||||||
class Manager;
|
class Manager;
|
||||||
|
|
||||||
Listener* const m_listener;
|
Listener* const m_listener;
|
||||||
SharedPtr <SharedSingleton <Manager> > m_manager;
|
|
||||||
bool m_isActive;
|
bool m_isActive;
|
||||||
RelativeTime m_notificationTime;
|
RelativeTime m_notificationTime;
|
||||||
double m_secondsRecurring; // non zero if recurring
|
double m_secondsRecurring; // non zero if recurring
|
||||||
|
|||||||
@@ -17,8 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
namespace beast
|
#include <beast/utility/static_initializer.h>
|
||||||
{
|
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
// Manages the list of hooks, and calls
|
// Manages the list of hooks, and calls
|
||||||
// whoever is in the list at exit time.
|
// whoever is in the list at exit time.
|
||||||
@@ -33,7 +34,9 @@ public:
|
|||||||
|
|
||||||
static inline Manager& get ()
|
static inline Manager& get ()
|
||||||
{
|
{
|
||||||
return StaticObject <Manager>::get();
|
static beast::static_initializer<
|
||||||
|
Manager> instance;
|
||||||
|
return *instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert (Item& item)
|
void insert (Item& item)
|
||||||
@@ -73,10 +76,6 @@ private:
|
|||||||
AtExitHook* const hook (item.hook ());
|
AtExitHook* const hook (item.hook ());
|
||||||
hook->onExit ();
|
hook->onExit ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now do the leak checking
|
|
||||||
//
|
|
||||||
LeakCheckedBase::checkForLeaks ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct StaticDestructor
|
struct StaticDestructor
|
||||||
|
|||||||
@@ -61,7 +61,6 @@
|
|||||||
#define BEAST_MODULE_SQDB_API_SESSION_H_INCLUDED
|
#define BEAST_MODULE_SQDB_API_SESSION_H_INCLUDED
|
||||||
|
|
||||||
#include <beast/smart_ptr/SharedPtr.h>
|
#include <beast/smart_ptr/SharedPtr.h>
|
||||||
#include <beast/module/core/memory/SharedSingleton.h>
|
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace sqdb {
|
namespace sqdb {
|
||||||
@@ -137,8 +136,6 @@ private:
|
|||||||
Error hard_exec(std::string const& query);
|
Error hard_exec(std::string const& query);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Sqlite3;
|
|
||||||
SharedPtr <SharedSingleton <Sqlite3> > m_instance;
|
|
||||||
bool m_bInTransaction;
|
bool m_bInTransaction;
|
||||||
sqlite3* m_connection;
|
sqlite3* m_connection;
|
||||||
String m_fileName;
|
String m_fileName;
|
||||||
|
|||||||
@@ -62,26 +62,27 @@
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace sqdb {
|
namespace sqdb {
|
||||||
|
|
||||||
class session::Sqlite3
|
class Sqlite3Instance
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Sqlite3()
|
Sqlite3Instance()
|
||||||
{
|
{
|
||||||
assert (sqlite3_threadsafe() != 0);
|
assert (sqlite3_threadsafe() != 0);
|
||||||
sqlite3_initialize();
|
sqlite3_initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
~Sqlite3()
|
~Sqlite3Instance()
|
||||||
{
|
{
|
||||||
sqlite3_shutdown();
|
sqlite3_shutdown();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Sqlite3Instance sqlite3_instance;
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
session::session()
|
session::session()
|
||||||
: prepare (this)
|
: prepare (this)
|
||||||
, m_instance (SharedSingleton <Sqlite3>::getInstance ())
|
|
||||||
, m_bInTransaction (false)
|
, m_bInTransaction (false)
|
||||||
, m_connection (nullptr)
|
, m_connection (nullptr)
|
||||||
{
|
{
|
||||||
@@ -89,7 +90,6 @@ session::session()
|
|||||||
|
|
||||||
session::session(const session& deferredClone)
|
session::session(const session& deferredClone)
|
||||||
: prepare (this)
|
: prepare (this)
|
||||||
, m_instance (SharedSingleton <Sqlite3>::getInstance ())
|
|
||||||
, m_bInTransaction (false)
|
, m_bInTransaction (false)
|
||||||
, m_connection (nullptr)
|
, m_connection (nullptr)
|
||||||
, m_fileName (deferredClone.m_fileName)
|
, m_fileName (deferredClone.m_fileName)
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#ifndef BEAST_THREADS_THREAD_H_INCLUDED
|
#ifndef BEAST_THREADS_THREAD_H_INCLUDED
|
||||||
#define BEAST_THREADS_THREAD_H_INCLUDED
|
#define BEAST_THREADS_THREAD_H_INCLUDED
|
||||||
|
|
||||||
#include <beast/utility/LeakChecked.h>
|
|
||||||
#include <beast/threads/RecursiveMutex.h>
|
#include <beast/threads/RecursiveMutex.h>
|
||||||
#include <beast/threads/WaitableEvent.h>
|
#include <beast/threads/WaitableEvent.h>
|
||||||
|
|
||||||
@@ -43,7 +42,7 @@ namespace beast {
|
|||||||
@see CriticalSection, WaitableEvent, Process, ThreadWithProgressWindow,
|
@see CriticalSection, WaitableEvent, Process, ThreadWithProgressWindow,
|
||||||
MessageManagerLock
|
MessageManagerLock
|
||||||
*/
|
*/
|
||||||
class Thread : LeakChecked <Thread>
|
class Thread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ namespace beast {
|
|||||||
method.
|
method.
|
||||||
*/
|
*/
|
||||||
class WaitableEvent
|
class WaitableEvent
|
||||||
//, LeakChecked <WaitableEvent> // VFALCO TODO Move LeakChecked to beast/
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|||||||
@@ -1,181 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
|
||||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
|
||||||
|
|
||||||
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 appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#ifndef BEAST_UTILITY_LEAKCHECKED_H_INCLUDED
|
|
||||||
#define BEAST_UTILITY_LEAKCHECKED_H_INCLUDED
|
|
||||||
|
|
||||||
#include <beast/Config.h>
|
|
||||||
#include <beast/intrusive/LockFreeStack.h>
|
|
||||||
#include <beast/utility/StaticObject.h>
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
class LeakCheckedBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void checkForLeaks ();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
class LeakCounterBase : public LockFreeStack <LeakCounterBase>::Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LeakCounterBase ();
|
|
||||||
|
|
||||||
virtual ~LeakCounterBase ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int increment ()
|
|
||||||
{
|
|
||||||
return ++m_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int decrement ()
|
|
||||||
{
|
|
||||||
return --m_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual char const* getClassName () const = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void checkForLeaks ();
|
|
||||||
virtual void checkPureVirtual () const = 0;
|
|
||||||
|
|
||||||
class Singleton;
|
|
||||||
friend class LeakCheckedBase;
|
|
||||||
|
|
||||||
std::atomic <int> m_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void reportDanglingPointer (char const* objectName);
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Detects leaks at program exit.
|
|
||||||
|
|
||||||
To use this, derive your class from this template using CRTP (curiously
|
|
||||||
recurring template pattern).
|
|
||||||
*/
|
|
||||||
template <class Object>
|
|
||||||
class LeakChecked : private LeakCheckedBase
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
LeakChecked () noexcept
|
|
||||||
{
|
|
||||||
getCounter ().increment ();
|
|
||||||
}
|
|
||||||
|
|
||||||
LeakChecked (LeakChecked const&) noexcept
|
|
||||||
{
|
|
||||||
getCounter ().increment ();
|
|
||||||
}
|
|
||||||
|
|
||||||
~LeakChecked ()
|
|
||||||
{
|
|
||||||
if (getCounter ().decrement () < 0)
|
|
||||||
{
|
|
||||||
reportDanglingPointer (getLeakCheckedName ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Singleton that maintains the count of this object
|
|
||||||
//
|
|
||||||
class LeakCounter : public LeakCounterBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LeakCounter () noexcept
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
char const* getClassName () const
|
|
||||||
{
|
|
||||||
return getLeakCheckedName ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkPureVirtual () const { }
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
/* Due to a bug in Visual Studio 10 and earlier, the string returned by
|
|
||||||
typeid().name() will appear to leak on exit. Therefore, we should
|
|
||||||
only call this function when there's an actual leak, or else there
|
|
||||||
will be spurious leak notices at exit.
|
|
||||||
*/
|
|
||||||
static const char* getLeakCheckedName ()
|
|
||||||
{
|
|
||||||
return typeid (Object).name ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve the singleton for this object
|
|
||||||
//
|
|
||||||
static LeakCounter& getCounter () noexcept
|
|
||||||
{
|
|
||||||
return StaticObject <LeakCounter>::get();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace disabled
|
|
||||||
{
|
|
||||||
|
|
||||||
class LeakCheckedBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void checkForLeaks ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Object>
|
|
||||||
class LeakChecked : public LeakCheckedBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Lift the appropriate implementation into our namespace
|
|
||||||
//
|
|
||||||
#if BEAST_CHECK_MEMORY_LEAKS
|
|
||||||
using detail::LeakChecked;
|
|
||||||
using detail::LeakCheckedBase;
|
|
||||||
#else
|
|
||||||
using detail::disabled::LeakChecked;
|
|
||||||
using detail::disabled::LeakCheckedBase;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
|
||||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
|
||||||
|
|
||||||
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 appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#ifndef BEAST_UTILITY_STATICOBJECT_H_INCLUDED
|
|
||||||
#define BEAST_UTILITY_STATICOBJECT_H_INCLUDED
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <chrono>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
|
|
||||||
// Spec: N2914=09-0104
|
|
||||||
//
|
|
||||||
// [3.6.2] Initialization of non-local objects
|
|
||||||
//
|
|
||||||
// Objects with static storage duration (3.7.1) or thread storage
|
|
||||||
// duration (3.7.2) shall be zero-initialized (8.5) before any
|
|
||||||
// other initialization takes place.
|
|
||||||
//
|
|
||||||
|
|
||||||
/** Wrapper to produce an object with static storage duration.
|
|
||||||
|
|
||||||
The object is constructed in a thread-safe fashion when the get function
|
|
||||||
is first called. Note that the destructor for Object is never called. To
|
|
||||||
invoke the destructor, use the AtExitHook facility (with caution).
|
|
||||||
|
|
||||||
The Tag parameter allows multiple instances of the same Object type, by
|
|
||||||
using different tags.
|
|
||||||
|
|
||||||
Object must meet these requirements:
|
|
||||||
DefaultConstructible
|
|
||||||
|
|
||||||
@see AtExitHook
|
|
||||||
*/
|
|
||||||
template <class Object, typename Tag = void>
|
|
||||||
class StaticObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static Object& get ()
|
|
||||||
{
|
|
||||||
StaticData& staticData (StaticData::get());
|
|
||||||
|
|
||||||
if (staticData.state.load () != initialized)
|
|
||||||
{
|
|
||||||
if (staticData.state.exchange (initializing) == uninitialized)
|
|
||||||
{
|
|
||||||
// Initialize the object.
|
|
||||||
new (&staticData.object) Object;
|
|
||||||
staticData.state = initialized;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::size_t n = 0;
|
|
||||||
|
|
||||||
while (staticData.state.load () != initialized)
|
|
||||||
{
|
|
||||||
++n;
|
|
||||||
|
|
||||||
std::this_thread::yield ();
|
|
||||||
|
|
||||||
if (n > 10)
|
|
||||||
{
|
|
||||||
std::chrono::milliseconds duration (1);
|
|
||||||
|
|
||||||
if (n > 100)
|
|
||||||
duration *= 10;
|
|
||||||
|
|
||||||
std::this_thread::sleep_for (duration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert (staticData.state.load () == initialized);
|
|
||||||
return staticData.object;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static int const uninitialized = 0;
|
|
||||||
static int const initializing = 1;
|
|
||||||
static int const initialized = 2;
|
|
||||||
|
|
||||||
// This structure gets zero-filled at static initialization time.
|
|
||||||
// No constructors are called.
|
|
||||||
//
|
|
||||||
class StaticData
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::atomic <int> state;
|
|
||||||
Object object;
|
|
||||||
|
|
||||||
static StaticData& get ()
|
|
||||||
{
|
|
||||||
static std::uint8_t storage [sizeof (StaticData)];
|
|
||||||
return *(reinterpret_cast <StaticData*> (&storage [0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
StaticData() = delete;
|
|
||||||
StaticData(StaticData const&) = delete;
|
|
||||||
StaticData& operator= (StaticData const&) = delete;
|
|
||||||
~StaticData() = delete;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
#include <beast/utility/impl/Debug.cpp>
|
#include <beast/utility/impl/Debug.cpp>
|
||||||
#include <beast/utility/impl/Journal.cpp>
|
#include <beast/utility/impl/Journal.cpp>
|
||||||
#include <beast/utility/impl/LeakChecked.cpp>
|
|
||||||
#include <beast/utility/impl/PropertyStream.cpp>
|
#include <beast/utility/impl/PropertyStream.cpp>
|
||||||
|
|
||||||
#include <beast/utility/tests/bassert.test.cpp>
|
#include <beast/utility/tests/bassert.test.cpp>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <beast/utility/Journal.h>
|
#include <beast/utility/Journal.h>
|
||||||
#include <beast/module/core/memory/SharedSingleton.h>
|
#include <beast/utility/static_initializer.h>
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
@@ -60,8 +60,8 @@ public:
|
|||||||
|
|
||||||
Journal::Sink& Journal::getNullSink ()
|
Journal::Sink& Journal::getNullSink ()
|
||||||
{
|
{
|
||||||
return *SharedSingleton <NullJournalSink>::get (
|
static beast::static_initializer<NullJournalSink> sink;
|
||||||
SingletonLifetime::neverDestroyed);
|
return *sink;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -1,102 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
|
||||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
|
||||||
|
|
||||||
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 appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
#include <beast/utility/LeakChecked.h>
|
|
||||||
|
|
||||||
namespace beast {
|
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
|
|
||||||
class LeakCheckedBase::LeakCounterBase::Singleton
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void push_back (LeakCounterBase* counter)
|
|
||||||
{
|
|
||||||
m_list.push_front (counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkForLeaks ()
|
|
||||||
{
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
LeakCounterBase* const counter = m_list.pop_front ();
|
|
||||||
|
|
||||||
if (!counter)
|
|
||||||
break;
|
|
||||||
|
|
||||||
counter->checkForLeaks ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Singleton& getInstance ()
|
|
||||||
{
|
|
||||||
static Singleton instance;
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class LeakCheckedBase;
|
|
||||||
|
|
||||||
LockFreeStack <LeakCounterBase> m_list;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
LeakCheckedBase::LeakCounterBase::LeakCounterBase ()
|
|
||||||
: m_count (0)
|
|
||||||
{
|
|
||||||
Singleton::getInstance ().push_back (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LeakCheckedBase::LeakCounterBase::checkForLeaks ()
|
|
||||||
{
|
|
||||||
// If there's a runtime error from this line, it means there's
|
|
||||||
// an order of destruction problem between different translation units!
|
|
||||||
//
|
|
||||||
this->checkPureVirtual ();
|
|
||||||
|
|
||||||
int const count = m_count.load ();
|
|
||||||
|
|
||||||
if (count > 0)
|
|
||||||
{
|
|
||||||
outputDebugString ("Leaked objects: " + std::to_string (count) +
|
|
||||||
" instances of " + getClassName ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void LeakCheckedBase::reportDanglingPointer (char const* objectName)
|
|
||||||
{
|
|
||||||
outputDebugString (std::string ("Dangling pointer deletion: ") + objectName);
|
|
||||||
bassertfalse;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void LeakCheckedBase::checkForLeaks ()
|
|
||||||
{
|
|
||||||
LeakCounterBase::Singleton::getInstance ().checkForLeaks ();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user