110 lines
3.8 KiB
C++
110 lines
3.8 KiB
C++
/*
|
|
==============================================================================
|
|
|
|
This file is part of the Water library.
|
|
Copyright (c) 2016 ROLI Ltd.
|
|
Copyright (C) 2017 Filipe Coelho <falktx@falktx.com>
|
|
|
|
Permission is granted to use this software under the terms of the ISC license
|
|
http://www.isc.org/downloads/software-support-policy/isc-license/
|
|
|
|
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 ISC DISCLAIMS ALL WARRANTIES WITH REGARD
|
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS. IN NO EVENT SHALL ISC 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 WATER_SPINLOCK_HPP_INCLUDED
|
|
#define WATER_SPINLOCK_HPP_INCLUDED
|
|
|
|
#include "Atomic.hpp"
|
|
#include "ScopedLock.hpp"
|
|
|
|
START_NAMESPACE_DISTRHO
|
|
|
|
//==============================================================================
|
|
/**
|
|
A simple spin-lock class that can be used as a simple, low-overhead mutex for
|
|
uncontended situations.
|
|
|
|
Note that unlike a CriticalSection, this type of lock is not re-entrant, and may
|
|
be less efficient when used it a highly contended situation, but it's very small and
|
|
requires almost no initialisation.
|
|
It's most appropriate for simple situations where you're only going to hold the
|
|
lock for a very brief time.
|
|
|
|
@see CriticalSection
|
|
*/
|
|
class SpinLock
|
|
{
|
|
public:
|
|
inline SpinLock() noexcept : lock() {}
|
|
inline ~SpinLock() noexcept {}
|
|
|
|
/** Acquires the lock.
|
|
This will block until the lock has been successfully acquired by this thread.
|
|
Note that a SpinLock is NOT re-entrant, and is not smart enough to know whether the
|
|
caller thread already has the lock - so if a thread tries to acquire a lock that it
|
|
already holds, this method will never return!
|
|
|
|
It's strongly recommended that you never call this method directly - instead use the
|
|
ScopedLockType class to manage the locking using an RAII pattern instead.
|
|
*/
|
|
void enter() const noexcept
|
|
{
|
|
if (! tryEnter())
|
|
{
|
|
for (int i = 20; --i >= 0;)
|
|
if (tryEnter())
|
|
return;
|
|
|
|
while (! tryEnter())
|
|
{
|
|
#ifdef DISTRHO_OS_WINDOWS
|
|
Sleep (0);
|
|
#else
|
|
sched_yield();
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Attempts to acquire the lock, returning true if this was successful. */
|
|
inline bool tryEnter() const noexcept
|
|
{
|
|
return lock.compareAndSetBool (1, 0);
|
|
}
|
|
|
|
/** Releases the lock. */
|
|
inline void exit() const noexcept
|
|
{
|
|
DISTRHO_SAFE_ASSERT_RETURN (lock.get() == 1,);
|
|
lock = 0;
|
|
}
|
|
|
|
//==============================================================================
|
|
/** Provides the type of scoped lock to use for locking a SpinLock. */
|
|
typedef GenericScopedLock <SpinLock> ScopedLockType;
|
|
|
|
/** Provides the type of scoped unlocker to use with a SpinLock. */
|
|
typedef GenericScopedUnlock <SpinLock> ScopedUnlockType;
|
|
|
|
private:
|
|
//==============================================================================
|
|
mutable Atomic<int> lock;
|
|
|
|
DISTRHO_DECLARE_NON_COPYABLE (SpinLock)
|
|
};
|
|
|
|
END_NAMESPACE_DISTRHO
|
|
|
|
#endif // WATER_SPINLOCK_HPP_INCLUDED
|