blob: 375e3822c1b13c19fe568738ee35953df30ea037 [file] [log] [blame]
/*
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <utils/fence.h>
#include <core/sdm_types.h>
#include <debug_handler.h>
#include <assert.h>
#include <string>
#include <vector>
#include <algorithm>
#define __CLASS__ "Fence"
namespace sdm {
#define ASSERT_IF_NO_BUFFER_SYNC(x) if (!x) { assert(false); }
BufferSyncHandler* Fence::g_buffer_sync_handler_ = nullptr;
std::vector<std::weak_ptr<Fence>> Fence::wps_;
Fence::Fence(int fd, const string &name) : fd_(fd), name_(name) {
}
Fence::~Fence() {
close(fd_);
// erase all expired weak references.
/*
wps_.erase(std::remove_if(wps_.begin(), wps_.end(), [](const std::weak_ptr<Fence> &wp) {
return wp.expired();
}), wps_.end());
*/
}
void Fence::Set(BufferSyncHandler *buffer_sync_handler) {
g_buffer_sync_handler_ = buffer_sync_handler;
}
shared_ptr<Fence> Fence::Create(int fd, const string &name) {
// Do not create Fence object for invalid fd, so that nullptr can be used for invalid fences.
if (fd < 0) {
return nullptr;
}
shared_ptr<Fence> fence(new Fence(fd, name));
if (!fence) {
close(fd);
}
// wps_.push_back(fence);
return fence;
}
int Fence::Dup(const shared_ptr<Fence> &fence) {
return (fence ? dup(fence->fd_) : -1);
}
int Fence::Get(const shared_ptr<Fence> &fence) {
return (fence ? fence->fd_ : -1);
}
shared_ptr<Fence> Fence::Merge(const shared_ptr<Fence> &fence1, const shared_ptr<Fence> &fence2) {
ASSERT_IF_NO_BUFFER_SYNC(g_buffer_sync_handler_);
// Sync merge will return a new unique fd if source fds are same.
int fd1 = fence1 ? fence1->fd_ : -1;
int fd2 = fence2 ? fence2->fd_ : -1;
int merged = -1;
std::string name = "merged[" + to_string(fd1) + ", " + to_string(fd2) + "]";
g_buffer_sync_handler_->SyncMerge(fd1, fd2, &merged);
return Create(merged, name);
}
shared_ptr<Fence> Fence::Merge(const std::vector<shared_ptr<Fence>> &fences, bool ignore_signaled) {
ASSERT_IF_NO_BUFFER_SYNC(g_buffer_sync_handler_);
shared_ptr<Fence> merged_fence = nullptr;
for (auto &fence : fences) {
if (ignore_signaled && (Fence::Wait(fence, 0) == kErrorNone)) {
continue;
}
merged_fence = Fence::Merge(fence, merged_fence);
}
return merged_fence;
}
int Fence::Wait(const shared_ptr<Fence> &fence) {
ASSERT_IF_NO_BUFFER_SYNC(g_buffer_sync_handler_);
return g_buffer_sync_handler_->SyncWait(Fence::Get(fence), 1000);
}
int Fence::Wait(const shared_ptr<Fence> &fence, int timeout) {
ASSERT_IF_NO_BUFFER_SYNC(g_buffer_sync_handler_);
return g_buffer_sync_handler_->SyncWait(Fence::Get(fence), timeout);
}
Fence::Status Fence::GetStatus(const shared_ptr<Fence> &fence) {
ASSERT_IF_NO_BUFFER_SYNC(g_buffer_sync_handler_);
if (!fence) {
return Fence::Status::kSignaled;
}
// Treat only timeout error as pending, assume other errors as signaled.
return (g_buffer_sync_handler_->SyncWait(Fence::Get(fence), 0) == -ETIME ?
Fence::Status::kPending : Fence::Status::kSignaled);
}
string Fence::GetStr(const shared_ptr<Fence> &fence) {
return std::to_string(Fence::Get(fence));
}
void Fence::Dump(std::ostringstream *os) {
ASSERT_IF_NO_BUFFER_SYNC(g_buffer_sync_handler_);
*os << "\n------------Active Fences Info---------";
/*
for (auto &wp : wps_) {
*os << "\n";
shared_ptr<Fence> fence = wp.lock();
if (!fence) {
continue;
}
*os << "FD: " << fence->fd_;
*os << ", name: " << fence->name_;
*os << ", use_count: " << fence.use_count() - 1; // Do not count wp lock reference
*os << ", ";
g_buffer_sync_handler_->GetSyncInfo(fence->fd_, os);
}
*/
*os << "\n---------------------------------------\n";
}
Fence::ScopedRef::~ScopedRef() {
for (int dup_fd : dup_fds_) {
close(dup_fd);
}
}
int Fence::ScopedRef::Get(const shared_ptr<Fence> &fence) {
int dup_fd = Fence::Dup(fence);
if (dup_fd >= 0) {
dup_fds_.push_back(dup_fd);
}
return dup_fd;
}
} // namespace sdm