vtk-m/vtkm/cont/Token.cxx
Kenneth Moreland 6b089be03e Add ArrayPortalToken object and implement Read/WritePortal
To get a portal to access ArrayHandle values in the control
environment, you now use the ReadPortal and WritePortal methods.
The portals returned are wrapped in an ArrayPortalToken object
so that the data between the portal and the ArrayHandle are
guaranteed to be consistent.
2020-02-26 13:10:37 -07:00

139 lines
3.7 KiB
C++

//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#include <vtkm/cont/Token.h>
#include <list>
using LockType = std::unique_lock<std::mutex>;
class vtkm::cont::Token::InternalStruct
{
std::mutex Mutex;
std::list<vtkm::cont::Token::HeldReference> HeldReferences;
VTKM_CONT void CheckLock(const LockType& lock) const
{
VTKM_ASSERT((lock.mutex() == &this->Mutex) && (lock.owns_lock()));
}
public:
LockType GetLock() { return LockType(this->Mutex); }
std::list<vtkm::cont::Token::HeldReference>* GetHeldReferences(const LockType& lock)
{
this->CheckLock(lock);
return &this->HeldReferences;
}
};
struct vtkm::cont::Token::HeldReference
{
std::unique_ptr<vtkm::cont::Token::ObjectReference> ObjectReference;
vtkm::cont::Token::ReferenceCount* ReferenceCountPointer;
std::mutex* MutexPointer;
std::condition_variable* ConditionVariablePointer;
HeldReference(std::unique_ptr<vtkm::cont::Token::ObjectReference>&& objRef,
vtkm::cont::Token::ReferenceCount* refCountP,
std::mutex* mutexP,
std::condition_variable* conditionVariableP)
: ObjectReference(std::move(objRef))
, ReferenceCountPointer(refCountP)
, MutexPointer(mutexP)
, ConditionVariablePointer(conditionVariableP)
{
}
};
vtkm::cont::Token::Token()
{
}
vtkm::cont::Token::Token(Token&& rhs)
: Internals(std::move(rhs.Internals))
{
}
vtkm::cont::Token::~Token()
{
this->DetachFromAll();
}
void vtkm::cont::Token::DetachFromAll()
{
if (!this->Internals)
{
// If internals is NULL, then we are not attached to anything.
return;
}
LockType localLock = this->Internals->GetLock();
auto heldReferences = this->Internals->GetHeldReferences(localLock);
for (auto&& held : *heldReferences)
{
LockType objectLock(*held.MutexPointer);
*held.ReferenceCountPointer -= 1;
objectLock.unlock();
held.ConditionVariablePointer->notify_all();
}
heldReferences->clear();
}
void vtkm::cont::Token::Attach(std::unique_ptr<vtkm::cont::Token::ObjectReference>&& objectRef,
vtkm::cont::Token::ReferenceCount* referenceCountPointer,
std::unique_lock<std::mutex>& lock,
std::condition_variable* conditionVariablePointer)
{
if (!this->Internals)
{
this->Internals.reset(new InternalStruct);
}
LockType localLock = this->Internals->GetLock();
if (this->IsAttached(localLock, referenceCountPointer))
{
// Already attached.
return;
}
if (!lock.owns_lock())
{
lock.lock();
}
*referenceCountPointer += 1;
this->Internals->GetHeldReferences(localLock)->emplace_back(
std::move(objectRef), referenceCountPointer, lock.mutex(), conditionVariablePointer);
}
inline bool vtkm::cont::Token::IsAttached(
LockType& lock,
vtkm::cont::Token::ReferenceCount* referenceCountPointer) const
{
if (!this->Internals)
{
return false;
}
for (auto&& heldReference : *this->Internals->GetHeldReferences(lock))
{
if (referenceCountPointer == heldReference.ReferenceCountPointer)
{
return true;
}
}
return false;
}
bool vtkm::cont::Token::IsAttached(vtkm::cont::Token::ReferenceCount* referenceCountPointer) const
{
if (!this->Internals)
{
return false;
}
LockType lock = this->Internals->GetLock();
return this->IsAttached(lock, referenceCountPointer);
}