mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 11:05:54 +00:00
268 lines
8.9 KiB
C++
268 lines
8.9 KiB
C++
//------------------------------------------------------------------------------
|
|
/*
|
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
|
|
|
Portions of this file are from JUCE.
|
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
|
Please visit http://www.juce.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_CRITICALSECTION_H_INCLUDED
|
|
#define BEAST_CRITICALSECTION_H_INCLUDED
|
|
|
|
#include <beast/module/core/threads/ScopedLock.h>
|
|
#include <cstdint>
|
|
|
|
namespace beast {
|
|
|
|
//==============================================================================
|
|
/**
|
|
A re-entrant mutex.
|
|
|
|
A CriticalSection acts as a re-entrant mutex object. The best way to lock and unlock
|
|
one of these is by using RAII in the form of a local ScopedLock object - have a look
|
|
through the codebase for many examples of how to do this.
|
|
|
|
@see ScopedLock, ScopedTryLock, ScopedUnlock, SpinLock, Thread
|
|
*/
|
|
class CriticalSection
|
|
{
|
|
public:
|
|
//==============================================================================
|
|
/** Creates a CriticalSection object. */
|
|
CriticalSection() noexcept;
|
|
|
|
CriticalSection (CriticalSection const&) = delete;
|
|
CriticalSection& operator= (CriticalSection const&) = delete;
|
|
|
|
/** Destructor.
|
|
If the critical section is deleted whilst locked, any subsequent behaviour
|
|
is unpredictable.
|
|
*/
|
|
~CriticalSection() noexcept;
|
|
|
|
//==============================================================================
|
|
/** Acquires the lock.
|
|
|
|
If the lock is already held by the caller thread, the method returns immediately.
|
|
If the lock is currently held by another thread, this will wait until it becomes free.
|
|
|
|
It's strongly recommended that you never call this method directly - instead use the
|
|
ScopedLock class to manage the locking using an RAII pattern instead.
|
|
|
|
@see exit, tryEnter, ScopedLock
|
|
*/
|
|
void enter() const noexcept;
|
|
|
|
/** Attempts to lock this critical section without blocking.
|
|
|
|
This method behaves identically to CriticalSection::enter, except that the caller thread
|
|
does not wait if the lock is currently held by another thread but returns false immediately.
|
|
|
|
@returns false if the lock is currently held by another thread, true otherwise.
|
|
@see enter
|
|
*/
|
|
bool tryEnter() const noexcept;
|
|
|
|
/** Releases the lock.
|
|
|
|
If the caller thread hasn't got the lock, this can have unpredictable results.
|
|
|
|
If the enter() method has been called multiple times by the thread, each
|
|
call must be matched by a call to exit() before other threads will be allowed
|
|
to take over the lock.
|
|
|
|
@see enter, ScopedLock
|
|
*/
|
|
void exit() const noexcept;
|
|
|
|
//==============================================================================
|
|
/** Provides the type of scoped lock to use with a CriticalSection. */
|
|
typedef GenericScopedLock <CriticalSection> ScopedLockType;
|
|
|
|
/** Provides the type of scoped unlocker to use with a CriticalSection. */
|
|
typedef GenericScopedUnlock <CriticalSection> ScopedUnlockType;
|
|
|
|
/** Provides the type of scoped try-locker to use with a CriticalSection. */
|
|
typedef GenericScopedTryLock <CriticalSection> ScopedTryLockType;
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Boost concept compatibility
|
|
// http://www.boost.org/doc/libs/1_54_0/doc/html/thread/synchronization.html#thread.synchronization.mutex_concepts
|
|
//
|
|
|
|
// BasicLockable
|
|
inline void lock () const noexcept { enter (); }
|
|
inline void unlock () const noexcept { exit (); }
|
|
|
|
// Lockable
|
|
inline bool try_lock () const noexcept { return tryEnter (); }
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
private:
|
|
//==============================================================================
|
|
#if BEAST_WINDOWS
|
|
// To avoid including windows.h in the public Beast headers, we'll just allocate
|
|
// a block of memory here that's big enough to be used internally as a windows
|
|
// CRITICAL_SECTION structure.
|
|
#if BEAST_64BIT
|
|
std::uint8_t section[44];
|
|
#else
|
|
std::uint8_t section[24];
|
|
#endif
|
|
#else
|
|
mutable pthread_mutex_t mutex;
|
|
#endif
|
|
};
|
|
|
|
//==============================================================================
|
|
/**
|
|
A class that can be used in place of a real CriticalSection object, but which
|
|
doesn't perform any locking.
|
|
|
|
This is currently used by some templated classes, and most compilers should
|
|
manage to optimise it out of existence.
|
|
|
|
@see CriticalSection, Array, SharedObjectArray
|
|
*/
|
|
class DummyCriticalSection
|
|
{
|
|
public:
|
|
DummyCriticalSection() = default;
|
|
DummyCriticalSection (DummyCriticalSection const&) = delete;
|
|
DummyCriticalSection& operator= (DummyCriticalSection const&) = delete;
|
|
~DummyCriticalSection() = default;
|
|
|
|
inline void enter() const noexcept {}
|
|
inline bool tryEnter() const noexcept { return true; }
|
|
inline void exit() const noexcept {}
|
|
|
|
//==============================================================================
|
|
/** A dummy scoped-lock type to use with a dummy critical section. */
|
|
struct ScopedLockType
|
|
{
|
|
ScopedLockType (const DummyCriticalSection&) noexcept {}
|
|
};
|
|
|
|
/** A dummy scoped-unlocker type to use with a dummy critical section. */
|
|
typedef ScopedLockType ScopedUnlockType;
|
|
};
|
|
|
|
//==============================================================================
|
|
/**
|
|
Automatically locks and unlocks a CriticalSection object.
|
|
|
|
Use one of these as a local variable to provide RAII-based locking of a CriticalSection.
|
|
|
|
e.g. @code
|
|
|
|
CriticalSection myCriticalSection;
|
|
|
|
for (;;)
|
|
{
|
|
const ScopedLock myScopedLock (myCriticalSection);
|
|
// myCriticalSection is now locked
|
|
|
|
...do some stuff...
|
|
|
|
// myCriticalSection gets unlocked here.
|
|
}
|
|
@endcode
|
|
|
|
@see CriticalSection, ScopedUnlock
|
|
*/
|
|
typedef CriticalSection::ScopedLockType ScopedLock;
|
|
|
|
//==============================================================================
|
|
/**
|
|
Automatically unlocks and re-locks a CriticalSection object.
|
|
|
|
This is the reverse of a ScopedLock object - instead of locking the critical
|
|
section for the lifetime of this object, it unlocks it.
|
|
|
|
Make sure you don't try to unlock critical sections that aren't actually locked!
|
|
|
|
e.g. @code
|
|
|
|
CriticalSection myCriticalSection;
|
|
|
|
for (;;)
|
|
{
|
|
const ScopedLock myScopedLock (myCriticalSection);
|
|
// myCriticalSection is now locked
|
|
|
|
... do some stuff with it locked ..
|
|
|
|
while (xyz)
|
|
{
|
|
... do some stuff with it locked ..
|
|
|
|
const ScopedUnlock unlocker (myCriticalSection);
|
|
|
|
// myCriticalSection is now unlocked for the remainder of this block,
|
|
// and re-locked at the end.
|
|
|
|
...do some stuff with it unlocked ...
|
|
}
|
|
|
|
// myCriticalSection gets unlocked here.
|
|
}
|
|
@endcode
|
|
|
|
@see CriticalSection, ScopedLock
|
|
*/
|
|
typedef CriticalSection::ScopedUnlockType ScopedUnlock;
|
|
|
|
//==============================================================================
|
|
/**
|
|
Automatically tries to lock and unlock a CriticalSection object.
|
|
|
|
Use one of these as a local variable to control access to a CriticalSection.
|
|
|
|
e.g. @code
|
|
CriticalSection myCriticalSection;
|
|
|
|
for (;;)
|
|
{
|
|
const ScopedTryLock myScopedTryLock (myCriticalSection);
|
|
|
|
// Unlike using a ScopedLock, this may fail to actually get the lock, so you
|
|
// should test this with the isLocked() method before doing your thread-unsafe
|
|
// action..
|
|
if (myScopedTryLock.isLocked())
|
|
{
|
|
...do some stuff...
|
|
}
|
|
else
|
|
{
|
|
..our attempt at locking failed because another thread had already locked it..
|
|
}
|
|
|
|
// myCriticalSection gets unlocked here (if it was locked)
|
|
}
|
|
@endcode
|
|
|
|
@see CriticalSection::tryEnter, ScopedLock, ScopedUnlock, ScopedReadLock
|
|
*/
|
|
typedef CriticalSection::ScopedTryLockType ScopedTryLock;
|
|
|
|
} // beast
|
|
|
|
#endif // BEAST_CRITICALSECTION_H_INCLUDED
|