urbackup_backend/btrfs/fuse/nt/resource.cpp
2021-07-05 19:49:25 +02:00

166 lines
3.7 KiB
C++

#include "resource.h"
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <thread>
#include <set>
struct ERESOURCE_INT {
ERESOURCE_INT()
: owner(std::thread::id()),
excl_count(0) {}
std::mutex mutex;
std::condition_variable cond;
std::thread::id owner;
std::set<std::thread::id> shared_threads;
int excl_count;
};
BOOLEAN ExAcquireResourceSharedLite(PERESOURCE Resource, BOOLEAN Wait)
{
std::unique_lock<std::mutex> lock(Resource->res->mutex);
if (Resource->res->owner!= std::thread::id() &&
Resource->res->owner == std::this_thread::get_id())
{
++Resource->res->excl_count;
return TRUE;
}
if (Resource->res->owner == std::thread::id())
{
Resource->res->shared_threads.insert(std::this_thread::get_id());
return TRUE;
}
if (!Wait)
{
return FALSE;
}
while (Resource->res->owner != std::thread::id())
{
Resource->res->cond.wait(lock);
}
Resource->res->shared_threads.insert(std::this_thread::get_id());
return TRUE;
}
BOOLEAN ExAcquireResourceExclusiveLite(PERESOURCE Resource, BOOLEAN Wait)
{
std::unique_lock<std::mutex> lock(Resource->res->mutex);
if (Resource->res->owner!=std::thread::id() &&
Resource->res->owner == std::this_thread::get_id())
{
++Resource->res->excl_count;
return TRUE;
}
if (Resource->res->shared_threads.empty() &&
Resource->res->owner == std::thread::id())
{
Resource->res->owner = std::this_thread::get_id();
Resource->res->excl_count = 1;
return TRUE;
}
if (!Wait)
{
return FALSE;
}
while (!Resource->res->shared_threads.empty() ||
Resource->res->owner != std::thread::id())
{
Resource->res->cond.wait(lock);
}
Resource->res->owner = std::this_thread::get_id();
Resource->res->excl_count = 1;
return TRUE;
}
BOOLEAN ExReleaseResourceLite(PERESOURCE Resource)
{
std::unique_lock<std::mutex> lock(Resource->res->mutex);
if (Resource->res->owner !=std::thread::id() &&
Resource->res->owner == std::this_thread::get_id())
{
if (Resource->res->excl_count > 1)
{
--Resource->res->excl_count;
}
else
{
Resource->res->owner = std::thread::id();
Resource->res->excl_count = 0;
Resource->res->cond.notify_all();
}
}
else
{
Resource->res->shared_threads.erase(std::this_thread::get_id());
if (Resource->res->shared_threads.empty())
{
Resource->res->cond.notify_all();
}
}
return TRUE;
}
void ExConvertExclusiveToSharedLite(PERESOURCE Res)
{
std::unique_lock<std::mutex> lock(Res->res->mutex);
Res->res->owner = std::thread::id();
Res->res->excl_count = 0;
Res->res->shared_threads.insert(std::this_thread::get_id());
}
BOOLEAN ExDeleteResourceLite(PERESOURCE Resource)
{
delete Resource->res;
return TRUE;
}
BOOLEAN ExInitializeResourceLite(PERESOURCE Resource)
{
Resource->res = new ERESOURCE_INT;
return TRUE;
}
BOOLEAN ExIsResourceAcquiredExclusiveLite(PERESOURCE Resource)
{
std::unique_lock<std::mutex> lock(Resource->res->mutex);
return Resource->res->owner != std::thread::id() &&
Resource->res->excl_count > 0 &&
Resource->res->owner == std::this_thread::get_id();
}
void ExReleaseResource(PERESOURCE Resource)
{
ExReleaseResourceLite(Resource);
}
BOOLEAN ExIsResourceAcquiredSharedLite(PERESOURCE Resource)
{
std::unique_lock<std::mutex> lock(Resource->res->mutex);
if (Resource->res->owner != std::thread::id())
{
return Resource->res->owner == std::this_thread::get_id() ? TRUE : FALSE;
}
return Resource->res->shared_threads.find(std::this_thread::get_id()) != Resource->res->shared_threads.end();
}
BOOLEAN ExIsResourceAcquiredExclusive(PERESOURCE Resource)
{
return ExIsResourceAcquiredExclusiveLite(Resource);
}