mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-16 05:42:32 +00:00
Move doc lock/unlock logic to a new RWLock class
This commit is contained in:
parent
341fb89053
commit
6e94f68ebb
@ -324,6 +324,7 @@ add_library(app-lib
|
|||||||
res/palettes_loader_delegate.cpp
|
res/palettes_loader_delegate.cpp
|
||||||
res/resources_loader.cpp
|
res/resources_loader.cpp
|
||||||
resource_finder.cpp
|
resource_finder.cpp
|
||||||
|
rw_lock.cpp
|
||||||
script/app_object.cpp
|
script/app_object.cpp
|
||||||
script/app_scripting.cpp
|
script/app_scripting.cpp
|
||||||
script/console_object.cpp
|
script/console_object.cpp
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2001-2015 David Capello
|
// Copyright (C) 2001-2016 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -44,7 +44,7 @@ void ContextFlags::update(Context* context)
|
|||||||
|
|
||||||
updateFlagsFromSite(site);
|
updateFlagsFromSite(site);
|
||||||
|
|
||||||
if (document->lockToWrite(0))
|
if (document->upgradeToWrite(0))
|
||||||
m_flags |= ActiveDocumentIsWritable;
|
m_flags |= ActiveDocumentIsWritable;
|
||||||
|
|
||||||
document->unlock();
|
document->unlock();
|
||||||
|
@ -8,10 +8,6 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Uncomment this line in case that you want TRACE() lock/unlock
|
|
||||||
// operations.
|
|
||||||
//#define DEBUG_DOCUMENT_LOCKS
|
|
||||||
|
|
||||||
#include "app/document.h"
|
#include "app/document.h"
|
||||||
|
|
||||||
#include "app/app.h"
|
#include "app/app.h"
|
||||||
@ -25,9 +21,6 @@
|
|||||||
#include "app/pref/preferences.h"
|
#include "app/pref/preferences.h"
|
||||||
#include "app/util/create_cel_copy.h"
|
#include "app/util/create_cel_copy.h"
|
||||||
#include "base/memory.h"
|
#include "base/memory.h"
|
||||||
#include "base/mutex.h"
|
|
||||||
#include "base/scoped_lock.h"
|
|
||||||
#include "base/thread.h"
|
|
||||||
#include "base/unique_ptr.h"
|
#include "base/unique_ptr.h"
|
||||||
#include "doc/cel.h"
|
#include "doc/cel.h"
|
||||||
#include "doc/context.h"
|
#include "doc/context.h"
|
||||||
@ -50,8 +43,6 @@ using namespace doc;
|
|||||||
Document::Document(Sprite* sprite)
|
Document::Document(Sprite* sprite)
|
||||||
: m_undo(new DocumentUndo)
|
: m_undo(new DocumentUndo)
|
||||||
, m_associated_to_file(false)
|
, m_associated_to_file(false)
|
||||||
, m_write_lock(false)
|
|
||||||
, m_read_locks(0)
|
|
||||||
// Information about the file format used to load/save this document
|
// Information about the file format used to load/save this document
|
||||||
, m_format_options(NULL)
|
, m_format_options(NULL)
|
||||||
// Mask
|
// Mask
|
||||||
@ -439,130 +430,6 @@ Document* Document::duplicate(DuplicateType type) const
|
|||||||
return documentCopy.release();
|
return documentCopy.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// Multi-threading ("sprite wrappers" use this)
|
|
||||||
|
|
||||||
bool Document::lock(LockType lockType, int timeout)
|
|
||||||
{
|
|
||||||
while (timeout >= 0) {
|
|
||||||
{
|
|
||||||
scoped_lock lock(m_mutex);
|
|
||||||
switch (lockType) {
|
|
||||||
|
|
||||||
case ReadLock:
|
|
||||||
// If no body is writting the sprite...
|
|
||||||
if (!m_write_lock) {
|
|
||||||
// We can read it
|
|
||||||
++m_read_locks;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WriteLock:
|
|
||||||
// If no body is reading and writting...
|
|
||||||
if (m_read_locks == 0 && !m_write_lock) {
|
|
||||||
// We can start writting the sprite...
|
|
||||||
m_write_lock = true;
|
|
||||||
|
|
||||||
#ifdef DEBUG_DOCUMENT_LOCKS
|
|
||||||
TRACE("DOC: Document::lock: Locked <%d> to write\n", id());
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeout > 0) {
|
|
||||||
int delay = MIN(100, timeout);
|
|
||||||
timeout -= delay;
|
|
||||||
|
|
||||||
#ifdef DEBUG_DOCUMENT_LOCKS
|
|
||||||
TRACE("DOC: Document::lock: wait 100 msecs for <%d>\n", id());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
base::this_thread::sleep_for(double(delay) / 1000.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_DOCUMENT_LOCKS
|
|
||||||
TRACE("DOC: Document::lock: Cannot lock <%d> to %s (has %d read locks and %d write locks)\n",
|
|
||||||
id(), (lockType == ReadLock ? "read": "write"), m_read_locks, m_write_lock);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Document::lockToWrite(int timeout)
|
|
||||||
{
|
|
||||||
while (timeout >= 0) {
|
|
||||||
{
|
|
||||||
scoped_lock lock(m_mutex);
|
|
||||||
// this only is possible if there are just one reader
|
|
||||||
if (m_read_locks == 1) {
|
|
||||||
ASSERT(!m_write_lock);
|
|
||||||
m_read_locks = 0;
|
|
||||||
m_write_lock = true;
|
|
||||||
|
|
||||||
#ifdef DEBUG_DOCUMENT_LOCKS
|
|
||||||
TRACE("DOC: Document::lockToWrite: Locked <%d> to write\n", id());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeout > 0) {
|
|
||||||
int delay = MIN(100, timeout);
|
|
||||||
timeout -= delay;
|
|
||||||
|
|
||||||
#ifdef DEBUG_DOCUMENT_LOCKS
|
|
||||||
TRACE("DOC: Document::lockToWrite: wait 100 msecs for <%d>\n", id());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
base::this_thread::sleep_for(double(delay) / 1000.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_DOCUMENT_LOCKS
|
|
||||||
TRACE("DOC: Document::lockToWrite: Cannot lock <%d> to write (has %d read locks and %d write locks)\n",
|
|
||||||
id(), m_read_locks, m_write_lock);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Document::unlockToRead()
|
|
||||||
{
|
|
||||||
scoped_lock lock(m_mutex);
|
|
||||||
|
|
||||||
ASSERT(m_read_locks == 0);
|
|
||||||
ASSERT(m_write_lock);
|
|
||||||
|
|
||||||
m_write_lock = false;
|
|
||||||
m_read_locks = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Document::unlock()
|
|
||||||
{
|
|
||||||
scoped_lock lock(m_mutex);
|
|
||||||
|
|
||||||
if (m_write_lock) {
|
|
||||||
m_write_lock = false;
|
|
||||||
}
|
|
||||||
else if (m_read_locks > 0) {
|
|
||||||
--m_read_locks;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ASSERT(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Document::onContextChanged()
|
void Document::onContextChanged()
|
||||||
{
|
{
|
||||||
m_undo->setContext(context());
|
m_undo->setContext(context());
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "app/extra_cel.h"
|
#include "app/extra_cel.h"
|
||||||
#include "app/file/format_options.h"
|
#include "app/file/format_options.h"
|
||||||
|
#include "app/rw_lock.h"
|
||||||
#include "app/transformation.h"
|
#include "app/transformation.h"
|
||||||
#include "base/disable_copying.h"
|
#include "base/disable_copying.h"
|
||||||
#include "base/mutex.h"
|
#include "base/mutex.h"
|
||||||
@ -50,13 +51,9 @@ namespace app {
|
|||||||
|
|
||||||
// An application document. It is the class used to contain one file
|
// An application document. It is the class used to contain one file
|
||||||
// opened and being edited by the user (a sprite).
|
// opened and being edited by the user (a sprite).
|
||||||
class Document : public doc::Document {
|
class Document : public doc::Document,
|
||||||
|
public RWLock {
|
||||||
public:
|
public:
|
||||||
enum LockType {
|
|
||||||
ReadLock,
|
|
||||||
WriteLock
|
|
||||||
};
|
|
||||||
|
|
||||||
Document(Sprite* sprite);
|
Document(Sprite* sprite);
|
||||||
~Document();
|
~Document();
|
||||||
|
|
||||||
@ -157,23 +154,6 @@ namespace app {
|
|||||||
void copyLayerContent(const Layer* sourceLayer, Document* destDoc, Layer* destLayer) const;
|
void copyLayerContent(const Layer* sourceLayer, Document* destDoc, Layer* destLayer) const;
|
||||||
Document* duplicate(DuplicateType type) const;
|
Document* duplicate(DuplicateType type) const;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// Multi-threading ("sprite wrappers" use this)
|
|
||||||
|
|
||||||
// Locks the sprite to read or write on it, returning true if the
|
|
||||||
// sprite can be accessed in the desired mode.
|
|
||||||
bool lock(LockType lockType, int timeout);
|
|
||||||
|
|
||||||
// If you've locked the sprite to read, using this method you can
|
|
||||||
// raise your access level to write it.
|
|
||||||
bool lockToWrite(int timeout);
|
|
||||||
|
|
||||||
// If you've locked the sprite to write, using this method you can
|
|
||||||
// your access level to only read it.
|
|
||||||
void unlockToRead();
|
|
||||||
|
|
||||||
void unlock();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void onContextChanged() override;
|
virtual void onContextChanged() override;
|
||||||
|
|
||||||
@ -187,15 +167,6 @@ namespace app {
|
|||||||
// Selected mask region boundaries
|
// Selected mask region boundaries
|
||||||
base::UniquePtr<doc::MaskBoundaries> m_maskBoundaries;
|
base::UniquePtr<doc::MaskBoundaries> m_maskBoundaries;
|
||||||
|
|
||||||
// Mutex to modify the 'locked' flag.
|
|
||||||
base::mutex m_mutex;
|
|
||||||
|
|
||||||
// True if some thread is writing the sprite.
|
|
||||||
bool m_write_lock;
|
|
||||||
|
|
||||||
// Greater than zero when one or more threads are reading the sprite.
|
|
||||||
int m_read_locks;
|
|
||||||
|
|
||||||
// Data to save the file in the same format that it was loaded
|
// Data to save the file in the same format that it was loaded
|
||||||
base::SharedPtr<FormatOptions> m_format_options;
|
base::SharedPtr<FormatOptions> m_format_options;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2001-2015 David Capello
|
// Copyright (C) 2001-2016 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
|
// TODO remove exceptions and use "DocumentAccess::operator bool()"
|
||||||
class LockedDocumentException : public base::Exception {
|
class LockedDocumentException : public base::Exception {
|
||||||
public:
|
public:
|
||||||
LockedDocumentException(const char* msg) throw()
|
LockedDocumentException(const char* msg) throw()
|
||||||
@ -141,7 +142,7 @@ namespace app {
|
|||||||
, m_from_reader(true)
|
, m_from_reader(true)
|
||||||
, m_locked(false) {
|
, m_locked(false) {
|
||||||
if (m_document) {
|
if (m_document) {
|
||||||
if (!m_document->lockToWrite(timeout))
|
if (!m_document->upgradeToWrite(timeout))
|
||||||
throw CannotWriteDocumentException();
|
throw CannotWriteDocumentException();
|
||||||
|
|
||||||
m_locked = true;
|
m_locked = true;
|
||||||
@ -156,7 +157,7 @@ namespace app {
|
|||||||
void unlock() {
|
void unlock() {
|
||||||
if (m_document && m_locked) {
|
if (m_document && m_locked) {
|
||||||
if (m_from_reader)
|
if (m_from_reader)
|
||||||
m_document->unlockToRead();
|
m_document->downgradeToRead();
|
||||||
else
|
else
|
||||||
m_document->unlock();
|
m_document->unlock();
|
||||||
|
|
||||||
|
157
src/app/rw_lock.cpp
Normal file
157
src/app/rw_lock.cpp
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2001-2016 David Capello
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Uncomment this line in case that you want TRACE() lock/unlock
|
||||||
|
// operations.
|
||||||
|
//#define DEBUG_OBJECT_LOCKS
|
||||||
|
|
||||||
|
#include "app/document.h"
|
||||||
|
|
||||||
|
#include "base/scoped_lock.h"
|
||||||
|
#include "base/thread.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
using namespace base;
|
||||||
|
|
||||||
|
RWLock::RWLock()
|
||||||
|
: m_write_lock(false)
|
||||||
|
, m_read_locks(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RWLock::~RWLock()
|
||||||
|
{
|
||||||
|
ASSERT(!m_write_lock);
|
||||||
|
ASSERT(m_read_locks == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RWLock::lock(LockType lockType, int timeout)
|
||||||
|
{
|
||||||
|
while (timeout >= 0) {
|
||||||
|
{
|
||||||
|
scoped_lock lock(m_mutex);
|
||||||
|
switch (lockType) {
|
||||||
|
|
||||||
|
case ReadLock:
|
||||||
|
// If no body is writting the object...
|
||||||
|
if (!m_write_lock) {
|
||||||
|
// We can read it
|
||||||
|
++m_read_locks;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WriteLock:
|
||||||
|
// If no body is reading and writting...
|
||||||
|
if (m_read_locks == 0 && !m_write_lock) {
|
||||||
|
// We can start writting the object...
|
||||||
|
m_write_lock = true;
|
||||||
|
|
||||||
|
#ifdef DEBUG_OBJECT_LOCKS
|
||||||
|
TRACE("LCK: lock: Locked <%p> to write\n", this);
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout > 0) {
|
||||||
|
int delay = MIN(100, timeout);
|
||||||
|
timeout -= delay;
|
||||||
|
|
||||||
|
#ifdef DEBUG_OBJECT_LOCKS
|
||||||
|
TRACE("LCK: lock: wait 100 msecs for <%p>\n", this);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
base::this_thread::sleep_for(double(delay) / 1000.0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_OBJECT_LOCKS
|
||||||
|
TRACE("LCK: lock: Cannot lock <%p> to %s (has %d read locks and %d write locks)\n",
|
||||||
|
this, (lockType == ReadLock ? "read": "write"), m_read_locks, m_write_lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RWLock::upgradeToWrite(int timeout)
|
||||||
|
{
|
||||||
|
while (timeout >= 0) {
|
||||||
|
{
|
||||||
|
scoped_lock lock(m_mutex);
|
||||||
|
// this only is possible if there are just one reader
|
||||||
|
if (m_read_locks == 1) {
|
||||||
|
ASSERT(!m_write_lock);
|
||||||
|
m_read_locks = 0;
|
||||||
|
m_write_lock = true;
|
||||||
|
|
||||||
|
#ifdef DEBUG_OBJECT_LOCKS
|
||||||
|
TRACE("LCK: upgradeToWrite: Locked <%p> to write\n", this);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout > 0) {
|
||||||
|
int delay = MIN(100, timeout);
|
||||||
|
timeout -= delay;
|
||||||
|
|
||||||
|
#ifdef DEBUG_OBJECT_LOCKS
|
||||||
|
TRACE("LCK: upgradeToWrite: wait 100 msecs for <%p>\n", this);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
base::this_thread::sleep_for(double(delay) / 1000.0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_OBJECT_LOCKS
|
||||||
|
TRACE("LCK: upgradeToWrite: Cannot lock <%p> to write (has %d read locks and %d write locks)\n",
|
||||||
|
this, m_read_locks, m_write_lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWLock::downgradeToRead()
|
||||||
|
{
|
||||||
|
scoped_lock lock(m_mutex);
|
||||||
|
|
||||||
|
ASSERT(m_read_locks == 0);
|
||||||
|
ASSERT(m_write_lock);
|
||||||
|
|
||||||
|
m_write_lock = false;
|
||||||
|
m_read_locks = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RWLock::unlock()
|
||||||
|
{
|
||||||
|
scoped_lock lock(m_mutex);
|
||||||
|
|
||||||
|
if (m_write_lock) {
|
||||||
|
m_write_lock = false;
|
||||||
|
}
|
||||||
|
else if (m_read_locks > 0) {
|
||||||
|
--m_read_locks;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
57
src/app/rw_lock.h
Normal file
57
src/app/rw_lock.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2001-2016 David Capello
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifndef APP_RW_LOCK_H_INCLUDED
|
||||||
|
#define APP_RW_LOCK_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "base/disable_copying.h"
|
||||||
|
#include "base/mutex.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
// A readers-writer lock implementation
|
||||||
|
class RWLock {
|
||||||
|
public:
|
||||||
|
enum LockType {
|
||||||
|
ReadLock,
|
||||||
|
WriteLock
|
||||||
|
};
|
||||||
|
|
||||||
|
RWLock();
|
||||||
|
~RWLock();
|
||||||
|
|
||||||
|
// Locks the object to read or write on it, returning true if the
|
||||||
|
// object can be accessed in the desired mode.
|
||||||
|
bool lock(LockType lockType, int timeout);
|
||||||
|
|
||||||
|
// If you've locked the object to read, using this method you can
|
||||||
|
// raise your access level to write it.
|
||||||
|
bool upgradeToWrite(int timeout);
|
||||||
|
|
||||||
|
// If we've locked the object to write, using this method we can
|
||||||
|
// lower our access to read-only.
|
||||||
|
void downgradeToRead();
|
||||||
|
|
||||||
|
// Unlocks a previously successfully lock() operation.
|
||||||
|
void unlock();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Mutex to modify the 'locked' flag.
|
||||||
|
base::mutex m_mutex;
|
||||||
|
|
||||||
|
// True if some thread is writing the object.
|
||||||
|
bool m_write_lock;
|
||||||
|
|
||||||
|
// Greater than zero when one or more threads are reading the object.
|
||||||
|
int m_read_locks;
|
||||||
|
|
||||||
|
DISABLE_COPYING(RWLock);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif
|
61
src/app/rw_lock_tests.cpp
Normal file
61
src/app/rw_lock_tests.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2001-2016 David Capello
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#include "tests/test.h"
|
||||||
|
|
||||||
|
#include "app/rw_lock.h"
|
||||||
|
|
||||||
|
using namespace app;
|
||||||
|
|
||||||
|
TEST(RWLock, MultipleReaders)
|
||||||
|
{
|
||||||
|
RWLock a;
|
||||||
|
EXPECT_TRUE(a.lock(RWLock::ReadLock, 0));
|
||||||
|
EXPECT_TRUE(a.lock(RWLock::ReadLock, 0));
|
||||||
|
EXPECT_TRUE(a.lock(RWLock::ReadLock, 0));
|
||||||
|
EXPECT_TRUE(a.lock(RWLock::ReadLock, 0));
|
||||||
|
EXPECT_FALSE(a.lock(RWLock::WriteLock, 0));
|
||||||
|
a.unlock();
|
||||||
|
a.unlock();
|
||||||
|
a.unlock();
|
||||||
|
a.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(RWLock, OneWriter)
|
||||||
|
{
|
||||||
|
RWLock a;
|
||||||
|
|
||||||
|
EXPECT_TRUE(a.lock(RWLock::WriteLock, 0));
|
||||||
|
EXPECT_FALSE(a.lock(RWLock::ReadLock, 0));
|
||||||
|
a.unlock();
|
||||||
|
|
||||||
|
EXPECT_TRUE(a.lock(RWLock::ReadLock, 0));
|
||||||
|
EXPECT_FALSE(a.lock(RWLock::WriteLock, 0));
|
||||||
|
a.unlock();
|
||||||
|
|
||||||
|
EXPECT_TRUE(a.lock(RWLock::ReadLock, 0));
|
||||||
|
EXPECT_TRUE(a.lock(RWLock::ReadLock, 0));
|
||||||
|
EXPECT_FALSE(a.lock(RWLock::WriteLock, 0));
|
||||||
|
a.unlock();
|
||||||
|
EXPECT_FALSE(a.lock(RWLock::WriteLock, 0));
|
||||||
|
a.unlock();
|
||||||
|
EXPECT_TRUE(a.lock(RWLock::WriteLock, 0));
|
||||||
|
EXPECT_FALSE(a.lock(RWLock::WriteLock, 0));
|
||||||
|
a.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(RWLock, UpgradeToWrite)
|
||||||
|
{
|
||||||
|
RWLock a;
|
||||||
|
|
||||||
|
EXPECT_TRUE(a.lock(RWLock::ReadLock, 0));
|
||||||
|
EXPECT_FALSE(a.lock(RWLock::WriteLock, 0));
|
||||||
|
EXPECT_TRUE(a.upgradeToWrite(0));
|
||||||
|
EXPECT_FALSE(a.lock(RWLock::ReadLock, 0));
|
||||||
|
EXPECT_FALSE(a.lock(RWLock::WriteLock, 0));
|
||||||
|
a.downgradeToRead();
|
||||||
|
a.unlock();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user