sdm: Enhance fence utility class

- Add scope reference for client to access native fd associated
  with fence in limited scope.
- Assert if buffer sync handler is not set by the client.
- Add sync status enumeration.

CRs-Fixed: 2579548
Change-Id: Id91826cd9e2be5bcffd82fcc4a66f551fcdda70b
diff --git a/sdm/include/utils/fence.h b/sdm/include/utils/fence.h
index 94bb01b..acc381f 100644
--- a/sdm/include/utils/fence.h
+++ b/sdm/include/utils/fence.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+* 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
@@ -35,6 +35,7 @@
 #include <utility>
 #include <memory>
 #include <string>
+#include <vector>
 
 namespace sdm {
 
@@ -43,8 +44,27 @@
 
 class Fence {
  public:
+  enum class Status : int32_t {
+    kSignaled = 0,
+    kPending
+  };
+
+  // This class methods allow client to get access to the native file descriptor of fence object
+  // during the scope of this class object. Underlying file descriptor is duped and returned to
+  // the client. Duped file descriptors are closed as soon as scope ends. Client can get access
+  // to multiple fences using the same scoped reference.
+  class ScopedRef {
+   public:
+    ~ScopedRef();
+    int Get(const shared_ptr<Fence> &fence);
+
+   private:
+    std::vector<int> dup_fds_ = {};
+  };
+
   ~Fence();
 
+  // Must be set once before using any other method of this class.
   static void Set(BufferSyncHandler *buffer_sync_handler);
 
   // Ownership of the file descriptor is transferred to this method.
@@ -56,8 +76,14 @@
   static int Dup(const shared_ptr<Fence> &fence);
 
   static shared_ptr<Fence> Merge(const shared_ptr<Fence> &fence1, const shared_ptr<Fence> &fence2);
+
+  // Wait on null fence will return success.
   static DisplayError Wait(const shared_ptr<Fence> &fence);
   static DisplayError Wait(const shared_ptr<Fence> &fence, int timeout);
+
+  // Status check on null fence will return signaled.
+  static Status GetStatus(const shared_ptr<Fence> &fence);
+
   static string GetStr(const shared_ptr<Fence> &fence);
 
  private:
diff --git a/sdm/libs/utils/fence.cpp b/sdm/libs/utils/fence.cpp
index 3cf26e4..bb0d541 100644
--- a/sdm/libs/utils/fence.cpp
+++ b/sdm/libs/utils/fence.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+* 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
@@ -28,12 +28,15 @@
 */
 
 #include <utils/fence.h>
+#include <assert.h>
 #include <string>
 
 #define __CLASS__ "Fence"
 
 namespace sdm {
 
+#define ASSERT_IF_NO_BUFFER_SYNC(x) if (!x) { assert(false); }
+
 BufferSyncHandler* Fence::buffer_sync_handler_ = nullptr;
 
 Fence::Fence(int fd) : fd_(fd) {
@@ -62,18 +65,17 @@
 }
 
 int Fence::Dup(const shared_ptr<Fence> &fence) {
-  if (!fence) {
-    return -1;
-  }
+  return (fence ? dup(fence->fd_) : -1);
+}
 
-  return dup(fence->fd_);
+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) {
-  if (!buffer_sync_handler_) {
-    return nullptr;
-  }
+  ASSERT_IF_NO_BUFFER_SYNC(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;
@@ -84,27 +86,46 @@
 }
 
 DisplayError Fence::Wait(const shared_ptr<Fence> &fence) {
-  if (!buffer_sync_handler_) {
-    return kErrorUndefined;
-  }
+  ASSERT_IF_NO_BUFFER_SYNC(buffer_sync_handler_);
 
-  return buffer_sync_handler_->SyncWait(Fence::Get(fence));
+  return buffer_sync_handler_->SyncWait(Fence::Get(fence), 1000);
 }
 
 DisplayError Fence::Wait(const shared_ptr<Fence> &fence, int timeout) {
-  if (!buffer_sync_handler_) {
-    return kErrorUndefined;
-  }
+  ASSERT_IF_NO_BUFFER_SYNC(buffer_sync_handler_);
 
   return buffer_sync_handler_->SyncWait(Fence::Get(fence), timeout);
 }
 
+Fence::Status Fence::GetStatus(const shared_ptr<Fence> &fence) {
+  ASSERT_IF_NO_BUFFER_SYNC(buffer_sync_handler_);
+
+  if (!fence) {
+    return Fence::Status::kSignaled;
+  }
+
+  // Treat only timeout error as pending, assume other errors as signaled.
+  return (buffer_sync_handler_->SyncWait(Fence::Get(fence), 0) == kErrorTimeOut ?
+                                    Fence::Status::kPending : Fence::Status::kSignaled);
+}
+
 string Fence::GetStr(const shared_ptr<Fence> &fence) {
   return std::to_string(Fence::Get(fence));
 }
 
-int Fence::Get(const shared_ptr<Fence> &fence) {
-  return (fence ? fence->fd_ : -1);
+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